igb: add register rd/wr for surprise removal
authorFujinaka, Todd <todd.fujinaka@intel.com>
Thu, 13 Mar 2014 04:29:01 +0000 (04:29 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Fri, 21 Mar 2014 10:00:49 +0000 (03:00 -0700)
Add initial register rd/wr for surprise removal (LER).

Signed-off-by: Todd Fujinaka <todd.fujinaka@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb_main.c

index d0f14be..bdb246e 100644 (file)
                                                        * Filter - RW */
 #define E1000_VMVIR(_n)        (0x03700 + (4 * (_n)))
 
-#define wr32(reg, value) (writel(value, hw->hw_addr + reg))
-#define rd32(reg) (readl(hw->hw_addr + reg))
+struct e1000_hw;
+
+u32 igb_rd32(struct e1000_hw *hw, u32 reg);
+
+/* write operations, indexed using DWORDS */
+#define wr32(reg, val) \
+do { \
+       u8 __iomem *hw_addr = ACCESS_ONCE((hw)->hw_addr); \
+       if (!E1000_REMOVED(hw_addr)) \
+               writel((val), &hw_addr[(reg)]); \
+} while (0)
+
+#define rd32(reg) (igb_rd32(hw, reg))
+
 #define wrfl() ((void)rd32(E1000_STATUS))
 
 #define array_wr32(reg, offset, value) \
-       (writel(value, hw->hw_addr + reg + ((offset) << 2)))
+       wr32((reg) + ((offset) << 2), (value))
+
 #define array_rd32(reg, offset) \
        (readl(hw->hw_addr + reg + ((offset) << 2)))
 
 #define E1000_INVM_DATA_REG(_n)        (0x12120 + 4*(_n))
 #define E1000_INVM_SIZE                64 /* Number of INVM Data Registers */
 
+#define E1000_REMOVED(h) unlikely(!(h))
+
 #endif
index f623e6c..e8b4f7b 100644 (file)
@@ -751,6 +751,28 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
        }
 }
 
+u32 igb_rd32(struct e1000_hw *hw, u32 reg)
+{
+       struct igb_adapter *igb = container_of(hw, struct igb_adapter, hw);
+       u8 __iomem *hw_addr = ACCESS_ONCE(hw->hw_addr);
+       u32 value = 0;
+
+       if (E1000_REMOVED(hw_addr))
+               return ~value;
+
+       value = readl(&hw_addr[reg]);
+
+       /* reads should not return all F's */
+       if (!(~value) && (!reg || !(~readl(hw_addr)))) {
+               struct net_device *netdev = igb->netdev;
+               hw->hw_addr = NULL;
+               netif_device_detach(netdev);
+               netdev_err(netdev, "PCIe link lost, device now detached\n");
+       }
+
+       return value;
+}
+
 /**
  *  igb_write_ivar - configure ivar for given MSI-X vector
  *  @hw: pointer to the HW structure