From d7bbcd32adafee94e965d9ca188ddeede4c94597 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 24 Oct 2012 06:19:01 +0000 Subject: [PATCH 01/13] ixgbe: Add support for pipeline reset Calling the ixgbe_reset_pipeline_82599 function will ensure a full pipeline reset on all 82599 devices. This is necessary to avoid possible link issues. Since this patch accomplishes this by modifying AUTOC.LMS we need to wrap all AUTOC writes when LESM is enabled. v2- fix LMS behaviour based on feedback by Martin Josefsson CC: Martin Josefsson Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 112 +++++++++++++----- .../net/ethernet/intel/ixgbe/ixgbe_common.c | 70 ++++++++++- 3 files changed, 152 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index c64a777b2c0b..a17116b3c470 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -693,6 +693,7 @@ extern s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, u16 soft_id); extern void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input, union ixgbe_atr_input *mask); +extern bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); extern void ixgbe_set_rx_mode(struct net_device *netdev); #ifdef CONFIG_IXGBE_DCB extern void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index b52781351659..e75f5a4a2a6d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -62,7 +62,6 @@ static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw, bool autoneg, bool autoneg_wait_to_complete); static s32 ixgbe_verify_fw_version_82599(struct ixgbe_hw *hw); -static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) { @@ -99,9 +98,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { s32 ret_val = 0; - u32 reg_anlp1 = 0; - u32 i = 0; u16 list_offset, data_offset, data_value; + bool got_lock = false; if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { ixgbe_init_mac_link_ops_82599(hw); @@ -137,28 +135,36 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) usleep_range(hw->eeprom.semaphore_delay * 1000, hw->eeprom.semaphore_delay * 2000); - /* Now restart DSP by setting Restart_AN and clearing LMS */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw, - IXGBE_AUTOC) & ~IXGBE_AUTOC_LMS_MASK) | - IXGBE_AUTOC_AN_RESTART)); + /* Need SW/FW semaphore around AUTOC writes if LESM on, + * likewise reset_pipeline requires lock as it also writes + * AUTOC. + */ + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val) + goto setup_sfp_out; - /* Wait for AN to leave state 0 */ - for (i = 0; i < 10; i++) { - usleep_range(4000, 8000); - reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1); - if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK) - break; + got_lock = true; } - if (!(reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)) { - hw_dbg(hw, "sfp module setup not complete\n"); + + /* Restart DSP and set SFI mode */ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw, + IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL)); + + ret_val = ixgbe_reset_pipeline_82599(hw); + + if (got_lock) { + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + got_lock = false; + } + + if (ret_val) { + hw_dbg(hw, " sfp module setup not complete\n"); ret_val = IXGBE_ERR_SFP_SETUP_NOT_COMPLETE; goto setup_sfp_out; } - - /* Restart DSP by setting Restart_AN and return to SFI mode */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw, - IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL | - IXGBE_AUTOC_AN_RESTART)); } setup_sfp_out: @@ -394,14 +400,26 @@ static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, u32 links_reg; u32 i; s32 status = 0; + bool got_lock = false; + + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + status = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (status) + goto out; + + got_lock = true; + } /* Restart link */ - autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); - autoc_reg |= IXGBE_AUTOC_AN_RESTART; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); /* Only poll for autoneg to complete if specified to do so */ if (autoneg_wait_to_complete) { + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) == IXGBE_AUTOC_LMS_KX4_KX_KR || (autoc_reg & IXGBE_AUTOC_LMS_MASK) == @@ -425,6 +443,7 @@ static s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, /* Add delay to filter out noises during initial link setup */ msleep(50); +out: return status; } @@ -779,6 +798,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, u32 links_reg; u32 i; ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; + bool got_lock = false; /* Check to see if speed passed in is supported. */ status = hw->mac.ops.get_link_capabilities(hw, &link_capabilities, @@ -836,9 +856,26 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, } if (autoc != start_autoc) { + /* Need SW/FW semaphore around AUTOC writes if LESM is on, + * likewise reset_pipeline requires us to hold this lock as + * it also writes to AUTOC. + */ + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + status = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (status != 0) + goto out; + + got_lock = true; + } + /* Restart link */ - autoc |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); /* Only poll for autoneg to complete if specified to do so */ if (autoneg_wait_to_complete) { @@ -994,9 +1031,28 @@ mac_reset_top: hw->mac.orig_autoc2 = autoc2; hw->mac.orig_link_settings_stored = true; } else { - if (autoc != hw->mac.orig_autoc) - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (hw->mac.orig_autoc | - IXGBE_AUTOC_AN_RESTART)); + if (autoc != hw->mac.orig_autoc) { + /* Need SW/FW semaphore around AUTOC writes if LESM is + * on, likewise reset_pipeline requires us to hold + * this lock as it also writes to AUTOC. + */ + bool got_lock = false; + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + status = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (status) + goto reset_hw_out; + + got_lock = true; + } + + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc); + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + } if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) != (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) { @@ -1983,7 +2039,7 @@ fw_version_out: * Returns true if the LESM FW module is present and enabled. Otherwise * returns false. Smart Speed must be disabled if LESM FW module is enabled. **/ -static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) +bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) { bool lesm_enabled = false; u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index a2a9bcca4915..8f285edb5094 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -90,6 +90,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) s32 ret_val = 0; u32 reg = 0, reg_bp = 0; u16 reg_cu = 0; + bool got_lock = false; /* * Validate the requested mode. Strict IEEE mode does not allow @@ -210,8 +211,29 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) * */ if (hw->phy.media_type == ixgbe_media_type_backplane) { - reg_bp |= IXGBE_AUTOC_AN_RESTART; + /* Need the SW/FW semaphore around AUTOC writes if 82599 and + * LESM is on, likewise reset_pipeline requries the lock as + * it also writes AUTOC. + */ + if ((hw->mac.type == ixgbe_mac_82599EB) && + ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val) + goto out; + + got_lock = true; + } + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp); + + if (hw->mac.type == ixgbe_mac_82599EB) + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + } else if ((hw->phy.media_type == ixgbe_media_type_copper) && (ixgbe_device_supports_autoneg_fc(hw) == 0)) { hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, @@ -2616,6 +2638,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) bool link_up = false; u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + s32 ret_val = 0; /* * Link must be up to auto-blink the LEDs; @@ -2624,10 +2647,28 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) hw->mac.ops.check_link(hw, &speed, &link_up, false); if (!link_up) { + /* Need the SW/FW semaphore around AUTOC writes if 82599 and + * LESM is on. + */ + bool got_lock = false; + + if ((hw->mac.type == ixgbe_mac_82599EB) && + ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val) + goto out; + + got_lock = true; + } autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); IXGBE_WRITE_FLUSH(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); usleep_range(10000, 20000); } @@ -2636,7 +2677,8 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); IXGBE_WRITE_FLUSH(hw); - return 0; +out: + return ret_val; } /** @@ -2648,18 +2690,40 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) { u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); + s32 ret_val = 0; + bool got_lock = false; + + /* Need the SW/FW semaphore around AUTOC writes if 82599 and + * LESM is on. + */ + if ((hw->mac.type == ixgbe_mac_82599EB) && + ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (ret_val) + goto out; + + got_lock = true; + } autoc_reg &= ~IXGBE_AUTOC_FLU; autoc_reg |= IXGBE_AUTOC_AN_RESTART; IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + if (hw->mac.type == ixgbe_mac_82599EB) + ixgbe_reset_pipeline_82599(hw); + + if (got_lock) + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg &= ~IXGBE_LED_BLINK(index); led_reg |= IXGBE_LED_LINK_ACTIVE << IXGBE_LED_MODE_SHIFT(index); IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg); IXGBE_WRITE_FLUSH(hw); - return 0; +out: + return ret_val; } /** From a30134053c3c4a14049037ee41b74ab3fe57cf9e Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Tue, 30 Oct 2012 00:40:02 +0000 Subject: [PATCH 02/13] ixgbe: Fix return value from macvlan filter function The function to set the macvlan filter should return success or failure instead of the index of the filter. The message processing function was misinterpreting the index as a non-zero return code indicating failure and NACKing MAC filter set messages that actually succeeded. Signed-off-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 96876b7442b1..8bdb341c14bf 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -742,7 +742,8 @@ static int ixgbe_set_vf_macvlan_msg(struct ixgbe_adapter *adapter, e_warn(drv, "VF %d has requested a MACVLAN filter but there is no space for it\n", vf); - return err; + + return err < 0; } static int ixgbe_negotiate_vf_api(struct ixgbe_adapter *adapter, From b3343a2a2c95b3b7ed4f6596e860c4276ba46217 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Tue, 18 Sep 2012 00:01:12 +0000 Subject: [PATCH 03/13] net, ixgbe: handle link local multicast addresses in SR-IOV mode In SR-IOV mode the PF driver acts as the uplink port and is used to send control packets e.g. lldpad, stp, etc. eth0.1 eth0.2 eth0 VF VF PF | | | <-- stand-in for uplink | | | -------------------------- | Embedded Switch | -------------------------- | MAC <-- uplink But the embedded switch is setup to forward multicast addresses to all interfaces both VFs and PF and onto the physical link. This results in reserved MAC addresses used by control protocols to be forwarded over the switch onto the VF. In the LLDP case the PF sends an LLDPDU and it is currently being forwarded to all the VFs who then see the PF as a peer. This is incorrect. This patch adds the multicast addresses to the RAR table in the hardware to prevent this behavior. Signed-off-by: John Fastabend Tested-by: Phil Schmitt Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- drivers/net/ethernet/intel/ixgbevf/vf.c | 3 +++ include/linux/etherdevice.h | 19 +++++++++++++++++++ net/bridge/br_device.c | 2 +- net/bridge/br_input.c | 15 --------------- net/bridge/br_private.h | 1 - net/bridge/br_sysfs_br.c | 3 ++- 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 88d636a7459c..97bab45ed95f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6967,7 +6967,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return -EINVAL; } - if (is_unicast_ether_addr(addr)) { + if (is_unicast_ether_addr(addr) || is_link_local(addr)) { u32 rar_uc_entries = IXGBE_MAX_PF_MACVLANS; if (netdev_uc_count(dev) < rar_uc_entries) diff --git a/drivers/net/ethernet/intel/ixgbevf/vf.c b/drivers/net/ethernet/intel/ixgbevf/vf.c index 5fa397b953eb..c0fd1ef49400 100644 --- a/drivers/net/ethernet/intel/ixgbevf/vf.c +++ b/drivers/net/ethernet/intel/ixgbevf/vf.c @@ -331,6 +331,9 @@ static s32 ixgbevf_update_mc_addr_list_vf(struct ixgbe_hw *hw, netdev_for_each_mc_addr(ha, netdev) { if (i == cnt) break; + if (is_link_local(ha->addr)) + continue; + vector_list[i++] = ixgbevf_mta_vector(hw, ha->addr); } diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index b006ba0a9f42..45ded4be7b43 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -51,6 +51,25 @@ extern struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, #define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1) #define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count) +/* Reserved Ethernet Addresses per IEEE 802.1Q */ +static const u8 br_reserved_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; + +/** + * is_link_local - Determine if given Eth addr is a link local mcast address. + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if address is link local reserved addr (01:80:c2:00:00:0X) per + * IEEE 802.1Q 8.6.3 Frame filtering. + */ +static inline int is_link_local(const unsigned char *dest) +{ + __be16 *a = (__be16 *)dest; + static const __be16 *b = (const __be16 *)br_reserved_address; + static const __be16 m = cpu_to_be16(0xfff0); + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; +} + /** * is_zero_ether_addr - Determine if give Ethernet address is all zeros. * @addr: Pointer to a six-byte array containing the Ethernet address diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 070e8a68cfc6..d41b6f9698d7 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -356,7 +356,7 @@ void br_dev_setup(struct net_device *dev) br->bridge_id.prio[0] = 0x80; br->bridge_id.prio[1] = 0x00; - memcpy(br->group_addr, br_group_address, ETH_ALEN); + memcpy(br->group_addr, br_reserved_address, ETH_ALEN); br->stp_enabled = BR_NO_STP; br->group_fwd_mask = BR_GROUPFWD_DEFAULT; diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index 76f15fda0212..d047978bf025 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -19,9 +19,6 @@ #include #include "br_private.h" -/* Bridge group multicast address 802.1d (pg 51). */ -const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; - /* Hook for brouter */ br_should_route_hook_t __rcu *br_should_route_hook __read_mostly; EXPORT_SYMBOL(br_should_route_hook); @@ -127,18 +124,6 @@ static int br_handle_local_finish(struct sk_buff *skb) return 0; /* process further */ } -/* Does address match the link local multicast address. - * 01:80:c2:00:00:0X - */ -static inline int is_link_local(const unsigned char *dest) -{ - __be16 *a = (__be16 *)dest; - static const __be16 *b = (const __be16 *)br_group_address; - static const __be16 m = cpu_to_be16(0xfff0); - - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; -} - /* * Return NULL if skb is handled * note: already called with rcu_read_lock diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 9b278c4ebee1..65b191a05dd6 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -288,7 +288,6 @@ struct br_input_skb_cb { pr_debug("%s: " format, (br)->dev->name, ##args) extern struct notifier_block br_device_notifier; -extern const u8 br_group_address[ETH_ALEN]; /* called under bridge lock */ static inline int br_is_root_bridge(const struct net_bridge *br) diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index c5c059333eab..e157b0dbcd82 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -310,7 +311,7 @@ static ssize_t store_group_addr(struct device *d, /* Must be 01:80:c2:00:00:0X */ for (i = 0; i < 5; i++) - if (new_addr[i] != br_group_address[i]) + if (new_addr[i] != br_reserved_address[i]) return -EINVAL; if (new_addr[5] & ~0xf) From ec74a4715549ed4823df7ad4ecc81a8416b7f6bd Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 20 Sep 2012 03:33:56 +0000 Subject: [PATCH 04/13] ixgbe: clean up the condition for turning on/off the laser This patch simplifies the check for calling en/disable_tx_laser() function pointer. The pointer is only set on parts that can use it. Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 31 +++++-------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 97bab45ed95f..ceab142bcf8a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -4087,11 +4087,8 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter) else ixgbe_configure_msi_and_legacy(adapter); - /* enable the optics for both mult-speed fiber and 82599 SFP+ fiber */ - if (hw->mac.ops.enable_tx_laser && - ((hw->phy.multispeed_fiber) || - ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) && - (hw->mac.type == ixgbe_mac_82599EB)))) + /* enable the optics for 82599 SFP+ fiber */ + if (hw->mac.ops.enable_tx_laser) hw->mac.ops.enable_tx_laser(hw); clear_bit(__IXGBE_DOWN, &adapter->state); @@ -4413,11 +4410,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter) if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter); - /* power down the optics for multispeed fiber and 82599 SFP+ fiber */ - if (hw->mac.ops.disable_tx_laser && - ((hw->phy.multispeed_fiber) || - ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) && - (hw->mac.type == ixgbe_mac_82599EB)))) + /* power down the optics for 82599 SFP+ fiber */ + if (hw->mac.ops.disable_tx_laser) hw->mac.ops.disable_tx_laser(hw); ixgbe_clean_all_tx_rings(adapter); @@ -5050,14 +5044,8 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) if (wufc) { ixgbe_set_rx_mode(netdev); - /* - * enable the optics for both mult-speed fiber and - * 82599 SFP+ fiber as we can WoL. - */ - if (hw->mac.ops.enable_tx_laser && - (hw->phy.multispeed_fiber || - (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber && - hw->mac.type == ixgbe_mac_82599EB))) + /* enable the optics for 82599 SFP+ fiber as we can WoL */ + if (hw->mac.ops.enable_tx_laser) hw->mac.ops.enable_tx_laser(hw); /* turn on all-multi mode if wake on multicast is enabled */ @@ -7468,11 +7456,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (err) goto err_register; - /* power down the optics for multispeed fiber and 82599 SFP+ fiber */ - if (hw->mac.ops.disable_tx_laser && - ((hw->phy.multispeed_fiber) || - ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) && - (hw->mac.type == ixgbe_mac_82599EB)))) + /* power down the optics for 82599 SFP+ fiber */ + if (hw->mac.ops.disable_tx_laser) hw->mac.ops.disable_tx_laser(hw); /* carrier off reporting is important to ethtool even BEFORE open */ From 3970c3234bbaac962a6c9213536dfcabc421d0d0 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Tue, 25 Sep 2012 02:25:30 +0000 Subject: [PATCH 05/13] ixgbe: Return success or failure on VF MAC filter set When setting a MAC filter for the VF the function should return a success or failure code, not the index of the new filter. It causes spurious NACK returns to the VF driver. Signed-off-by: Greg Rose Tested-by: Phil Schmitt Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 8bdb341c14bf..bfeb7ec2abd9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -675,7 +675,7 @@ static int ixgbe_set_vf_mac_addr(struct ixgbe_adapter *adapter, return -1; } - return ixgbe_set_vf_mac(adapter, vf, new_mac); + return ixgbe_set_vf_mac(adapter, vf, new_mac) < 0; } static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter, From f4de00ed58df50e522d920990976b39433a406aa Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 25 Sep 2012 00:29:37 +0000 Subject: [PATCH 06/13] ixgbe: Do not decrement budget in ixgbe_clean_rx_irq This change makes it so that compare the total_rx_packets cleaned to budget instead of decrementing budget. The advantage to this approach is that budget can now be const and we only end up modifying total_rx_packets instead of modifying both it and budget. Signed-off-by: Alexander Duyck Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index ceab142bcf8a..a34ee7d63563 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1794,7 +1794,7 @@ dma_sync: **/ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, struct ixgbe_ring *rx_ring, - int budget) + const int budget) { unsigned int total_rx_bytes = 0, total_rx_packets = 0; #ifdef IXGBE_FCOE @@ -1845,7 +1845,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; - total_rx_packets++; /* populate checksum, timestamp, VLAN, and protocol */ ixgbe_process_skb_fields(rx_ring, rx_desc, skb); @@ -1878,8 +1877,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, ixgbe_rx_skb(q_vector, skb); /* update budget accounting */ - budget--; - } while (likely(budget)); + total_rx_packets++; + } while (likely(total_rx_packets < budget)); u64_stats_update_begin(&rx_ring->syncp); rx_ring->stats.packets += total_rx_packets; @@ -1891,7 +1890,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, if (cleaned_count) ixgbe_alloc_rx_buffers(rx_ring, cleaned_count); - return !!budget; + return (total_rx_packets < budget); } /** From 39ac868a7c8c8b7406205b7b4c09417a0df0dec0 Mon Sep 17 00:00:00 2001 From: Josh Hay Date: Wed, 26 Sep 2012 05:59:36 +0000 Subject: [PATCH 07/13] ixgbe: add/update descriptor maps in comments Adds/updates ASCII descriptor maps for 82598 and 82599 Tx/Rx descriptors. Current descriptor maps were out of date for 82598 and incorrect for 82599. Signed-off-by: Josh Hay Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 61 +++++++++++++++++-- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index a34ee7d63563..603567457516 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -355,13 +355,37 @@ static void ixgbe_dump(struct ixgbe_adapter *adapter) /* Transmit Descriptor Formats * - * Advanced Transmit Descriptor + * 82598 Advanced Transmit Descriptor * +--------------------------------------------------------------+ * 0 | Buffer Address [63:0] | * +--------------------------------------------------------------+ - * 8 | PAYLEN | PORTS | IDX | STA | DCMD |DTYP | RSV | DTALEN | + * 8 | PAYLEN | POPTS | IDX | STA | DCMD |DTYP | RSV | DTALEN | * +--------------------------------------------------------------+ * 63 46 45 40 39 36 35 32 31 24 23 20 19 0 + * + * 82598 Advanced Transmit Descriptor (Write-Back Format) + * +--------------------------------------------------------------+ + * 0 | RSV [63:0] | + * +--------------------------------------------------------------+ + * 8 | RSV | STA | NXTSEQ | + * +--------------------------------------------------------------+ + * 63 36 35 32 31 0 + * + * 82599+ Advanced Transmit Descriptor + * +--------------------------------------------------------------+ + * 0 | Buffer Address [63:0] | + * +--------------------------------------------------------------+ + * 8 |PAYLEN |POPTS|CC|IDX |STA |DCMD |DTYP |MAC |RSV |DTALEN | + * +--------------------------------------------------------------+ + * 63 46 45 40 39 38 36 35 32 31 24 23 20 19 18 17 16 15 0 + * + * 82599+ Advanced Transmit Descriptor (Write-Back Format) + * +--------------------------------------------------------------+ + * 0 | RSV [63:0] | + * +--------------------------------------------------------------+ + * 8 | RSV | STA | RSV | + * +--------------------------------------------------------------+ + * 63 36 35 32 31 0 */ for (n = 0; n < adapter->num_tx_queues; n++) { @@ -422,7 +446,9 @@ rx_ring_summary: dev_info(&adapter->pdev->dev, "RX Rings Dump\n"); - /* Advanced Receive Descriptor (Read) Format + /* Receive Descriptor Formats + * + * 82598 Advanced Receive Descriptor (Read) Format * 63 1 0 * +-----------------------------------------------------+ * 0 | Packet Buffer Address [63:1] |A0/NSE| @@ -431,17 +457,40 @@ rx_ring_summary: * +-----------------------------------------------------+ * * - * Advanced Receive Descriptor (Write-Back) Format + * 82598 Advanced Receive Descriptor (Write-Back) Format * * 63 48 47 32 31 30 21 20 16 15 4 3 0 * +------------------------------------------------------+ - * 0 | Packet IP |SPH| HDR_LEN | RSV|Packet| RSS | - * | Checksum Ident | | | | Type | Type | + * 0 | RSS Hash / |SPH| HDR_LEN | RSV |Packet| RSS | + * | Packet | IP | | | | Type | Type | + * | Checksum | Ident | | | | | | * +------------------------------------------------------+ * 8 | VLAN Tag | Length | Extended Error | Extended Status | * +------------------------------------------------------+ * 63 48 47 32 31 20 19 0 + * + * 82599+ Advanced Receive Descriptor (Read) Format + * 63 1 0 + * +-----------------------------------------------------+ + * 0 | Packet Buffer Address [63:1] |A0/NSE| + * +----------------------------------------------+------+ + * 8 | Header Buffer Address [63:1] | DD | + * +-----------------------------------------------------+ + * + * + * 82599+ Advanced Receive Descriptor (Write-Back) Format + * + * 63 48 47 32 31 30 21 20 17 16 4 3 0 + * +------------------------------------------------------+ + * 0 |RSS / Frag Checksum|SPH| HDR_LEN |RSC- |Packet| RSS | + * |/ RTT / PCoE_PARAM | | | CNT | Type | Type | + * |/ Flow Dir Flt ID | | | | | | + * +------------------------------------------------------+ + * 8 | VLAN Tag | Length |Extended Error| Xtnd Status/NEXTP | + * +------------------------------------------------------+ + * 63 48 47 32 31 20 19 0 */ + for (n = 0; n < adapter->num_rx_queues; n++) { rx_ring = adapter->rx_ring[n]; pr_info("------------------------------------\n"); From f42df16756dbcaba7b50cb7bbb0833b65d3ae167 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 25 Oct 2012 18:12:05 +0000 Subject: [PATCH 08/13] ixgbe: reduce PTP rx path overhead Hw timestamping code caused performance regression in ixgbe driver when the timestamping is not enabled. The culprit is IXGBE_READ_REG call in the Rx path which is executed for every received skb. This call is not needed when the timestamping is disabled or for non-ptp packets. netperf results: The ixgbe side of the connection was acting as a server, the netperf command line on the other side was: netperf -H 192.168.1.23 -T0,0 -t UDP_STREAM -l 20 The values below mean throughput as reported by netperf (local/remote), for 3 runs, with timestamping not enabled. 3.7.0-rc1+ with CONFIG_IXGBE_PTP off: 5373.83 / 3329.32 5721.88 / 3033.89 5653.42 / 3112.38 3.7.0-rc1+ with CONFIG_IXGBE_PTP on: 5233.64 / 1226.85 5448.67 / 1039.32 5421.36 / 1095.66 Patched 3.7.0-rc1+ with CONFIG_IXGBE_PTP on: 5594.72 / 2942.53 5428.95 / 3110.16 5343.56 / 3200.48 Reported-by: Jesper Brouer Signed-off-by: Jiri Benc Signed-off-by: Andy Gospodarek Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 5e71ddbb3414..842ba15550a5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -554,12 +554,14 @@ void ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector, adapter = q_vector->adapter; hw = &adapter->hw; + if (likely(!ixgbe_ptp_match(skb, adapter->rx_hwtstamp_filter))) + return; + tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); /* Check if we have a valid timestamp and make sure the skb should * have been timestamped */ - if (likely(!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID) || - !ixgbe_ptp_match(skb, adapter->rx_hwtstamp_filter))) + if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) return; /* From f9d08f165b8a5a4af6f827318e692b57bc683825 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Tue, 2 Oct 2012 00:50:52 +0000 Subject: [PATCH 09/13] ixgbevf: Do not forward LLDP type frames The driver should not forward LLDP type frames. Inspect the ether type and do not send if it is an LLDP ethertype frame. Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 07d7eaba6f1b..b5979ba52b4c 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -2968,6 +2968,11 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) #if PAGE_SIZE > IXGBE_MAX_DATA_PER_TXD unsigned short f; #endif + u8 *dst_mac = skb_header_pointer(skb, 0, 0, NULL); + if (!dst_mac || is_link_local(dst_mac)) { + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } tx_ring = &adapter->tx_ring[r_idx]; From 91ffb8e0dc662868addeff9fd013145c49a43c4a Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 21 Sep 2012 00:21:39 +0000 Subject: [PATCH 10/13] igbvf: Check for error on dma_map_single call Ignoring the return value from a call to the kernel dma_map API functions can cause data corruption and system instability. Check the return value and take appropriate action. Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igbvf/netdev.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 0ac11f527a84..4051ec404613 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -184,6 +184,13 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, buffer_info->page_offset, PAGE_SIZE / 2, DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, + buffer_info->page_dma)) { + __free_page(buffer_info->page); + buffer_info->page = NULL; + dev_err(&pdev->dev, "RX DMA map failed\n"); + break; + } } if (!buffer_info->skb) { @@ -197,6 +204,12 @@ static void igbvf_alloc_rx_buffers(struct igbvf_ring *rx_ring, buffer_info->dma = dma_map_single(&pdev->dev, skb->data, bufsz, DMA_FROM_DEVICE); + if (dma_mapping_error(&pdev->dev, buffer_info->dma)) { + dev_kfree_skb(buffer_info->skb); + buffer_info->skb = NULL; + dev_err(&pdev->dev, "RX DMA map failed\n"); + goto no_buffers; + } } /* Refresh the desc even if buffer_addrs didn't change because * each write-back erases this info. */ From 9f0b8516198e8b0919774a1874fab064a2ea3ae8 Mon Sep 17 00:00:00 2001 From: Matthew Vick Date: Tue, 16 Oct 2012 07:44:45 +0000 Subject: [PATCH 11/13] igb: Enable auto-crossover during forced operation on 82580 and above. Newer devices supported by igb can support auto-crossover detection in forced operation modes. Enable this in the driver, rather than clobbering this functionality in forced operation. Signed-off-by: Matthew Vick Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_mac.c | 4 +++ drivers/net/ethernet/intel/igb/e1000_phy.c | 29 +++++++++++++--------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index 819c145ac762..7acddfe9e6d5 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -1391,6 +1391,10 @@ s32 igb_validate_mdi_setting(struct e1000_hw *hw) { s32 ret_val = 0; + /* All MDI settings are supported on 82580 and newer. */ + if (hw->mac.type >= e1000_82580) + goto out; + if (!hw->mac.autoneg && (hw->phy.mdix == 0 || hw->phy.mdix == 3)) { hw_dbg("Invalid MDI setting detected\n"); hw->phy.mdix = 1; diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index c62a4c388194..fe76004aca4e 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1207,20 +1207,25 @@ s32 igb_phy_force_speed_duplex_m88(struct e1000_hw *hw) u16 phy_data; bool link; - /* - * Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI - * forced whenever speed and duplex are forced. - */ - ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); - if (ret_val) - goto out; + /* I210 and I211 devices support Auto-Crossover in forced operation. */ + if (phy->type != e1000_phy_i210) { + /* + * Clear Auto-Crossover to force MDI manually. M88E1000 + * requires MDI forced whenever speed and duplex are forced. + */ + ret_val = phy->ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, + &phy_data); + if (ret_val) + goto out; - phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; - ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); - if (ret_val) - goto out; + phy_data &= ~M88E1000_PSCR_AUTO_X_MODE; + ret_val = phy->ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, + phy_data); + if (ret_val) + goto out; - hw_dbg("M88E1000 PSCR: %X\n", phy_data); + hw_dbg("M88E1000 PSCR: %X\n", phy_data); + } ret_val = phy->ops.read_reg(hw, PHY_CONTROL, &phy_data); if (ret_val) From 0b1a6f2ee85d77d02e73ea8be43e1a9d8d97ccee Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Thu, 18 Oct 2012 07:16:19 +0000 Subject: [PATCH 12/13] igb: Update firmware version info for ethtool output. There are multiple places in our device nvm where the version is stored. This update fixes some output errors with some types of images and refactors the way the version data is gathered and stored for ethtool output. Signed-off-by: Carolyn Wyborny Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/igb/e1000_defines.h | 14 ++++ drivers/net/ethernet/intel/igb/e1000_nvm.c | 70 +++++++++++++++++++ drivers/net/ethernet/intel/igb/e1000_nvm.h | 16 +++++ drivers/net/ethernet/intel/igb/igb_main.c | 70 ++++++------------- 4 files changed, 123 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index de4b41ec3c40..e647cff9a5e3 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -636,6 +636,7 @@ /* NVM Word Offsets */ #define NVM_COMPAT 0x0003 #define NVM_ID_LED_SETTINGS 0x0004 /* SERDES output amplitude */ +#define NVM_VERSION 0x0005 #define NVM_INIT_CONTROL2_REG 0x000F #define NVM_INIT_CONTROL3_PORT_B 0x0014 #define NVM_INIT_CONTROL3_PORT_A 0x0024 @@ -653,6 +654,19 @@ #define NVM_LED_1_CFG 0x001C #define NVM_LED_0_2_CFG 0x001F +/* NVM version defines */ +#define NVM_ETRACK_WORD 0x0042 +#define NVM_COMB_VER_OFF 0x0083 +#define NVM_COMB_VER_PTR 0x003d +#define NVM_MAJOR_MASK 0xF000 +#define NVM_MINOR_MASK 0x0FF0 +#define NVM_BUILD_MASK 0x000F +#define NVM_COMB_VER_MASK 0x00FF +#define NVM_MAJOR_SHIFT 12 +#define NVM_MINOR_SHIFT 4 +#define NVM_COMB_VER_SHFT 8 +#define NVM_VER_INVALID 0xFFFF +#define NVM_ETRACK_SHIFT 16 #define E1000_NVM_CFG_DONE_PORT_0 0x040000 /* MNG config cycle done */ #define E1000_NVM_CFG_DONE_PORT_1 0x080000 /* ...for second port */ diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c index aa5fcdf3f357..54ff53905ffe 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.c +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c @@ -710,3 +710,73 @@ s32 igb_update_nvm_checksum(struct e1000_hw *hw) out: return ret_val; } + +/** + * igb_get_fw_version - Get firmware version information + * @hw: pointer to the HW structure + * @fw_vers: pointer to output structure + * + * unsupported MAC types will return all 0 version structure + **/ +void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers) +{ + u16 eeprom_verh, eeprom_verl, comb_verh, comb_verl, comb_offset; + u16 fw_version; + + memset(fw_vers, 0, sizeof(struct e1000_fw_version)); + + switch (hw->mac.type) { + case e1000_i211: + return; + case e1000_82575: + case e1000_82576: + case e1000_82580: + case e1000_i350: + case e1000_i210: + break; + default: + return; + } + /* basic eeprom version numbers */ + hw->nvm.ops.read(hw, NVM_VERSION, 1, &fw_version); + fw_vers->eep_major = (fw_version & NVM_MAJOR_MASK) >> NVM_MAJOR_SHIFT; + fw_vers->eep_minor = (fw_version & NVM_MINOR_MASK); + + /* etrack id */ + hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verl); + hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verh); + fw_vers->etrack_id = (eeprom_verh << NVM_ETRACK_SHIFT) | eeprom_verl; + + switch (hw->mac.type) { + case e1000_i210: + case e1000_i350: + /* find combo image version */ + hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset); + if ((comb_offset != 0x0) && (comb_offset != NVM_VER_INVALID)) { + + hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset + + 1), 1, &comb_verh); + hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset), + 1, &comb_verl); + + /* get Option Rom version if it exists and is valid */ + if ((comb_verh && comb_verl) && + ((comb_verh != NVM_VER_INVALID) && + (comb_verl != NVM_VER_INVALID))) { + + fw_vers->or_valid = true; + fw_vers->or_major = + comb_verl >> NVM_COMB_VER_SHFT; + fw_vers->or_build = + ((comb_verl << NVM_COMB_VER_SHFT) + | (comb_verh >> NVM_COMB_VER_SHFT)); + fw_vers->or_patch = + comb_verh & NVM_COMB_VER_MASK; + } + } + break; + default: + break; + } + return; +} diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h index 825b0228cac0..7012d458c6f7 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.h +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h @@ -40,4 +40,20 @@ s32 igb_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data); s32 igb_validate_nvm_checksum(struct e1000_hw *hw); s32 igb_update_nvm_checksum(struct e1000_hw *hw); +struct e1000_fw_version { + u32 etrack_id; + u16 eep_major; + u16 eep_minor; + + u8 invm_major; + u8 invm_minor; + u8 invm_img_type; + + bool or_valid; + u16 or_major; + u16 or_build; + u16 or_patch; +}; +void igb_get_fw_version(struct e1000_hw *hw, struct e1000_fw_version *fw_vers); + #endif diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index b07d679b46f2..df1e7907bbaf 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1785,58 +1785,34 @@ static const struct net_device_ops igb_netdev_ops = { void igb_set_fw_version(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; - u16 eeprom_verh, eeprom_verl, comb_verh, comb_verl, comb_offset; - u16 major, build, patch, fw_version; - u32 etrack_id; + struct e1000_fw_version fw; - hw->nvm.ops.read(hw, 5, 1, &fw_version); - if (adapter->hw.mac.type != e1000_i211) { - hw->nvm.ops.read(hw, NVM_ETRACK_WORD, 1, &eeprom_verh); - hw->nvm.ops.read(hw, (NVM_ETRACK_WORD + 1), 1, &eeprom_verl); - etrack_id = (eeprom_verh << IGB_ETRACK_SHIFT) | eeprom_verl; + igb_get_fw_version(hw, &fw); - /* combo image version needs to be found */ - hw->nvm.ops.read(hw, NVM_COMB_VER_PTR, 1, &comb_offset); - if ((comb_offset != 0x0) && - (comb_offset != IGB_NVM_VER_INVALID)) { - hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset - + 1), 1, &comb_verh); - hw->nvm.ops.read(hw, (NVM_COMB_VER_OFF + comb_offset), - 1, &comb_verl); + switch (hw->mac.type) { + case e1000_i211: + snprintf(adapter->fw_version, sizeof(adapter->fw_version), + "%2d.%2d-%d", + fw.invm_major, fw.invm_minor, fw.invm_img_type); + break; - /* Only display Option Rom if it exists and is valid */ - if ((comb_verh && comb_verl) && - ((comb_verh != IGB_NVM_VER_INVALID) && - (comb_verl != IGB_NVM_VER_INVALID))) { - major = comb_verl >> IGB_COMB_VER_SHFT; - build = (comb_verl << IGB_COMB_VER_SHFT) | - (comb_verh >> IGB_COMB_VER_SHFT); - patch = comb_verh & IGB_COMB_VER_MASK; - snprintf(adapter->fw_version, - sizeof(adapter->fw_version), - "%d.%d%d, 0x%08x, %d.%d.%d", - (fw_version & IGB_MAJOR_MASK) >> - IGB_MAJOR_SHIFT, - (fw_version & IGB_MINOR_MASK) >> - IGB_MINOR_SHIFT, - (fw_version & IGB_BUILD_MASK), - etrack_id, major, build, patch); - goto out; - } + default: + /* if option is rom valid, display its version too */ + if (fw.or_valid) { + snprintf(adapter->fw_version, + sizeof(adapter->fw_version), + "%d.%d, 0x%08x, %d.%d.%d", + fw.eep_major, fw.eep_minor, fw.etrack_id, + fw.or_major, fw.or_build, fw.or_patch); + /* no option rom */ + } else { + snprintf(adapter->fw_version, + sizeof(adapter->fw_version), + "%d.%d, 0x%08x", + fw.eep_major, fw.eep_minor, fw.etrack_id); } - snprintf(adapter->fw_version, sizeof(adapter->fw_version), - "%d.%d%d, 0x%08x", - (fw_version & IGB_MAJOR_MASK) >> IGB_MAJOR_SHIFT, - (fw_version & IGB_MINOR_MASK) >> IGB_MINOR_SHIFT, - (fw_version & IGB_BUILD_MASK), etrack_id); - } else { - snprintf(adapter->fw_version, sizeof(adapter->fw_version), - "%d.%d%d", - (fw_version & IGB_MAJOR_MASK) >> IGB_MAJOR_SHIFT, - (fw_version & IGB_MINOR_MASK) >> IGB_MINOR_SHIFT, - (fw_version & IGB_BUILD_MASK)); + break; } -out: return; } From ac61d515f14fd205d8c917a34b27a767b4fe9e05 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 23 Oct 2012 00:01:04 +0000 Subject: [PATCH 13/13] igb: Fix sparse warning in igb_ptp_rx_pktstamp This change fixes a sparse warning triggered by us casting the timestamp in the packet as a u64 instead of as a __le64. This change corrects that in order to resolve the sparse warning. Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ptp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index a7db4cec7a1c..aa10f69f9f16 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -455,7 +455,7 @@ void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va, struct sk_buff *skb) { - u64 *regval = (u64 *)va; + __le64 *regval = (__le64 *)va; /* * The timestamp is recorded in little endian format.