Skip to content

Commit

Permalink
Merge branch 'intel-next'
Browse files Browse the repository at this point in the history
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 <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jan 15, 2014
2 parents e1f7ded + b0483c8 commit fb52cab
Show file tree
Hide file tree
Showing 6 changed files with 194 additions and 77 deletions.
7 changes: 7 additions & 0 deletions drivers/net/ethernet/intel/ixgbe/ixgbe.h
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,11 @@ static inline u16 ixgbe_desc_unused(struct ixgbe_ring *ring)
return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1;
}

static inline void ixgbe_write_tail(struct ixgbe_ring *ring, u32 value)
{
writel(value, ring->tail);
}

#define IXGBE_RX_DESC(R, i) \
(&(((union ixgbe_adv_rx_desc *)((R)->desc))[i]))
#define IXGBE_TX_DESC(R, i) \
Expand Down Expand Up @@ -742,6 +747,7 @@ struct ixgbe_adapter {
#ifdef IXGBE_FCOE
struct ixgbe_fcoe fcoe;
#endif /* IXGBE_FCOE */
u8 __iomem *io_addr; /* Mainly for iounmap use */
u32 wol;

u16 bd_number;
Expand Down Expand Up @@ -798,6 +804,7 @@ enum ixgbe_state_t {
__IXGBE_TESTING,
__IXGBE_RESETTING,
__IXGBE_DOWN,
__IXGBE_REMOVING,
__IXGBE_SERVICE_SCHED,
__IXGBE_IN_SFP_INIT,
__IXGBE_PTP_RUNNING,
Expand Down
65 changes: 53 additions & 12 deletions drivers/net/ethernet/intel/ixgbe/ixgbe_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,24 +124,65 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw);
s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw);
s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw);

#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
#define IXGBE_FAILED_READ_REG 0xffffffffU

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

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

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

#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
writel((value), ((a)->hw_addr + (reg) + ((offset) << 2))))
if (ixgbe_removed(reg_addr))
return;
writel(value, reg_addr + reg);
}
#define IXGBE_WRITE_REG(a, reg, value) ixgbe_write_reg((a), (reg), (value))

#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\
readl((a)->hw_addr + (reg) + ((offset) << 2)))
#ifndef writeq
#define writeq writeq
static inline void writeq(u64 val, void __iomem *addr)
{
writel((u32)val, addr);
writel((u32)(val >> 32), addr + 4);
}
#endif

#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value)
{
u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);

if (ixgbe_removed(reg_addr))
return;
writeq(value, reg_addr + reg);
}
#define IXGBE_WRITE_REG64(a, reg, value) ixgbe_write_reg64((a), (reg), (value))

static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg)
{
u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr);
u32 value;

if (ixgbe_removed(reg_addr))
return IXGBE_FAILED_READ_REG;
value = readl(reg_addr + reg);
if (unlikely(value == IXGBE_FAILED_READ_REG))
ixgbe_check_remove(hw, reg);
return value;
}
#define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg))

#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \
ixgbe_write_reg((a), (reg) + ((offset) << 2), (value))

#define IXGBE_READ_REG_ARRAY(a, reg, offset) \
ixgbe_read_reg((a), (reg) + ((offset) << 2))

#define IXGBE_WRITE_FLUSH(a) ixgbe_read_reg((a), IXGBE_STATUS)

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

Expand Down
120 changes: 69 additions & 51 deletions drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1342,61 +1342,61 @@ static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg,
static const u32 test_pattern[] = {
0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};

if (ixgbe_removed(adapter->hw.hw_addr)) {
*data = 1;
return 1;
}
for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) {
before = readl(adapter->hw.hw_addr + reg);
writel((test_pattern[pat] & write),
(adapter->hw.hw_addr + reg));
val = readl(adapter->hw.hw_addr + reg);
before = ixgbe_read_reg(&adapter->hw, reg);
ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write);
val = ixgbe_read_reg(&adapter->hw, reg);
if (val != (test_pattern[pat] & write & mask)) {
e_err(drv, "pattern test reg %04X failed: got "
"0x%08X expected 0x%08X\n",
reg, val, (test_pattern[pat] & write & mask));
*data = reg;
writel(before, adapter->hw.hw_addr + reg);
return 1;
ixgbe_write_reg(&adapter->hw, reg, before);
return true;
}
writel(before, adapter->hw.hw_addr + reg);
ixgbe_write_reg(&adapter->hw, reg, before);
}
return 0;
return false;
}

