diff options
Diffstat (limited to 'drivers/net/e100.c')
-rw-r--r-- | drivers/net/e100.c | 50 |
1 files changed, 38 insertions, 12 deletions
diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 22cd04556707..4726722a0635 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) |
@@ -587,7 +592,7 @@ static inline void e100_write_flush(struct nic *nic) | |||
587 | (void)readb(&nic->csr->scb.status); | 592 | (void)readb(&nic->csr->scb.status); |
588 | } | 593 | } |
589 | 594 | ||
590 | static inline void e100_enable_irq(struct nic *nic) | 595 | static void e100_enable_irq(struct nic *nic) |
591 | { | 596 | { |
592 | unsigned long flags; | 597 | unsigned long flags; |
593 | 598 | ||
@@ -597,7 +602,7 @@ static inline void e100_enable_irq(struct nic *nic) | |||
597 | e100_write_flush(nic); | 602 | e100_write_flush(nic); |
598 | } | 603 | } |
599 | 604 | ||
600 | static inline void e100_disable_irq(struct nic *nic) | 605 | static void e100_disable_irq(struct nic *nic) |
601 | { | 606 | { |
602 | unsigned long flags; | 607 | unsigned long flags; |
603 | 608 | ||
@@ -786,7 +791,7 @@ static int e100_eeprom_save(struct nic *nic, u16 start, u16 count) | |||
786 | 791 | ||
787 | #define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */ | 792 | #define E100_WAIT_SCB_TIMEOUT 20000 /* we might have to wait 100ms!!! */ |
788 | #define E100_WAIT_SCB_FAST 20 /* delay like the old code */ | 793 | #define E100_WAIT_SCB_FAST 20 /* delay like the old code */ |
789 | static inline int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) | 794 | static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) |
790 | { | 795 | { |
791 | unsigned long flags; | 796 | unsigned long flags; |
792 | unsigned int i; | 797 | unsigned int i; |
@@ -817,7 +822,7 @@ err_unlock: | |||
817 | return err; | 822 | return err; |
818 | } | 823 | } |
819 | 824 | ||
820 | static inline int e100_exec_cb(struct nic *nic, struct sk_buff *skb, | 825 | static int e100_exec_cb(struct nic *nic, struct sk_buff *skb, |
821 | void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) | 826 | void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) |
822 | { | 827 | { |
823 | struct cb *cb; | 828 | struct cb *cb; |
@@ -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); |
@@ -1542,7 +1567,7 @@ static void e100_watchdog(unsigned long data) | |||
1542 | mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); | 1567 | mod_timer(&nic->watchdog, jiffies + E100_WATCHDOG_PERIOD); |
1543 | } | 1568 | } |
1544 | 1569 | ||
1545 | static inline void e100_xmit_prepare(struct nic *nic, struct cb *cb, | 1570 | static void e100_xmit_prepare(struct nic *nic, struct cb *cb, |
1546 | struct sk_buff *skb) | 1571 | struct sk_buff *skb) |
1547 | { | 1572 | { |
1548 | cb->command = nic->tx_command; | 1573 | cb->command = nic->tx_command; |
@@ -1592,7 +1617,7 @@ static int e100_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
1592 | return 0; | 1617 | return 0; |
1593 | } | 1618 | } |
1594 | 1619 | ||
1595 | static inline int e100_tx_clean(struct nic *nic) | 1620 | static int e100_tx_clean(struct nic *nic) |
1596 | { | 1621 | { |
1597 | struct cb *cb; | 1622 | struct cb *cb; |
1598 | int tx_cleaned = 0; | 1623 | int tx_cleaned = 0; |
@@ -1703,7 +1728,7 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx) | |||
1703 | } | 1728 | } |
1704 | 1729 | ||
1705 | #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) | 1730 | #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) |
1706 | static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) | 1731 | static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) |
1707 | { | 1732 | { |
1708 | if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN))) | 1733 | if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN))) |
1709 | return -ENOMEM; | 1734 | return -ENOMEM; |
@@ -1737,7 +1762,7 @@ static inline int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) | |||
1737 | return 0; | 1762 | return 0; |
1738 | } | 1763 | } |
1739 | 1764 | ||
1740 | static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, | 1765 | static int e100_rx_indicate(struct nic *nic, struct rx *rx, |
1741 | unsigned int *work_done, unsigned int work_to_do) | 1766 | unsigned int *work_done, unsigned int work_to_do) |
1742 | { | 1767 | { |
1743 | struct sk_buff *skb = rx->skb; | 1768 | struct sk_buff *skb = rx->skb; |
@@ -1797,7 +1822,7 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, | |||
1797 | return 0; | 1822 | return 0; |
1798 | } | 1823 | } |
1799 | 1824 | ||
1800 | static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done, | 1825 | static void e100_rx_clean(struct nic *nic, unsigned int *work_done, |
1801 | unsigned int work_to_do) | 1826 | unsigned int work_to_do) |
1802 | { | 1827 | { |
1803 | struct rx *rx; | 1828 | struct rx *rx; |
@@ -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 |