Skip to content

Commit fb52cab

Browse files
committed
Merge branch 'intel-next'
Aaron Brown says: ==================== Intel Wired LAN Driver Updates, ixgbe: Add LER support The following patches add Live Error Recovery (LER) support to the ixgbe driver. This support also improves behavior in Thunderbolt environments. This involves checking all register reads for a value of all ones and when that is seen, to read the status register, which should never properly return all ones, to confirm whether the received value was correct. When this detects a removal, the hw_addr field is cleared to indicate the removal. This then blocks subsequent access to the device registers. All register access macros have been changed to static inline functions and all register accesses now use them.· Macro versions are temporarily provided. The __IXGBE_DOWN bit is no longer overloaded to also mean that device removal has been initiated. Now the bit can be used to protect ixgbe_down from multiple entry via test_and_set_bit. A needed smp_mb__before_clear_bit was also added. V2 Changes: - Use ACCESS_ONCE where needed, thanks to Ben Hutchings - Fix crash on module removal - Use boolean values for boolean returns instead of 0 and 1 - Reword Kconfig help text V3 Changes: - Drop config option, per David Miller - Drop tail register write checks, per Alexander Duyck - Change writeq implementation to a static inline, thanks to Joe Perches V4 Changes: - Change __IXGBE_REMOVE to __IXGBE_REMOVING, per Scott Feldman's comment - Add #define writeq writeq, per Alexander Duyck - Change static inline functions to lower case, per David Miller - Use new lower case names in added and modified register accesses - Provide temporary upper case macros for register access functions - Change IXGBE_REMOVED from macro to static inline and change references - Correct IXGBE_WRITE_FLUSH to properly enclose parameter expansion ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents e1f7ded + b0483c8 commit fb52cab

File tree

6 files changed

+194
-77
lines changed

6 files changed

+194
-77
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,11 @@ static inline u16 ixgbe_desc_unused(struct ixgbe_ring *ring)
585585
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
586586
}
587587

588+
static inline void ixgbe_write_tail(struct ixgbe_ring *ring, u32 value)
589+
{
590+
writel(value, ring->tail);
591+
}
592+
588593
#define IXGBE_RX_DESC(R, i) \
589594
(&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
590595
#define IXGBE_TX_DESC(R, i) \
@@ -742,6 +747,7 @@ struct ixgbe_adapter {
742747
#ifdef IXGBE_FCOE
743748
struct ixgbe_fcoe fcoe;
744749
#endif /* IXGBE_FCOE */
750+
u8 __iomem *io_addr; /* Mainly for iounmap use */
745751
u32 wol;
746752

747753
u16 bd_number;
@@ -798,6 +804,7 @@ enum ixgbe_state_t {
798804
__IXGBE_TESTING,
799805
__IXGBE_RESETTING,
800806
__IXGBE_DOWN,
807+
__IXGBE_REMOVING,
801808
__IXGBE_SERVICE_SCHED,
802809
__IXGBE_IN_SFP_INIT,
803810
__IXGBE_PTP_RUNNING,

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

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -124,24 +124,65 @@ 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_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
127+
#define IXGBE_FAILED_READ_REG 0xffffffffU
128128

129-
#ifndef writeq
130-
#define writeq(val, addr) writel((u32) (val), addr); \
131-
writel((u32) (val >> 32), (addr + 4));
132-
#endif
129+
static inline bool ixgbe_removed(void __iomem *addr)
130+
{
131+
return unlikely(!addr);
132+
}
133133

134-
#define IXGBE_WRITE_REG64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
134+
void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg);
135135

136-
#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
136+
static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value)
137+
{
138+
u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
137139

138-
#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
139-
writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
140+
if (ixgbe_removed(reg_addr))
141+
return;
142+
writel(value, reg_addr + reg);
143+
}
144+
#define IXGBE_WRITE_REG(a, reg, value) ixgbe_write_reg((a), (reg), (value))
140145

141-
#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
142-
readl((a)->hw_addr + (reg) + ((offset) << 2)))
146+
#ifndef writeq
147+
#define writeq writeq
148+
static inline void writeq(u64 val, void __iomem *addr)
149+
{
150+
writel((u32)val, addr);
151+
writel((u32)(val >> 32), addr + 4);
152+
}
153+
#endif
143154

