diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2006-06-06 13:11:11 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-06-08 15:44:54 -0400 |
commit | d85b514fd9aa95d2089fa16dccc25863fb2a766c (patch) | |
tree | 7a46eaf6bfa9d745e821cedc51d9deb81b2d7108 /drivers/net/skge.c | |
parent | b10c066823c97c0e40989b2048540e85f5190501 (diff) |
[PATCH] skge: use workq for PHY handling
Since accessing the PHY can take 100's of usecs, use a work queue to
allow spinning in outside of soft/hard irq.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/skge.c')
-rw-r--r-- | drivers/net/skge.c | 46 |
1 files changed, 23 insertions, 23 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 5ca5a1b546a1..55245dbaecbc 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -603,7 +603,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) | |||
603 | struct skge_hw *hw = skge->hw; | 603 | struct skge_hw *hw = skge->hw; |
604 | int port = skge->port; | 604 | int port = skge->port; |
605 | 605 | ||
606 | spin_lock_bh(&hw->phy_lock); | 606 | mutex_lock(&hw->phy_mutex); |
607 | if (hw->chip_id == CHIP_ID_GENESIS) { | 607 | if (hw->chip_id == CHIP_ID_GENESIS) { |
608 | switch (mode) { | 608 | switch (mode) { |
609 | case LED_MODE_OFF: | 609 | case LED_MODE_OFF: |
@@ -663,7 +663,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) | |||
663 | PHY_M_LED_MO_RX(MO_LED_ON)); | 663 | PHY_M_LED_MO_RX(MO_LED_ON)); |
664 | } | 664 | } |
665 | } | 665 | } |
666 | spin_unlock_bh(&hw->phy_lock); | 666 | mutex_unlock(&hw->phy_mutex); |
667 | } | 667 | } |
668 | 668 | ||
669 | /* blink LED's for finding board */ | 669 | /* blink LED's for finding board */ |
@@ -2038,7 +2038,7 @@ static void skge_phy_reset(struct skge_port *skge) | |||
2038 | netif_stop_queue(skge->netdev); | 2038 | netif_stop_queue(skge->netdev); |
2039 | netif_carrier_off(skge->netdev); | 2039 | netif_carrier_off(skge->netdev); |
2040 | 2040 | ||
2041 | spin_lock_bh(&hw->phy_lock); | 2041 | mutex_lock(&hw->phy_mutex); |
2042 | if (hw->chip_id == CHIP_ID_GENESIS) { | 2042 | if (hw->chip_id == CHIP_ID_GENESIS) { |
2043 | genesis_reset(hw, port); | 2043 | genesis_reset(hw, port); |
2044 | genesis_mac_init(hw, port); | 2044 | genesis_mac_init(hw, port); |
@@ -2046,7 +2046,7 @@ static void skge_phy_reset(struct skge_port *skge) | |||
2046 | yukon_reset(hw, port); | 2046 | yukon_reset(hw, port); |
2047 | yukon_init(hw, port); | 2047 | yukon_init(hw, port); |
2048 | } | 2048 | } |
2049 | spin_unlock_bh(&hw->phy_lock); | 2049 | mutex_unlock(&hw->phy_mutex); |
2050 | } | 2050 | } |
2051 | 2051 | ||
2052 | /* Basic MII support */ | 2052 | /* Basic MII support */ |
@@ -2067,12 +2067,12 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
2067 | /* fallthru */ | 2067 | /* fallthru */ |
2068 | case SIOCGMIIREG: { | 2068 | case SIOCGMIIREG: { |
2069 | u16 val = 0; | 2069 | u16 val = 0; |
2070 | spin_lock_bh(&hw->phy_lock); | 2070 | mutex_lock(&hw->phy_mutex); |
2071 | if (hw->chip_id == CHIP_ID_GENESIS) | 2071 | if (hw->chip_id == CHIP_ID_GENESIS) |
2072 | err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); | 2072 | err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); |
2073 | else | 2073 | else |
2074 | err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); | 2074 | err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); |
2075 | spin_unlock_bh(&hw->phy_lock); | 2075 | mutex_unlock(&hw->phy_mutex); |
2076 | data->val_out = val; | 2076 | data->val_out = val; |
2077 | break; | 2077 | break; |
2078 | } | 2078 | } |
@@ -2081,14 +2081,14 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
2081 | if (!capable(CAP_NET_ADMIN)) | 2081 | if (!capable(CAP_NET_ADMIN)) |
2082 | return -EPERM; | 2082 | return -EPERM; |
2083 | 2083 | ||
2084 | spin_lock_bh(&hw->phy_lock); | 2084 | mutex_lock(&hw->phy_mutex); |
2085 | if (hw->chip_id == CHIP_ID_GENESIS) | 2085 | if (hw->chip_id == CHIP_ID_GENESIS) |
2086 | err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, | 2086 | err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, |
2087 | data->val_in); | 2087 | data->val_in); |
2088 | else | 2088 | else |
2089 | err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f, | 2089 | err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f, |
2090 | data->val_in); | 2090 | data->val_in); |
2091 | spin_unlock_bh(&hw->phy_lock); | 2091 | mutex_unlock(&hw->phy_mutex); |
2092 | break; | 2092 | break; |
2093 | } | 2093 | } |
2094 | return err; | 2094 | return err; |
@@ -2191,12 +2191,12 @@ static int skge_up(struct net_device *dev) | |||
2191 | goto free_rx_ring; | 2191 | goto free_rx_ring; |
2192 | 2192 | ||
2193 | /* Initialize MAC */ | 2193 | /* Initialize MAC */ |
2194 | spin_lock_bh(&hw->phy_lock); | 2194 | mutex_lock(&hw->phy_mutex); |
2195 | if (hw->chip_id == CHIP_ID_GENESIS) | 2195 | if (hw->chip_id == CHIP_ID_GENESIS) |
2196 | genesis_mac_init(hw, port); | 2196 | genesis_mac_init(hw, port); |
2197 | else | 2197 | else |
2198 | yukon_mac_init(hw, port); | 2198 | yukon_mac_init(hw, port); |
2199 | spin_unlock_bh(&hw->phy_lock); | 2199 | mutex_unlock(&hw->phy_mutex); |
2200 | 2200 | ||
2201 | /* Configure RAMbuffers */ | 2201 | /* Configure RAMbuffers */ |
2202 | chunk = hw->ram_size / ((hw->ports + 1)*2); | 2202 | chunk = hw->ram_size / ((hw->ports + 1)*2); |
@@ -2847,16 +2847,16 @@ static void skge_error_irq(struct skge_hw *hw) | |||
2847 | } | 2847 | } |
2848 | 2848 | ||
2849 | /* | 2849 | /* |
2850 | * Interrupt from PHY are handled in tasklet (soft irq) | 2850 | * Interrupt from PHY are handled in work queue |
2851 | * because accessing phy registers requires spin wait which might | 2851 | * because accessing phy registers requires spin wait which might |
2852 | * cause excess interrupt latency. | 2852 | * cause excess interrupt latency. |
2853 | */ | 2853 | */ |
2854 | static void skge_extirq(unsigned long data) | 2854 | static void skge_extirq(void *arg) |
2855 | { | 2855 | { |
2856 | struct skge_hw *hw = (struct skge_hw *) data; | 2856 | struct skge_hw *hw = arg; |
2857 | int port; | 2857 | int port; |
2858 | 2858 | ||
2859 | spin_lock(&hw->phy_lock); | 2859 | mutex_lock(&hw->phy_mutex); |
2860 | for (port = 0; port < hw->ports; port++) { | 2860 | for (port = 0; port < hw->ports; port++) { |
2861 | struct net_device *dev = hw->dev[port]; | 2861 | struct net_device *dev = hw->dev[port]; |
2862 | struct skge_port *skge = netdev_priv(dev); | 2862 | struct skge_port *skge = netdev_priv(dev); |
@@ -2868,7 +2868,7 @@ static void skge_extirq(unsigned long data) | |||
2868 | bcom_phy_intr(skge); | 2868 | bcom_phy_intr(skge); |
2869 | } | 2869 | } |
2870 | } | 2870 | } |
2871 | spin_unlock(&hw->phy_lock); | 2871 | mutex_unlock(&hw->phy_mutex); |
2872 | 2872 | ||
2873 | hw->intr_mask |= IS_EXT_REG; | 2873 | hw->intr_mask |= IS_EXT_REG; |
2874 | skge_write32(hw, B0_IMSK, hw->intr_mask); | 2874 | skge_write32(hw, B0_IMSK, hw->intr_mask); |
@@ -2886,7 +2886,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) | |||
2886 | 2886 | ||
2887 | if (status & IS_EXT_REG) { | 2887 | if (status & IS_EXT_REG) { |
2888 | hw->intr_mask &= ~IS_EXT_REG; | 2888 | hw->intr_mask &= ~IS_EXT_REG; |
2889 | tasklet_schedule(&hw->ext_tasklet); | 2889 | schedule_work(&hw->phy_work); |
2890 | } | 2890 | } |
2891 | 2891 | ||
2892 | if (status & (IS_R1_F|IS_XA1_F)) { | 2892 | if (status & (IS_R1_F|IS_XA1_F)) { |
@@ -2957,7 +2957,7 @@ static int skge_set_mac_address(struct net_device *dev, void *p) | |||
2957 | if (!is_valid_ether_addr(addr->sa_data)) | 2957 | if (!is_valid_ether_addr(addr->sa_data)) |
2958 | return -EADDRNOTAVAIL; | 2958 | return -EADDRNOTAVAIL; |
2959 | 2959 | ||
2960 | spin_lock_bh(&hw->phy_lock); | 2960 | mutex_lock(&hw->phy_mutex); |
2961 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 2961 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
2962 | memcpy_toio(hw->regs + B2_MAC_1 + port*8, | 2962 | memcpy_toio(hw->regs + B2_MAC_1 + port*8, |
2963 | dev->dev_addr, ETH_ALEN); | 2963 | dev->dev_addr, ETH_ALEN); |
@@ -2970,7 +2970,7 @@ static int skge_set_mac_address(struct net_device *dev, void *p) | |||
2970 | gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); | 2970 | gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); |
2971 | gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); | 2971 | gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); |
2972 | } | 2972 | } |
2973 | spin_unlock_bh(&hw->phy_lock); | 2973 | mutex_unlock(&hw->phy_mutex); |
2974 | 2974 | ||
2975 | return 0; | 2975 | return 0; |
2976 | } | 2976 | } |
@@ -3150,14 +3150,14 @@ static int skge_reset(struct skge_hw *hw) | |||
3150 | 3150 | ||
3151 | skge_write32(hw, B0_IMSK, hw->intr_mask); | 3151 | skge_write32(hw, B0_IMSK, hw->intr_mask); |
3152 | 3152 | ||
3153 | spin_lock_bh(&hw->phy_lock); | 3153 | mutex_lock(&hw->phy_mutex); |
3154 | for (i = 0; i < hw->ports; i++) { | 3154 | for (i = 0; i < hw->ports; i++) { |
3155 | if (hw->chip_id == CHIP_ID_GENESIS) | 3155 | if (hw->chip_id == CHIP_ID_GENESIS) |
3156 | genesis_reset(hw, i); | 3156 | genesis_reset(hw, i); |
3157 | else | 3157 | else |
3158 | yukon_reset(hw, i); | 3158 | yukon_reset(hw, i); |
3159 | } | 3159 | } |
3160 | spin_unlock_bh(&hw->phy_lock); | 3160 | mutex_unlock(&hw->phy_mutex); |
3161 | 3161 | ||
3162 | return 0; | 3162 | return 0; |
3163 | } | 3163 | } |
@@ -3305,8 +3305,8 @@ static int __devinit skge_probe(struct pci_dev *pdev, | |||
3305 | } | 3305 | } |
3306 | 3306 | ||
3307 | hw->pdev = pdev; | 3307 | hw->pdev = pdev; |
3308 | spin_lock_init(&hw->phy_lock); | 3308 | mutex_init(&hw->phy_mutex); |
3309 | tasklet_init(&hw->ext_tasklet, skge_extirq, (unsigned long) hw); | 3309 | INIT_WORK(&hw->phy_work, skge_extirq, hw); |
3310 | 3310 | ||
3311 | hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); | 3311 | hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); |
3312 | if (!hw->regs) { | 3312 | if (!hw->regs) { |
@@ -3392,7 +3392,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) | |||
3392 | skge_write16(hw, B0_LED, LED_STAT_OFF); | 3392 | skge_write16(hw, B0_LED, LED_STAT_OFF); |
3393 | skge_write8(hw, B0_CTST, CS_RST_SET); | 3393 | skge_write8(hw, B0_CTST, CS_RST_SET); |
3394 | 3394 | ||
3395 | tasklet_kill(&hw->ext_tasklet); | 3395 | flush_scheduled_work(); |
3396 | 3396 | ||
3397 | free_irq(pdev->irq, hw); | 3397 | free_irq(pdev->irq, hw); |
3398 | pci_release_regions(pdev); | 3398 | pci_release_regions(pdev); |