Re: Intel 82559 NIC corrupted EEPROM

2 messages, 2 authors, 2007-02-13 · open the first message on its own page

Re: Intel 82559 NIC corrupted EEPROM

From: John <hidden>
Date: 2007-02-07 11:08:40

Jesse Brandeburg wrote:
John wrote:
quoted
Jesse Brandeburg wrote:
quoted
can you try adding mdelay(100); in e100_eeprom_load before the for loop,
and then change the multiple udelay(4) to mdelay(1) in e100_eeprom_read
I applied the attached patch.

Loading the driver now takes around one minute :-)
ouch, but yep, thats what happens when you use "super extra delay"
quoted
I ran 'source load_unload' 25 times in a loop.

The first 12 times were successful. The last 13 times failed.
(cf. attached archive)

I noticed something very strange.

The number of words obviously in error (0xFFFF) returned by the EEPROM
on 00:09.0 is not constant.
That is very strange, I would think that maybe you have something else
on the bus with the e100 that may be hogging bus cycles you have
failing hardware (maybe a bad eeprom, or possibly a bad mac chip)
quoted
$ grep -c 0xFFFF insmod*
insmod_300.txt:0
insmod_301.txt:0
insmod_302.txt:0
insmod_303.txt:0
insmod_304.txt:0
insmod_305.txt:0
insmod_306.txt:0
insmod_307.txt:0
insmod_308.txt:0
insmod_309.txt:0
insmod_310.txt:0
insmod_311.txt:0
insmod_312.txt:1
insmod_313.txt:5
insmod_314.txt:24
insmod_315.txt:45
insmod_316.txt:243
insmod_317.txt:256
insmod_318.txt:256
insmod_319.txt:256
insmod_320.txt:256
insmod_321.txt:256
insmod_322.txt:256
insmod_323.txt:253
insmod_324.txt:240
this is even stranger, does it cycle back down (sine wave) to zero
again?  The delays did seem to work, at least sometimes.  This
indicates that something needs that extra delay to successfully read
the eeprom.  I might try changing all the udelay(4) to udelay(40) (x10
increase) and see if that gives you a happy medium of "most times
driver loads without error"

John, this problem seems to be very specific to your hardware.  I know
that you have put in a lot of time debugging this, but I'm not sure
what we can do from here.  If this were a generic code problem more
people would be reporting the issue.

What would you like to do?  At this stage I would like e100 to work
better than it is, but I'm not sure what to do next.
Hello everyone,

I'm resurrecting this thread because it appears we'll need to support 
these motherboards for several months to come, yet Adrian Bunk has 
scheduled the removal of eepro100 in January 2007.

To recap, we have to support ~30 EBC-2000T motherboards.
http://www.adlinktech.com/PD/web/PD_detail.php?pid=213
These motherboards come with three on-board Intel 82559 NICs.

Last time I checked, i.e. two months ago, e100 did not correctly 
initialize all three NICs on these motherboards. Therefore, we've been 
using eepro100.

I will be testing the latest 2.6.20 kernel to see if the situation has 
changed, but I wanted to let you all know that there are still some 
eepro100 users out there, out of necessity.

Regards,

John

RE: Intel 82559 NIC corrupted EEPROM

From: Brandeburg, Jesse <hidden>
Date: 2007-02-13 19:45:48

John wrote:
Jesse Brandeburg wrote:
quoted
What would you like to do?  At this stage I would like e100 to work
better than it is, but I'm not sure what to do next.
Hello everyone,

I'm resurrecting this thread because it appears we'll need to support
these motherboards for several months to come, yet Adrian Bunk has
scheduled the removal of eepro100 in January 2007.

To recap, we have to support ~30 EBC-2000T motherboards.
http://www.adlinktech.com/PD/web/PD_detail.php?pid=213
These motherboards come with three on-board Intel 82559 NICs.

Last time I checked, i.e. two months ago, e100 did not correctly
initialize all three NICs on these motherboards. Therefore, we've been
using eepro100.

I will be testing the latest 2.6.20 kernel to see if the situation has
changed, but I wanted to let you all know that there are still some
eepro100 users out there, out of necessity.
John, I've made this patch against 2.6.20 to enable IO access for e100,
in the hope it might change something with the timings. I smoke tested
it against one e100 in one of my machines, and I disabled the Mem bit in
the COMMAND register after loading the driver to make sure that it
wasn't using memory access to the registers.