144-
#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
155+
static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value)
156+
{
157+
u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
158+
159+
if (ixgbe_removed(reg_addr))
160+
return;
161+
writeq(value, reg_addr + reg);
162+
}
163+
#define IXGBE_WRITE_REG64(a, reg, value) ixgbe_write_reg64((a), (reg), (value))
164+
165+
static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
166+
{
167+
u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
168+
u32 value;
169+
170+
if (ixgbe_removed(reg_addr))
171+
return IXGBE_FAILED_READ_REG;
172+
value = readl(reg_addr + reg);
173+
if (unlikely(value == IXGBE_FAILED_READ_REG))
174+
ixgbe_check_remove(hw, reg);
175+
return value;
176+
}
177+
#define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg))
178+
179+
#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \
180+
ixgbe_write_reg((a), (reg) + ((offset) << 2), (value))
181+
182+
#define IXGBE_READ_REG_ARRAY(a, reg, offset) \
183+
ixgbe_read_reg((a), (reg) + ((offset) << 2))
184+
185+
#define IXGBE_WRITE_FLUSH(a) ixgbe_read_reg((a), IXGBE_STATUS)
145186

146187
#define ixgbe_hw_to_netdev(hw) (((struct ixgbe_adapter *)(hw)->back)->netdev)
147188

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

Lines changed: 69 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,61 +1342,61 @@ static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
13421342
static const u32 test_pattern[] = {
13431343
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
13441344

1345+
if (ixgbe_removed(adapter->hw.hw_addr)) {
1346+
*data = 1;
1347+
return 1;
1348+
}
13451349
for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
1346-
before = readl(adapter->hw.hw_addr + reg);
1347-
writel((test_pattern[pat] & write),
1348-
(adapter->hw.hw_addr + reg));
1349-
val = readl(adapter->hw.hw_addr + reg);
1350+
before = ixgbe_read_reg(&adapter->hw, reg);
1351+
ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write);
1352+
val = ixgbe_read_reg(&adapter->hw, reg);
13501353
if (val != (test_pattern[pat] & write & mask)) {
13511354
e_err(drv, "pattern test reg %04X failed: got "
13521355
"0x%08X expected 0x%08X\n",
13531356
reg, val, (test_pattern[pat] & write & mask));
13541357
*data = reg;
1355-
writel(before, adapter->hw.hw_addr + reg);
1356-
return 1;
1358+
ixgbe_write_reg(&adapter->hw, reg, before);
1359+
return true;
13571360
}
1358-
writel(before, adapter->hw.hw_addr + reg);
1361+
ixgbe_write_reg(&adapter->hw, reg, before);
13591362
}
1360-
return 0;
1363+
return false;
13611364
}
13621365

13631366
static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
13641367
u32 mask, u32 write)
13651368
{
13661369
u32 val, before;
1367-
before = readl(adapter->hw.hw_addr + reg);
1368-
writel((write & mask), (adapter->hw.hw_addr + reg));
1369-
val = readl(adapter->hw.hw_addr + reg);
1370+
1371+
if (ixgbe_removed(adapter->hw.hw_addr)) {
1372+
*data = 1;
1373+
return 1;
1374+
}
1375+
before = ixgbe_read_reg(&adapter->hw, reg);
1376+
ixgbe_write_reg(&adapter->hw, reg, write & mask);
1377+
val = ixgbe_read_reg(&adapter->hw, reg);
13701378
if ((write & mask) != (val & mask)) {
13711379
e_err(drv, "set/check reg %04X test failed: got 0x%08X "
13721380
"expected 0x%08X\n", reg, (val & mask), (write & mask));
13731381
*data = reg;
1374-
writel(before, (adapter->hw.hw_addr + reg));
1375-
return 1;
1382+
ixgbe_write_reg(&adapter->hw, reg, before);
1383+
return true;
13761384
}
1377-
writel(before, (adapter->hw.hw_addr + reg));
1378-
return 0;
1385+
ixgbe_write_reg(&adapter->hw, reg, before);
1386+
return false;
13791387
}
13801388