static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg,
u32 mask, u32 write)
{
u32 val, before;
before = readl(adapter->hw.hw_addr + reg);
writel((write & mask), (adapter->hw.hw_addr + reg));
val = readl(adapter->hw.hw_addr + reg);

if (ixgbe_removed(adapter->hw.hw_addr)) {
*data = 1;
return 1;
}
before = ixgbe_read_reg(&adapter->hw, reg);
ixgbe_write_reg(&adapter->hw, reg, write & mask);
val = ixgbe_read_reg(&adapter->hw, reg);
if ((write & mask) != (val & mask)) {
e_err(drv, "set/check reg %04X test failed: got 0x%08X "
"expected 0x%08X\n", reg, (val & mask), (write & mask));
*data = reg;
writel(before, (adapter->hw.hw_addr + reg));
return 1;
ixgbe_write_reg(&adapter->hw, reg, before);
return true;
}
writel(before, (adapter->hw.hw_addr + reg));
return 0;
ixgbe_write_reg(&adapter->hw, reg, before);
return false;
}

#define REG_PATTERN_TEST(reg, mask, write) \
do { \
if (reg_pattern_test(adapter, data, reg, mask, write)) \
return 1; \
} while (0) \


#define REG_SET_AND_CHECK(reg, mask, write) \
do { \
if (reg_set_and_check(adapter, data, reg, mask, write)) \
return 1; \
} while (0) \

static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
{
const struct ixgbe_reg_test *test;
u32 value, before, after;
u32 i, toggle;

if (ixgbe_removed(adapter->hw.hw_addr)) {
e_err(drv, "Adapter removed - register test blocked\n");
*data = 1;
return 1;
}
switch (adapter->hw.mac.type) {
case ixgbe_mac_82598EB:
toggle = 0x7FFFF3FF;
Expand All @@ -1419,57 +1419,66 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
* tests. Some bits are read-only, some toggle, and some
* are writeable on newer MACs.
*/
before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS);
value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS);
value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle);
ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle);
after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle;
if (value != after) {
e_err(drv, "failed STATUS register test got: 0x%08X "
"expected: 0x%08X\n", after, value);
*data = 1;
return 1;
}
/* restore previous status */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before);
ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before);

/*
* Perform the remainder of the register test, looping through
* the test table until we either fail or reach the null entry.
*/
while (test->reg) {
for (i = 0; i < test->array_len; i++) {
bool b = false;

switch (test->test_type) {
case PATTERN_TEST:
REG_PATTERN_TEST(test->reg + (i * 0x40),
test->mask,
test->write);
b = reg_pattern_test(adapter, data,
test->reg + (i * 0x40),
test->mask,
test->write);
break;
case SET_READ_TEST:
REG_SET_AND_CHECK(test->reg + (i * 0x40),
test->mask,
test->write);
b = reg_set_and_check(adapter, data,
test->reg + (i * 0x40),
test->mask,
test->write);
break;
case WRITE_NO_TEST:
writel(test->write,
(adapter->hw.hw_addr + test->reg)
+ (i * 0x40));
ixgbe_write_reg(&adapter->hw,
test->reg + (i * 0x40),
test->write);
break;
case TABLE32_TEST:
REG_PATTERN_TEST(test->reg + (i * 4),
test->mask,
test->write);
b = reg_pattern_test(adapter, data,
test->reg + (i * 4),
test->mask,
test->write);
break;
case TABLE64_TEST_LO:
REG_PATTERN_TEST(test->reg + (i * 8),
test->mask,
test->write);
b = reg_pattern_test(adapter, data,
test->reg + (i * 8),
test->mask,
test->write);
break;
case TABLE64_TEST_HI:
REG_PATTERN_TEST((test->reg + 4) + (i * 8),
test->mask,
test->write);
b = reg_pattern_test(adapter, data,
(test->reg + 4) + (i * 8),
test->mask,
test->write);
break;
}
if (b)
return 1;
}
test++;
}
Expand Down Expand Up @@ -1954,6 +1963,15 @@ static void ixgbe_diag_test(struct net_device *netdev,
struct ixgbe_adapter *adapter = netdev_priv(netdev);
bool if_running = netif_running(netdev);

if (ixgbe_removed(adapter->hw.hw_addr)) {
e_err(hw, "Adapter removed - test blocked\n");
data[0] = 1;
data[1] = 1;
data[2] = 1;
data[3] = 1;
eth_test->flags |= ETH_TEST_FL_FAILED;
return;
}
set_bit(__IXGBE_TESTING, &adapter->state);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
struct ixgbe_hw *hw = &adapter->hw;
Expand Down
Loading

0 comments on commit fb52cab

Please sign in to comment.