Please test with insmod e100.ko use_io=1

The patch is actually short, considering the magnitude of the change,
its inline and attached in case my mailer corrupts it.

Please let me know if it changes something, I still believe this is
something very specific to your systems (or more likely the eeprom on
your systems)

== begin patch ==

e100: try using io only
Signed-off-by: Jesse Brandeburg <redacted>
---

 drivers/net/e100.c |   74
++++++++++++++++++++++++++++------------------------
 1 files changed, 40 insertions(+), 34 deletions(-)
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 0cefef5..df3d2e7 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -159,7 +159,7 @@ #include <asm/unaligned.h>
 
 #define DRV_NAME		"e100"
 #define DRV_EXT			"-NAPI"
-#define DRV_VERSION		"3.5.17-k2"DRV_EXT
+#define DRV_VERSION		"3.5.17-k2_iodebug"DRV_EXT
 #define DRV_DESCRIPTION		"Intel(R) PRO/100 Network
Driver"
 #define DRV_COPYRIGHT		"Copyright(c) 1999-2006 Intel
Corporation"
 #define PFX			DRV_NAME ": "
@@ -174,10 +174,13 @@ MODULE_VERSION(DRV_VERSION);
 
 static int debug = 3;
 static int eeprom_bad_csum_allow = 0;
+static int use_io = 0;
 module_param(debug, int, 0);
 module_param(eeprom_bad_csum_allow, int, 0);