1381-
#define REG_PATTERN_TEST(reg, mask, write) \
1382-
do { \
1383-
if (reg_pattern_test(adapter, data, reg, mask, write)) \
1384-
return 1; \
1385-
} while (0) \
1386-
1387-
1388-
#define REG_SET_AND_CHECK(reg, mask, write) \
1389-
do { \
1390-
if (reg_set_and_check(adapter, data, reg, mask, write)) \
1391-
return 1; \
1392-
} while (0) \
1393-
13941389
static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
13951390
{
13961391
const struct ixgbe_reg_test *test;
13971392
u32 value, before, after;
13981393
u32 i, toggle;
13991394

1395+
if (ixgbe_removed(adapter->hw.hw_addr)) {
1396+
e_err(drv, "Adapter removed - register test blocked\n");
1397+
*data = 1;
1398+
return 1;
1399+
}
14001400
switch (adapter->hw.mac.type) {
14011401
case ixgbe_mac_82598EB:
14021402
toggle = 0x7FFFF3FF;
@@ -1419,57 +1419,66 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
14191419
* tests. Some bits are read-only, some toggle, and some
14201420
* are writeable on newer MACs.
14211421
*/
1422-
before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS);
1423-
value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle);
1424-
IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
1425-
after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
1422+
before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS);
1423+
value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle);
1424+
ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle);
1425+
after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle;
14261426
if (value != after) {
14271427
e_err(drv, "failed STATUS register test got: 0x%08X "
14281428
"expected: 0x%08X\n", after, value);
14291429
*data = 1;
14301430
return 1;
14311431
}
14321432
/* restore previous status */
1433-
IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before);
1433+
ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before);
14341434

14351435
/*
14361436
* Perform the remainder of the register test, looping through
14371437
* the test table until we either fail or reach the null entry.
14381438
*/
14391439
while (test->reg) {
14401440
for (i = 0; i < test->array_len; i++) {
1441+
bool b = false;
1442+
14411443
switch (test->test_type) {
14421444
case PATTERN_TEST:
1443-
REG_PATTERN_TEST(test->reg + (i * 0x40),
1444-
test->mask,
1445-
test->write);
1445+
b = reg_pattern_test(adapter, data,
1446+
test->reg + (i * 0x40),
1447+
test->mask,
1448+
test->write);
14461449
break;
14471450
case SET_READ_TEST:
1448-
REG_SET_AND_CHECK(test->reg + (i * 0x40),
1449-
test->mask,
1450-
test->write);
1451+
b = reg_set_and_check(adapter, data,
1452+
test->reg + (i * 0x40),
1453+
test->mask,
1454+
test->write);
14511455
break;
14521456
case WRITE_NO_TEST:
1453-
writel(test->write,
1454-
(adapter->hw.hw_addr + test->reg)
1455-
+ (i * 0x40));
1457+
ixgbe_write_reg(&adapter->hw,
1458+
test->reg + (i * 0x40),
1459+
test->write);
14561460
break;
14571461
case TABLE32_TEST:
1458-
REG_PATTERN_TEST(test->reg + (i * 4),
1459-
test->mask,
1460-
test->write);
1462+
b = reg_pattern_test(adapter, data,
1463+
test->reg + (i * 4),
1464+
test->mask,
1465+
test->write);
14611466
break;
14621467
case TABLE64_TEST_LO:
1463-
REG_PATTERN_TEST(test->reg + (i * 8),
1464-
test->mask,
1465-
test->write);
1468+
b = reg_pattern_test(adapter, data,
1469+
test->reg + (i * 8),
1470+
test->mask,
1471+
test->write);
14661472
break;
14671473
case TABLE64_TEST_HI:
1468-
REG_PATTERN_TEST((test->reg + 4) + (i * 8),
1469-
test->mask,
1470-
test->write);
1474+
b = reg_pattern_test(adapter, data,
1475+
(test->reg + 4) + (i * 8),
1476+
test->mask,
1477+
test->write);
14711478
break;
14721479
}
1480+
if (b)
1481+
return 1;
14731482
}
14741483
test++;
14751484
}
@@ -1954,6 +1963,15 @@ static void ixgbe_diag_test(struct net_device *netdev,
19541963
struct ixgbe_adapter *adapter = netdev_priv(netdev);
19551964
bool if_running = netif_running(netdev);
19561965

1966+
if (ixgbe_removed(adapter->hw.hw_addr)) {
1967+
e_err(hw, "Adapter removed - test blocked\n");
1968+
data[0] = 1;
1969+
data[1] = 1;
1970+
data[2] = 1;
1971+
data[3] = 1;
1972+
eth_test->flags |= ETH_TEST_FL_FAILED;
1973+
return;
1974+
}
19571975
set_bit(__IXGBE_TESTING, &adapter->state);
19581976
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
19591977
struct ixgbe_hw *hw = &adapter->hw;

0 commit comments

Comments
 (0)