diff options
| author | Stephen Hemminger <shemminger@linux-foundation.org> | 2007-03-16 17:01:28 -0400 |
|---|---|---|
| committer | Jeff Garzik <jeff@garzik.org> | 2007-03-23 01:48:33 -0400 |
| commit | 9cbe330f1fbbc8de15a5914aa6e91d89eb9daac4 (patch) | |
| tree | 42cf338b904d2d2e538416359c1b96fe80c62301 | |
| parent | 4ebabfcb1d6af5191ef5c8305717ccbc24979f6c (diff) | |
skge: use per-port phy locking
Rather than a workqueue and a per-board mutex to control PHY,
use a tasklet and spinlock. Tasklet is lower overhead and works
just as well for this.
Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
| -rw-r--r-- | drivers/net/skge.c | 82 | ||||
| -rw-r--r-- | drivers/net/skge.h | 6 |
2 files changed, 47 insertions, 41 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 6e1eb23d93c4..39c6677dff5e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
| @@ -672,7 +672,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) | |||
| 672 | struct skge_hw *hw = skge->hw; | 672 | struct skge_hw *hw = skge->hw; |
| 673 | int port = skge->port; | 673 | int port = skge->port; |
| 674 | 674 | ||
| 675 | mutex_lock(&hw->phy_mutex); | 675 | spin_lock_bh(&hw->phy_lock); |
| 676 | if (hw->chip_id == CHIP_ID_GENESIS) { | 676 | if (hw->chip_id == CHIP_ID_GENESIS) { |
| 677 | switch (mode) { | 677 | switch (mode) { |
| 678 | case LED_MODE_OFF: | 678 | case LED_MODE_OFF: |
| @@ -743,7 +743,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) | |||
| 743 | PHY_M_LED_MO_RX(MO_LED_ON)); | 743 | PHY_M_LED_MO_RX(MO_LED_ON)); |
| 744 | } | 744 | } |
| 745 | } | 745 | } |
| 746 | mutex_unlock(&hw->phy_mutex); | 746 | spin_unlock_bh(&hw->phy_lock); |
| 747 | } | 747 | } |
| 748 | 748 | ||
| 749 | /* blink LED's for finding board */ | 749 | /* blink LED's for finding board */ |
| @@ -1317,7 +1317,7 @@ static void xm_phy_init(struct skge_port *skge) | |||
| 1317 | xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl); | 1317 | xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl); |
| 1318 | 1318 | ||
| 1319 | /* Poll PHY for status changes */ | 1319 | /* Poll PHY for status changes */ |
| 1320 | schedule_delayed_work(&skge->link_thread, LINK_HZ); | 1320 | mod_timer(&skge->link_timer, jiffies + LINK_HZ); |
| 1321 | } | 1321 | } |
| 1322 | 1322 | ||
| 1323 | static void xm_check_link(struct net_device *dev) | 1323 | static void xm_check_link(struct net_device *dev) |
| @@ -1392,10 +1392,9 @@ static void xm_check_link(struct net_device *dev) | |||
| 1392 | * Since internal PHY is wired to a level triggered pin, can't | 1392 | * Since internal PHY is wired to a level triggered pin, can't |
| 1393 | * get an interrupt when carrier is detected. | 1393 | * get an interrupt when carrier is detected. |
| 1394 | */ | 1394 | */ |
| 1395 | static void xm_link_timer(struct work_struct *work) | 1395 | static void xm_link_timer(unsigned long arg) |
| 1396 | { | 1396 | { |
| 1397 | struct skge_port *skge = | 1397 | struct skge_port *skge = (struct skge_port *) arg; |
| 1398 | container_of(work, struct skge_port, link_thread.work); | ||
| 1399 | struct net_device *dev = skge->netdev; | 1398 | struct net_device *dev = skge->netdev; |
| 1400 | struct skge_hw *hw = skge->hw; | 1399 | struct skge_hw *hw = skge->hw; |
| 1401 | int port = skge->port; | 1400 | int port = skge->port; |
| @@ -1415,13 +1414,13 @@ static void xm_link_timer(struct work_struct *work) | |||
| 1415 | goto nochange; | 1414 | goto nochange; |
| 1416 | } | 1415 | } |
| 1417 | 1416 | ||
| 1418 | mutex_lock(&hw->phy_mutex); | 1417 | spin_lock(&hw->phy_lock); |
| 1419 | xm_check_link(dev); | 1418 | xm_check_link(dev); |
| 1420 | mutex_unlock(&hw->phy_mutex); | 1419 | spin_unlock(&hw->phy_lock); |
| 1421 | 1420 | ||
| 1422 | nochange: | 1421 | nochange: |
| 1423 | if (netif_running(dev)) | 1422 | if (netif_running(dev)) |
| 1424 | schedule_delayed_work(&skge->link_thread, LINK_HZ); | 1423 | mod_timer(&skge->link_timer, jiffies + LINK_HZ); |
| 1425 | } | 1424 | } |
| 1426 | 1425 | ||
| 1427 | static void genesis_mac_init(struct skge_hw *hw, int port) | 1426 | static void genesis_mac_init(struct skge_hw *hw, int port) |
| @@ -2324,7 +2323,7 @@ static void skge_phy_reset(struct skge_port *skge) | |||
| 2324 | netif_stop_queue(skge->netdev); | 2323 | netif_stop_queue(skge->netdev); |
| 2325 | netif_carrier_off(skge->netdev); | 2324 | netif_carrier_off(skge->netdev); |
| 2326 | 2325 | ||
| 2327 | mutex_lock(&hw->phy_mutex); | 2326 | spin_lock_bh(&hw->phy_lock); |
| 2328 | if (hw->chip_id == CHIP_ID_GENESIS) { | 2327 | if (hw->chip_id == CHIP_ID_GENESIS) { |
| 2329 | genesis_reset(hw, port); | 2328 | genesis_reset(hw, port); |
| 2330 | genesis_mac_init(hw, port); | 2329 | genesis_mac_init(hw, port); |
| @@ -2332,7 +2331,7 @@ static void skge_phy_reset(struct skge_port *skge) | |||
| 2332 | yukon_reset(hw, port); | 2331 | yukon_reset(hw, port); |
| 2333 | yukon_init(hw, port); | 2332 | yukon_init(hw, port); |
| 2334 | } | 2333 | } |
| 2335 | mutex_unlock(&hw->phy_mutex); | 2334 | spin_unlock_bh(&hw->phy_lock); |
| 2336 | 2335 | ||
| 2337 | dev->set_multicast_list(dev); | 2336 | dev->set_multicast_list(dev); |
| 2338 | } | 2337 | } |
| @@ -2355,12 +2354,12 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 2355 | /* fallthru */ | 2354 | /* fallthru */ |
| 2356 | case SIOCGMIIREG: { | 2355 | case SIOCGMIIREG: { |
| 2357 | u16 val = 0; | 2356 | u16 val = 0; |
| 2358 | mutex_lock(&hw->phy_mutex); | 2357 | spin_lock_bh(&hw->phy_lock); |
| 2359 | if (hw->chip_id == CHIP_ID_GENESIS) | 2358 | if (hw->chip_id == CHIP_ID_GENESIS) |
| 2360 | err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); | 2359 | err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); |
| 2361 | else | 2360 | else |
| 2362 | err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); | 2361 | err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); |
| 2363 | mutex_unlock(&hw->phy_mutex); | 2362 | spin_unlock_bh(&hw->phy_lock); |
| 2364 | data->val_out = val; | 2363 | data->val_out = val; |
| 2365 | break; | 2364 | break; |
| 2366 | } | 2365 | } |
| @@ -2369,14 +2368,14 @@ static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | |||
| 2369 | if (!capable(CAP_NET_ADMIN)) | 2368 | if (!capable(CAP_NET_ADMIN)) |
| 2370 | return -EPERM; | 2369 | return -EPERM; |
| 2371 | 2370 | ||
| 2372 | mutex_lock(&hw->phy_mutex); | 2371 | spin_lock_bh(&hw->phy_lock); |
| 2373 | if (hw->chip_id == CHIP_ID_GENESIS) | 2372 | if (hw->chip_id == CHIP_ID_GENESIS) |
| 2374 | err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, | 2373 | err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, |
| 2375 | data->val_in); | 2374 | data->val_in); |
| 2376 | else | 2375 | else |
| 2377 | err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f, | 2376 | err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f, |
| 2378 | data->val_in); | 2377 | data->val_in); |
| 2379 | mutex_unlock(&hw->phy_mutex); | 2378 | spin_unlock_bh(&hw->phy_lock); |
| 2380 | break; | 2379 | break; |
| 2381 | } | 2380 | } |
| 2382 | return err; | 2381 | return err; |
| @@ -2482,12 +2481,12 @@ static int skge_up(struct net_device *dev) | |||
| 2482 | goto free_rx_ring; | 2481 | goto free_rx_ring; |
| 2483 | 2482 | ||
| 2484 | /* Initialize MAC */ | 2483 | /* Initialize MAC */ |
| 2485 | mutex_lock(&hw->phy_mutex); | 2484 | spin_lock_bh(&hw->phy_lock); |
| 2486 | if (hw->chip_id == CHIP_ID_GENESIS) | 2485 | if (hw->chip_id == CHIP_ID_GENESIS) |
| 2487 | genesis_mac_init(hw, port); | 2486 | genesis_mac_init(hw, port); |
| 2488 | else | 2487 | else |
| 2489 | yukon_mac_init(hw, port); | 2488 | yukon_mac_init(hw, port); |
| 2490 | mutex_unlock(&hw->phy_mutex); | 2489 | spin_unlock_bh(&hw->phy_lock); |
| 2491 | 2490 | ||
| 2492 | /* Configure RAMbuffers */ | 2491 | /* Configure RAMbuffers */ |
| 2493 | chunk = hw->ram_size / ((hw->ports + 1)*2); | 2492 | chunk = hw->ram_size / ((hw->ports + 1)*2); |
| @@ -2537,7 +2536,7 @@ static int skge_down(struct net_device *dev) | |||
| 2537 | 2536 | ||
| 2538 | netif_stop_queue(dev); | 2537 | netif_stop_queue(dev); |
| 2539 | if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) | 2538 | if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC) |
| 2540 | cancel_delayed_work(&skge->link_thread); | 2539 | del_timer_sync(&skge->link_timer); |
| 2541 | 2540 | ||
| 2542 | netif_poll_disable(dev); | 2541 | netif_poll_disable(dev); |
| 2543 | 2542 | ||
| @@ -3173,28 +3172,29 @@ static void skge_error_irq(struct skge_hw *hw) | |||
| 3173 | } | 3172 | } |
| 3174 | 3173 | ||
| 3175 | /* | 3174 | /* |
| 3176 | * Interrupt from PHY are handled in work queue | 3175 | * Interrupt from PHY are handled in tasklet (softirq) |
| 3177 | * because accessing phy registers requires spin wait which might | 3176 | * because accessing phy registers requires spin wait which might |
| 3178 | * cause excess interrupt latency. | 3177 | * cause excess interrupt latency. |
| 3179 | */ | 3178 | */ |
| 3180 | static void skge_extirq(struct work_struct *work) | 3179 | static void skge_extirq(unsigned long arg) |
| 3181 | { | 3180 | { |
| 3182 | struct skge_hw *hw = container_of(work, struct skge_hw, phy_work); | 3181 | struct skge_hw *hw = (struct skge_hw *) arg; |
| 3183 | int port; | 3182 | int port; |
| 3184 | 3183 | ||
| 3185 | mutex_lock(&hw->phy_mutex); | ||
| 3186 | for (port = 0; port < hw->ports; port++) { | 3184 | for (port = 0; port < hw->ports; port++) { |
| 3187 | struct net_device *dev = hw->dev[port]; | 3185 | struct net_device *dev = hw->dev[port]; |
| 3188 | struct skge_port *skge = netdev_priv(dev); | ||
| 3189 | 3186 | ||
| 3190 | if (netif_running(dev)) { | 3187 | if (netif_running(dev)) { |
| 3188 | struct skge_port *skge = netdev_priv(dev); | ||
| 3189 | |||
| 3190 | spin_lock(&hw->phy_lock); | ||
| 3191 | if (hw->chip_id != CHIP_ID_GENESIS) | 3191 | if (hw->chip_id != CHIP_ID_GENESIS) |
| 3192 | yukon_phy_intr(skge); | 3192 | yukon_phy_intr(skge); |
| 3193 | else if (hw->phy_type == SK_PHY_BCOM) | 3193 | else if (hw->phy_type == SK_PHY_BCOM) |
| 3194 | bcom_phy_intr(skge); | 3194 | bcom_phy_intr(skge); |
| 3195 | spin_unlock(&hw->phy_lock); | ||
| 3195 | } | 3196 | } |
| 3196 | } | 3197 | } |
| 3197 | mutex_unlock(&hw->phy_mutex); | ||
| 3198 | 3198 | ||
| 3199 | spin_lock_irq(&hw->hw_lock); | 3199 | spin_lock_irq(&hw->hw_lock); |
| 3200 | hw->intr_mask |= IS_EXT_REG; | 3200 | hw->intr_mask |= IS_EXT_REG; |
| @@ -3219,7 +3219,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id) | |||
| 3219 | status &= hw->intr_mask; | 3219 | status &= hw->intr_mask; |
| 3220 | if (status & IS_EXT_REG) { | 3220 | if (status & IS_EXT_REG) { |
| 3221 | hw->intr_mask &= ~IS_EXT_REG; | 3221 | hw->intr_mask &= ~IS_EXT_REG; |
| 3222 | schedule_work(&hw->phy_work); | 3222 | tasklet_schedule(&hw->phy_task); |
| 3223 | } | 3223 | } |
| 3224 | 3224 | ||
| 3225 | if (status & (IS_XA1_F|IS_R1_F)) { | 3225 | if (status & (IS_XA1_F|IS_R1_F)) { |
| @@ -3295,23 +3295,28 @@ static int skge_set_mac_address(struct net_device *dev, void *p) | |||
| 3295 | 3295 | ||
| 3296 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); | 3296 | memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); |
| 3297 | 3297 | ||
| 3298 | /* disable Rx */ | 3298 | if (!netif_running(dev)) { |
| 3299 | ctrl = gma_read16(hw, port, GM_GP_CTRL); | 3299 | memcpy_toio(hw->regs + B2_MAC_1 + port*8, dev->dev_addr, ETH_ALEN); |
| 3300 | gma_write16(hw, port, GM_GP_CTRL, ctrl & ~GM_GPCR_RX_ENA); | 3300 | memcpy_toio(hw->regs + B2_MAC_2 + port*8, dev->dev_addr, ETH_ALEN); |
| 3301 | } else { | ||
| 3302 | /* disable Rx */ | ||
| 3303 | spin_lock_bh(&hw->phy_lock); | ||
| 3304 | ctrl = gma_read16(hw, port, GM_GP_CTRL); | ||
| 3305 | gma_write16(hw, port, GM_GP_CTRL, ctrl & ~GM_GPCR_RX_ENA); | ||
| 3301 | 3306 | ||
| 3302 | memcpy_toio(hw->regs + B2_MAC_1 + port*8, dev->dev_addr, ETH_ALEN); | 3307 | memcpy_toio(hw->regs + B2_MAC_1 + port*8, dev->dev_addr, ETH_ALEN); |
| 3303 | memcpy_toio(hw->regs + B2_MAC_2 + port*8, dev->dev_addr, ETH_ALEN); | 3308 | memcpy_toio(hw->regs + B2_MAC_2 + port*8, dev->dev_addr, ETH_ALEN); |
| 3304 | 3309 | ||
| 3305 | if (netif_running(dev)) { | ||
| 3306 | if (hw->chip_id == CHIP_ID_GENESIS) | 3310 | if (hw->chip_id == CHIP_ID_GENESIS) |
| 3307 | xm_outaddr(hw, port, XM_SA, dev->dev_addr); | 3311 | xm_outaddr(hw, port, XM_SA, dev->dev_addr); |
| 3308 | else { | 3312 | else { |
| 3309 | gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); | 3313 | gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr); |
| 3310 | gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); | 3314 | gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr); |
| 3311 | } | 3315 | } |
| 3312 | } | ||
| 3313 | 3316 | ||
| 3314 | gma_write16(hw, port, GM_GP_CTRL, ctrl); | 3317 | gma_write16(hw, port, GM_GP_CTRL, ctrl); |
| 3318 | spin_unlock_bh(&hw->phy_lock); | ||
| 3319 | } | ||
| 3315 | 3320 | ||
| 3316 | return 0; | 3321 | return 0; |
| 3317 | } | 3322 | } |
| @@ -3496,14 +3501,12 @@ static int skge_reset(struct skge_hw *hw) | |||
| 3496 | 3501 | ||
| 3497 | skge_write32(hw, B0_IMSK, hw->intr_mask); | 3502 | skge_write32(hw, B0_IMSK, hw->intr_mask); |
| 3498 | 3503 | ||
| 3499 | mutex_lock(&hw->phy_mutex); | ||
| 3500 | for (i = 0; i < hw->ports; i++) { | 3504 | for (i = 0; i < hw->ports; i++) { |
| 3501 | if (hw->chip_id == CHIP_ID_GENESIS) | 3505 | if (hw->chip_id == CHIP_ID_GENESIS) |
| 3502 | genesis_reset(hw, i); | 3506 | genesis_reset(hw, i); |
| 3503 | else | 3507 | else |
| 3504 | yukon_reset(hw, i); | 3508 | yukon_reset(hw, i); |
| 3505 | } | 3509 | } |
| 3506 | mutex_unlock(&hw->phy_mutex); | ||
| 3507 | 3510 | ||
| 3508 | return 0; | 3511 | return 0; |
| 3509 | } | 3512 | } |
| @@ -3551,6 +3554,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, | |||
| 3551 | skge->netdev = dev; | 3554 | skge->netdev = dev; |
| 3552 | skge->hw = hw; | 3555 | skge->hw = hw; |
| 3553 | skge->msg_enable = netif_msg_init(debug, default_msg); | 3556 | skge->msg_enable = netif_msg_init(debug, default_msg); |
| 3557 | |||
| 3554 | skge->tx_ring.count = DEFAULT_TX_RING_SIZE; | 3558 | skge->tx_ring.count = DEFAULT_TX_RING_SIZE; |
| 3555 | skge->rx_ring.count = DEFAULT_RX_RING_SIZE; | 3559 | skge->rx_ring.count = DEFAULT_RX_RING_SIZE; |
| 3556 | 3560 | ||
| @@ -3567,7 +3571,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, | |||
| 3567 | skge->port = port; | 3571 | skge->port = port; |
| 3568 | 3572 | ||
| 3569 | /* Only used for Genesis XMAC */ | 3573 | /* Only used for Genesis XMAC */ |
| 3570 | INIT_DELAYED_WORK(&skge->link_thread, xm_link_timer); | 3574 | setup_timer(&skge->link_timer, xm_link_timer, (unsigned long) skge); |
| 3571 | 3575 | ||
| 3572 | if (hw->chip_id != CHIP_ID_GENESIS) { | 3576 | if (hw->chip_id != CHIP_ID_GENESIS) { |
| 3573 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; | 3577 | dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; |
| @@ -3649,9 +3653,9 @@ static int __devinit skge_probe(struct pci_dev *pdev, | |||
| 3649 | } | 3653 | } |
| 3650 | 3654 | ||
| 3651 | hw->pdev = pdev; | 3655 | hw->pdev = pdev; |
| 3652 | mutex_init(&hw->phy_mutex); | ||
| 3653 | INIT_WORK(&hw->phy_work, skge_extirq); | ||
| 3654 | spin_lock_init(&hw->hw_lock); | 3656 | spin_lock_init(&hw->hw_lock); |
| 3657 | spin_lock_init(&hw->phy_lock); | ||
| 3658 | tasklet_init(&hw->phy_task, &skge_extirq, (unsigned long) hw); | ||
| 3655 | 3659 | ||
| 3656 | hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); | 3660 | hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); |
| 3657 | if (!hw->regs) { | 3661 | if (!hw->regs) { |
| @@ -3737,6 +3741,8 @@ static void __devexit skge_remove(struct pci_dev *pdev) | |||
| 3737 | dev0 = hw->dev[0]; | 3741 | dev0 = hw->dev[0]; |
| 3738 | unregister_netdev(dev0); | 3742 | unregister_netdev(dev0); |
| 3739 | 3743 | ||
| 3744 | tasklet_disable(&hw->phy_task); | ||
| 3745 | |||
| 3740 | spin_lock_irq(&hw->hw_lock); | 3746 | spin_lock_irq(&hw->hw_lock); |
| 3741 | hw->intr_mask = 0; | 3747 | hw->intr_mask = 0; |
| 3742 | skge_write32(hw, B0_IMSK, 0); | 3748 | skge_write32(hw, B0_IMSK, 0); |
diff --git a/drivers/net/skge.h b/drivers/net/skge.h index e9354dfa7e9a..86467ae74d45 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h | |||
| @@ -2424,8 +2424,8 @@ struct skge_hw { | |||
| 2424 | u32 ram_size; | 2424 | u32 ram_size; |
| 2425 | u32 ram_offset; | 2425 | u32 ram_offset; |
| 2426 | u16 phy_addr; | 2426 | u16 phy_addr; |
| 2427 | struct work_struct phy_work; | 2427 | spinlock_t phy_lock; |
| 2428 | struct mutex phy_mutex; | 2428 | struct tasklet_struct phy_task; |
| 2429 | }; | 2429 | }; |
| 2430 | 2430 | ||
| 2431 | enum pause_control { | 2431 | enum pause_control { |
| @@ -2457,7 +2457,7 @@ struct skge_port { | |||
| 2457 | 2457 | ||
| 2458 | struct net_device_stats net_stats; | 2458 | struct net_device_stats net_stats; |
| 2459 | 2459 | ||
| 2460 | struct delayed_work link_thread; | 2460 | struct timer_list link_timer; |
| 2461 | enum pause_control flow_control; | 2461 | enum pause_control flow_control; |
| 2462 | enum pause_status flow_status; | 2462 | enum pause_status flow_status; |
| 2463 | u8 rx_csum; | 2463 | u8 rx_csum; |
