From cf6645f8ebc69775a857b7c51928f3ad9e37aa66 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:28 -0400 Subject: [PATCH 01/11] bnxt_en: Add function for VF driver to query default VLAN. The PF can setup a default VLAN for a VF. The default VLAN tag is automatically inserted and stripped without the knowledge of the stack running on the VF. The VF driver needs to know that default VLAN is enabled as VLAN acceleration on the RX side is no longer supported. Call netdev_update_features() to fix up the VLAN features as necessary. Also, VLAN strip mode must be enabled to strip out the default VLAN tag. Only allow VF default VLAN to be set if the firmware spec is >= 1.2.1. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 47 ++++++++++++++++++- .../net/ethernet/broadcom/bnxt/bnxt_sriov.c | 3 ++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c777cde85ce4..67608d57c5f0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3277,6 +3277,7 @@ static int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) unsigned int ring = 0, grp_idx; struct bnxt_vnic_info *vnic = &bp->vnic_info[vnic_id]; struct hwrm_vnic_cfg_input req = {0}; + u16 def_vlan = 0; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_VNIC_CFG, -1, -1); /* Only RSS support for now TBD: COS & LB */ @@ -3297,7 +3298,11 @@ static int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id) req.mru = cpu_to_le16(bp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN); - if (bp->flags & BNXT_FLAG_STRIP_VLAN) +#ifdef CONFIG_BNXT_SRIOV + if (BNXT_VF(bp)) + def_vlan = bp->vf.vlan; +#endif + if ((bp->flags & BNXT_FLAG_STRIP_VLAN) || def_vlan) req.flags |= cpu_to_le32(VNIC_CFG_REQ_FLAGS_VLAN_STRIP_MODE); return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); @@ -3836,6 +3841,32 @@ static int bnxt_hwrm_stat_ctx_alloc(struct bnxt *bp) return 0; } +static int bnxt_hwrm_func_qcfg(struct bnxt *bp) +{ + struct hwrm_func_qcfg_input req = {0}; + int rc; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1); + req.fid = cpu_to_le16(0xffff); + mutex_lock(&bp->hwrm_cmd_lock); + rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); + if (rc) + goto func_qcfg_exit; + +#ifdef CONFIG_BNXT_SRIOV + if (BNXT_VF(bp)) { + struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_vf_info *vf = &bp->vf; + + vf->vlan = le16_to_cpu(resp->vlan) & VLAN_VID_MASK; + } +#endif + +func_qcfg_exit: + mutex_unlock(&bp->hwrm_cmd_lock); + return rc; +} + int bnxt_hwrm_func_qcaps(struct bnxt *bp) { int rc = 0; @@ -4230,6 +4261,11 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init) netdev_warn(bp->dev, "HWRM set coalescing failure rc: %x\n", rc); + if (BNXT_VF(bp)) { + bnxt_hwrm_func_qcfg(bp); + netdev_update_features(bp->dev); + } + return 0; err_out: @@ -5469,7 +5505,14 @@ static netdev_features_t bnxt_fix_features(struct net_device *dev, features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX; } - +#ifdef CONFIG_BNXT_SRIOV + if (BNXT_VF(bp)) { + if (bp->vf.vlan) { + features &= ~(NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_STAG_RX); + } + } +#endif return features; } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 363884dd9e8a..50d2007a2640 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -143,6 +143,9 @@ int bnxt_set_vf_vlan(struct net_device *dev, int vf_id, u16 vlan_id, u8 qos) u16 vlan_tag; int rc; + if (bp->hwrm_spec_code < 0x10201) + return -ENOTSUPP; + rc = bnxt_vf_ndo_prep(bp, vf_id); if (rc) return rc; From 6988bd920c6ea53497ed15db947408b7488c9e36 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:29 -0400 Subject: [PATCH 02/11] bnxt_en: Add new function bnxt_reset(). When a default VLAN is added to the VF, the VF driver needs to reset to pick up the default VLAN ID. We can use the same tx timeout reset logic to do that, without the debug output. This new function, with the silent parameter to suppress debug output will now serve both purposes. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 34 +++++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 67608d57c5f0..e30c43b693db 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5628,9 +5628,10 @@ static void bnxt_dbg_dump_states(struct bnxt *bp) } } -static void bnxt_reset_task(struct bnxt *bp) +static void bnxt_reset_task(struct bnxt *bp, bool silent) { - bnxt_dbg_dump_states(bp); + if (!silent) + bnxt_dbg_dump_states(bp); if (netif_running(bp->dev)) { bnxt_close_nic(bp, false, false); bnxt_open_nic(bp, false, false); @@ -5681,6 +5682,23 @@ bnxt_restart_timer: mod_timer(&bp->timer, jiffies + bp->current_interval); } +/* Only called from bnxt_sp_task() */ +static void bnxt_reset(struct bnxt *bp, bool silent) +{ + /* bnxt_reset_task() calls bnxt_close_nic() which waits + * for BNXT_STATE_IN_SP_TASK to clear. + * If there is a parallel dev_close(), bnxt_close() may be holding + * rtnl() and waiting for BNXT_STATE_IN_SP_TASK to clear. So we + * must clear BNXT_STATE_IN_SP_TASK before holding rtnl(). + */ + clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); + rtnl_lock(); + if (test_bit(BNXT_STATE_OPEN, &bp->state)) + bnxt_reset_task(bp, silent); + set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); + rtnl_unlock(); +} + static void bnxt_cfg_ntp_filters(struct bnxt *); static void bnxt_sp_task(struct work_struct *work) @@ -5717,16 +5735,8 @@ static void bnxt_sp_task(struct work_struct *work) bnxt_hwrm_tunnel_dst_port_free( bp, TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN); } - if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) { - /* bnxt_reset_task() calls bnxt_close_nic() which waits - * for BNXT_STATE_IN_SP_TASK to clear. - */ - clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); - rtnl_lock(); - bnxt_reset_task(bp); - set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); - rtnl_unlock(); - } + if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) + bnxt_reset(bp, false); if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) bnxt_get_port_module_status(bp); From fc0f19294d1ffaf9366b10d966f86e6cf13335a4 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:30 -0400 Subject: [PATCH 03/11] bnxt_en: Handle VF_CFG_CHANGE event from firmware. When the VF driver gets this event, the VF configuration has changed (such as default VLAN). The VF driver will initiate a silent reset to pick up the new configuration. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 +++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e30c43b693db..51f9e3839ee9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -125,6 +125,7 @@ static const u16 bnxt_async_events_arr[] = { HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED, + HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE, HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE, }; @@ -1358,6 +1359,11 @@ static int bnxt_async_event_process(struct bnxt *bp, set_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event); break; } + case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_VF_CFG_CHANGE: + if (BNXT_PF(bp)) + goto async_event_process_exit; + set_bit(BNXT_RESET_TASK_SILENT_SP_EVENT, &bp->sp_event); + break; default: netdev_err(bp->dev, "unhandled ASYNC event (id 0x%x)\n", event_id); @@ -5738,6 +5744,9 @@ static void bnxt_sp_task(struct work_struct *work) if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) bnxt_reset(bp, false); + if (test_and_clear_bit(BNXT_RESET_TASK_SILENT_SP_EVENT, &bp->sp_event)) + bnxt_reset(bp, true); + if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) bnxt_get_port_module_status(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 2824d65b2e35..538eb1c52d94 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1018,6 +1018,7 @@ struct bnxt { #define BNXT_HWRM_PF_UNLOAD_SP_EVENT 8 #define BNXT_PERIODIC_STATS_SP_EVENT 9 #define BNXT_HWRM_PORT_MODULE_SP_EVENT 10 +#define BNXT_RESET_TASK_SILENT_SP_EVENT 11 struct bnxt_pf_info pf; #ifdef CONFIG_BNXT_SRIOV From 567b2abe68551781b725b3b739672da41cb92ef0 Mon Sep 17 00:00:00 2001 From: Satish Baddipadige Date: Mon, 13 Jun 2016 02:25:31 -0400 Subject: [PATCH 04/11] bnxt_en: Enable NPAR (NIC Partitioning) Support. NPAR type is read from bnxt_hwrm_func_qcfg. Do not allow changing link parameters if in NPAR mode sinc ethe port is shared among multiple partitions. The link parameters are set up by firmware. Signed-off-by: Satish Baddipadige Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 13 +++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 +++ drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 6 +++--- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 51f9e3839ee9..9d785e6d194f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -3850,6 +3850,7 @@ static int bnxt_hwrm_stat_ctx_alloc(struct bnxt *bp) static int bnxt_hwrm_func_qcfg(struct bnxt *bp) { struct hwrm_func_qcfg_input req = {0}; + struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr; int rc; bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_QCFG, -1, -1); @@ -3861,12 +3862,18 @@ static int bnxt_hwrm_func_qcfg(struct bnxt *bp) #ifdef CONFIG_BNXT_SRIOV if (BNXT_VF(bp)) { - struct hwrm_func_qcfg_output *resp = bp->hwrm_cmd_resp_addr; struct bnxt_vf_info *vf = &bp->vf; vf->vlan = le16_to_cpu(resp->vlan) & VLAN_VID_MASK; } #endif + switch (resp->port_partition_type) { + case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_0: + case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR1_5: + case FUNC_QCFG_RESP_PORT_PARTITION_TYPE_NPAR2_0: + bp->port_partition_type = resp->port_partition_type; + break; + } func_qcfg_exit: mutex_unlock(&bp->hwrm_cmd_lock); @@ -4965,7 +4972,7 @@ static int bnxt_hwrm_shutdown_link(struct bnxt *bp) { struct hwrm_port_phy_cfg_input req = {0}; - if (BNXT_VF(bp)) + if (!BNXT_SINGLE_PF(bp)) return 0; if (pci_num_vf(bp->pdev)) @@ -6427,6 +6434,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto init_err; } + bnxt_hwrm_func_qcfg(bp); + bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); if (BNXT_PF(bp)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 538eb1c52d94..ec18a07f90b4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -907,6 +907,8 @@ struct bnxt { #define BNXT_PF(bp) (!((bp)->flags & BNXT_FLAG_VF)) #define BNXT_VF(bp) ((bp)->flags & BNXT_FLAG_VF) +#define BNXT_NPAR(bp) ((bp)->port_partition_type) +#define BNXT_SINGLE_PF(bp) (BNXT_PF(bp) && !BNXT_NPAR(bp)) struct bnxt_napi **bnapi; @@ -993,6 +995,7 @@ struct bnxt { __le16 vxlan_fw_dst_port_id; u8 nge_port_cnt; __le16 nge_fw_dst_port_id; + u8 port_partition_type; u16 rx_coal_ticks; u16 rx_coal_ticks_irq; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index a38cb047b540..89050ed2046f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -823,7 +823,7 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) u32 speed, fw_advertising = 0; bool set_pause = false; - if (BNXT_VF(bp)) + if (!BNXT_SINGLE_PF(bp)) return rc; if (cmd->autoneg == AUTONEG_ENABLE) { @@ -911,7 +911,7 @@ static int bnxt_set_pauseparam(struct net_device *dev, struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; - if (BNXT_VF(bp)) + if (!BNXT_SINGLE_PF(bp)) return rc; if (epause->autoneg) { @@ -1433,7 +1433,7 @@ static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata) _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0); int rc = 0; - if (BNXT_VF(bp)) + if (!BNXT_SINGLE_PF(bp)) return 0; if (!(bp->flags & BNXT_FLAG_EEE_CAP)) From ebcd4eeb2a0b4859d7aaa3308b222a30d51a643f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:32 -0400 Subject: [PATCH 05/11] bnxt_en: Add PCI device ID for 57404 NPAR devices. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9d785e6d194f..1cf885ad5138 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -78,6 +78,7 @@ enum board_idx { BCM57402, BCM57404, BCM57406, + BCM57404_NPAR, BCM57314, BCM57304_VF, BCM57404_VF, @@ -93,6 +94,7 @@ static const struct { { "Broadcom BCM57402 NetXtreme-E Dual-port 10Gb Ethernet" }, { "Broadcom BCM57404 NetXtreme-E Dual-port 10Gb/25Gb Ethernet" }, { "Broadcom BCM57406 NetXtreme-E Dual-port 10GBase-T Ethernet" }, + { "Broadcom BCM57404 NetXtreme-E Ethernet Partition" }, { "Broadcom BCM57314 NetXtreme-C Dual-port 10Gb/25Gb/40Gb/50Gb Ethernet" }, { "Broadcom BCM57304 NetXtreme-C Ethernet Virtual Function" }, { "Broadcom BCM57404 NetXtreme-E Ethernet Virtual Function" }, @@ -105,6 +107,7 @@ static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x16d0), .driver_data = BCM57402 }, { PCI_VDEVICE(BROADCOM, 0x16d1), .driver_data = BCM57404 }, { PCI_VDEVICE(BROADCOM, 0x16d2), .driver_data = BCM57406 }, + { PCI_VDEVICE(BROADCOM, 0x16d4), .driver_data = BCM57404_NPAR }, { PCI_VDEVICE(BROADCOM, 0x16df), .driver_data = BCM57314 }, #ifdef CONFIG_BNXT_SRIOV { PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = BCM57304_VF }, From 659c805cc01b3c5a6d972db0408164371a2bab4b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:33 -0400 Subject: [PATCH 06/11] bnxt_en: Define the supported chip numbers. Define all the supported chip numbers and chip categories. Store the chip_num returned by firmware. If the call to get the version and chip number fails, we should abort. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 38 +++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1cf885ad5138..0fd27b0350b1 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4037,6 +4037,8 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp) if (resp->hwrm_intf_maj >= 1) bp->hwrm_max_req_len = le16_to_cpu(resp->max_req_win_len); + bp->chip_num = le16_to_cpu(resp->chip_num); + hwrm_ver_get_exit: mutex_unlock(&bp->hwrm_cmd_lock); return rc; @@ -6414,7 +6416,9 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto init_err; mutex_init(&bp->hwrm_cmd_lock); - bnxt_hwrm_ver_get(bp); + rc = bnxt_hwrm_ver_get(bp); + if (rc) + goto init_err; rc = bnxt_hwrm_func_drv_rgtr(bp); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index ec18a07f90b4..b754be60f829 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -873,6 +873,44 @@ struct bnxt { void __iomem *bar2; u32 reg_base; + u16 chip_num; +#define CHIP_NUM_57301 0x16c8 +#define CHIP_NUM_57302 0x16c9 +#define CHIP_NUM_57304 0x16ca +#define CHIP_NUM_57402 0x16d0 +#define CHIP_NUM_57404 0x16d1 +#define CHIP_NUM_57406 0x16d2 + +#define CHIP_NUM_57311 0x16ce +#define CHIP_NUM_57312 0x16cf +#define CHIP_NUM_57314 0x16df +#define CHIP_NUM_57412 0x16d6 +#define CHIP_NUM_57414 0x16d7 +#define CHIP_NUM_57416 0x16d8 +#define CHIP_NUM_57417 0x16d9 + +#define BNXT_CHIP_NUM_5730X(chip_num) \ + ((chip_num) >= CHIP_NUM_57301 && \ + (chip_num) <= CHIP_NUM_57304) + +#define BNXT_CHIP_NUM_5740X(chip_num) \ + ((chip_num) >= CHIP_NUM_57402 && \ + (chip_num) <= CHIP_NUM_57406) + +#define BNXT_CHIP_NUM_5731X(chip_num) \ + ((chip_num) == CHIP_NUM_57311 || \ + (chip_num) == CHIP_NUM_57312 || \ + (chip_num) == CHIP_NUM_57314) + +#define BNXT_CHIP_NUM_5741X(chip_num) \ + ((chip_num) >= CHIP_NUM_57412 && \ + (chip_num) <= CHIP_NUM_57417) + +#define BNXT_CHIP_NUM_57X0X(chip_num) \ + (BNXT_CHIP_NUM_5730X(chip_num) || BNXT_CHIP_NUM_5740X(chip_num)) + +#define BNXT_CHIP_NUM_57X1X(chip_num) \ + (BNXT_CHIP_NUM_5731X(chip_num) || BNXT_CHIP_NUM_5741X(chip_num)) struct net_device *dev; struct pci_dev *pdev; From 309369c9b3f6a8665e581d9014f222b602f6845a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:34 -0400 Subject: [PATCH 07/11] bnxt_en: Refactor bnxt_gro_skb(). Newer chips require different logic to handle GRO packets. So refactor the code so that we can call different functions depending on the chip. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 52 ++++++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 ++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0fd27b0350b1..4e3b9f5295a6 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -945,29 +945,15 @@ static void bnxt_abort_tpa(struct bnxt *bp, struct bnxt_napi *bnapi, #define BNXT_IPV4_HDR_SIZE (sizeof(struct iphdr) + sizeof(struct tcphdr)) #define BNXT_IPV6_HDR_SIZE (sizeof(struct ipv6hdr) + sizeof(struct tcphdr)) -static inline struct sk_buff *bnxt_gro_skb(struct bnxt_tpa_info *tpa_info, - struct rx_tpa_end_cmp *tpa_end, - struct rx_tpa_end_cmp_ext *tpa_end1, +static struct sk_buff *bnxt_gro_func_5730x(struct bnxt_tpa_info *tpa_info, + int payload_off, int tcp_ts, struct sk_buff *skb) { #ifdef CONFIG_INET struct tcphdr *th; - int payload_off, tcp_opt_len = 0; - int len, nw_off; - u16 segs; + int len, nw_off, tcp_opt_len; - segs = TPA_END_TPA_SEGS(tpa_end); - if (segs == 1) - return skb; - - NAPI_GRO_CB(skb)->count = segs; - skb_shinfo(skb)->gso_size = - le32_to_cpu(tpa_end1->rx_tpa_end_cmp_seg_len); - skb_shinfo(skb)->gso_type = tpa_info->gso_type; - payload_off = (le32_to_cpu(tpa_end->rx_tpa_end_cmp_misc_v1) & - RX_TPA_END_CMP_PAYLOAD_OFFSET) >> - RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT; - if (TPA_END_GRO_TS(tpa_end)) + if (tcp_ts) tcp_opt_len = 12; if (tpa_info->gso_type == SKB_GSO_TCPV4) { @@ -1024,6 +1010,32 @@ static inline struct sk_buff *bnxt_gro_skb(struct bnxt_tpa_info *tpa_info, return skb; } +static inline struct sk_buff *bnxt_gro_skb(struct bnxt *bp, + struct bnxt_tpa_info *tpa_info, + struct rx_tpa_end_cmp *tpa_end, + struct rx_tpa_end_cmp_ext *tpa_end1, + struct sk_buff *skb) +{ +#ifdef CONFIG_INET + int payload_off; + u16 segs; + + segs = TPA_END_TPA_SEGS(tpa_end); + if (segs == 1) + return skb; + + NAPI_GRO_CB(skb)->count = segs; + skb_shinfo(skb)->gso_size = + le32_to_cpu(tpa_end1->rx_tpa_end_cmp_seg_len); + skb_shinfo(skb)->gso_type = tpa_info->gso_type; + payload_off = (le32_to_cpu(tpa_end->rx_tpa_end_cmp_misc_v1) & + RX_TPA_END_CMP_PAYLOAD_OFFSET) >> + RX_TPA_END_CMP_PAYLOAD_OFFSET_SHIFT; + skb = bp->gro_func(tpa_info, payload_off, TPA_END_GRO_TS(tpa_end), skb); +#endif + return skb; +} + static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons, @@ -1134,7 +1146,7 @@ static inline struct sk_buff *bnxt_tpa_end(struct bnxt *bp, } if (TPA_END_GRO(tpa_end)) - skb = bnxt_gro_skb(tpa_info, tpa_end, tpa_end1, skb); + skb = bnxt_gro_skb(bp, tpa_info, tpa_end, tpa_end1, skb); return skb; } @@ -6420,6 +6432,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err; + bp->gro_func = bnxt_gro_func_5730x; + rc = bnxt_hwrm_func_drv_rgtr(bp); if (rc) goto init_err; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index b754be60f829..d62f4c2039f8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -953,6 +953,9 @@ struct bnxt { struct bnxt_rx_ring_info *rx_ring; struct bnxt_tx_ring_info *tx_ring; + struct sk_buff * (*gro_func)(struct bnxt_tpa_info *, int, int, + struct sk_buff *); + u32 rx_buf_size; u32 rx_buf_use_size; /* useable size */ u32 rx_ring_size; From 94758f8de037cf5c62eb56287f5d5e937cda8c9b Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:35 -0400 Subject: [PATCH 08/11] bnxt_en: Add GRO logic for BCM5731X chips. Add bnxt_gro_func_5731x() to handle GRO packets for this chip. The completion structures used in the new chip have new data to help determine the header offsets. The offsets can be off by 4 if the packet is an internal loopback packet (e.g. from one VF to another VF). Some additional logic is added to adjust the offsets if it is a loopback packet. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 89 ++++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 16 +++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 4e3b9f5295a6..5f9285c2bad9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -924,6 +924,7 @@ static void bnxt_tpa_start(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, } tpa_info->flags2 = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_flags2); tpa_info->metadata = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_metadata); + tpa_info->hdr_info = le32_to_cpu(tpa_start1->rx_tpa_start_cmp_hdr_info); rxr->rx_prod = NEXT_RX(prod); cons = NEXT_RX(cons); @@ -942,6 +943,90 @@ static void bnxt_abort_tpa(struct bnxt *bp, struct bnxt_napi *bnapi, bnxt_reuse_rx_agg_bufs(bnapi, cp_cons, agg_bufs); } +static struct sk_buff *bnxt_gro_func_5731x(struct bnxt_tpa_info *tpa_info, + int payload_off, int tcp_ts, + struct sk_buff *skb) +{ +#ifdef CONFIG_INET + struct tcphdr *th; + int len, nw_off; + u16 outer_ip_off, inner_ip_off, inner_mac_off; + u32 hdr_info = tpa_info->hdr_info; + bool loopback = false; + + inner_ip_off = BNXT_TPA_INNER_L3_OFF(hdr_info); + inner_mac_off = BNXT_TPA_INNER_L2_OFF(hdr_info); + outer_ip_off = BNXT_TPA_OUTER_L3_OFF(hdr_info); + + /* If the packet is an internal loopback packet, the offsets will + * have an extra 4 bytes. + */ + if (inner_mac_off == 4) { + loopback = true; + } else if (inner_mac_off > 4) { + __be16 proto = *((__be16 *)(skb->data + inner_ip_off - + ETH_HLEN - 2)); + + /* We only support inner iPv4/ipv6. If we don't see the + * correct protocol ID, it must be a loopback packet where + * the offsets are off by 4. + */ + if (proto != htons(ETH_P_IP) && proto && htons(ETH_P_IPV6)) + loopback = true; + } + if (loopback) { + /* internal loopback packet, subtract all offsets by 4 */ + inner_ip_off -= 4; + inner_mac_off -= 4; + outer_ip_off -= 4; + } + + nw_off = inner_ip_off - ETH_HLEN; + skb_set_network_header(skb, nw_off); + if (tpa_info->flags2 & RX_TPA_START_CMP_FLAGS2_IP_TYPE) { + struct ipv6hdr *iph = ipv6_hdr(skb); + + skb_set_transport_header(skb, nw_off + sizeof(struct ipv6hdr)); + len = skb->len - skb_transport_offset(skb); + th = tcp_hdr(skb); + th->check = ~tcp_v6_check(len, &iph->saddr, &iph->daddr, 0); + } else { + struct iphdr *iph = ip_hdr(skb); + + skb_set_transport_header(skb, nw_off + sizeof(struct iphdr)); + len = skb->len - skb_transport_offset(skb); + th = tcp_hdr(skb); + th->check = ~tcp_v4_check(len, iph->saddr, iph->daddr, 0); + } + + if (inner_mac_off) { /* tunnel */ + struct udphdr *uh = NULL; + __be16 proto = *((__be16 *)(skb->data + outer_ip_off - + ETH_HLEN - 2)); + + if (proto == htons(ETH_P_IP)) { + struct iphdr *iph = (struct iphdr *)skb->data; + + if (iph->protocol == IPPROTO_UDP) + uh = (struct udphdr *)(iph + 1); + } else { + struct ipv6hdr *iph = (struct ipv6hdr *)skb->data; + + if (iph->nexthdr == IPPROTO_UDP) + uh = (struct udphdr *)(iph + 1); + } + if (uh) { + if (uh->check) + skb_shinfo(skb)->gso_type |= + SKB_GSO_UDP_TUNNEL_CSUM; + else + skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; + } + } +#endif + return skb; +} + #define BNXT_IPV4_HDR_SIZE (sizeof(struct iphdr) + sizeof(struct tcphdr)) #define BNXT_IPV6_HDR_SIZE (sizeof(struct ipv6hdr) + sizeof(struct tcphdr)) @@ -2283,7 +2368,7 @@ static void bnxt_set_tpa_flags(struct bnxt *bp) bp->flags &= ~BNXT_FLAG_TPA; if (bp->dev->features & NETIF_F_LRO) bp->flags |= BNXT_FLAG_LRO; - if ((bp->dev->features & NETIF_F_GRO) && (bp->pdev->revision > 0)) + if (bp->dev->features & NETIF_F_GRO) bp->flags |= BNXT_FLAG_GRO; } @@ -6433,6 +6518,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto init_err; bp->gro_func = bnxt_gro_func_5730x; + if (BNXT_CHIP_NUM_57X1X(bp->chip_num)) + bp->gro_func = bnxt_gro_func_5731x; rc = bnxt_hwrm_func_drv_rgtr(bp); if (rc) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index d62f4c2039f8..c1b41fb216dc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -298,13 +298,14 @@ struct rx_tpa_start_cmp_ext { #define RX_TPA_START_CMP_FLAGS2_L4_CS_CALC (0x1 << 1) #define RX_TPA_START_CMP_FLAGS2_T_IP_CS_CALC (0x1 << 2) #define RX_TPA_START_CMP_FLAGS2_T_L4_CS_CALC (0x1 << 3) + #define RX_TPA_START_CMP_FLAGS2_IP_TYPE (0x1 << 8) __le32 rx_tpa_start_cmp_metadata; __le32 rx_tpa_start_cmp_cfa_code_v2; #define RX_TPA_START_CMP_V2 (0x1 << 0) #define RX_TPA_START_CMP_CFA_CODE (0xffff << 16) #define RX_TPA_START_CMPL_CFA_CODE_SHIFT 16 - __le32 rx_tpa_start_cmp_unused5; + __le32 rx_tpa_start_cmp_hdr_info; }; struct rx_tpa_end_cmp { @@ -584,6 +585,19 @@ struct bnxt_tpa_info { u32 metadata; enum pkt_hash_types hash_type; u32 rss_hash; + u32 hdr_info; + +#define BNXT_TPA_L4_SIZE(hdr_info) \ + (((hdr_info) & 0xf8000000) ? ((hdr_info) >> 27) : 32) + +#define BNXT_TPA_INNER_L3_OFF(hdr_info) \ + (((hdr_info) >> 18) & 0x1ff) + +#define BNXT_TPA_INNER_L2_OFF(hdr_info) \ + (((hdr_info) >> 9) & 0x1ff) + +#define BNXT_TPA_OUTER_L3_OFF(hdr_info) \ + ((hdr_info) & 0x1ff) }; struct bnxt_rx_ring_info { From b24eb6ae7058ca1a42b0532489e5f5796c107d65 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:36 -0400 Subject: [PATCH 09/11] bnxt_en: Add BCM5731X and BCM5741X device IDs. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 30 ++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 5f9285c2bad9..c2753296e75e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -75,13 +75,22 @@ enum board_idx { BCM57301, BCM57302, BCM57304, + BCM57311, + BCM57312, BCM57402, BCM57404, BCM57406, BCM57404_NPAR, + BCM57412, + BCM57414, + BCM57416, + BCM57417, + BCM57414_NPAR, BCM57314, BCM57304_VF, BCM57404_VF, + BCM57414_VF, + BCM57314_VF, }; /* indexed by enum above */ @@ -91,27 +100,45 @@ static const struct { { "Broadcom BCM57301 NetXtreme-C Single-port 10Gb Ethernet" }, { "Broadcom BCM57302 NetXtreme-C Dual-port 10Gb/25Gb Ethernet" }, { "Broadcom BCM57304 NetXtreme-C Dual-port 10Gb/25Gb/40Gb/50Gb Ethernet" }, + { "Broadcom BCM57311 NetXtreme-C Single-port 10Gb Ethernet" }, + { "Broadcom BCM57312 NetXtreme-C Dual-port 10Gb/25Gb Ethernet" }, { "Broadcom BCM57402 NetXtreme-E Dual-port 10Gb Ethernet" }, { "Broadcom BCM57404 NetXtreme-E Dual-port 10Gb/25Gb Ethernet" }, { "Broadcom BCM57406 NetXtreme-E Dual-port 10GBase-T Ethernet" }, { "Broadcom BCM57404 NetXtreme-E Ethernet Partition" }, + { "Broadcom BCM57412 NetXtreme-E Dual-port 10Gb Ethernet" }, + { "Broadcom BCM57414 NetXtreme-E Dual-port 10Gb/25Gb Ethernet" }, + { "Broadcom BCM57416 NetXtreme-E Dual-port 10GBase-T Ethernet" }, + { "Broadcom BCM57417 NetXtreme-E Dual-port 10GBase-T Ethernet" }, + { "Broadcom BCM57414 NetXtreme-E Ethernet Partition" }, { "Broadcom BCM57314 NetXtreme-C Dual-port 10Gb/25Gb/40Gb/50Gb Ethernet" }, { "Broadcom BCM57304 NetXtreme-C Ethernet Virtual Function" }, { "Broadcom BCM57404 NetXtreme-E Ethernet Virtual Function" }, + { "Broadcom BCM57414 NetXtreme-E Ethernet Virtual Function" }, + { "Broadcom BCM57314 NetXtreme-E Ethernet Virtual Function" }, }; static const struct pci_device_id bnxt_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, 0x16c8), .driver_data = BCM57301 }, { PCI_VDEVICE(BROADCOM, 0x16c9), .driver_data = BCM57302 }, { PCI_VDEVICE(BROADCOM, 0x16ca), .driver_data = BCM57304 }, + { PCI_VDEVICE(BROADCOM, 0x16ce), .driver_data = BCM57311 }, + { PCI_VDEVICE(BROADCOM, 0x16cf), .driver_data = BCM57312 }, { PCI_VDEVICE(BROADCOM, 0x16d0), .driver_data = BCM57402 }, { PCI_VDEVICE(BROADCOM, 0x16d1), .driver_data = BCM57404 }, { PCI_VDEVICE(BROADCOM, 0x16d2), .driver_data = BCM57406 }, { PCI_VDEVICE(BROADCOM, 0x16d4), .driver_data = BCM57404_NPAR }, + { PCI_VDEVICE(BROADCOM, 0x16d6), .driver_data = BCM57412 }, + { PCI_VDEVICE(BROADCOM, 0x16d7), .driver_data = BCM57414 }, + { PCI_VDEVICE(BROADCOM, 0x16d8), .driver_data = BCM57416 }, + { PCI_VDEVICE(BROADCOM, 0x16d9), .driver_data = BCM57417 }, + { PCI_VDEVICE(BROADCOM, 0x16de), .driver_data = BCM57414_NPAR }, { PCI_VDEVICE(BROADCOM, 0x16df), .driver_data = BCM57314 }, #ifdef CONFIG_BNXT_SRIOV { PCI_VDEVICE(BROADCOM, 0x16cb), .driver_data = BCM57304_VF }, { PCI_VDEVICE(BROADCOM, 0x16d3), .driver_data = BCM57404_VF }, + { PCI_VDEVICE(BROADCOM, 0x16dc), .driver_data = BCM57414_VF }, + { PCI_VDEVICE(BROADCOM, 0x16e1), .driver_data = BCM57314_VF }, #endif { 0 } }; @@ -134,7 +161,8 @@ static const u16 bnxt_async_events_arr[] = { static bool bnxt_vf_pciid(enum board_idx idx) { - return (idx == BCM57304_VF || idx == BCM57404_VF); + return (idx == BCM57304_VF || idx == BCM57404_VF || + idx == BCM57314_VF || idx == BCM57414_VF); } #define DB_CP_REARM_FLAGS (DB_KEY_CP | DB_IDX_VALID) From 93ed8117336485af2cedb069d28f3d4270fb90a1 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:37 -0400 Subject: [PATCH 10/11] bnxt_en: Don't allow autoneg on cards that don't support it. Some cards do not support autoneg. The current code does not prevent the user from enabling autoneg with ethtool on such cards, causing confusion. Firmware provides the autoneg capability information and we just need to store it in the support_auto_speeds field in bnxt_link_info struct. The ethtool set_settings() call will check this field before proceeding with autoneg. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 9 ++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 29 +++++++++++++------ 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c2753296e75e..9aaa6a61c800 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4823,6 +4823,7 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) int rc = 0; struct hwrm_port_phy_qcaps_input req = {0}; struct hwrm_port_phy_qcaps_output *resp = bp->hwrm_cmd_resp_addr; + struct bnxt_link_info *link_info = &bp->link_info; if (bp->hwrm_spec_code < 0x10201) return 0; @@ -4845,6 +4846,8 @@ static int bnxt_hwrm_phy_qcaps(struct bnxt *bp) bp->lpi_tmr_hi = le32_to_cpu(resp->valid_tx_lpi_timer_high) & PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_HIGH_MASK; } + link_info->support_auto_speeds = + le16_to_cpu(resp->supported_speeds_auto_mode); hwrm_phy_qcaps_exit: mutex_unlock(&bp->hwrm_cmd_lock); @@ -6368,6 +6371,12 @@ static int bnxt_probe_phy(struct bnxt *bp) return rc; } + /* Older firmware does not have supported_auto_speeds, so assume + * that all supported speeds can be autonegotiated. + */ + if (link_info->auto_link_speeds && !link_info->support_auto_speeds) + link_info->support_auto_speeds = link_info->support_speeds; + /*initialize the ethool setting copy with NVM settings */ if (BNXT_AUTO_MODE(link_info->auto_mode)) { link_info->autoneg = BNXT_AUTONEG_SPEED; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index c1b41fb216dc..04cc69bb9e6a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -849,6 +849,7 @@ struct bnxt_link_info { #define BNXT_LINK_SPEED_MSK_25GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_25GB #define BNXT_LINK_SPEED_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_40GB #define BNXT_LINK_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_50GB + u16 support_auto_speeds; u16 lp_auto_link_speeds; u16 force_link_speed; u32 preemphasis; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 89050ed2046f..3362e9043a51 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -659,6 +659,17 @@ static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info) return supported | SUPPORTED_Pause | SUPPORTED_Asym_Pause; } +static u32 bnxt_fw_to_ethtool_support_adv_spds(struct bnxt_link_info *link_info) +{ + u16 fw_speeds = link_info->support_auto_speeds; + u32 supported; + + supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); + if (supported) + supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + return supported; +} + u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) { switch (fw_link_speed) { @@ -691,7 +702,7 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info); - if (link_info->auto_link_speeds) + if (link_info->support_auto_speeds) cmd->supported |= SUPPORTED_Autoneg; if (link_info->autoneg) { @@ -827,8 +838,14 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) return rc; if (cmd->autoneg == AUTONEG_ENABLE) { - u32 supported_spds = bnxt_fw_to_ethtool_support_spds(link_info); + u32 supported_spds = + bnxt_fw_to_ethtool_support_adv_spds(link_info); + if (!supported_spds) { + netdev_err(dev, "Autoneg not supported\n"); + rc = -EINVAL; + goto set_setting_exit; + } if (cmd->advertising & ~(supported_spds | ADVERTISED_Autoneg | ADVERTISED_TP | ADVERTISED_FIBRE)) { netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n", @@ -837,15 +854,9 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) goto set_setting_exit; } fw_advertising = bnxt_get_fw_auto_link_speeds(cmd->advertising); - if (fw_advertising & ~link_info->support_speeds) { - netdev_err(dev, "Advertising parameters are not supported! (adv: 0x%x)\n", - cmd->advertising); - rc = -EINVAL; - goto set_setting_exit; - } link_info->autoneg |= BNXT_AUTONEG_SPEED; if (!fw_advertising) - link_info->advertising = link_info->support_speeds; + link_info->advertising = link_info->support_auto_speeds; else link_info->advertising = fw_advertising; /* any change to autoneg will cause link change, therefore the From 00c04a928572991d30b2473a7e992c1be8e646f3 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 13 Jun 2016 02:25:38 -0400 Subject: [PATCH 11/11] bnxt_en: Support new ETHTOOL_{G|S}LINKSETTINGS API. To fully support 25G and 50G link settings. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 198 +++++++++++------- 1 file changed, 118 insertions(+), 80 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 3362e9043a51..d7ab2d7982c2 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -628,7 +628,66 @@ u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause) return speed_mask; } -static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info) +#define BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, name)\ +{ \ + if ((fw_speeds) & BNXT_LINK_SPEED_MSK_100MB) \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + 100baseT_Full); \ + if ((fw_speeds) & BNXT_LINK_SPEED_MSK_1GB) \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + 1000baseT_Full); \ + if ((fw_speeds) & BNXT_LINK_SPEED_MSK_10GB) \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + 10000baseT_Full); \ + if ((fw_speeds) & BNXT_LINK_SPEED_MSK_25GB) \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + 25000baseCR_Full); \ + if ((fw_speeds) & BNXT_LINK_SPEED_MSK_40GB) \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + 40000baseCR4_Full);\ + if ((fw_speeds) & BNXT_LINK_SPEED_MSK_50GB) \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + 50000baseCR2_Full);\ + if ((fw_pause) & BNXT_LINK_PAUSE_RX) { \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + Pause); \ + if (!((fw_pause) & BNXT_LINK_PAUSE_TX)) \ + ethtool_link_ksettings_add_link_mode( \ + lk_ksettings, name, Asym_Pause);\ + } else if ((fw_pause) & BNXT_LINK_PAUSE_TX) { \ + ethtool_link_ksettings_add_link_mode(lk_ksettings, name,\ + Asym_Pause); \ + } \ +} + +#define BNXT_ETHTOOL_TO_FW_SPDS(fw_speeds, lk_ksettings, name) \ +{ \ + if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 100baseT_Full) || \ + ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 100baseT_Half)) \ + (fw_speeds) |= BNXT_LINK_SPEED_MSK_100MB; \ + if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 1000baseT_Full) || \ + ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 1000baseT_Half)) \ + (fw_speeds) |= BNXT_LINK_SPEED_MSK_1GB; \ + if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 10000baseT_Full)) \ + (fw_speeds) |= BNXT_LINK_SPEED_MSK_10GB; \ + if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 25000baseCR_Full)) \ + (fw_speeds) |= BNXT_LINK_SPEED_MSK_25GB; \ + if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 40000baseCR4_Full)) \ + (fw_speeds) |= BNXT_LINK_SPEED_MSK_40GB; \ + if (ethtool_link_ksettings_test_link_mode(lk_ksettings, name, \ + 50000baseCR2_Full)) \ + (fw_speeds) |= BNXT_LINK_SPEED_MSK_50GB; \ +} + +static void bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info, + struct ethtool_link_ksettings *lk_ksettings) { u16 fw_speeds = link_info->auto_link_speeds; u8 fw_pause = 0; @@ -636,10 +695,11 @@ static u32 bnxt_fw_to_ethtool_advertised_spds(struct bnxt_link_info *link_info) if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) fw_pause = link_info->auto_pause_setting; - return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause); + BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, advertising); } -static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info) +static void bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info, + struct ethtool_link_ksettings *lk_ksettings) { u16 fw_speeds = link_info->lp_auto_link_speeds; u8 fw_pause = 0; @@ -647,27 +707,24 @@ static u32 bnxt_fw_to_ethtool_lp_adv(struct bnxt_link_info *link_info) if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) fw_pause = link_info->lp_pause; - return _bnxt_fw_to_ethtool_adv_spds(fw_speeds, fw_pause); + BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, fw_pause, lk_ksettings, + lp_advertising); } -static u32 bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info) +static void bnxt_fw_to_ethtool_support_spds(struct bnxt_link_info *link_info, + struct ethtool_link_ksettings *lk_ksettings) { u16 fw_speeds = link_info->support_speeds; - u32 supported; - supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); - return supported | SUPPORTED_Pause | SUPPORTED_Asym_Pause; -} + BNXT_FW_TO_ETHTOOL_SPDS(fw_speeds, 0, lk_ksettings, supported); -static u32 bnxt_fw_to_ethtool_support_adv_spds(struct bnxt_link_info *link_info) -{ - u16 fw_speeds = link_info->support_auto_speeds; - u32 supported; + ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, Pause); + ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, + Asym_Pause); - supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0); - if (supported) - supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; - return supported; + if (link_info->support_auto_speeds) + ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, + Autoneg); } u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) @@ -694,65 +751,62 @@ u32 bnxt_fw_to_ethtool_speed(u16 fw_link_speed) } } -static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int bnxt_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *lk_ksettings) { struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; - u16 ethtool_speed; + struct ethtool_link_settings *base = &lk_ksettings->base; + u32 ethtool_speed; - cmd->supported = bnxt_fw_to_ethtool_support_spds(link_info); - - if (link_info->support_auto_speeds) - cmd->supported |= SUPPORTED_Autoneg; + ethtool_link_ksettings_zero_link_mode(lk_ksettings, supported); + bnxt_fw_to_ethtool_support_spds(link_info, lk_ksettings); + ethtool_link_ksettings_zero_link_mode(lk_ksettings, advertising); if (link_info->autoneg) { - cmd->advertising = - bnxt_fw_to_ethtool_advertised_spds(link_info); - cmd->advertising |= ADVERTISED_Autoneg; - cmd->autoneg = AUTONEG_ENABLE; + bnxt_fw_to_ethtool_advertised_spds(link_info, lk_ksettings); + ethtool_link_ksettings_add_link_mode(lk_ksettings, + advertising, Autoneg); + base->autoneg = AUTONEG_ENABLE; if (link_info->phy_link_status == BNXT_LINK_LINK) - cmd->lp_advertising = - bnxt_fw_to_ethtool_lp_adv(link_info); + bnxt_fw_to_ethtool_lp_adv(link_info, lk_ksettings); ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed); if (!netif_carrier_ok(dev)) - cmd->duplex = DUPLEX_UNKNOWN; + base->duplex = DUPLEX_UNKNOWN; else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL) - cmd->duplex = DUPLEX_FULL; + base->duplex = DUPLEX_FULL; else - cmd->duplex = DUPLEX_HALF; + base->duplex = DUPLEX_HALF; } else { - cmd->autoneg = AUTONEG_DISABLE; - cmd->advertising = 0; + base->autoneg = AUTONEG_DISABLE; ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->req_link_speed); - cmd->duplex = DUPLEX_HALF; + base->duplex = DUPLEX_HALF; if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL) - cmd->duplex = DUPLEX_FULL; + base->duplex = DUPLEX_FULL; } - ethtool_cmd_speed_set(cmd, ethtool_speed); + base->speed = ethtool_speed; - cmd->port = PORT_NONE; + base->port = PORT_NONE; if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { - cmd->port = PORT_TP; - cmd->supported |= SUPPORTED_TP; - cmd->advertising |= ADVERTISED_TP; + base->port = PORT_TP; + ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, + TP); + ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, + TP); } else { - cmd->supported |= SUPPORTED_FIBRE; - cmd->advertising |= ADVERTISED_FIBRE; + ethtool_link_ksettings_add_link_mode(lk_ksettings, supported, + FIBRE); + ethtool_link_ksettings_add_link_mode(lk_ksettings, advertising, + FIBRE); if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_DAC) - cmd->port = PORT_DA; + base->port = PORT_DA; else if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_FIBRE) - cmd->port = PORT_FIBRE; + base->port = PORT_FIBRE; } - - if (link_info->transceiver == - PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL) - cmd->transceiver = XCVR_INTERNAL; - else - cmd->transceiver = XCVR_EXTERNAL; - cmd->phy_address = link_info->phy_addr; + base->phy_address = link_info->phy_addr; return 0; } @@ -826,34 +880,22 @@ u16 bnxt_get_fw_auto_link_speeds(u32 advertising) return fw_speed_mask; } -static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int bnxt_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *lk_ksettings) { - int rc = 0; struct bnxt *bp = netdev_priv(dev); struct bnxt_link_info *link_info = &bp->link_info; + const struct ethtool_link_settings *base = &lk_ksettings->base; u32 speed, fw_advertising = 0; bool set_pause = false; + int rc = 0; if (!BNXT_SINGLE_PF(bp)) - return rc; + return -EOPNOTSUPP; - if (cmd->autoneg == AUTONEG_ENABLE) { - u32 supported_spds = - bnxt_fw_to_ethtool_support_adv_spds(link_info); - - if (!supported_spds) { - netdev_err(dev, "Autoneg not supported\n"); - rc = -EINVAL; - goto set_setting_exit; - } - if (cmd->advertising & ~(supported_spds | ADVERTISED_Autoneg | - ADVERTISED_TP | ADVERTISED_FIBRE)) { - netdev_err(dev, "Unsupported advertising mask (adv: 0x%x)\n", - cmd->advertising); - rc = -EINVAL; - goto set_setting_exit; - } - fw_advertising = bnxt_get_fw_auto_link_speeds(cmd->advertising); + if (base->autoneg == AUTONEG_ENABLE) { + BNXT_ETHTOOL_TO_FW_SPDS(fw_advertising, lk_ksettings, + advertising); link_info->autoneg |= BNXT_AUTONEG_SPEED; if (!fw_advertising) link_info->advertising = link_info->support_auto_speeds; @@ -874,16 +916,12 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) rc = -EINVAL; goto set_setting_exit; } - /* TODO: currently don't support half duplex */ - if (cmd->duplex == DUPLEX_HALF) { + if (base->duplex == DUPLEX_HALF) { netdev_err(dev, "HALF DUPLEX is not supported!\n"); rc = -EINVAL; goto set_setting_exit; } - /* If received a request for an unknown duplex, assume full*/ - if (cmd->duplex == DUPLEX_UNKNOWN) - cmd->duplex = DUPLEX_FULL; - speed = ethtool_cmd_speed(cmd); + speed = base->speed; fw_speed = bnxt_get_fw_speed(dev, speed); if (!fw_speed) { rc = -EINVAL; @@ -1629,8 +1667,8 @@ static int bnxt_get_module_eeprom(struct net_device *dev, } const struct ethtool_ops bnxt_ethtool_ops = { - .get_settings = bnxt_get_settings, - .set_settings = bnxt_set_settings, + .get_link_ksettings = bnxt_get_link_ksettings, + .set_link_ksettings = bnxt_set_link_ksettings, .get_pauseparam = bnxt_get_pauseparam, .set_pauseparam = bnxt_set_pauseparam, .get_drvinfo = bnxt_get_drvinfo,