aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@osdl.org>2005-12-09 14:34:57 -0500
committerJeff Garzik <jgarzik@pobox.com>2005-12-12 15:27:20 -0500
commit91c86df5a8a44157b456bf1e91fc6d878582e68c (patch)
tree74f9e3f1c9b78ede4350d3ad59914dd75def74e0
parentfb17358fe31e01baf902a9fd1fce0e29e3493517 (diff)
[PATCH] sky2: phy processing in workqueue rather than tasklet
Do phy processing in a work queue rather than a tasklet. This means we can let bottom halves run. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r--drivers/net/sky2.c58
-rw-r--r--drivers/net/sky2.h6
2 files changed, 33 insertions, 31 deletions
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 0ab376845e39..2cb6406c9635 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -43,6 +43,7 @@
43#include <linux/tcp.h> 43#include <linux/tcp.h>
44#include <linux/in.h> 44#include <linux/in.h>
45#include <linux/delay.h> 45#include <linux/delay.h>
46#include <linux/workqueue.h>
46#include <linux/if_vlan.h> 47#include <linux/if_vlan.h>
47#include <linux/mii.h> 48#include <linux/mii.h>
48 49
@@ -535,9 +536,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
535 536
536 sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); 537 sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
537 538
538 spin_lock_bh(&hw->phy_lock); 539 down(&sky2->phy_sema);
539 sky2_phy_init(hw, port); 540 sky2_phy_init(hw, port);
540 spin_unlock_bh(&hw->phy_lock); 541 up(&sky2->phy_sema);
541 542
542 /* MIB clear */ 543 /* MIB clear */
543 reg = gma_read16(hw, port, GM_PHY_ADDR); 544 reg = gma_read16(hw, port, GM_PHY_ADDR);
@@ -839,9 +840,11 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
839 /* fallthru */ 840 /* fallthru */
840 case SIOCGMIIREG: { 841 case SIOCGMIIREG: {
841 u16 val = 0; 842 u16 val = 0;
842 spin_lock_bh(&hw->phy_lock); 843
844 down(&sky2->phy_sema);
843 err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val); 845 err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val);
844 spin_unlock_bh(&hw->phy_lock); 846 up(&sky2->phy_sema);
847
845 data->val_out = val; 848 data->val_out = val;
846 break; 849 break;
847 } 850 }
@@ -850,10 +853,10 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
850 if (!capable(CAP_NET_ADMIN)) 853 if (!capable(CAP_NET_ADMIN))
851 return -EPERM; 854 return -EPERM;
852 855
853 spin_lock_bh(&hw->phy_lock); 856 down(&sky2->phy_sema);
854 err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f, 857 err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f,
855 data->val_in); 858 data->val_in);
856 spin_unlock_bh(&hw->phy_lock); 859 up(&sky2->phy_sema);
857 break; 860 break;
858 } 861 }
859 return err; 862 return err;
@@ -1308,6 +1311,7 @@ static int sky2_down(struct net_device *dev)
1308 sky2_write32(hw, B0_IMSK, hw->intr_mask); 1311 sky2_write32(hw, B0_IMSK, hw->intr_mask);
1309 local_irq_enable(); 1312 local_irq_enable();
1310 1313
1314 flush_scheduled_work();
1311 1315
1312 sky2_phy_reset(hw, port); 1316 sky2_phy_reset(hw, port);
1313 1317
@@ -1520,17 +1524,17 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
1520} 1524}
1521 1525
1522/* 1526/*
1523 * Interrupt from PHY are handled in tasklet (soft irq) 1527 * Interrupt from PHY are handled outside of interrupt context
1524 * because accessing phy registers requires spin wait which might 1528 * because accessing phy registers requires spin wait which might
1525 * cause excess interrupt latency. 1529 * cause excess interrupt latency.
1526 */ 1530 */
1527static void sky2_phy_task(unsigned long data) 1531static void sky2_phy_task(void *arg)
1528{ 1532{
1529 struct sky2_port *sky2 = (struct sky2_port *)data; 1533 struct sky2_port *sky2 = arg;
1530 struct sky2_hw *hw = sky2->hw; 1534 struct sky2_hw *hw = sky2->hw;
1531 u16 istatus, phystat; 1535 u16 istatus, phystat;
1532 1536
1533 spin_lock(&hw->phy_lock); 1537 down(&sky2->phy_sema);
1534 istatus = gm_phy_read(hw, sky2->port, PHY_MARV_INT_STAT); 1538 istatus = gm_phy_read(hw, sky2->port, PHY_MARV_INT_STAT);
1535 phystat = gm_phy_read(hw, sky2->port, PHY_MARV_PHY_STAT); 1539 phystat = gm_phy_read(hw, sky2->port, PHY_MARV_PHY_STAT);
1536 1540
@@ -1558,7 +1562,7 @@ static void sky2_phy_task(unsigned long data)
1558 sky2_link_down(sky2); 1562 sky2_link_down(sky2);
1559 } 1563 }
1560out: 1564out:
1561 spin_unlock(&hw->phy_lock); 1565 up(&sky2->phy_sema);
1562 1566
1563 local_irq_disable(); 1567 local_irq_disable();
1564 hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2; 1568 hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2;
@@ -1960,7 +1964,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
1960 1964
1961 hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); 1965 hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2);
1962 sky2_write32(hw, B0_IMSK, hw->intr_mask); 1966 sky2_write32(hw, B0_IMSK, hw->intr_mask);
1963 tasklet_schedule(&sky2->phy_task); 1967 schedule_work(&sky2->phy_task);
1964} 1968}
1965 1969
1966static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) 1970static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
@@ -2150,10 +2154,8 @@ static int sky2_reset(struct sky2_hw *hw)
2150 2154
2151 sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); 2155 sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK);
2152 2156
2153 spin_lock_bh(&hw->phy_lock);
2154 for (i = 0; i < hw->ports; i++) 2157 for (i = 0; i < hw->ports; i++)
2155 sky2_phy_reset(hw, i); 2158 sky2_phy_reset(hw, i);
2156 spin_unlock_bh(&hw->phy_lock);
2157 2159
2158 memset(hw->st_le, 0, STATUS_LE_BYTES); 2160 memset(hw->st_le, 0, STATUS_LE_BYTES);
2159 hw->st_idx = 0; 2161 hw->st_idx = 0;
@@ -2386,10 +2388,10 @@ static int sky2_nway_reset(struct net_device *dev)
2386 2388
2387 netif_stop_queue(dev); 2389 netif_stop_queue(dev);
2388 2390
2389 spin_lock_irq(&hw->phy_lock); 2391 down(&sky2->phy_sema);
2390 sky2_phy_reset(hw, sky2->port); 2392 sky2_phy_reset(hw, sky2->port);
2391 sky2_phy_init(hw, sky2->port); 2393 sky2_phy_init(hw, sky2->port);
2392 spin_unlock_irq(&hw->phy_lock); 2394 up(&sky2->phy_sema);
2393 2395
2394 return 0; 2396 return 0;
2395} 2397}
@@ -2528,11 +2530,10 @@ static void sky2_set_multicast(struct net_device *dev)
2528/* Can have one global because blinking is controlled by 2530/* Can have one global because blinking is controlled by
2529 * ethtool and that is always under RTNL mutex 2531 * ethtool and that is always under RTNL mutex
2530 */ 2532 */
2531static inline void sky2_led(struct sky2_hw *hw, unsigned port, int on) 2533static void sky2_led(struct sky2_hw *hw, unsigned port, int on)
2532{ 2534{
2533 u16 pg; 2535 u16 pg;
2534 2536
2535 spin_lock_bh(&hw->phy_lock);
2536 switch (hw->chip_id) { 2537 switch (hw->chip_id) {
2537 case CHIP_ID_YUKON_XL: 2538 case CHIP_ID_YUKON_XL:
2538 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 2539 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
@@ -2562,7 +2563,6 @@ static inline void sky2_led(struct sky2_hw *hw, unsigned port, int on)
2562 PHY_M_LED_MO_RX(MO_LED_OFF)); 2563 PHY_M_LED_MO_RX(MO_LED_OFF));
2563 2564
2564 } 2565 }
2565 spin_unlock_bh(&hw->phy_lock);
2566} 2566}
2567 2567
2568/* blink LED's for finding board */ 2568/* blink LED's for finding board */
@@ -2573,6 +2573,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
2573 unsigned port = sky2->port; 2573 unsigned port = sky2->port;
2574 u16 ledctrl, ledover = 0; 2574 u16 ledctrl, ledover = 0;
2575 long ms; 2575 long ms;
2576 int interrupted;
2576 int onoff = 1; 2577 int onoff = 1;
2577 2578
2578 if (!data || data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ)) 2579 if (!data || data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))
@@ -2581,7 +2582,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
2581 ms = data * 1000; 2582 ms = data * 1000;
2582 2583
2583 /* save initial values */ 2584 /* save initial values */
2584 spin_lock_bh(&hw->phy_lock); 2585 down(&sky2->phy_sema);
2585 if (hw->chip_id == CHIP_ID_YUKON_XL) { 2586 if (hw->chip_id == CHIP_ID_YUKON_XL) {
2586 u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 2587 u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
2587 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 2588 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
@@ -2591,19 +2592,20 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
2591 ledctrl = gm_phy_read(hw, port, PHY_MARV_LED_CTRL); 2592 ledctrl = gm_phy_read(hw, port, PHY_MARV_LED_CTRL);
2592 ledover = gm_phy_read(hw, port, PHY_MARV_LED_OVER); 2593 ledover = gm_phy_read(hw, port, PHY_MARV_LED_OVER);
2593 } 2594 }
2594 spin_unlock_bh(&hw->phy_lock);
2595 2595
2596 while (ms > 0) { 2596 interrupted = 0;
2597 while (!interrupted && ms > 0) {
2597 sky2_led(hw, port, onoff); 2598 sky2_led(hw, port, onoff);
2598 onoff = !onoff; 2599 onoff = !onoff;
2599 2600
2600 if (msleep_interruptible(250)) 2601 up(&sky2->phy_sema);
2601 break; /* interrupted */ 2602 interrupted = msleep_interruptible(250);
2603 down(&sky2->phy_sema);
2604
2602 ms -= 250; 2605 ms -= 250;
2603 } 2606 }
2604 2607
2605 /* resume regularly scheduled programming */ 2608 /* resume regularly scheduled programming */
2606 spin_lock_bh(&hw->phy_lock);
2607 if (hw->chip_id == CHIP_ID_YUKON_XL) { 2609 if (hw->chip_id == CHIP_ID_YUKON_XL) {
2608 u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); 2610 u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
2609 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); 2611 gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
@@ -2613,7 +2615,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
2613 gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); 2615 gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
2614 gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); 2616 gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
2615 } 2617 }
2616 spin_unlock_bh(&hw->phy_lock); 2618 up(&sky2->phy_sema);
2617 2619
2618 return 0; 2620 return 0;
2619} 2621}
@@ -2917,7 +2919,8 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
2917 sky2->speed = -1; 2919 sky2->speed = -1;
2918 sky2->advertising = sky2_supported_modes(hw); 2920 sky2->advertising = sky2_supported_modes(hw);
2919 sky2->rx_csum = 1; 2921 sky2->rx_csum = 1;
2920 tasklet_init(&sky2->phy_task, sky2_phy_task, (unsigned long)sky2); 2922 INIT_WORK(&sky2->phy_task, sky2_phy_task, sky2);
2923 init_MUTEX(&sky2->phy_sema);
2921 sky2->tx_pending = TX_DEF_PENDING; 2924 sky2->tx_pending = TX_DEF_PENDING;
2922 sky2->rx_pending = is_ec_a1(hw) ? 8 : RX_DEF_PENDING; 2925 sky2->rx_pending = is_ec_a1(hw) ? 8 : RX_DEF_PENDING;
2923 2926
@@ -3027,7 +3030,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
3027 3030
3028 memset(hw, 0, sizeof(*hw)); 3031 memset(hw, 0, sizeof(*hw));
3029 hw->pdev = pdev; 3032 hw->pdev = pdev;
3030 spin_lock_init(&hw->phy_lock);
3031 3033
3032 hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); 3034 hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
3033 if (!hw->regs) { 3035 if (!hw->regs) {
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 7943dd42ac94..29ebca099f99 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1823,8 +1823,10 @@ struct sky2_port {
1823 u8 rx_csum; 1823 u8 rx_csum;
1824 u8 wol; 1824 u8 wol;
1825 1825
1826 struct tasklet_struct phy_task;
1827 struct net_device_stats net_stats; 1826 struct net_device_stats net_stats;
1827
1828 struct work_struct phy_task;
1829 struct semaphore phy_sema;
1828}; 1830};
1829 1831
1830struct sky2_hw { 1832struct sky2_hw {
@@ -1842,8 +1844,6 @@ struct sky2_hw {
1842 struct sky2_status_le *st_le; 1844 struct sky2_status_le *st_le;
1843 u32 st_idx; 1845 u32 st_idx;
1844 dma_addr_t st_dma; 1846 dma_addr_t st_dma;
1845
1846 spinlock_t phy_lock;
1847}; 1847};
1848 1848
1849/* Register accessor for memory mapped device */ 1849/* Register accessor for memory mapped device */