On Fri, 23 Jun 2006, Linas Vepstas wrote: > I've got another ixgb driver bug I'm struggling with; clues or hints > appreciated. > > I've got a patch for PCI error recovery for the ixgb, which works on > many older kernels but seems to be broken on linux-2.6.17-rc6-mm2 > (which is ixgb version 1.0.109). After performing a PCI reset on the > card, I try to re-initialize the cad and the driver, with the following > sequence: > > pci_set_master(pdev); > netif_carrier_off(netdev); > netif_stop_queue(netdev); > ixgb_check_options(adapter); > ixgb_reset(adapter); > > This is only a subset of the ixgb_probe code, since I don't need to > request regions or do any of the other setup. However, this code > fails in an unexpected way. The last call invokes ixgb_mac_reset() > which writes a reset bit, delays a few millisecs, and reads the reset > bit. The problem I'm seeing is that the read > > ctrl_reg = IXGB_READ_REG(hw, CTRL0); > > triggers some PCI bus error that off-lines the device. Any hints > about where to look? This doesn't occur on other driver versions, > and doesn't occur on this driver during the ordinary probe() sequence. > Increasing the dealy doesn't seem to help.
you probably need to do something similar to stopping the transmitter and receiver using the TCTL and RCTL registers, and then waiting for any pending master requests to finish. Ah, it appears the code in ixgb_adapter_stop is missing a IXGB_WRITE_FLUSH before the msec_delay. try this patch? it is compile tested. <snip> [PATCH] ixgb: make sure to flush writes before waiting ixgb is missing some write flushes when issuing the reset, and a few others for that matter. Signed-off-by: Jesse Brandeburg <[EMAIL PROTECTED]> --- drivers/net/ixgb/ixgb_ee.c | 9 +++++++++ drivers/net/ixgb/ixgb_hw.c | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c index 8357c55..2359973 100644 --- a/drivers/net/ixgb/ixgb_ee.c +++ b/drivers/net/ixgb/ixgb_ee.c @@ -55,6 +55,7 @@ ixgb_raise_clock(struct ixgb_hw *hw, */ *eecd_reg = *eecd_reg | IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, *eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); return; } @@ -74,6 +75,7 @@ ixgb_lower_clock(struct ixgb_hw *hw, */ *eecd_reg = *eecd_reg & ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, *eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); return; } @@ -112,6 +114,7 @@ ixgb_shift_out_bits(struct ixgb_hw *hw, eecd_reg |= IXGB_EECD_DI; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); @@ -208,21 +211,25 @@ ixgb_standby_eeprom(struct ixgb_hw *hw) /* Deselct EEPROM */ eecd_reg &= ~(IXGB_EECD_CS | IXGB_EECD_SK); IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Clock high */ eecd_reg |= IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Select EEPROM */ eecd_reg |= IXGB_EECD_CS; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Clock low */ eecd_reg &= ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); return; } @@ -242,11 +249,13 @@ ixgb_clock_eeprom(struct ixgb_hw *hw) /* Rising edge of clock */ eecd_reg |= IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); /* Falling edge of clock */ eecd_reg &= ~IXGB_EECD_SK; IXGB_WRITE_REG(hw, EECD, eecd_reg); + IXGB_WRITE_FLUSH(hw); udelay(50); return; } diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c index f7fa10e..3e08ba8 100644 --- a/drivers/net/ixgb/ixgb_hw.c +++ b/drivers/net/ixgb/ixgb_hw.c @@ -81,7 +81,7 @@ static uint32_t ixgb_mac_reset(struct ix #else IXGB_WRITE_REG(hw, CTRL0, ctrl_reg); #endif - + IXGB_WRITE_FLUSH(hw); /* Delay a few ms just to allow the reset to complete */ msec_delay(IXGB_DELAY_AFTER_RESET); ctrl_reg = IXGB_READ_REG(hw, CTRL0); @@ -133,6 +133,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw) */ IXGB_WRITE_REG(hw, RCTL, IXGB_READ_REG(hw, RCTL) & ~IXGB_RCTL_RXEN); IXGB_WRITE_REG(hw, TCTL, IXGB_READ_REG(hw, TCTL) & ~IXGB_TCTL_TXEN); + IXGB_WRITE_FLUSH(hw); msec_delay(IXGB_DELAY_BEFORE_RESET); /* Issue a global reset to the MAC. This will reset the chip's @@ -287,7 +288,7 @@ ixgb_init_hw(struct ixgb_hw *hw) #else IXGB_WRITE_REG(hw, CTRL1, IXGB_CTRL1_EE_RST); #endif - + IXGB_WRITE_FLUSH(hw); /* Delay a few ms just to allow the reset to complete */ msec_delay(IXGB_DELAY_AFTER_EE_RESET); - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html