aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorGreg Rose <gregory.v.rose@intel.com>2011-09-07 01:59:35 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2011-10-13 01:45:24 -0400
commit83c61fa97a7d4ef16506a760f9e52b3144978346 (patch)
tree470c146ce7a19da9836a16b9bc454941b2b9a428 /drivers/net
parent9687c637388f63b87fcc18eee6e65bcfca4f49ca (diff)
ixgbe: Add protection from VF invalid target DMA
It is possible for a VF to set an invalid target DMA address in its Tx/Rx descriptor buffer pointers. The workarounds in this patch will guard against such an event and issue a VFLR to the VF in response. The VFLR will shut down the VF until an administrator can take action to investigate the event and correct the problem. Signed-off-by: Greg Rose <gregory.v.rose@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c172
2 files changed, 175 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 38940d72991d..c1f76aaf8774 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -116,6 +116,8 @@
116#define MAX_EMULATION_MAC_ADDRS 16 116#define MAX_EMULATION_MAC_ADDRS 16
117#define IXGBE_MAX_PF_MACVLANS 15 117#define IXGBE_MAX_PF_MACVLANS 15
118#define VMDQ_P(p) ((p) + adapter->num_vfs) 118#define VMDQ_P(p) ((p) + adapter->num_vfs)
119#define IXGBE_82599_VF_DEVICE_ID 0x10ED
120#define IXGBE_X540_VF_DEVICE_ID 0x1515
119 121
120struct vf_data_storage { 122struct vf_data_storage {
121 unsigned char vf_mac_addresses[ETH_ALEN]; 123 unsigned char vf_mac_addresses[ETH_ALEN];
@@ -512,6 +514,8 @@ struct ixgbe_adapter {
512 struct hlist_head fdir_filter_list; 514 struct hlist_head fdir_filter_list;
513 union ixgbe_atr_input fdir_mask; 515 union ixgbe_atr_input fdir_mask;
514 int fdir_filter_count; 516 int fdir_filter_count;
517 u32 timer_event_accumulator;
518 u32 vferr_refcount;
515}; 519};
516 520
517struct ixgbe_fdir_filter { 521struct ixgbe_fdir_filter {
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 1519a23421af..b95c6e979832 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -6112,6 +6112,51 @@ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
6112 clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); 6112 clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
6113} 6113}
6114 6114
6115#ifdef CONFIG_PCI_IOV
6116static void ixgbe_check_for_bad_vf(struct ixgbe_adapter *adapter)
6117{
6118 int vf;
6119 struct ixgbe_hw *hw = &adapter->hw;
6120 struct net_device *netdev = adapter->netdev;
6121 u32 gpc;
6122 u32 ciaa, ciad;
6123
6124 gpc = IXGBE_READ_REG(hw, IXGBE_TXDGPC);
6125 if (gpc) /* If incrementing then no need for the check below */
6126 return;
6127 /*
6128 * Check to see if a bad DMA write target from an errant or
6129 * malicious VF has caused a PCIe error. If so then we can
6130 * issue a VFLR to the offending VF(s) and then resume without
6131 * requesting a full slot reset.
6132 */
6133
6134 for (vf = 0; vf < adapter->num_vfs; vf++) {
6135 ciaa = (vf << 16) | 0x80000000;
6136 /* 32 bit read so align, we really want status at offset 6 */
6137 ciaa |= PCI_COMMAND;
6138 IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
6139 ciad = IXGBE_READ_REG(hw, IXGBE_CIAD_82599);
6140 ciaa &= 0x7FFFFFFF;
6141 /* disable debug mode asap after reading data */
6142 IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
6143 /* Get the upper 16 bits which will be the PCI status reg */
6144 ciad >>= 16;
6145 if (ciad & PCI_STATUS_REC_MASTER_ABORT) {
6146 netdev_err(netdev, "VF %d Hung DMA\n", vf);
6147 /* Issue VFLR */
6148 ciaa = (vf << 16) | 0x80000000;
6149 ciaa |= 0xA8;
6150 IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
6151 ciad = 0x00008000; /* VFLR */
6152 IXGBE_WRITE_REG(hw, IXGBE_CIAD_82599, ciad);
6153 ciaa &= 0x7FFFFFFF;
6154 IXGBE_WRITE_REG(hw, IXGBE_CIAA_82599, ciaa);
6155 }
6156 }
6157}
6158
6159#endif
6115/** 6160/**
6116 * ixgbe_service_timer - Timer Call-back 6161 * ixgbe_service_timer - Timer Call-back
6117 * @data: pointer to adapter cast into an unsigned long 6162 * @data: pointer to adapter cast into an unsigned long
@@ -6120,17 +6165,49 @@ static void ixgbe_service_timer(unsigned long data)
6120{ 6165{
6121 struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; 6166 struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
6122 unsigned long next_event_offset; 6167 unsigned long next_event_offset;
6168 bool ready = true;
6123 6169
6170#ifdef CONFIG_PCI_IOV
6171 ready = false;
6172
6173 /*
6174 * don't bother with SR-IOV VF DMA hang check if there are
6175 * no VFs or the link is down
6176 */
6177 if (!adapter->num_vfs ||
6178 (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) {
6179 ready = true;
6180 goto normal_timer_service;
6181 }
6182
6183 /* If we have VFs allocated then we must check for DMA hangs */
6184 ixgbe_check_for_bad_vf(adapter);
6185 next_event_offset = HZ / 50;
6186 adapter->timer_event_accumulator++;
6187
6188 if (adapter->timer_event_accumulator >= 100) {
6189 ready = true;
6190 adapter->timer_event_accumulator = 0;
6191 }
6192
6193 goto schedule_event;
6194
6195normal_timer_service:
6196#endif
6124 /* poll faster when waiting for link */ 6197 /* poll faster when waiting for link */
6125 if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) 6198 if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)
6126 next_event_offset = HZ / 10; 6199 next_event_offset = HZ / 10;
6127 else 6200 else
6128 next_event_offset = HZ * 2; 6201 next_event_offset = HZ * 2;
6129 6202
6203#ifdef CONFIG_PCI_IOV
6204schedule_event:
6205#endif
6130 /* Reset the timer */ 6206 /* Reset the timer */
6131 mod_timer(&adapter->service_timer, next_event_offset + jiffies); 6207 mod_timer(&adapter->service_timer, next_event_offset + jiffies);
6132 6208
6133 ixgbe_service_event_schedule(adapter); 6209 if (ready)
6210 ixgbe_service_event_schedule(adapter);
6134} 6211}
6135 6212
6136static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) 6213static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter)
@@ -7717,6 +7794,91 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev,
7717 struct ixgbe_adapter *adapter = pci_get_drvdata(pdev); 7794 struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
7718 struct net_device *netdev = adapter->netdev; 7795 struct net_device *netdev = adapter->netdev;
7719 7796
7797#ifdef CONFIG_PCI_IOV
7798 struct pci_dev *bdev, *vfdev;
7799 u32 dw0, dw1, dw2, dw3;
7800 int vf, pos;
7801 u16 req_id, pf_func;
7802
7803 if (adapter->hw.mac.type == ixgbe_mac_82598EB ||
7804 adapter->num_vfs == 0)
7805 goto skip_bad_vf_detection;
7806
7807 bdev = pdev->bus->self;
7808 while (bdev && (bdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT))
7809 bdev = bdev->bus->self;
7810
7811 if (!bdev)
7812 goto skip_bad_vf_detection;
7813
7814 pos = pci_find_ext_capability(bdev, PCI_EXT_CAP_ID_ERR);
7815 if (!pos)
7816 goto skip_bad_vf_detection;
7817
7818 pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG, &dw0);
7819 pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 4, &dw1);
7820 pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 8, &dw2);
7821 pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 12, &dw3);
7822
7823 req_id = dw1 >> 16;
7824 /* On the 82599 if bit 7 of the requestor ID is set then it's a VF */
7825 if (!(req_id & 0x0080))
7826 goto skip_bad_vf_detection;
7827
7828 pf_func = req_id & 0x01;
7829 if ((pf_func & 1) == (pdev->devfn & 1)) {
7830 unsigned int device_id;
7831
7832 vf = (req_id & 0x7F) >> 1;
7833 e_dev_err("VF %d has caused a PCIe error\n", vf);
7834 e_dev_err("TLP: dw0: %8.8x\tdw1: %8.8x\tdw2: "
7835 "%8.8x\tdw3: %8.8x\n",
7836 dw0, dw1, dw2, dw3);
7837 switch (adapter->hw.mac.type) {
7838 case ixgbe_mac_82599EB:
7839 device_id = IXGBE_82599_VF_DEVICE_ID;
7840 break;
7841 case ixgbe_mac_X540:
7842 device_id = IXGBE_X540_VF_DEVICE_ID;
7843 break;
7844 default:
7845 device_id = 0;
7846 break;
7847 }
7848
7849 /* Find the pci device of the offending VF */
7850 vfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID, device_id, NULL);
7851 while (vfdev) {
7852 if (vfdev->devfn == (req_id & 0xFF))
7853 break;
7854 vfdev = pci_get_device(IXGBE_INTEL_VENDOR_ID,
7855 device_id, vfdev);
7856 }
7857 /*
7858 * There's a slim chance the VF could have been hot plugged,
7859 * so if it is no longer present we don't need to issue the
7860 * VFLR. Just clean up the AER in that case.
7861 */
7862 if (vfdev) {
7863 e_dev_err("Issuing VFLR to VF %d\n", vf);
7864 pci_write_config_dword(vfdev, 0xA8, 0x00008000);
7865 }
7866
7867 pci_cleanup_aer_uncorrect_error_status(pdev);
7868 }
7869
7870 /*
7871 * Even though the error may have occurred on the other port
7872 * we still need to increment the vf error reference count for
7873 * both ports because the I/O resume function will be called
7874 * for both of them.
7875 */
7876 adapter->vferr_refcount++;
7877
7878 return PCI_ERS_RESULT_RECOVERED;
7879
7880skip_bad_vf_detection:
7881#endif /* CONFIG_PCI_IOV */
7720 netif_device_detach(netdev); 7882 netif_device_detach(netdev);
7721 7883
7722 if (state == pci_channel_io_perm_failure) 7884 if (state == pci_channel_io_perm_failure)
@@ -7779,6 +7941,14 @@ static void ixgbe_io_resume(struct pci_dev *pdev)
7779 struct ixgbe_adapter *adapter = pci_get_drvdata(pdev); 7941 struct ixgbe_adapter *adapter = pci_get_drvdata(pdev);
7780 struct net_device *netdev = adapter->netdev; 7942 struct net_device *netdev = adapter->netdev;
7781 7943
7944#ifdef CONFIG_PCI_IOV
7945 if (adapter->vferr_refcount) {
7946 e_info(drv, "Resuming after VF err\n");
7947 adapter->vferr_refcount--;
7948 return;
7949 }
7950
7951#endif
7782 if (netif_running(netdev)) 7952 if (netif_running(netdev))
7783 ixgbe_up(adapter); 7953 ixgbe_up(adapter);
7784 7954