From 4ccc650cc845476885f73660b2e6335852f0f75c Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 2 Sep 2015 13:47:54 -0700 Subject: [PATCH 01/18] ixgbe: fix issue with SFP events with new X550 devices Add checks for systems that don't have SFP's to avoid incorrectly acting on interrupts that are falsely interpreted as SFP events. This also includes a modified check generating the EICR mask to be more forward-looking. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 63b2cfe9416b..b9267e20e269 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2495,17 +2495,26 @@ static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw) static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr) { struct ixgbe_hw *hw = &adapter->hw; + u32 eicr_mask = IXGBE_EICR_GPI_SDP2(hw); - if (eicr & IXGBE_EICR_GPI_SDP2(hw)) { + if (!ixgbe_is_sfp(hw)) + return; + + /* Later MAC's use different SDP */ + if (hw->mac.type >= ixgbe_mac_X540) + eicr_mask = IXGBE_EICR_GPI_SDP0_X540; + + if (eicr & eicr_mask) { /* Clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2(hw)); + IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr_mask); if (!test_bit(__IXGBE_DOWN, &adapter->state)) { adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; ixgbe_service_event_schedule(adapter); } } - if (eicr & IXGBE_EICR_GPI_SDP1(hw)) { + if (adapter->hw.mac.type == ixgbe_mac_82599EB && + (eicr & IXGBE_EICR_GPI_SDP1(hw))) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1(hw)); if (!test_bit(__IXGBE_DOWN, &adapter->state)) { From 6b010e9b1f0a406d1d35202a694fa724a559bf77 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Wed, 29 Jul 2015 14:38:21 -0600 Subject: [PATCH 02/18] ixgbe: Teardown SR-IOV before unregister_netdev() When the .remove() callback for a PF is called, SR-IOV support for the device is disabled, which requires unbinding and removing the VFs. The VFs may be in-use either by the host kernel or userspace, such as assigned to a VM through vfio-pci. In this latter case, the VFs may be removed either by shutting down the VM or hot-unplugging the devices from the VM. Unfortunately in the case of a Windows 2012 R2 guest, hot-unplug is broken due to the ordering of the PF driver teardown. Disabling SR-IOV prior to unregister_netdev() avoids this issue. Signed-off-by: Alex Williamson Acked-by: Mitch Williams Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index b9267e20e269..c04480ed905e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9028,12 +9028,12 @@ static void ixgbe_remove(struct pci_dev *pdev) /* remove the added san mac */ ixgbe_del_sanmac_netdev(netdev); - if (netdev->reg_state == NETREG_REGISTERED) - unregister_netdev(netdev); - #ifdef CONFIG_PCI_IOV ixgbe_disable_sriov(adapter); #endif + if (netdev->reg_state == NETREG_REGISTERED) + unregister_netdev(netdev); + ixgbe_clear_interrupt_scheme(adapter); ixgbe_release_hw_control(adapter); From 8ac34f10a5ea4c7b6f57dfd52b0693a2b67d9ac4 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 30 Jul 2015 15:19:28 -0700 Subject: [PATCH 03/18] ixgbe: Limit lowest interrupt rate for adaptive interrupt moderation to 12K This patch updates the lowest limit for adaptive interrupt interrupt moderation to roughly 12K interrupts per second. The way I came about reaching 12K as the desired interrupt rate is by testing with UDP flows. Specifically I had a simple test that ran a netperf UDP_STREAM test at varying sizes. What I found was as the packet sizes increased the performance fell steadily behind until we were only able to receive at ~4Gb/s with a message size of 65507. A bit of digging found that we were dropping packets for the socket in the network stack, and looking at things further what I found was I could solve it by increasing the interrupt rate, or increasing the rmem_default/rmem_max. What I found was that when the interrupt coalescing resulted in more data being processed per interrupt than could be stored in the socket buffer we started losing packets and the performance dropped. So I reached 12K based on the following math. rmem_default = 212992 skb->truesize = 2994 212992 / 2994 = 71.14 packets to fill the buffer packet rate at 1514 packet size is 812744pps 71.14 / 812744 = 87.9us to fill socket buffer From there it was just a matter of choosing the interrupt rate and providing a bit of wiggle room which is why I decided to go with 12K interrupts per second as that uses a value of 84us. The data below is based on VM to VM over a direct assigned ixgbe interface. The test run was: netperf -H -t UDP_STREAM" Socket Message Elapsed Messages CPU Service Size Size Time Okay Errors Throughput Util Demand bytes bytes secs # # 10^6bits/sec % SS us/KB Before: 212992 65507 60.00 1100662 0 9613.4 10.89 0.557 212992 60.00 473474 4135.4 11.27 0.576 After: 212992 65507 60.00 1100413 0 9611.2 10.73 0.549 212992 60.00 974132 8508.3 11.69 0.598 Using bare metal the data is similar but not as dramatic as the throughput increases from about 8.5Gb/s to 9.5Gb/s. Signed-off-by: Alexander Duyck Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 3 +-- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 2 +- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index edf1fb913209..a699c991ad2c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -539,8 +539,7 @@ struct hwmon_buff { #define IXGBE_MIN_RSC_ITR 24 #define IXGBE_100K_ITR 40 #define IXGBE_20K_ITR 200 -#define IXGBE_10K_ITR 400 -#define IXGBE_8K_ITR 500 +#define IXGBE_12K_ITR 336 /* ixgbe_test_staterr - tests bits in Rx descriptor status and error fields */ static inline __le32 ixgbe_test_staterr(union ixgbe_adv_rx_desc *rx_desc, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index ab2edc8e7703..94c4912b2330 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2286,7 +2286,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev, adapter->tx_itr_setting = ec->tx_coalesce_usecs; if (adapter->tx_itr_setting == 1) - tx_itr_param = IXGBE_10K_ITR; + tx_itr_param = IXGBE_12K_ITR; else tx_itr_param = adapter->tx_itr_setting; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index 68e1e757ecef..f3168bcc7d87 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -866,7 +866,7 @@ static int ixgbe_alloc_q_vector(struct ixgbe_adapter *adapter, if (txr_count && !rxr_count) { /* tx only vector */ if (adapter->tx_itr_setting == 1) - q_vector->itr = IXGBE_10K_ITR; + q_vector->itr = IXGBE_12K_ITR; else q_vector->itr = adapter->tx_itr_setting; } else { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index c04480ed905e..acb1b91408ec 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -2261,7 +2261,7 @@ static void ixgbe_update_itr(struct ixgbe_q_vector *q_vector, /* simple throttlerate management * 0-10MB/s lowest (100000 ints/s) * 10-20MB/s low (20000 ints/s) - * 20-1249MB/s bulk (8000 ints/s) + * 20-1249MB/s bulk (12000 ints/s) */ /* what was last interrupt timeslice? */ timepassed_us = q_vector->itr >> 2; @@ -2350,7 +2350,7 @@ static void ixgbe_set_itr(struct ixgbe_q_vector *q_vector) new_itr = IXGBE_20K_ITR; break; case bulk_latency: - new_itr = IXGBE_8K_ITR; + new_itr = IXGBE_12K_ITR; break; default: break; From e40296628bec7400f529927eef4bc87cb425a22a Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 15 Jun 2015 15:00:51 -0700 Subject: [PATCH 04/18] fm10k: disable service task during suspend The service task reads some registers as part of its normal routine, even while the interface is down. Normally this is ok. However, during suspend we have disabled the PCI device. Due to this, registers will read in the same way as a surprise-remove event. Disable the service task while we suspend, and re-enable it after we resume. If we don't do this, the device could be UP when you suspend and come back from resume as closed (since fm10k closes the device when it gets a surprise remove). Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index ce53ff25f88d..8413ab548eba 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -1983,6 +1983,16 @@ static int fm10k_resume(struct pci_dev *pdev) if (err) return err; + /* assume host is not ready, to prevent race with watchdog in case we + * actually don't have connection to the switch + */ + interface->host_ready = false; + fm10k_watchdog_host_not_ready(interface); + + /* clear the service task disable bit to allow service task to start */ + clear_bit(__FM10K_SERVICE_DISABLE, &interface->state); + fm10k_service_event_schedule(interface); + /* restore SR-IOV interface */ fm10k_iov_resume(pdev); @@ -2010,6 +2020,15 @@ static int fm10k_suspend(struct pci_dev *pdev, fm10k_iov_suspend(pdev); + /* the watchdog tasks may read registers, which will appear like a + * surprise-remove event once the PCI device is disabled. This will + * cause us to close the netdevice, so we don't retain the open/closed + * state post-resume. Prevent this by disabling the service task while + * suspended, until we actually resume. + */ + set_bit(__FM10K_SERVICE_DISABLE, &interface->state); + cancel_work_sync(&interface->service_task); + rtnl_lock(); if (netif_running(netdev)) From 56f0569e3ab741d3c5cebc4b4c882b471df53738 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 15 Jun 2015 15:00:53 -0700 Subject: [PATCH 05/18] fm10k: only prevent removal of default VID rules This allows us to correctly add a VLAN even if it matches our default VID. However, we don't want to remove the VID rules once that VLAN is deleted. Correctly remove the stack layers information of the VLAN, but then return to forwarding that VID as untagged frames. If we deleted the VID rules here, we would begin dropping traffic due to VLAN membership violations. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 99228bf46c12..818bc8b1fa58 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -775,8 +775,8 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) if (!set) clear_bit(vid, interface->active_vlans); - /* if default VLAN is already present do nothing */ - if (vid == hw->mac.default_vid) + /* Do not remove default VID related entries from VLAN and MAC tables */ + if (!set && vid == hw->mac.default_vid) return 0; fm10k_mbx_lock(interface); From 106c07a49506359f7663770ef33f4997d68316c1 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 15 Jun 2015 15:00:55 -0700 Subject: [PATCH 06/18] fm10k: update fm10k_slot_warn to use pcie_get_minimum link This is useful in cases where we connect to a slot at Gen3, but the slot is behind a bus which only connected at Gen2. This generally only happens when a PCIe switch is in the sequence of devices, and can be very confusing when you see slow performance with no obvious cause. I am aware this patch has a few lines that break 80 characters, but there does not seem to be a readable way to format them to less than 80 characters. Suggestions welcome. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 105 ++++++++++++++----- 1 file changed, 76 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 8413ab548eba..2d87c3282c0c 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -1705,22 +1705,86 @@ static int fm10k_sw_init(struct fm10k_intfc *interface, static void fm10k_slot_warn(struct fm10k_intfc *interface) { - struct device *dev = &interface->pdev->dev; + enum pcie_link_width width = PCIE_LNK_WIDTH_UNKNOWN; + enum pci_bus_speed speed = PCI_SPEED_UNKNOWN; struct fm10k_hw *hw = &interface->hw; + int max_gts = 0, expected_gts = 0; - if (hw->mac.ops.is_slot_appropriate(hw)) + if (pcie_get_minimum_link(interface->pdev, &speed, &width) || + speed == PCI_SPEED_UNKNOWN || width == PCIE_LNK_WIDTH_UNKNOWN) { + dev_warn(&interface->pdev->dev, + "Unable to determine PCI Express bandwidth.\n"); return; + } - dev_warn(dev, - "For optimal performance, a %s %s slot is recommended.\n", - (hw->bus_caps.width == fm10k_bus_width_pcie_x1 ? "x1" : - hw->bus_caps.width == fm10k_bus_width_pcie_x4 ? "x4" : - "x8"), - (hw->bus_caps.speed == fm10k_bus_speed_2500 ? "2.5GT/s" : - hw->bus_caps.speed == fm10k_bus_speed_5000 ? "5.0GT/s" : - "8.0GT/s")); - dev_warn(dev, - "A slot with more lanes and/or higher speed is suggested.\n"); + switch (speed) { + case PCIE_SPEED_2_5GT: + /* 8b/10b encoding reduces max throughput by 20% */ + max_gts = 2 * width; + break; + case PCIE_SPEED_5_0GT: + /* 8b/10b encoding reduces max throughput by 20% */ + max_gts = 4 * width; + break; + case PCIE_SPEED_8_0GT: + /* 128b/130b encoding has less than 2% impact on throughput */ + max_gts = 8 * width; + break; + default: + dev_warn(&interface->pdev->dev, + "Unable to determine PCI Express bandwidth.\n"); + return; + } + + dev_info(&interface->pdev->dev, + "PCI Express bandwidth of %dGT/s available\n", + max_gts); + dev_info(&interface->pdev->dev, + "(Speed:%s, Width: x%d, Encoding Loss:%s, Payload:%s)\n", + (speed == PCIE_SPEED_8_0GT ? "8.0GT/s" : + speed == PCIE_SPEED_5_0GT ? "5.0GT/s" : + speed == PCIE_SPEED_2_5GT ? "2.5GT/s" : + "Unknown"), + hw->bus.width, + (speed == PCIE_SPEED_2_5GT ? "20%" : + speed == PCIE_SPEED_5_0GT ? "20%" : + speed == PCIE_SPEED_8_0GT ? "<2%" : + "Unknown"), + (hw->bus.payload == fm10k_bus_payload_128 ? "128B" : + hw->bus.payload == fm10k_bus_payload_256 ? "256B" : + hw->bus.payload == fm10k_bus_payload_512 ? "512B" : + "Unknown")); + + switch (hw->bus_caps.speed) { + case fm10k_bus_speed_2500: + /* 8b/10b encoding reduces max throughput by 20% */ + expected_gts = 2 * hw->bus_caps.width; + break; + case fm10k_bus_speed_5000: + /* 8b/10b encoding reduces max throughput by 20% */ + expected_gts = 4 * hw->bus_caps.width; + break; + case fm10k_bus_speed_8000: + /* 128b/130b encoding has less than 2% impact on throughput */ + expected_gts = 8 * hw->bus_caps.width; + break; + default: + dev_warn(&interface->pdev->dev, + "Unable to determine expected PCI Express bandwidth.\n"); + return; + } + + if (max_gts < expected_gts) { + dev_warn(&interface->pdev->dev, + "This device requires %dGT/s of bandwidth for optimal performance.\n", + expected_gts); + dev_warn(&interface->pdev->dev, + "A %sslot with x%d lanes is suggested.\n", + (hw->bus_caps.speed == fm10k_bus_speed_2500 ? "2.5GT/s " : + hw->bus_caps.speed == fm10k_bus_speed_5000 ? "5.0GT/s " : + hw->bus_caps.speed == fm10k_bus_speed_8000 ? "8.0GT/s " : ""), + hw->bus_caps.width); + } } /** @@ -1739,7 +1803,6 @@ static int fm10k_probe(struct pci_dev *pdev, { struct net_device *netdev; struct fm10k_intfc *interface; - struct fm10k_hw *hw; int err; err = pci_enable_device_mem(pdev); @@ -1783,7 +1846,6 @@ static int fm10k_probe(struct pci_dev *pdev, interface->netdev = netdev; interface->pdev = pdev; - hw = &interface->hw; interface->uc_addr = ioremap(pci_resource_start(pdev, 0), FM10K_UC_ADDR_SIZE); @@ -1825,21 +1887,6 @@ static int fm10k_probe(struct pci_dev *pdev, /* Register PTP interface */ fm10k_ptp_register(interface); - /* print bus type/speed/width info */ - dev_info(&pdev->dev, "(PCI Express:%s Width: %s Payload: %s)\n", - (hw->bus.speed == fm10k_bus_speed_8000 ? "8.0GT/s" : - hw->bus.speed == fm10k_bus_speed_5000 ? "5.0GT/s" : - hw->bus.speed == fm10k_bus_speed_2500 ? "2.5GT/s" : - "Unknown"), - (hw->bus.width == fm10k_bus_width_pcie_x8 ? "x8" : - hw->bus.width == fm10k_bus_width_pcie_x4 ? "x4" : - hw->bus.width == fm10k_bus_width_pcie_x1 ? "x1" : - "Unknown"), - (hw->bus.payload == fm10k_bus_payload_128 ? "128B" : - hw->bus.payload == fm10k_bus_payload_256 ? "256B" : - hw->bus.payload == fm10k_bus_payload_512 ? "512B" : - "Unknown")); - /* print warning for non-optimal configurations */ fm10k_slot_warn(interface); From bdc7f5902d22e7297b8f0d7a8d6ed8429cdba636 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Mon, 15 Jun 2015 15:00:56 -0700 Subject: [PATCH 07/18] fm10k: update netdev perm_addr during reinit, instead of at up Update the netdev permanent address during fm10k_reinit enables the user to immediately see the new MAC address on the VF even if the device isn't up. The previous code required that the device by opened before changes would appear. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 15 --------------- drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 818bc8b1fa58..b2065cb44edc 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -996,21 +996,6 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface) int xcast_mode; u16 vid, glort; - /* restore our address if perm_addr is set */ - if (hw->mac.type == fm10k_mac_vf) { - if (is_valid_ether_addr(hw->mac.perm_addr)) { - ether_addr_copy(hw->mac.addr, hw->mac.perm_addr); - ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr); - ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr); - netdev->addr_assign_type &= ~NET_ADDR_RANDOM; - } - - if (hw->mac.vlan_override) - netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; - else - netdev->features |= NETIF_F_HW_VLAN_CTAG_RX; - } - /* record glort for this interface */ glort = interface->glort; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 2d87c3282c0c..db237b7dd088 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -170,6 +170,21 @@ static void fm10k_reinit(struct fm10k_intfc *interface) /* reassociate interrupts */ fm10k_mbx_request_irq(interface); + /* update hardware address for VFs if perm_addr has changed */ + if (hw->mac.type == fm10k_mac_vf) { + if (is_valid_ether_addr(hw->mac.perm_addr)) { + ether_addr_copy(hw->mac.addr, hw->mac.perm_addr); + ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr); + ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr); + netdev->addr_assign_type &= ~NET_ADDR_RANDOM; + } + + if (hw->mac.vlan_override) + netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; + else + netdev->features |= NETIF_F_HW_VLAN_CTAG_RX; + } + /* reset clock */ fm10k_ts_reset(interface); From aae072e363bed4e91c00d57f753c799276ddb161 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 16 Jun 2015 11:47:12 -0700 Subject: [PATCH 08/18] fm10k: Don't assume page fragments are page size This change pulls out the optimization that assumed that all fragments would be limited to page size. That hasn't been the case for some time now and to assume this is incorrect as the TCP allocator can provide up to a 32K page fragment. Signed-off-by: Alexander Duyck Acked-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index b5b2925103ec..6ad03e0f2e30 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -1079,9 +1079,7 @@ netdev_tx_t fm10k_xmit_frame_ring(struct sk_buff *skb, struct fm10k_tx_buffer *first; int tso; u32 tx_flags = 0; -#if PAGE_SIZE > FM10K_MAX_DATA_PER_TXD unsigned short f; -#endif u16 count = TXD_USE_COUNT(skb_headlen(skb)); /* need: 1 descriptor per page * PAGE_SIZE/FM10K_MAX_DATA_PER_TXD, @@ -1089,12 +1087,9 @@ netdev_tx_t fm10k_xmit_frame_ring(struct sk_buff *skb, * + 2 desc gap to keep tail from touching head * otherwise try next time */ -#if PAGE_SIZE > FM10K_MAX_DATA_PER_TXD for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size); -#else - count += skb_shinfo(skb)->nr_frags; -#endif + if (fm10k_maybe_stop_tx(tx_ring, count + 3)) { tx_ring->tx_stats.tx_busy++; return NETDEV_TX_BUSY; From 0ff36676a3778d0655933ace201fca7c11b4e8b5 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 18 Jun 2015 19:41:10 -0700 Subject: [PATCH 09/18] fm10k: Report MAC address on driver load This change adds the MAC address to the list of values recorded on driver load. The MAC address represents the serial number of the unit and allows us to track the value should a card be replaced in a system. The log message should now be similar in output to that of ixgbe. Signed-off-by: Alexander Duyck Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index db237b7dd088..9f2b2f19e2a4 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -1905,6 +1905,9 @@ static int fm10k_probe(struct pci_dev *pdev, /* print warning for non-optimal configurations */ fm10k_slot_warn(interface); + /* report MAC address for logging */ + dev_info(&pdev->dev, "%pM\n", netdev->dev_addr); + /* enable SR-IOV after registering netdev to enforce PF/VF ordering */ fm10k_iov_configure(pdev, 0); From 3f0bdb2e2ce7db7425856686d9ccd8fd0ddf9bf0 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 19 Jun 2015 10:56:09 -0700 Subject: [PATCH 10/18] fm10k: allow creation of VLAN interfaces even while down We re-sync upon going up, so there is little reason to worry about not syncing immediately with switch. This prevents an error that occurs if you add a VLAN interface while down. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index b2065cb44edc..e1ceb3a2e2cd 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -779,6 +779,12 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) if (!set && vid == hw->mac.default_vid) return 0; + /* Do not throw an error if the interface is down. We will sync once + * we come up + */ + if (test_bit(__FM10K_DOWN, &interface->state)) + return 0; + fm10k_mbx_lock(interface); /* only need to update the VLAN if not in promiscuous mode */ From b655a5c735867c1a80e7ceaa1f1c45d1dd34909f Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Fri, 19 Jun 2015 10:56:10 -0700 Subject: [PATCH 11/18] fm10k: don't store sw_vid at reset If we store the sw_vid at reset of PF, then we accidentally prevent the VF from receiving the message to update its default VID. This only occurs if the VF is created before the PF has come up, which is the standard way of creating VFs when using the module parameter. This fixes an issue where we request the incorrect MAC/VLAN combinations, and prevents us from accidentally reporting some frames as VLAN tagged. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_iov.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c index 94571e6e790c..0e25a80417b9 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_iov.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_iov.c @@ -228,9 +228,6 @@ int fm10k_iov_resume(struct pci_dev *pdev) hw->iov.ops.set_lport(hw, vf_info, i, FM10K_VF_FLAG_MULTI_CAPABLE); - /* assign our default vid to the VF following reset */ - vf_info->sw_vid = hw->mac.default_vid; - /* mailbox is disconnected so we don't send a message */ hw->iov.ops.assign_default_mac_vlan(hw, vf_info); From 855c40fc31ca2392845558235f7e92e406936fbe Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 24 Jun 2015 13:34:41 -0700 Subject: [PATCH 12/18] fm10k: remove is_slot_appropriate This function is no longer used now that we have updated fm10k_slot_warn functionality. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pf.c | 14 -------------- drivers/net/ethernet/intel/fm10k/fm10k_type.h | 1 - drivers/net/ethernet/intel/fm10k/fm10k_vf.c | 14 -------------- 3 files changed, 29 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c index 3ca0233b3ea2..241b969626bc 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c @@ -184,19 +184,6 @@ static s32 fm10k_init_hw_pf(struct fm10k_hw *hw) return 0; } -/** - * fm10k_is_slot_appropriate_pf - Indicate appropriate slot for this SKU - * @hw: pointer to hardware structure - * - * Looks at the PCIe bus info to confirm whether or not this slot can support - * the necessary bandwidth for this device. - **/ -static bool fm10k_is_slot_appropriate_pf(struct fm10k_hw *hw) -{ - return (hw->bus.speed == hw->bus_caps.speed) && - (hw->bus.width == hw->bus_caps.width); -} - /** * fm10k_update_vlan_pf - Update status of VLAN ID in VLAN filter table * @hw: pointer to hardware structure @@ -1849,7 +1836,6 @@ static struct fm10k_mac_ops mac_ops_pf = { .init_hw = &fm10k_init_hw_pf, .start_hw = &fm10k_start_hw_generic, .stop_hw = &fm10k_stop_hw_generic, - .is_slot_appropriate = &fm10k_is_slot_appropriate_pf, .update_vlan = &fm10k_update_vlan_pf, .read_mac_addr = &fm10k_read_mac_addr_pf, .update_uc_addr = &fm10k_update_uc_addr_pf, diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h index 2a17d82fa37d..bac8d486d75f 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h +++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h @@ -521,7 +521,6 @@ struct fm10k_mac_ops { s32 (*stop_hw)(struct fm10k_hw *); s32 (*get_bus_info)(struct fm10k_hw *); s32 (*get_host_state)(struct fm10k_hw *, bool *); - bool (*is_slot_appropriate)(struct fm10k_hw *); s32 (*update_vlan)(struct fm10k_hw *, u32, u8, bool); s32 (*read_mac_addr)(struct fm10k_hw *); s32 (*update_uc_addr)(struct fm10k_hw *, u16, const u8 *, diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c index 94f0f6a146d9..36c8b0aa08fd 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_vf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_vf.c @@ -131,19 +131,6 @@ static s32 fm10k_init_hw_vf(struct fm10k_hw *hw) return 0; } -/** - * fm10k_is_slot_appropriate_vf - Indicate appropriate slot for this SKU - * @hw: pointer to hardware structure - * - * Looks at the PCIe bus info to confirm whether or not this slot can support - * the necessary bandwidth for this device. Since the VF has no control over - * the "slot" it is in, always indicate that the slot is appropriate. - **/ -static bool fm10k_is_slot_appropriate_vf(struct fm10k_hw *hw) -{ - return true; -} - /* This structure defines the attibutes to be parsed below */ const struct fm10k_tlv_attr fm10k_mac_vlan_msg_attr[] = { FM10K_TLV_ATTR_U32(FM10K_MAC_VLAN_MSG_VLAN), @@ -552,7 +539,6 @@ static struct fm10k_mac_ops mac_ops_vf = { .init_hw = &fm10k_init_hw_vf, .start_hw = &fm10k_start_hw_generic, .stop_hw = &fm10k_stop_hw_vf, - .is_slot_appropriate = &fm10k_is_slot_appropriate_vf, .update_vlan = &fm10k_update_vlan_vf, .read_mac_addr = &fm10k_read_mac_addr_vf, .update_uc_addr = &fm10k_update_uc_addr_vf, From 6fbc6b358b3f63e701d15e9d330a3b0dbb03f802 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 24 Jun 2015 13:34:44 -0700 Subject: [PATCH 13/18] fm10k: TRIVIAL fix up ordering of __always_unused and style Fix some style issues in debugfs code, and correct ordering of void and __always_unused. Technically, the order does not matter, but preferred style is to put the macro between the type and name. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c b/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c index f45b4d71adb8..08ecf43dffc7 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_debugfs.c @@ -37,7 +37,8 @@ static void *fm10k_dbg_desc_seq_start(struct seq_file *s, loff_t *pos) } static void *fm10k_dbg_desc_seq_next(struct seq_file *s, - void __always_unused *v, loff_t *pos) + void __always_unused *v, + loff_t *pos) { struct fm10k_ring *ring = s->private; @@ -45,7 +46,7 @@ static void *fm10k_dbg_desc_seq_next(struct seq_file *s, } static void fm10k_dbg_desc_seq_stop(struct seq_file __always_unused *s, - __always_unused void *v) + void __always_unused *v) { /* Do nothing. */ } From e71c9318428fb16de808b497e0229994010d32a1 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 24 Jun 2015 13:34:46 -0700 Subject: [PATCH 14/18] fm10k: send traffic on default VID to VLAN device if we have one This patch ensures that VLAN traffic on the default VID will go to the corresponding VLAN device if it exists. To do this, mask the rx_ring VID if we have an active VLAN on that VID. For this to work correctly, we need to update fm10k_process_skb_fields to correctly mask off the VLAN_PRIO_MASK bits and compare them separately, otherwise we incorrectly compare the priority bits with the cleared flag. This also happens to fix a related bug where having priority bits set causes us to incorrectly classify traffic. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_main.c | 5 ++++- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 12 ++++++++++++ drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 4 ++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c index 6ad03e0f2e30..92d415584749 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c @@ -497,8 +497,11 @@ static unsigned int fm10k_process_skb_fields(struct fm10k_ring *rx_ring, if (rx_desc->w.vlan) { u16 vid = le16_to_cpu(rx_desc->w.vlan); - if (vid != rx_ring->vid) + if ((vid & VLAN_VID_MASK) != rx_ring->vid) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); + else if (vid & VLAN_PRIO_MASK) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + vid & VLAN_PRIO_MASK); } fm10k_type_trans(rx_ring, rx_desc, skb); diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index e1ceb3a2e2cd..3a6230b405fe 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -758,6 +758,7 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_hw *hw = &interface->hw; s32 err; + int i; /* updates do not apply to VLAN 0 */ if (!vid) @@ -775,6 +776,17 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set) if (!set) clear_bit(vid, interface->active_vlans); + /* disable the default VID on ring if we have an active VLAN */ + for (i = 0; i < interface->num_rx_queues; i++) { + struct fm10k_ring *rx_ring = interface->rx_ring[i]; + u16 rx_vid = rx_ring->vid & (VLAN_N_VID - 1); + + if (test_bit(rx_vid, interface->active_vlans)) + rx_ring->vid |= FM10K_VLAN_CLEAR; + else + rx_ring->vid &= ~FM10K_VLAN_CLEAR; + } + /* Do not remove default VID related entries from VLAN and MAC tables */ if (!set && vid == hw->mac.default_vid) return 0; diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 9f2b2f19e2a4..9bdc04da451e 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -678,6 +678,10 @@ static void fm10k_configure_rx_ring(struct fm10k_intfc *interface, /* assign default VLAN to queue */ ring->vid = hw->mac.default_vid; + /* if we have an active VLAN, disable default VID */ + if (test_bit(hw->mac.default_vid, interface->active_vlans)) + ring->vid |= FM10K_VLAN_CLEAR; + /* Map interrupt */ if (ring->q_vector) { rxint = ring->q_vector->v_idx + NON_Q_VECTORS(hw); From 5c2d642fd0cf0f4f7396dfd3754bc03f6e50e359 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 24 Jun 2015 13:34:47 -0700 Subject: [PATCH 15/18] fm10k: TRIVIAL fix typo in fm10k_netdev.c Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c index 3a6230b405fe..639263d5e833 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c @@ -1048,7 +1048,7 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface) vid, true, 0); } - /* update xcast mode before syncronizing addresses */ + /* update xcast mode before synchronizing addresses */ hw->mac.ops.update_xcast_mode(hw, glort, xcast_mode); /* synchronize all of the addresses */ From 95f4f8da644256d8c0ff5bab2c93ba33d2a42cd8 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 24 Jun 2015 13:34:48 -0700 Subject: [PATCH 16/18] fm10k: re-enable VF after a full reset on detection of a Malicious event Modify behavior of Malicious Driver Detection events. Presently, the hardware disables the VF queues and re-assigns them to the PF. This causes the VF in question to continuously Tx hang, because it assumes that it can transmit over the queues in question. For transient events, this results in continuous logging of malicious events. New behavior is to reset the LPORT and VF state, so that the VF will have to reset and re-enable itself. This does mean that malicious VFs will possibly be able to continue and attempt malicious events again. However, it is expected that system administrators will step in and manually remove or disable the VF in question. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 30 ++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c index 9bdc04da451e..3d71c5206110 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pci.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pci.c @@ -880,10 +880,12 @@ void fm10k_netpoll(struct net_device *netdev) #endif #define FM10K_ERR_MSG(type) case (type): error = #type; break -static void fm10k_print_fault(struct fm10k_intfc *interface, int type, +static void fm10k_handle_fault(struct fm10k_intfc *interface, int type, struct fm10k_fault *fault) { struct pci_dev *pdev = interface->pdev; + struct fm10k_hw *hw = &interface->hw; + struct fm10k_iov_data *iov_data = interface->iov_data; char *error; switch (type) { @@ -937,6 +939,30 @@ static void fm10k_print_fault(struct fm10k_intfc *interface, int type, "%s Address: 0x%llx SpecInfo: 0x%x Func: %02x.%0x\n", error, fault->address, fault->specinfo, PCI_SLOT(fault->func), PCI_FUNC(fault->func)); + + /* For VF faults, clear out the respective LPORT, reset the queue + * resources, and then reconnect to the mailbox. This allows the + * VF in question to resume behavior. For transient faults that are + * the result of non-malicious behavior this will log the fault and + * allow the VF to resume functionality. Obviously for malicious VFs + * they will be able to attempt malicious behavior again. In this + * case, the system administrator will need to step in and manually + * remove or disable the VF in question. + */ + if (fault->func && iov_data) { + int vf = fault->func - 1; + struct fm10k_vf_info *vf_info = &iov_data->vf_info[vf]; + + hw->iov.ops.reset_lport(hw, vf_info); + hw->iov.ops.reset_resources(hw, vf_info); + + /* reset_lport disables the VF, so re-enable it */ + hw->iov.ops.set_lport(hw, vf_info, vf, + FM10K_VF_FLAG_MULTI_CAPABLE); + + /* reset_resources will disconnect from the mbx */ + vf_info->mbx.ops.connect(hw, &vf_info->mbx); + } } static void fm10k_report_fault(struct fm10k_intfc *interface, u32 eicr) @@ -960,7 +986,7 @@ static void fm10k_report_fault(struct fm10k_intfc *interface, u32 eicr) continue; } - fm10k_print_fault(interface, type, &fault); + fm10k_handle_fault(interface, type, &fault); } } From ac98100359e098d03dbd98783ca4becaf2ea7ec3 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 24 Jun 2015 13:34:49 -0700 Subject: [PATCH 17/18] fm10k: Only trigger data path reset if fabric is up This change makes it so that we only trigger the data path reset if the fabric is ready to handle traffic. The general idea is to avoid triggering the reset unless the switch API is ready for us. Otherwise we can just postpone the reset until we receive a switch ready notification. Signed-off-by: Alexander Duyck Signed-off-by: Jacob Keller Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c index 241b969626bc..d806d87a6192 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c @@ -59,6 +59,11 @@ static s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) if (reg & (FM10K_DMA_CTRL_TX_ACTIVE | FM10K_DMA_CTRL_RX_ACTIVE)) return FM10K_ERR_DMA_PENDING; + /* verify the switch is ready for reset */ + reg = fm10k_read_reg(hw, FM10K_DMA_CTRL2); + if (!(reg & FM10K_DMA_CTRL2_SWITCH_READY)) + goto out; + /* Inititate data path reset */ reg |= FM10K_DMA_CTRL_DATAPATH_RESET; fm10k_write_reg(hw, FM10K_DMA_CTRL, reg); @@ -72,6 +77,7 @@ static s32 fm10k_reset_hw_pf(struct fm10k_hw *hw) if (!(reg & FM10K_IP_NOTINRESET)) err = FM10K_ERR_RESET_FAILED; +out: return err; } From 9adbac599a71bc25a2617850ffcaa4388dc5c20d Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 24 Jun 2015 13:34:50 -0700 Subject: [PATCH 18/18] fm10k: fix iov_msg_mac_vlan_pf VID checks The VF will send a message to request multicast addresses with the default VID. In the current code, if the PF has statically assigned a VLAN to a VF, then the VF will not get the multicast addresses. Fix up all of the various VLAN messages to use identical checks (since each check was different). Also use set as a variable, so that it simplifies our check for whether VLAN matches the pf_vid. The new logic will allow set of a VLAN if it is zero, automatically converting to the default VID. Otherwise it will allow setting the PF VID, or any VLAN if PF has not statically assigned a VLAN. This is consistent behavior, and allows VF to request either 0 or the default_vid without silently failing. Note that we need the check for zero since VFs might not get the default VID message in time to actually request non-zero VLANs. Signed-off-by: Jacob Keller Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/fm10k/fm10k_pf.c | 85 +++++++++++++-------- 1 file changed, 52 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c index d806d87a6192..8c0bdc4e4edd 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c @@ -1154,6 +1154,24 @@ s32 fm10k_iov_msg_msix_pf(struct fm10k_hw *hw, u32 **results, return hw->iov.ops.assign_int_moderator(hw, vf_idx); } +/** + * fm10k_iov_select_vid - Select correct default VID + * @hw: Pointer to hardware structure + * @vid: VID to correct + * + * Will report an error if VID is out of range. For VID = 0, it will return + * either the pf_vid or sw_vid depending on which one is set. + */ +static inline s32 fm10k_iov_select_vid(struct fm10k_vf_info *vf_info, u16 vid) +{ + if (!vid) + return vf_info->pf_vid ? vf_info->pf_vid : vf_info->sw_vid; + else if (vf_info->pf_vid && vid != vf_info->pf_vid) + return FM10K_ERR_PARAM; + else + return vid; +} + /** * fm10k_iov_msg_mac_vlan_pf - Message handler for MAC/VLAN request from VF * @hw: Pointer to hardware structure @@ -1168,9 +1186,10 @@ s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, struct fm10k_mbx_info *mbx) { struct fm10k_vf_info *vf_info = (struct fm10k_vf_info *)mbx; - int err = 0; u8 mac[ETH_ALEN]; u32 *result; + int err = 0; + bool set; u16 vlan; u32 vid; @@ -1186,19 +1205,21 @@ s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, if (err) return err; - /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ - if (!vid || (vid == FM10K_VLAN_CLEAR)) { - if (vf_info->pf_vid) - vid |= vf_info->pf_vid; - else - vid |= vf_info->sw_vid; - } else if (vid != vf_info->pf_vid) { + /* verify upper 16 bits are zero */ + if (vid >> 16) return FM10K_ERR_PARAM; - } + + set = !(vid & FM10K_VLAN_CLEAR); + vid &= ~FM10K_VLAN_CLEAR; + + err = fm10k_iov_select_vid(vf_info, vid); + if (err < 0) + return err; + else + vid = err; /* update VSI info for VF in regards to VLAN table */ - err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, - !(vid & FM10K_VLAN_CLEAR)); + err = hw->mac.ops.update_vlan(hw, vid, vf_info->vsi, set); } if (!err && !!results[FM10K_MAC_VLAN_MSG_MAC]) { @@ -1214,19 +1235,18 @@ s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, memcmp(mac, vf_info->mac, ETH_ALEN)) return FM10K_ERR_PARAM; - /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ - if (!vlan || (vlan == FM10K_VLAN_CLEAR)) { - if (vf_info->pf_vid) - vlan |= vf_info->pf_vid; - else - vlan |= vf_info->sw_vid; - } else if (vf_info->pf_vid) { - return FM10K_ERR_PARAM; - } + set = !(vlan & FM10K_VLAN_CLEAR); + vlan &= ~FM10K_VLAN_CLEAR; + + err = fm10k_iov_select_vid(vf_info, vlan); + if (err < 0) + return err; + else + vlan = err; /* notify switch of request for new unicast address */ - err = hw->mac.ops.update_uc_addr(hw, vf_info->glort, mac, vlan, - !(vlan & FM10K_VLAN_CLEAR), 0); + err = hw->mac.ops.update_uc_addr(hw, vf_info->glort, + mac, vlan, set, 0); } if (!err && !!results[FM10K_MAC_VLAN_MSG_MULTICAST]) { @@ -1241,19 +1261,18 @@ s32 fm10k_iov_msg_mac_vlan_pf(struct fm10k_hw *hw, u32 **results, if (!(vf_info->vf_flags & FM10K_VF_FLAG_MULTI_ENABLED)) return FM10K_ERR_PARAM; - /* if VLAN ID is 0, set the default VLAN ID instead of 0 */ - if (!vlan || (vlan == FM10K_VLAN_CLEAR)) { - if (vf_info->pf_vid) - vlan |= vf_info->pf_vid; - else - vlan |= vf_info->sw_vid; - } else if (vf_info->pf_vid) { - return FM10K_ERR_PARAM; - } + set = !(vlan & FM10K_VLAN_CLEAR); + vlan &= ~FM10K_VLAN_CLEAR; + + err = fm10k_iov_select_vid(vf_info, vlan); + if (err < 0) + return err; + else + vlan = err; /* notify switch of request for new multicast address */ - err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, mac, vlan, - !(vlan & FM10K_VLAN_CLEAR)); + err = hw->mac.ops.update_mc_addr(hw, vf_info->glort, + mac, vlan, set); } return err;