diff options
-rw-r--r-- | drivers/net/fec.c | 55 |
1 files changed, 33 insertions, 22 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 5f9c2c1a9d40..32a4f17d35fc 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c | |||
@@ -209,7 +209,10 @@ struct fec_enet_private { | |||
209 | cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ | 209 | cbd_t *cur_rx, *cur_tx; /* The next free ring entry */ |
210 | cbd_t *dirty_tx; /* The ring entries to be free()ed. */ | 210 | cbd_t *dirty_tx; /* The ring entries to be free()ed. */ |
211 | uint tx_full; | 211 | uint tx_full; |
212 | spinlock_t lock; | 212 | /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ |
213 | spinlock_t hw_lock; | ||
214 | /* hold while accessing the mii_list_t() elements */ | ||
215 | spinlock_t mii_lock; | ||
213 | 216 | ||
214 | uint phy_id; | 217 | uint phy_id; |
215 | uint phy_id_done; | 218 | uint phy_id_done; |
@@ -313,6 +316,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
313 | volatile fec_t *fecp; | 316 | volatile fec_t *fecp; |
314 | volatile cbd_t *bdp; | 317 | volatile cbd_t *bdp; |
315 | unsigned short status; | 318 | unsigned short status; |
319 | unsigned long flags; | ||
316 | 320 | ||
317 | fep = netdev_priv(dev); | 321 | fep = netdev_priv(dev); |
318 | fecp = (volatile fec_t*)dev->base_addr; | 322 | fecp = (volatile fec_t*)dev->base_addr; |
@@ -322,6 +326,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
322 | return 1; | 326 | return 1; |
323 | } | 327 | } |
324 | 328 | ||
329 | spin_lock_irqsave(&fep->hw_lock, flags); | ||
325 | /* Fill in a Tx ring entry */ | 330 | /* Fill in a Tx ring entry */ |
326 | bdp = fep->cur_tx; | 331 | bdp = fep->cur_tx; |
327 | 332 | ||
@@ -332,6 +337,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
332 | * This should not happen, since dev->tbusy should be set. | 337 | * This should not happen, since dev->tbusy should be set. |
333 | */ | 338 | */ |
334 | printk("%s: tx queue full!.\n", dev->name); | 339 | printk("%s: tx queue full!.\n", dev->name); |
340 | spin_unlock_irqrestore(&fep->hw_lock, flags); | ||
335 | return 1; | 341 | return 1; |
336 | } | 342 | } |
337 | #endif | 343 | #endif |
@@ -370,8 +376,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
370 | flush_dcache_range((unsigned long)skb->data, | 376 | flush_dcache_range((unsigned long)skb->data, |
371 | (unsigned long)skb->data + skb->len); | 377 | (unsigned long)skb->data + skb->len); |
372 | 378 | ||
373 | spin_lock_irq(&fep->lock); | ||
374 | |||
375 | /* Send it on its way. Tell FEC it's ready, interrupt when done, | 379 | /* Send it on its way. Tell FEC it's ready, interrupt when done, |
376 | * it's the last BD of the frame, and to put the CRC on the end. | 380 | * it's the last BD of the frame, and to put the CRC on the end. |
377 | */ | 381 | */ |
@@ -400,7 +404,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
400 | 404 | ||
401 | fep->cur_tx = (cbd_t *)bdp; | 405 | fep->cur_tx = (cbd_t *)bdp; |
402 | 406 | ||
403 | spin_unlock_irq(&fep->lock); | 407 | spin_unlock_irqrestore(&fep->hw_lock, flags); |
404 | 408 | ||
405 | return 0; | 409 | return 0; |
406 | } | 410 | } |
@@ -458,19 +462,20 @@ fec_enet_interrupt(int irq, void * dev_id) | |||
458 | struct net_device *dev = dev_id; | 462 | struct net_device *dev = dev_id; |
459 | volatile fec_t *fecp; | 463 | volatile fec_t *fecp; |
460 | uint int_events; | 464 | uint int_events; |
461 | int handled = 0; | 465 | irqreturn_t ret = IRQ_NONE; |
462 | 466 | ||
463 | fecp = (volatile fec_t*)dev->base_addr; | 467 | fecp = (volatile fec_t*)dev->base_addr; |
464 | 468 | ||
465 | /* Get the interrupt events that caused us to be here. | 469 | /* Get the interrupt events that caused us to be here. |
466 | */ | 470 | */ |
467 | while ((int_events = fecp->fec_ievent) != 0) { | 471 | do { |
472 | int_events = fecp->fec_ievent; | ||
468 | fecp->fec_ievent = int_events; | 473 | fecp->fec_ievent = int_events; |
469 | 474 | ||
470 | /* Handle receive event in its own function. | 475 | /* Handle receive event in its own function. |
471 | */ | 476 | */ |
472 | if (int_events & FEC_ENET_RXF) { | 477 | if (int_events & FEC_ENET_RXF) { |
473 | handled = 1; | 478 | ret = IRQ_HANDLED; |
474 | fec_enet_rx(dev); | 479 | fec_enet_rx(dev); |
475 | } | 480 | } |
476 | 481 | ||
@@ -479,17 +484,18 @@ fec_enet_interrupt(int irq, void * dev_id) | |||
479 | them as part of the transmit process. | 484 | them as part of the transmit process. |
480 | */ | 485 | */ |
481 | if (int_events & FEC_ENET_TXF) { | 486 | if (int_events & FEC_ENET_TXF) { |
482 | handled = 1; | 487 | ret = IRQ_HANDLED; |
483 | fec_enet_tx(dev); | 488 | fec_enet_tx(dev); |
484 | } | 489 | } |
485 | 490 | ||
486 | if (int_events & FEC_ENET_MII) { | 491 | if (int_events & FEC_ENET_MII) { |
487 | handled = 1; | 492 | ret = IRQ_HANDLED; |
488 | fec_enet_mii(dev); | 493 | fec_enet_mii(dev); |
489 | } | 494 | } |
490 | 495 | ||
491 | } | 496 | } while (int_events); |
492 | return IRQ_RETVAL(handled); | 497 | |
498 | return ret; | ||
493 | } | 499 | } |
494 | 500 | ||
495 | 501 | ||
@@ -502,7 +508,7 @@ fec_enet_tx(struct net_device *dev) | |||
502 | struct sk_buff *skb; | 508 | struct sk_buff *skb; |
503 | 509 | ||
504 | fep = netdev_priv(dev); | 510 | fep = netdev_priv(dev); |
505 | spin_lock(&fep->lock); | 511 | spin_lock_irq(&fep->hw_lock); |
506 | bdp = fep->dirty_tx; | 512 | bdp = fep->dirty_tx; |
507 | 513 | ||
508 | while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { | 514 | while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { |
@@ -561,7 +567,7 @@ fec_enet_tx(struct net_device *dev) | |||
561 | } | 567 | } |
562 | } | 568 | } |
563 | fep->dirty_tx = (cbd_t *)bdp; | 569 | fep->dirty_tx = (cbd_t *)bdp; |
564 | spin_unlock(&fep->lock); | 570 | spin_unlock_irq(&fep->hw_lock); |
565 | } | 571 | } |
566 | 572 | ||
567 | 573 | ||
@@ -588,6 +594,8 @@ fec_enet_rx(struct net_device *dev) | |||
588 | fep = netdev_priv(dev); | 594 | fep = netdev_priv(dev); |
589 | fecp = (volatile fec_t*)dev->base_addr; | 595 | fecp = (volatile fec_t*)dev->base_addr; |
590 | 596 | ||
597 | spin_lock_irq(&fep->hw_lock); | ||
598 | |||
591 | /* First, grab all of the stats for the incoming packet. | 599 | /* First, grab all of the stats for the incoming packet. |
592 | * These get messed up if we get called due to a busy condition. | 600 | * These get messed up if we get called due to a busy condition. |
593 | */ | 601 | */ |
@@ -693,6 +701,8 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { | |||
693 | */ | 701 | */ |
694 | fecp->fec_r_des_active = 0; | 702 | fecp->fec_r_des_active = 0; |
695 | #endif | 703 | #endif |
704 | |||
705 | spin_unlock_irq(&fep->hw_lock); | ||
696 | } | 706 | } |
697 | 707 | ||
698 | 708 | ||
@@ -706,11 +716,11 @@ fec_enet_mii(struct net_device *dev) | |||
706 | uint mii_reg; | 716 | uint mii_reg; |
707 | 717 | ||
708 | fep = netdev_priv(dev); | 718 | fep = netdev_priv(dev); |
719 | spin_lock_irq(&fep->mii_lock); | ||
720 | |||
709 | ep = fep->hwp; | 721 | ep = fep->hwp; |
710 | mii_reg = ep->fec_mii_data; | 722 | mii_reg = ep->fec_mii_data; |
711 | 723 | ||
712 | spin_lock(&fep->lock); | ||
713 | |||
714 | if ((mip = mii_head) == NULL) { | 724 | if ((mip = mii_head) == NULL) { |
715 | printk("MII and no head!\n"); | 725 | printk("MII and no head!\n"); |
716 | goto unlock; | 726 | goto unlock; |
@@ -727,7 +737,7 @@ fec_enet_mii(struct net_device *dev) | |||
727 | ep->fec_mii_data = mip->mii_regval; | 737 | ep->fec_mii_data = mip->mii_regval; |
728 | 738 | ||
729 | unlock: | 739 | unlock: |
730 | spin_unlock(&fep->lock); | 740 | spin_unlock_irq(&fep->mii_lock); |
731 | } | 741 | } |
732 | 742 | ||
733 | static int | 743 | static int |
@@ -741,12 +751,11 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi | |||
741 | /* Add PHY address to register command. | 751 | /* Add PHY address to register command. |
742 | */ | 752 | */ |
743 | fep = netdev_priv(dev); | 753 | fep = netdev_priv(dev); |
744 | regval |= fep->phy_addr << 23; | 754 | spin_lock_irqsave(&fep->mii_lock, flags); |
745 | 755 | ||
756 | regval |= fep->phy_addr << 23; | ||
746 | retval = 0; | 757 | retval = 0; |
747 | 758 | ||
748 | spin_lock_irqsave(&fep->lock,flags); | ||
749 | |||
750 | if ((mip = mii_free) != NULL) { | 759 | if ((mip = mii_free) != NULL) { |
751 | mii_free = mip->mii_next; | 760 | mii_free = mip->mii_next; |
752 | mip->mii_regval = regval; | 761 | mip->mii_regval = regval; |
@@ -763,9 +772,8 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi | |||
763 | retval = 1; | 772 | retval = 1; |
764 | } | 773 | } |
765 | 774 | ||
766 | spin_unlock_irqrestore(&fep->lock,flags); | 775 | spin_unlock_irqrestore(&fep->mii_lock, flags); |
767 | 776 | return retval; | |
768 | return(retval); | ||
769 | } | 777 | } |
770 | 778 | ||
771 | static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) | 779 | static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c) |
@@ -2308,6 +2316,9 @@ int __init fec_enet_init(struct net_device *dev) | |||
2308 | return -ENOMEM; | 2316 | return -ENOMEM; |
2309 | } | 2317 | } |
2310 | 2318 | ||
2319 | spin_lock_init(&fep->hw_lock); | ||
2320 | spin_lock_init(&fep->mii_lock); | ||
2321 | |||
2311 | /* Create an Ethernet device instance. | 2322 | /* Create an Ethernet device instance. |
2312 | */ | 2323 | */ |
2313 | fecp = (volatile fec_t *) fec_hw[index]; | 2324 | fecp = (volatile fec_t *) fec_hw[index]; |