Skip to content

Commit 2a1a091

Browse files
mdrustaddavem330
authored andcommitted
ixgbe: Check register reads for adapter removal
Check all register reads for adapter removal by checking the status register after any register read that returns 0xFFFFFFFF. Since the status register will never return 0xFFFFFFFF unless the adapter is removed, such a value from a status register read confirms the removal. Signed-off-by: Mark Rustad <[email protected]> Tested-by: Phil Schmitt <[email protected]> Signed-off-by: Aaron Brown <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 49bde31 commit 2a1a091

File tree

3 files changed

+53
-5
lines changed

3 files changed

+53
-5
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,7 @@ struct ixgbe_adapter {
747747
#ifdef IXGBE_FCOE
748748
struct ixgbe_fcoe fcoe;
749749
#endif /* IXGBE_FCOE */
750+
u8 __iomem *io_addr; /* Mainly for iounmap use */
750751
u32 wol;
751752

752753
u16 bd_number;

drivers/net/ethernet/intel/ixgbe/ixgbe_common.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
124124
s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
125125
s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);
126126

127+
#define IXGBE_FAILED_READ_REG 0xffffffffU
128+
129+
static inline bool ixgbe_removed(void __iomem *addr)
130+
{
131+
return unlikely(!addr);
132+
}
133+
134+
void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg);
135+
127136
static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
128137
{
129138
writel(value, hw->hw_addr + reg);
@@ -147,7 +156,15 @@ static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value)
147156

148157
static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
149158
{
150-
return readl(hw->hw_addr + reg);
159+
u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
160+
u32 value;
161+
162+
if (ixgbe_removed(reg_addr))
163+
return IXGBE_FAILED_READ_REG;
164+
value = readl(reg_addr + reg);
165+
if (unlikely(value == IXGBE_FAILED_READ_REG))
166+
ixgbe_check_remove(hw, reg);
167+
return value;
151168
}
152169
#define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg))
153170

drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,35 @@ static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
283283
schedule_work(&adapter->service_task);
284284
}
285285

286+
static void ixgbe_remove_adapter(struct ixgbe_hw *hw)
287+
{
288+
struct ixgbe_adapter *adapter = hw->back;
289+
290+
if (!hw->hw_addr)
291+
return;
292+
hw->hw_addr = NULL;
293+
e_dev_err("Adapter removed\n");
294+
}
295+
296+
void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg)
297+
{
298+
u32 value;
299+
300+
/* The following check not only optimizes a bit by not
301+
* performing a read on the status register when the
302+
* register just read was a status register read that
303+
* returned IXGBE_FAILED_READ_REG. It also blocks any
304+
* potential recursion.
305+
*/
306+
if (reg == IXGBE_STATUS) {
307+
ixgbe_remove_adapter(hw);
308+
return;
309+
}
310+
value = ixgbe_read_reg(hw, IXGBE_STATUS);
311+
if (value == IXGBE_FAILED_READ_REG)
312+
ixgbe_remove_adapter(hw);
313+
}
314+
286315
static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter)
287316
{
288317
BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state));
@@ -2970,7 +2999,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter,
29702999
ring->count * sizeof(union ixgbe_adv_tx_desc));
29713000
IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0);
29723001
IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0);
2973-
ring->tail = hw->hw_addr + IXGBE_TDT(reg_idx);
3002+
ring->tail = adapter->io_addr + IXGBE_TDT(reg_idx);
29743003

29753004
/*
29763005
* set WTHRESH to encourage burst writeback, it should not be set
@@ -3373,7 +3402,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter,
33733402
ring->count * sizeof(union ixgbe_adv_rx_desc));
33743403
IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0);
33753404
IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0);
3376-
ring->tail = hw->hw_addr + IXGBE_RDT(reg_idx);
3405+
ring->tail = adapter->io_addr + IXGBE_RDT(reg_idx);
33773406

33783407
ixgbe_configure_srrctl(adapter, ring);
33793408
ixgbe_configure_rscctl(adapter, ring);
@@ -7880,6 +7909,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
78807909

78817910
hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
78827911
pci_resource_len(pdev, 0));
7912+
adapter->io_addr = hw->hw_addr;
78837913
if (!hw->hw_addr) {
78847914
err = -EIO;
78857915
goto err_ioremap;
@@ -8188,7 +8218,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
81888218
err_sw_init:
81898219
ixgbe_disable_sriov(adapter);
81908220
adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
8191-
iounmap(hw->hw_addr);
8221+
iounmap(adapter->io_addr);
81928222
err_ioremap:
81938223
free_netdev(netdev);
81948224
err_alloc_etherdev:
@@ -8255,7 +8285,7 @@ static void ixgbe_remove(struct pci_dev *pdev)
82558285
kfree(adapter->ixgbe_ieee_ets);
82568286

82578287
#endif
8258-
iounmap(adapter->hw.hw_addr);
8288+
iounmap(adapter->io_addr);
82598289
pci_release_selected_regions(pdev, pci_select_bars(pdev,
82608290
IORESOURCE_MEM));
82618291

0 commit comments

Comments
 (0)