+module_param(use_io, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
+MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
 #define DPRINTK(nlevel, klevel, fmt, args...) \
 	(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
 	printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -591,7 +594,7 @@ static inline void e100_write_flush(stru
 {
 	/* Flush previous PCI writes through intermediate bridges
 	 * by doing a benign read */
-	(void)readb(&nic->csr->scb.status);
+	(void)ioread8(&nic->csr->scb.status);
 }
 
 static void e100_enable_irq(struct nic *nic)
@@ -599,7 +602,7 @@ static void e100_enable_irq(struct nic *
 	unsigned long flags;
 
 	spin_lock_irqsave(&nic->cmd_lock, flags);
-	writeb(irq_mask_none, &nic->csr->scb.cmd_hi);
+	iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi);
 	e100_write_flush(nic);
 	spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
@@ -609,7 +612,7 @@ static void e100_disable_irq(struct nic 
 	unsigned long flags;
 
 	spin_lock_irqsave(&nic->cmd_lock, flags);
-	writeb(irq_mask_all, &nic->csr->scb.cmd_hi);
+	iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi);
 	e100_write_flush(nic);
 	spin_unlock_irqrestore(&nic->cmd_lock, flags);
 }
@@ -618,11 +621,11 @@ static void e100_hw_reset(struct nic *ni
 {
 	/* Put CU and RU into idle with a selective reset to get
 	 * device off of PCI bus */
-	writel(selective_reset, &nic->csr->port);
+	iowrite32(selective_reset, &nic->csr->port);
 	e100_write_flush(nic); udelay(20);
 
 	/* Now fully reset device */
-	writel(software_reset, &nic->csr->port);
+	iowrite32(software_reset, &nic->csr->port);
 	e100_write_flush(nic); udelay(20);
 
 	/* Mask off our interrupt line - it's unmasked after reset */
@@ -639,7 +642,7 @@ static int e100_self_test(struct nic *ni
 	nic->mem->selftest.signature = 0;
 	nic->mem->selftest.result = 0xFFFFFFFF;
 
-	writel(selftest | dma_addr, &nic->csr->port);
+	iowrite32(selftest | dma_addr, &nic->csr->port);
 	e100_write_flush(nic);
 	/* Wait 10 msec for self-test to complete */
 	msleep(10);
@@ -677,23 +680,23 @@ static void e100_eeprom_write(struct nic
 	for(j = 0; j < 3; j++) {
 
 		/* Chip select */
-		writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 
 		for(i = 31; i >= 0; i--) {
 			ctrl = (cmd_addr_data[j] & (1 << i)) ?
 				eecs | eedi : eecs;
-			writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+			iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
 			e100_write_flush(nic); udelay(4);
 
-			writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+			iowrite8(ctrl | eesk,
&nic->csr->eeprom_ctrl_lo);
 			e100_write_flush(nic); udelay(4);
 		}
 		/* Wait 10 msec for cmd to complete */
 		msleep(10);
 
 		/* Chip deselect */
-		writeb(0, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(0, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 	}
 };
@@ -709,21 +712,21 @@ static u16 e100_eeprom_read(struct nic *
 	cmd_addr_data = ((op_read << *addr_len) | addr) << 16;
 
 	/* Chip select */
-	writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
+	iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo);
 	e100_write_flush(nic); udelay(4);
 
 	/* Bit-bang to read word from eeprom */
 	for(i = 31; i >= 0; i--) {
 		ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs;
-		writeb(ctrl, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 
-		writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
+		iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo);
 		e100_write_flush(nic); udelay(4);
 
 		/* Eeprom drives a dummy zero to EEDO after receiving
 		 * complete address.  Use this to adjust addr_len. */
-		ctrl = readb(&nic->csr->eeprom_ctrl_lo);
+		ctrl = ioread8(&nic->csr->eeprom_ctrl_lo);
 		if(!(ctrl & eedo) && i > 16) {
 			*addr_len -= (i - 16);
 			i = 17;
@@ -733,7 +736,7 @@ static u16 e100_eeprom_read(struct nic *
 	}
 
 	/* Chip deselect */
-	writeb(0, &nic->csr->eeprom_ctrl_lo);
+	iowrite8(0, &nic->csr->eeprom_ctrl_lo);
 	e100_write_flush(nic); udelay(4);
 
 	return le16_to_cpu(data);
@@ -804,7 +807,7 @@ static int e100_exec_cmd(struct nic *nic
 
 	/* Previous command is accepted when SCB clears */
 	for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) {
-		if(likely(!readb(&nic->csr->scb.cmd_lo)))
+		if(likely(!ioread8(&nic->csr->scb.cmd_lo)))
 			break;
 		cpu_relax();
 		if(unlikely(i > E100_WAIT_SCB_FAST))
@@ -816,8 +819,8 @@ static int e100_exec_cmd(struct nic *nic
 	}
 
 	if(unlikely(cmd != cuc_resume))
-		writel(dma_addr, &nic->csr->scb.gen_ptr);
-	writeb(cmd, &nic->csr->scb.cmd_lo);
+		iowrite32(dma_addr, &nic->csr->scb.gen_ptr);
+	iowrite8(cmd, &nic->csr->scb.cmd_lo);
 
 err_unlock:
 	spin_unlock_irqrestore(&nic->cmd_lock, flags);
@@ -895,7 +898,7 @@ static u16 mdio_ctrl(struct nic *nic, u3
 	 */
 	spin_lock_irqsave(&nic->mdio_lock, flags);
 	for (i = 100; i; --i) {
-		if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
+		if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready)
 			break;
 		udelay(20);
 	}
@@ -905,11 +908,11 @@ static u16 mdio_ctrl(struct nic *nic, u3
 		spin_unlock_irqrestore(&nic->mdio_lock, flags);
 		return 0;		/* No way to indicate timeout
error */
 	}
-	writel((reg << 16) | (addr << 21) | dir | data,
&nic->csr->mdi_ctrl);
+	iowrite32((reg << 16) | (addr << 21) | dir | data,
&nic->csr->mdi_ctrl);
 
 	for (i = 0; i < 100; i++) {
 		udelay(20);
-		if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
+		if ((data_out = ioread32(&nic->csr->mdi_ctrl)) &
mdi_ready)
 			break;
 	}
 	spin_unlock_irqrestore(&nic->mdio_lock, flags);
@@ -1318,7 +1321,7 @@ static inline int e100_exec_cb_wait(stru
 	}
 
 	/* ack any interupts, something could have been set */
-	writeb(~0, &nic->csr->scb.stat_ack);
+	iowrite8(~0, &nic->csr->scb.stat_ack);
 
 	/* if the command failed, or is not OK, notify and return */
 	if (!counter || !(cb->status & cpu_to_le16(cb_ok))) {
@@ -1580,7 +1583,7 @@ static void e100_watchdog(unsigned long 
 	 * accidentally, due to hardware that shares a register between
the
 	 * interrupt mask bit and the SW Interrupt generation bit */
 	spin_lock_irq(&nic->cmd_lock);
-	writeb(readb(&nic->csr->scb.cmd_hi) |
irq_sw_gen,&nic->csr->scb.cmd_hi);
+	iowrite8(ioread8(&nic->csr->scb.cmd_hi) |
irq_sw_gen,&nic->csr->scb.cmd_hi);
 	e100_write_flush(nic);
 	spin_unlock_irq(&nic->cmd_lock);
 
@@ -1893,7 +1896,7 @@ static void e100_rx_clean(struct nic *ni
 
 	if(restart_required) {
 		// ack the rnr?
-		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
+		iowrite8(stat_ack_rnr, &nic->csr->scb.stat_ack);
 		e100_start_receiver(nic, rx_to_start);
 		if(work_done)
 			(*work_done)++;
@@ -1952,7 +1955,7 @@ static irqreturn_t e100_intr(int irq, vo
 {
 	struct net_device *netdev = dev_id;
 	struct nic *nic = netdev_priv(netdev);
-	u8 stat_ack = readb(&nic->csr->scb.stat_ack);
+	u8 stat_ack = ioread8(&nic->csr->scb.stat_ack);
 
 	DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);
 
@@ -1961,7 +1964,7 @@ static irqreturn_t e100_intr(int irq, vo
 		return IRQ_NONE;
 
 	/* Ack interrupt(s) */
-	writeb(stat_ack, &nic->csr->scb.stat_ack);
+	iowrite8(stat_ack, &nic->csr->scb.stat_ack);
 
 	/* We hit Receive No Resource (RNR); restart RU after cleaning
*/
 	if(stat_ack & stat_ack_rnr)
@@ -2107,7 +2110,7 @@ static void e100_tx_timeout_task(struct 
 	struct net_device *netdev = nic->netdev;
 
 	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",
-		readb(&nic->csr->scb.status));
+		ioread8(&nic->csr->scb.status));
 	e100_down(netdev_priv(netdev));
 	e100_up(netdev_priv(netdev));
 }
@@ -2230,9 +2233,9 @@ static void e100_get_regs(struct net_dev
 	int i;
 
 	regs->version = (1 << 24) | nic->rev_id;
-	buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 |
-		readb(&nic->csr->scb.cmd_lo) << 16 |
-		readw(&nic->csr->scb.status);
+	buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 |
+		ioread8(&nic->csr->scb.cmd_lo) << 16 |
+		ioread16(&nic->csr->scb.status);
 	for(i = E100_PHY_REGS; i >= 0; i--)
 		buff[1 + E100_PHY_REGS - i] =
 			mdio_read(netdev, nic->mii.phy_id, i);
@@ -2604,7 +2607,10 @@ #endif
 	SET_MODULE_OWNER(netdev);
 	SET_NETDEV_DEV(netdev, &pdev->dev);
 
-	nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct
csr));
+	if (use_io)
+		DPRINTK(PROBE, INFO, "using i/o access mode\n");
+
+	nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct
csr));
 	if(!nic->csr) {
 		DPRINTK(PROBE, ERR, "Cannot map device registers,
aborting.\n");
 		err = -ENOMEM;
@@ -2676,7 +2682,7 @@ #endif
 
 	DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
 		"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
-		(unsigned long long)pci_resource_start(pdev, 0),
pdev->irq,
+		(unsigned long long)pci_resource_start(pdev, use_io ? 1
: 0), pdev->irq,
 		netdev->dev_addr[0], netdev->dev_addr[1],
netdev->dev_addr[2],
 		netdev->dev_addr[3], netdev->dev_addr[4],
netdev->dev_addr[5]);
 
@@ -2685,7 +2691,7 @@ #endif
 err_out_free:
 	e100_free(nic);
 err_out_iounmap:
-	iounmap(nic->csr);
+	pci_iounmap(pdev, nic->csr);
 err_out_free_res:
 	pci_release_regions(pdev);
 err_out_disable_pdev:
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help