diff options
Diffstat (limited to 'drivers/net/ethernet')
17 files changed, 449 insertions, 50 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 28e653e9c856..2125903043fb 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -350,6 +350,7 @@ struct adapter_params { unsigned int nsched_cls; /* number of traffic classes */ unsigned int max_ordird_qp; /* Max read depth per RDMA QP */ unsigned int max_ird_adapter; /* Max read depth per adapter */ + bool fr_nsmr_tpte_wr_support; /* FW support for FR_NSMR_TPTE_WR */ }; /* State needed to monitor the forward progress of SGE Ingress DMA activities diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index cf147ca419a8..f320497368f4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3668,6 +3668,12 @@ static int adap_init0(struct adapter *adap) adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0); } + /* See if FW supports FW_RI_FR_NSMR_TPTE_WR work request */ + params[0] = FW_PARAM_DEV(RI_FR_NSMR_TPTE_WR); + ret = t4_query_params(adap, adap->mbox, adap->pf, 0, + 1, params, val); + adap->params.fr_nsmr_tpte_wr_support = (ret == 0 && val[0] != 0); + /* * Get device capabilities so we can determine what resources we need * to manage. diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c index b4b2d20aab3c..0945fa49a5dd 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.c @@ -550,6 +550,7 @@ static void uld_init(struct adapter *adap, struct cxgb4_lld_info *lld) lld->max_ird_adapter = adap->params.max_ird_adapter; lld->ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl; lld->nodeid = dev_to_node(adap->pdev_dev); + lld->fr_nsmr_tpte_wr_support = adap->params.fr_nsmr_tpte_wr_support; } static void uld_attach(struct adapter *adap, unsigned int uld) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 47bd14f602db..2996793b1aaa 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -308,6 +308,7 @@ struct cxgb4_lld_info { unsigned int iscsi_llimit; /* chip's iscsi region llimit */ void **iscsi_ppm; /* iscsi page pod manager */ int nodeid; /* device numa node id */ + bool fr_nsmr_tpte_wr_support; /* FW supports FR_NSMR_TPTE_WR */ }; struct cxgb4_uld_info { diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 4b58b32105f7..8d9e4b7a8e84 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -100,6 +100,7 @@ enum fw_wr_opcodes { FW_RI_RECV_WR = 0x17, FW_RI_BIND_MW_WR = 0x18, FW_RI_FR_NSMR_WR = 0x19, + FW_RI_FR_NSMR_TPTE_WR = 0x20, FW_RI_INV_LSTAG_WR = 0x1a, FW_ISCSI_TX_DATA_WR = 0x45, FW_CRYPTO_LOOKASIDE_WR = 0X6d, @@ -1121,6 +1122,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */ FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, FW_PARAMS_PARAM_DEV_FWCACHE = 0x18, + FW_PARAMS_PARAM_DEV_RI_FR_NSMR_TPTE_WR = 0x1C, }; /* diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c index 751c1264c811..22e141005cd9 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_mac.c @@ -644,21 +644,6 @@ hns_mac_phy_parse_addr(struct device *dev, struct fwnode_handle *fwnode) return addr; } -static int hns_mac_phydev_match(struct device *dev, void *fwnode) -{ - return dev->fwnode == fwnode; -} - -static struct -platform_device *hns_mac_find_platform_device(struct fwnode_handle *fwnode) -{ - struct device *dev; - - dev = bus_find_device(&platform_bus_type, NULL, - fwnode, hns_mac_phydev_match); - return dev ? to_platform_device(dev) : NULL; -} - static int hns_mac_register_phydev(struct mii_bus *mdio, struct hns_mac_cb *mac_cb, u32 addr) @@ -724,7 +709,7 @@ static void hns_mac_register_phy(struct hns_mac_cb *mac_cb) return; /* dev address in adev */ - pdev = hns_mac_find_platform_device(acpi_fwnode_handle(args.adev)); + pdev = hns_dsaf_find_platform_device(acpi_fwnode_handle(args.adev)); mii_bus = platform_get_drvdata(pdev); rc = hns_mac_register_phydev(mii_bus, mac_cb, addr); if (!rc) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c index eb448dff7564..8e5b3f51b47b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c @@ -2780,7 +2780,7 @@ module_platform_driver(g_dsaf_driver); * @enable: false - request reset , true - drop reset * retuen 0 - success , negative -fail */ -int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool enable) +int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset) { struct dsaf_device *dsaf_dev; struct platform_device *pdev; @@ -2809,24 +2809,44 @@ int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool enable) {DSAF_ROCE_SL_1, DSAF_ROCE_SL_1, DSAF_ROCE_SL_3}, }; - if (!is_of_node(dsaf_fwnode)) { - pr_err("hisi_dsaf: Only support DT node!\n"); + /* find the platform device corresponding to fwnode */ + if (is_of_node(dsaf_fwnode)) { + pdev = of_find_device_by_node(to_of_node(dsaf_fwnode)); + } else if (is_acpi_device_node(dsaf_fwnode)) { + pdev = hns_dsaf_find_platform_device(dsaf_fwnode); + } else { + pr_err("fwnode is neither OF or ACPI type\n"); return -EINVAL; } - pdev = of_find_device_by_node(to_of_node(dsaf_fwnode)); + + /* check if we were a success in fetching pdev */ + if (!pdev) { + pr_err("couldn't find platform device for node\n"); + return -ENODEV; + } + + /* retrieve the dsaf_device from the driver data */ dsaf_dev = dev_get_drvdata(&pdev->dev); + if (!dsaf_dev) { + dev_err(&pdev->dev, "dsaf_dev is NULL\n"); + return -ENODEV; + } + + /* now, make sure we are running on compatible SoC */ if (AE_IS_VER1(dsaf_dev->dsaf_ver)) { dev_err(dsaf_dev->dev, "%s v1 chip doesn't support RoCE!\n", dsaf_dev->ae_dev.name); return -ENODEV; } - if (!enable) { - /* Reset rocee-channels in dsaf and rocee */ - hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK, false); - hns_dsaf_roce_srst(dsaf_dev, false); + /* do reset or de-reset according to the flag */ + if (!dereset) { + /* reset rocee-channels in dsaf and rocee */ + dsaf_dev->misc_op->hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK, + false); + dsaf_dev->misc_op->hns_dsaf_roce_srst(dsaf_dev, false); } else { - /* Configure dsaf tx roce correspond to port map and sl map */ + /* configure dsaf tx roce correspond to port map and sl map */ mp = dsaf_read_dev(dsaf_dev, DSAF_ROCE_PORT_MAP_REG); for (i = 0; i < DSAF_ROCE_CREDIT_CHN; i++) dsaf_set_field(mp, 7 << i * 3, i * 3, @@ -2840,12 +2860,13 @@ int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool enable) sl_map[i][DSAF_ROCE_6PORT_MODE]); dsaf_write_dev(dsaf_dev, DSAF_ROCE_SL_MAP_REG, sl); - /* De-reset rocee-channels in dsaf and rocee */ - hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK, true); + /* de-reset rocee-channels in dsaf and rocee */ + dsaf_dev->misc_op->hns_dsaf_srst_chns(dsaf_dev, DSAF_CHNS_MASK, + true); msleep(SRST_TIME_INTERVAL); - hns_dsaf_roce_srst(dsaf_dev, true); + dsaf_dev->misc_op->hns_dsaf_roce_srst(dsaf_dev, true); - /* Eanble dsaf channel rocee credit */ + /* enable dsaf channel rocee credit */ credit = dsaf_read_dev(dsaf_dev, DSAF_SBM_ROCEE_CFG_REG_REG); dsaf_set_bit(credit, DSAF_SBM_ROCEE_CFG_CRD_EN_B, 0); dsaf_write_dev(dsaf_dev, DSAF_SBM_ROCEE_CFG_REG_REG, credit); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index f3681d566ae6..35df187e66f1 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -305,7 +305,7 @@ struct dsaf_misc_op { void (*cpld_reset_led)(struct hns_mac_cb *mac_cb); int (*cpld_set_led_id)(struct hns_mac_cb *mac_cb, enum hnae_led_state status); - /* reset seris function, it will be reset if the dereseet is 0 */ + /* reset series function, it will be reset if the dereset is 0 */ void (*dsaf_reset)(struct dsaf_device *dsaf_dev, bool dereset); void (*xge_srst)(struct dsaf_device *dsaf_dev, u32 port, bool dereset); void (*xge_core_srst)(struct dsaf_device *dsaf_dev, u32 port, @@ -313,6 +313,9 @@ struct dsaf_misc_op { void (*ge_srst)(struct dsaf_device *dsaf_dev, u32 port, bool dereset); void (*ppe_srst)(struct dsaf_device *dsaf_dev, u32 port, bool dereset); void (*ppe_comm_srst)(struct dsaf_device *dsaf_dev, bool dereset); + void (*hns_dsaf_srst_chns)(struct dsaf_device *dsaf_dev, u32 msk, + bool dereset); + void (*hns_dsaf_roce_srst)(struct dsaf_device *dsaf_dev, bool dereset); phy_interface_t (*get_phy_if)(struct hns_mac_cb *mac_cb); int (*get_sfp_prsnt)(struct hns_mac_cb *mac_cb, int *sfp_prsnt); @@ -445,10 +448,6 @@ int hns_dsaf_get_mac_entry_by_index( void hns_dsaf_fix_mac_mode(struct hns_mac_cb *mac_cb); -void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool enable); - -void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool enable); - int hns_dsaf_ae_init(struct dsaf_device *dsaf_dev); void hns_dsaf_ae_uninit(struct dsaf_device *dsaf_dev); diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c index 36b9f791cf2f..67accce1d33d 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.c @@ -26,6 +26,8 @@ enum _dsm_rst_type { HNS_XGE_CORE_RESET_FUNC = 0x3, HNS_XGE_RESET_FUNC = 0x4, HNS_GE_RESET_FUNC = 0x5, + HNS_DSAF_CHN_RESET_FUNC = 0x6, + HNS_ROCE_RESET_FUNC = 0x7, }; const u8 hns_dsaf_acpi_dsm_uuid[] = { @@ -241,11 +243,11 @@ static void hns_dsaf_xge_core_srst_by_port(struct dsaf_device *dsaf_dev, * bit18-19 for com/dfx * @enable: false - request reset , true - drop reset */ -void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool enable) +void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool dereset) { u32 reg_addr; - if (!enable) + if (!dereset) reg_addr = DSAF_SUB_SC_DSAF_RESET_REQ_REG; else reg_addr = DSAF_SUB_SC_DSAF_RESET_DREQ_REG; @@ -253,9 +255,27 @@ void hns_dsaf_srst_chns(struct dsaf_device *dsaf_dev, u32 msk, bool enable) dsaf_write_sub(dsaf_dev, reg_addr, msk); } -void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool enable) +/** + * hns_dsaf_srst_chns - reset dsaf channels + * @dsaf_dev: dsaf device struct pointer + * @msk: xbar channels mask value: + * bit0-5 for xge0-5 + * bit6-11 for ppe0-5 + * bit12-17 for roce0-5 + * bit18-19 for com/dfx + * @enable: false - request reset , true - drop reset + */ +void +hns_dsaf_srst_chns_acpi(struct dsaf_device *dsaf_dev, u32 msk, bool dereset) { - if (!enable) { + hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, + HNS_DSAF_CHN_RESET_FUNC, + msk, dereset); +} + +void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool dereset) +{ + if (!dereset) { dsaf_write_sub(dsaf_dev, DSAF_SUB_SC_ROCEE_RESET_REQ_REG, 1); } else { dsaf_write_sub(dsaf_dev, @@ -267,6 +287,12 @@ void hns_dsaf_roce_srst(struct dsaf_device *dsaf_dev, bool enable) } } +void hns_dsaf_roce_srst_acpi(struct dsaf_device *dsaf_dev, bool dereset) +{ + hns_dsaf_acpi_srst_by_port(dsaf_dev, HNS_OP_RESET_FUNC, + HNS_ROCE_RESET_FUNC, 0, dereset); +} + static void hns_dsaf_xge_core_srst_by_port_acpi(struct dsaf_device *dsaf_dev, u32 port, bool dereset) @@ -575,6 +601,8 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) misc_op->ge_srst = hns_dsaf_ge_srst_by_port; misc_op->ppe_srst = hns_ppe_srst_by_port; misc_op->ppe_comm_srst = hns_ppe_com_srst; + misc_op->hns_dsaf_srst_chns = hns_dsaf_srst_chns; + misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst; misc_op->get_phy_if = hns_mac_get_phy_if; misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt; @@ -591,6 +619,8 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) misc_op->ge_srst = hns_dsaf_ge_srst_by_port_acpi; misc_op->ppe_srst = hns_ppe_srst_by_port_acpi; misc_op->ppe_comm_srst = hns_ppe_com_srst; + misc_op->hns_dsaf_srst_chns = hns_dsaf_srst_chns_acpi; + misc_op->hns_dsaf_roce_srst = hns_dsaf_roce_srst_acpi; misc_op->get_phy_if = hns_mac_get_phy_if_acpi; misc_op->get_sfp_prsnt = hns_mac_get_sfp_prsnt; @@ -603,3 +633,18 @@ struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev) return (void *)misc_op; } + +static int hns_dsaf_dev_match(struct device *dev, void *fwnode) +{ + return dev->fwnode == fwnode; +} + +struct +platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode) +{ + struct device *dev; + + dev = bus_find_device(&platform_bus_type, NULL, + fwnode, hns_dsaf_dev_match); + return dev ? to_platform_device(dev) : NULL; +} diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h index f06bb03d47a6..310e80261366 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_misc.h @@ -34,5 +34,6 @@ #define DSAF_LED_ANCHOR_B 5 struct dsaf_misc_op *hns_misc_op_get(struct dsaf_device *dsaf_dev); - +struct +platform_device *hns_dsaf_find_platform_device(struct fwnode_handle *fwnode); #endif diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h index 13c16ab7be48..4b8b803822d1 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h @@ -78,10 +78,10 @@ #define DSAF_SUB_SC_RCB_PPE_COM_RESET_REQ_REG 0xA88 #define DSAF_SUB_SC_RCB_PPE_COM_RESET_DREQ_REG 0xA8C #define DSAF_SUB_SC_DSAF_RESET_REQ_REG 0xAA8 -#define DSAF_SUB_SC_ROCEE_RESET_REQ_REG 0xA50 #define DSAF_SUB_SC_DSAF_RESET_DREQ_REG 0xAAC -#define DSAF_SUB_SC_ROCEE_CLK_DIS_REG 0x32C +#define DSAF_SUB_SC_ROCEE_RESET_REQ_REG 0xA50 #define DSAF_SUB_SC_ROCEE_RESET_DREQ_REG 0xA54 +#define DSAF_SUB_SC_ROCEE_CLK_DIS_REG 0x32C #define DSAF_SUB_SC_ROCEE_CLK_EN_REG 0x328 #define DSAF_SUB_SC_LIGHT_MODULE_DETECT_EN_REG 0x2060 #define DSAF_SUB_SC_TCAM_MBIST_EN_REG 0x2300 diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index f9cbc67f1694..c41ab31a39f8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -160,6 +160,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [33] = "RoCEv2 support", [34] = "DMFS Sniffer support (UC & MC)", [35] = "QinQ VST mode support", + [36] = "sl to vl mapping table change event support" }; int i; @@ -789,6 +790,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_FLOW_STEERING_IPOIB_OFFSET 0x74 #define QUERY_DEV_CAP_FLOW_STEERING_RANGE_EN_OFFSET 0x76 #define QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET 0x77 +#define QUERY_DEV_CAP_SL2VL_EVENT_OFFSET 0x78 #define QUERY_DEV_CAP_CQ_EQ_CACHE_LINE_STRIDE 0x7a #define QUERY_DEV_CAP_ECN_QCN_VER_OFFSET 0x7b #define QUERY_DEV_CAP_RDMARC_ENTRY_SZ_OFFSET 0x80 @@ -904,6 +906,9 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_DMFS_IPOIB; MLX4_GET(field, outbox, QUERY_DEV_CAP_FLOW_STEERING_MAX_QP_OFFSET); dev_cap->fs_max_num_qp_per_entry = field; + MLX4_GET(field, outbox, QUERY_DEV_CAP_SL2VL_EVENT_OFFSET); + if (field & (1 << 5)) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SL_TO_VL_CHANGE_EVENT; MLX4_GET(field, outbox, QUERY_DEV_CAP_ECN_QCN_VER_OFFSET); if (field & 0x1) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_QCN; @@ -2783,7 +2788,6 @@ static int mlx4_check_smp_firewall_active(struct mlx4_dev *dev, int mlx4_config_mad_demux(struct mlx4_dev *dev) { struct mlx4_cmd_mailbox *mailbox; - int secure_host_active; int err; /* Check if mad_demux is supported */ @@ -2806,7 +2810,8 @@ int mlx4_config_mad_demux(struct mlx4_dev *dev) goto out; } - secure_host_active = mlx4_check_smp_firewall_active(dev, mailbox); + if (mlx4_check_smp_firewall_active(dev, mailbox)) + dev->flags |= MLX4_FLAG_SECURE_HOST; /* Config mad_demux to handle all MADs returned by the query above */ err = mlx4_cmd(dev, mailbox->dma, 0x01 /* subn mgmt class */, @@ -2817,7 +2822,7 @@ int mlx4_config_mad_demux(struct mlx4_dev *dev) goto out; } - if (secure_host_active) + if (dev->flags & MLX4_FLAG_SECURE_HOST) mlx4_warn(dev, "HCA operating in secure-host mode. SMP firewall activated.\n"); out: mlx4_free_cmd_mailbox(dev, mailbox); diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index c732b8ce2528..3818c5e06eba 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -61,13 +61,13 @@ config DWMAC_LPC18XX config DWMAC_MESON tristate "Amlogic Meson dwmac support" default ARCH_MESON - depends on OF && (ARCH_MESON || COMPILE_TEST) + depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST) help Support for Ethernet controller on Amlogic Meson SoCs. This selects the Amlogic Meson SoC glue layer support for - the stmmac device driver. This driver is used for Meson6 and - Meson8 SoCs. + the stmmac device driver. This driver is used for Meson6, + Meson8, Meson8b and GXBB SoCs. config DWMAC_ROCKCHIP tristate "Rockchip dwmac support" diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index f0c9396fa28e..5d6ece5919b3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -9,7 +9,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o -obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o +obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index c1bac1912b37..309d99536a2c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c @@ -1,5 +1,5 @@ /* - * Amlogic Meson DWMAC glue layer + * Amlogic Meson6 and Meson8 DWMAC glue layer * * Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com> * @@ -96,5 +96,5 @@ static struct platform_driver meson6_dwmac_driver = { module_platform_driver(meson6_dwmac_driver); MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>"); -MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer"); +MODULE_DESCRIPTION("Amlogic Meson6 and Meson8 DWMAC glue layer"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c new file mode 100644 index 000000000000..250e4ceafc8d --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -0,0 +1,324 @@ +/* + * Amlogic Meson8b and GXBB DWMAC glue layer + * + * Copyright (C) 2016 Martin Blumenstingl <martin.blumenstingl@googlemail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/ethtool.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/of_net.h> +#include <linux/mfd/syscon.h> +#include <linux/platform_device.h> +#include <linux/stmmac.h> + +#include "stmmac_platform.h" + +#define PRG_ETH0 0x0 + +#define PRG_ETH0_RGMII_MODE BIT(0) + +/* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */ +#define PRG_ETH0_CLK_M250_SEL_SHIFT 4 +#define PRG_ETH0_CLK_M250_SEL_MASK GENMASK(4, 4) + +#define PRG_ETH0_TXDLY_SHIFT 5 +#define PRG_ETH0_TXDLY_MASK GENMASK(6, 5) +#define PRG_ETH0_TXDLY_OFF (0x0 << PRG_ETH0_TXDLY_SHIFT) +#define PRG_ETH0_TXDLY_QUARTER (0x1 << PRG_ETH0_TXDLY_SHIFT) +#define PRG_ETH0_TXDLY_HALF (0x2 << PRG_ETH0_TXDLY_SHIFT) +#define PRG_ETH0_TXDLY_THREE_QUARTERS (0x3 << PRG_ETH0_TXDLY_SHIFT) + +/* divider for the result of m250_sel */ +#define PRG_ETH0_CLK_M250_DIV_SHIFT 7 +#define PRG_ETH0_CLK_M250_DIV_WIDTH 3 + +/* divides the result of m25_sel by either 5 (bit unset) or 10 (bit set) */ +#define PRG_ETH0_CLK_M25_DIV_SHIFT 10 +#define PRG_ETH0_CLK_M25_DIV_WIDTH 1 + +#define PRG_ETH0_INVERTED_RMII_CLK BIT(11) +#define PRG_ETH0_TX_AND_PHY_REF_CLK BIT(12) + +#define MUX_CLK_NUM_PARENTS 2 + +struct meson8b_dwmac { + struct platform_device *pdev; + + void __iomem *regs; + + phy_interface_t phy_mode; + + struct clk_mux m250_mux; + struct clk *m250_mux_clk; + struct clk *m250_mux_parent[MUX_CLK_NUM_PARENTS]; + + struct clk_divider m250_div; + struct clk *m250_div_clk; + + struct clk_divider m25_div; + struct clk *m25_div_clk; +}; + +static void meson8b_dwmac_mask_bits(struct meson8b_dwmac *dwmac, u32 reg, + u32 mask, u32 value) +{ + u32 data; + + data = readl(dwmac->regs + reg); + data &= ~mask; + data |= (value & mask); + + writel(data, dwmac->regs + reg); +} + +static int meson8b_init_clk(struct meson8b_dwmac *dwmac) +{ + struct clk_init_data init; + int i, ret; + struct device *dev = &dwmac->pdev->dev; + char clk_name[32]; + const char *clk_div_parents[1]; + const char *mux_parent_names[MUX_CLK_NUM_PARENTS]; + static struct clk_div_table clk_25m_div_table[] = { + { .val = 0, .div = 5 }, + { .val = 1, .div = 10 }, + { /* sentinel */ }, + }; + + /* get the mux parents from DT */ + for (i = 0; i < MUX_CLK_NUM_PARENTS; i++) { + char name[16]; + + snprintf(name, sizeof(name), "clkin%d", i); + dwmac->m250_mux_parent[i] = devm_clk_get(dev, name); + if (IS_ERR(dwmac->m250_mux_parent[i])) { + ret = PTR_ERR(dwmac->m250_mux_parent[i]); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Missing clock %s\n", name); + return ret; + } + + mux_parent_names[i] = + __clk_get_name(dwmac->m250_mux_parent[i]); + } + + /* create the m250_mux */ + snprintf(clk_name, sizeof(clk_name), "%s#m250_sel", dev_name(dev)); + init.name = clk_name; + init.ops = &clk_mux_ops; + init.flags = 0; + init.parent_names = mux_parent_names; + init.num_parents = MUX_CLK_NUM_PARENTS; + + dwmac->m250_mux.reg = dwmac->regs + PRG_ETH0; + dwmac->m250_mux.shift = PRG_ETH0_CLK_M250_SEL_SHIFT; + dwmac->m250_mux.mask = PRG_ETH0_CLK_M250_SEL_MASK; + dwmac->m250_mux.flags = 0; + dwmac->m250_mux.table = NULL; + dwmac->m250_mux.hw.init = &init; + + dwmac->m250_mux_clk = devm_clk_register(dev, &dwmac->m250_mux.hw); + if (WARN_ON(IS_ERR(dwmac->m250_mux_clk))) + return PTR_ERR(dwmac->m250_mux_clk); + + /* create the m250_div */ + snprintf(clk_name, sizeof(clk_name), "%s#m250_div", dev_name(dev)); + init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL); + init.ops = &clk_divider_ops; + init.flags = CLK_SET_RATE_PARENT; + clk_div_parents[0] = __clk_get_name(dwmac->m250_mux_clk); + init.parent_names = clk_div_parents; + init.num_parents = ARRAY_SIZE(clk_div_parents); + + dwmac->m250_div.reg = dwmac->regs + PRG_ETH0; + dwmac->m250_div.shift = PRG_ETH0_CLK_M250_DIV_SHIFT; + dwmac->m250_div.width = PRG_ETH0_CLK_M250_DIV_WIDTH; + dwmac->m250_div.hw.init = &init; + dwmac->m250_div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO; + + dwmac->m250_div_clk = devm_clk_register(dev, &dwmac->m250_div.hw); + if (WARN_ON(IS_ERR(dwmac->m250_div_clk))) + return PTR_ERR(dwmac->m250_div_clk); + + /* create the m25_div */ + snprintf(clk_name, sizeof(clk_name), "%s#m25_div", dev_name(dev)); + init.name = devm_kstrdup(dev, clk_name, GFP_KERNEL); + init.ops = &clk_divider_ops; + init.flags = CLK_IS_BASIC | CLK_SET_RATE_PARENT; + clk_div_parents[0] = __clk_get_name(dwmac->m250_div_clk); + init.parent_names = clk_div_parents; + init.num_parents = ARRAY_SIZE(clk_div_parents); + + dwmac->m25_div.reg = dwmac->regs + PRG_ETH0; + dwmac->m25_div.shift = PRG_ETH0_CLK_M25_DIV_SHIFT; + dwmac->m25_div.width = PRG_ETH0_CLK_M25_DIV_WIDTH; + dwmac->m25_div.table = clk_25m_div_table; + dwmac->m25_div.hw.init = &init; + dwmac->m25_div.flags = CLK_DIVIDER_ALLOW_ZERO; + + dwmac->m25_div_clk = devm_clk_register(dev, &dwmac->m25_div.hw); + if (WARN_ON(IS_ERR(dwmac->m25_div_clk))) + return PTR_ERR(dwmac->m25_div_clk); + + return 0; +} + +static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac) +{ + int ret; + unsigned long clk_rate; + + switch (dwmac->phy_mode) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + /* Generate a 25MHz clock for the PHY */ + clk_rate = 25 * 1000 * 1000; + + /* enable RGMII mode */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE, + PRG_ETH0_RGMII_MODE); + + /* only relevant for RMII mode -> disable in RGMII mode */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, + PRG_ETH0_INVERTED_RMII_CLK, 0); + + /* TX clock delay - all known boards use a 1/4 cycle delay */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK, + PRG_ETH0_TXDLY_QUARTER); + break; + + case PHY_INTERFACE_MODE_RMII: + /* Use the rate of the mux clock for the internal RMII PHY */ + clk_rate = clk_get_rate(dwmac->m250_mux_clk); + + /* disable RGMII mode -> enables RMII mode */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_RGMII_MODE, + 0); + + /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, + PRG_ETH0_INVERTED_RMII_CLK, + PRG_ETH0_INVERTED_RMII_CLK); + + /* TX clock delay cannot be configured in RMII mode */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TXDLY_MASK, + 0); + + break; + + default: + dev_err(&dwmac->pdev->dev, "unsupported phy-mode %s\n", + phy_modes(dwmac->phy_mode)); + return -EINVAL; + } + + ret = clk_prepare_enable(dwmac->m25_div_clk); + if (ret) { + dev_err(&dwmac->pdev->dev, "failed to enable the PHY clock\n"); + return ret; + } + + ret = clk_set_rate(dwmac->m25_div_clk, clk_rate); + if (ret) { + clk_disable_unprepare(dwmac->m25_div_clk); + + dev_err(&dwmac->pdev->dev, "failed to set PHY clock\n"); + return ret; + } + + /* enable TX_CLK and PHY_REF_CLK generator */ + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_TX_AND_PHY_REF_CLK, + PRG_ETH0_TX_AND_PHY_REF_CLK); + + return 0; +} + +static int meson8b_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct resource *res; + struct meson8b_dwmac *dwmac; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + dwmac->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dwmac->regs)) + return PTR_ERR(dwmac->regs); + + dwmac->pdev = pdev; + dwmac->phy_mode = of_get_phy_mode(pdev->dev.of_node); + if (dwmac->phy_mode < 0) { + dev_err(&pdev->dev, "missing phy-mode property\n"); + return -EINVAL; + } + + ret = meson8b_init_clk(dwmac); + if (ret) + return ret; + + ret = meson8b_init_prg_eth(dwmac); + if (ret) + return ret; + + plat_dat->bsp_priv = dwmac; + + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} + +static int meson8b_dwmac_remove(struct platform_device *pdev) +{ + struct meson8b_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); + + clk_disable_unprepare(dwmac->m25_div_clk); + + return stmmac_pltfr_remove(pdev); +} + +static const struct of_device_id meson8b_dwmac_match[] = { + { .compatible = "amlogic,meson8b-dwmac" }, + { .compatible = "amlogic,meson-gxbb-dwmac" }, + { } +}; +MODULE_DEVICE_TABLE(of, meson8b_dwmac_match); + +static struct platform_driver meson8b_dwmac_driver = { + .probe = meson8b_dwmac_probe, + .remove = meson8b_dwmac_remove, + .driver = { + .name = "meson8b-dwmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = meson8b_dwmac_match, + }, +}; +module_platform_driver(meson8b_dwmac_driver); + +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); +MODULE_DESCRIPTION("Amlogic Meson8b and GXBB DWMAC glue layer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index ffeb8d9e2b2e..64e147f53a9c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -30,4 +30,12 @@ int stmmac_get_platform_resources(struct platform_device *pdev, int stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; +static inline void *get_stmmac_bsp_priv(struct device *dev) +{ + struct net_device *ndev = dev_get_drvdata(dev); + struct stmmac_priv *priv = netdev_priv(ndev); + + return priv->plat->bsp_priv; +} + #endif /* __STMMAC_PLATFORM_H__ */ |