aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorODonnell, Michael <Michael.ODonnell@stratus.com>2006-01-11 14:26:22 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-01-12 16:31:51 -0500
commitac7c66698a2c51e4c6a34b84621c79e7cb89e07d (patch)
treee128ebef78d7250fe7351580d7d44646faab9de5 /drivers/net
parentbf785ee0aeea7a3e717cb1e11df4135b6cbde7da (diff)
[PATCH] corruption during e100 MDI register access
We have identified two related bugs in the e100 driver. Both bugs are related to manipulation of the MDI control register. The first problem is that the Ready bit is being ignored when writing to the Control register; we noticed this because the Linux bonding driver would occasionally come to the spurious conclusion that the link was down when querying Link State. It turned out that by failing to wait for a previous command to complete it was selecting what was essentially a random register in the MDI register set. When we added code that waits for the Ready bit (as shown in the patch file below) all such problems ceased. The second problem is that, although access to the MDI registers involves multiple steps which must not be intermixed, nothing was defending against two or more threads attempting simultaneous access. The most obvious situation where such interference could occur involves the watchdog versus ioctl paths, but there are probably others, so we recommend the locking shown in our patch file. Signed-off-by: Michael O'Donnell <Michael.ODonnell@stratus.com> Cc: "David S. Miller" <davem@davemloft.net> Cc: Jeff Garzik <jgarzik@pobox.com> Cc: John Ronciak <john.ronciak@intel.com> Cc: Ganesh Venkatesan <ganesh.venkatesan@intel.com> Cc: Jesse Brandeburg <jesse.brandeburg@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/e100.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 22cd04556707..23de22631c64 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -132,6 +132,10 @@
132 * TODO: 132 * TODO:
133 * o several entry points race with dev->close 133 * o several entry points race with dev->close
134 * o check for tx-no-resources/stop Q races with tx clean/wake Q 134 * o check for tx-no-resources/stop Q races with tx clean/wake Q
135 *
136 * FIXES:
137 * 2005/12/02 - Michael O'Donnell <Michael.ODonnell at stratus dot com>
138 * - Stratus87247: protect MDI control register manipulations
135 */ 139 */
136 140
137#include <linux/config.h> 141#include <linux/config.h>
@@ -578,6 +582,7 @@ struct nic {
578 u16 leds; 582 u16 leds;
579 u16 eeprom_wc; 583 u16 eeprom_wc;
580 u16 eeprom[256]; 584 u16 eeprom[256];
585 spinlock_t mdio_lock;
581}; 586};
582 587
583static inline void e100_write_flush(struct nic *nic) 588static inline void e100_write_flush(struct nic *nic)
@@ -876,15 +881,35 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data)
876{ 881{
877 u32 data_out = 0; 882 u32 data_out = 0;
878 unsigned int i; 883 unsigned int i;
884 unsigned long flags;
879 885
886
887 /*
888 * Stratus87247: we shouldn't be writing the MDI control
889 * register until the Ready bit shows True. Also, since
890 * manipulation of the MDI control registers is a multi-step
891 * procedure it should be done under lock.
892 */
893 spin_lock_irqsave(&nic->mdio_lock, flags);
894 for (i = 100; i; --i) {
895 if (readl(&nic->csr->mdi_ctrl) & mdi_ready)
896 break;
897 udelay(20);
898 }
899 if (unlikely(!i)) {
900 printk("e100.mdio_ctrl(%s) won't go Ready\n",
901 nic->netdev->name );
902 spin_unlock_irqrestore(&nic->mdio_lock, flags);
903 return 0; /* No way to indicate timeout error */
904 }
880 writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); 905 writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl);
881 906
882 for(i = 0; i < 100; i++) { 907 for (i = 0; i < 100; i++) {
883 udelay(20); 908 udelay(20);
884 if((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) 909 if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready)
885 break; 910 break;
886 } 911 }
887 912 spin_unlock_irqrestore(&nic->mdio_lock, flags);
888 DPRINTK(HW, DEBUG, 913 DPRINTK(HW, DEBUG,
889 "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n", 914 "%s:addr=%d, reg=%d, data_in=0x%04X, data_out=0x%04X\n",
890 dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out); 915 dir == mdi_read ? "READ" : "WRITE", addr, reg, data, data_out);
@@ -2562,6 +2587,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
2562 /* locks must be initialized before calling hw_reset */ 2587 /* locks must be initialized before calling hw_reset */
2563 spin_lock_init(&nic->cb_lock); 2588 spin_lock_init(&nic->cb_lock);
2564 spin_lock_init(&nic->cmd_lock); 2589 spin_lock_init(&nic->cmd_lock);
2590 spin_lock_init(&nic->mdio_lock);
2565 2591
2566 /* Reset the device before pci_set_master() in case device is in some 2592 /* Reset the device before pci_set_master() in case device is in some
2567 * funky state and has an interrupt pending - hint: we don't have the 2593 * funky state and has an interrupt pending - hint: we don't have the