diff options
-rw-r--r-- | drivers/net/e100.c | 32 |
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 | ||
583 | static inline void e100_write_flush(struct nic *nic) | 588 | static 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 |