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 |
