From 03efbec03198a0f505c2a6c93268c3c5df321c90 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 11 Apr 2016 04:11:11 -0400 Subject: [PATCH 1/4] bnxt_en: Disallow forced speed for 10GBaseT devices. 10GBaseT devices must autonegotiate to determine master/slave clocking. Disallow forced speed in ethtool .set_settings() for these devices. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 8 ++++++++ 3 files changed, 10 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 597e4724a474..a06dcaa75f6e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4611,6 +4611,7 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) link_info->phy_ver[1] = resp->phy_min; link_info->phy_ver[2] = resp->phy_bld; link_info->media_type = resp->media_type; + link_info->phy_type = resp->phy_type; link_info->transceiver = resp->xcvr_pkg_type; link_info->phy_addr = resp->eee_config_phy_addr & PORT_PHY_QCFG_RESP_PHY_ADDR_MASK; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index cc8e38a9f684..26dac2f3c63c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -759,6 +759,7 @@ struct bnxt_ntuple_filter { }; struct bnxt_link_info { + u8 phy_type; u8 media_type; u8 transceiver; u8 phy_addr; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index a2e93241b06b..d6e41f237f2c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -850,7 +850,15 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) set_pause = true; } else { u16 fw_speed; + u8 phy_type = link_info->phy_type; + if (phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASET || + phy_type == PORT_PHY_QCFG_RESP_PHY_TYPE_BASETE || + link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) { + netdev_err(dev, "10GBase-T devices must autoneg\n"); + rc = -EINVAL; + goto set_setting_exit; + } /* TODO: currently don't support half duplex */ if (cmd->duplex == DUPLEX_HALF) { netdev_err(dev, "HALF DUPLEX is not supported!\n"); From 33f7d55f07ab964055d73d38774346f8d4821f00 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 11 Apr 2016 04:11:12 -0400 Subject: [PATCH 2/4] bnxt_en: Shutdown link when device is closed. Let firmware know that the driver is giving up control of the link so that it can be shutdown if no management firmware is running. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a06dcaa75f6e..e874a564f40b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4790,6 +4790,21 @@ int bnxt_hwrm_set_link_setting(struct bnxt *bp, bool set_pause, bool set_eee) return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); } +static int bnxt_hwrm_shutdown_link(struct bnxt *bp) +{ + struct hwrm_port_phy_cfg_input req = {0}; + + if (BNXT_VF(bp)) + return 0; + + if (pci_num_vf(bp->pdev)) + return 0; + + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_CFG, -1, -1); + req.flags = cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE_LINK_DOWN); + return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +} + static bool bnxt_eee_config_ok(struct bnxt *bp) { struct ethtool_eee *eee = &bp->eee; @@ -5044,6 +5059,7 @@ static int bnxt_close(struct net_device *dev) struct bnxt *bp = netdev_priv(dev); bnxt_close_nic(bp, true, true); + bnxt_hwrm_shutdown_link(bp); return 0; } From 84c33dd342ad596a271a61da0119bf34e80bb1c5 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 11 Apr 2016 04:11:13 -0400 Subject: [PATCH 3/4] bnxt_en: Call firmware to approve VF MAC address change. Some hypervisors (e.g. ESX) require the VF MAC address to be forwarded to the PF for approval. In Linux PF, the call is not forwarded and the firmware will simply check and approve the MAC address if the PF has not previously administered a valid MAC address for this VF. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 7 ++--- .../net/ethernet/broadcom/bnxt/bnxt_sriov.c | 30 +++++++++++++++++++ .../net/ethernet/broadcom/bnxt/bnxt_sriov.h | 1 + 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e874a564f40b..c83a5a1862d0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5696,10 +5696,9 @@ static int bnxt_change_mac_addr(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; -#ifdef CONFIG_BNXT_SRIOV - if (BNXT_VF(bp) && is_valid_ether_addr(bp->vf.mac_addr)) - return -EADDRNOTAVAIL; -#endif + rc = bnxt_approve_mac(bp, addr->sa_data); + if (rc) + return rc; if (ether_addr_equal(addr->sa_data, dev->dev_addr)) return 0; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 8457850b0bdd..363884dd9e8a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -865,6 +865,31 @@ update_vf_mac_exit: mutex_unlock(&bp->hwrm_cmd_lock); } +int bnxt_approve_mac(struct bnxt *bp, u8 *mac) +{ + struct hwrm_func_vf_cfg_input req = {0}; + int rc = 0; + + if (!BNXT_VF(bp)) + return 0; + + if (bp->hwrm_spec_code < 0x10202) { + if (is_valid_ether_addr(bp->vf.mac_addr)) + rc = -EADDRNOTAVAIL; + goto mac_done; + } + bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_CFG, -1, -1); + req.enables = cpu_to_le32(FUNC_VF_CFG_REQ_ENABLES_DFLT_MAC_ADDR); + memcpy(req.dflt_mac_addr, mac, ETH_ALEN); + rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT); +mac_done: + if (rc) { + rc = -EADDRNOTAVAIL; + netdev_warn(bp->dev, "VF MAC address %pM not approved by the PF\n", + mac); + } + return rc; +} #else void bnxt_sriov_disable(struct bnxt *bp) @@ -879,4 +904,9 @@ void bnxt_hwrm_exec_fwd_req(struct bnxt *bp) void bnxt_update_vf_mac(struct bnxt *bp) { } + +int bnxt_approve_mac(struct bnxt *bp, u8 *mac) +{ + return 0; +} #endif diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h index 3f08354a247e..0392670ab49c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.h @@ -20,4 +20,5 @@ int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs); void bnxt_sriov_disable(struct bnxt *); void bnxt_hwrm_exec_fwd_req(struct bnxt *); void bnxt_update_vf_mac(struct bnxt *); +int bnxt_approve_mac(struct bnxt *, u8 *); #endif From 8cbde1175e3c8565edbb777cd09cbfdb93c78397 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 11 Apr 2016 04:11:14 -0400 Subject: [PATCH 4/4] bnxt_en: Add async event handling for speed config changes. On some dual port cards, link speeds on both ports have to be compatible. Firmware will inform the driver when a certain speed is no longer supported if the other port has linked up at a certain speed. Add logic to handle this event by logging a message and getting the updated list of supported speeds. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c83a5a1862d0..4645c44e7c15 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -122,6 +122,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_LINK_SPEED_CFG_CHANGE, }; static bool bnxt_vf_pciid(enum board_idx idx) @@ -1257,6 +1258,21 @@ static int bnxt_async_event_process(struct bnxt *bp, /* TODO CHIMP_FW: Define event id's for link change, error etc */ switch (event_id) { + case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_SPEED_CFG_CHANGE: { + u32 data1 = le32_to_cpu(cmpl->event_data1); + struct bnxt_link_info *link_info = &bp->link_info; + + if (BNXT_VF(bp)) + goto async_event_process_exit; + if (data1 & 0x20000) { + u16 fw_speed = link_info->force_link_speed; + u32 speed = bnxt_fw_to_ethtool_speed(fw_speed); + + netdev_warn(bp->dev, "Link speed %d no longer supported\n", + speed); + } + /* fall thru */ + } case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE: set_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event); break;