aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorMichael Reiss <michael.f.reiss@freescale.com>2007-04-13 02:26:11 -0400
committerJeff Garzik <jeff@garzik.org>2007-04-28 11:01:04 -0400
commit702ff12ce7e9643084232a8d50b0b1eec26026ae (patch)
treed00d43218efdc3f6e5356c638438f2f0a2bc3774 /drivers/net
parent728de4c927a3544b6d3da331b634035d4c75ca17 (diff)
ucc_geth: NAPI-related bug fixes
Based partly on the gianfar driver, this patch fixes several bugs which were causing NAPI to be completely unusable. * An IRQ is still needed in NAPI, to kick off NAPI task, and for Tx processing. Request the IRQ. * If rx_work_limit = 0 we are not complete. * While running Rx NAPI processing we must mask Rx events, including Rx busy. * ucc_geth_rx function does not need a lock. Could lead to deadlock in NAPI case. * There's no need to loop reading ucce multiple times in the ISR, so while adding the call to schedule NAPI which was not there, simplify the event processing into if-else format. * Rx Busy now kicks off NAPI processing, while still being counted as an error. Signed-off-by: Michael Reiss <michael.f.reiss@freescale.com> Signed-off-by: Michael Barkowski <michael.barkowski@freescale.com> Signed-off-by: Kim Phillips <kim.phillips@freescale.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ucc_geth.c98
-rw-r--r--drivers/net/ucc_geth.h3
2 files changed, 61 insertions, 40 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index d93cfde663e9..60be1e775380 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3416,7 +3416,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
3416 3416
3417 ugeth_vdbg("%s: IN", __FUNCTION__); 3417 ugeth_vdbg("%s: IN", __FUNCTION__);
3418 3418
3419 spin_lock(&ugeth->lock);
3420 /* collect received buffers */ 3419 /* collect received buffers */
3421 bd = ugeth->rxBd[rxQ]; 3420 bd = ugeth->rxBd[rxQ];
3422 3421
@@ -3464,7 +3463,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
3464 skb = get_new_skb(ugeth, bd); 3463 skb = get_new_skb(ugeth, bd);
3465 if (!skb) { 3464 if (!skb) {
3466 ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); 3465 ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
3467 spin_unlock(&ugeth->lock);
3468 ugeth->stats.rx_dropped++; 3466 ugeth->stats.rx_dropped++;
3469 break; 3467 break;
3470 } 3468 }
@@ -3485,7 +3483,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit
3485 } 3483 }
3486 3484
3487 ugeth->rxBd[rxQ] = bd; 3485 ugeth->rxBd[rxQ] = bd;
3488 spin_unlock(&ugeth->lock);
3489 return howmany; 3486 return howmany;
3490} 3487}
3491 3488
@@ -3537,23 +3534,38 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ)
3537static int ucc_geth_poll(struct net_device *dev, int *budget) 3534static int ucc_geth_poll(struct net_device *dev, int *budget)
3538{ 3535{
3539 struct ucc_geth_private *ugeth = netdev_priv(dev); 3536 struct ucc_geth_private *ugeth = netdev_priv(dev);
3537 struct ucc_geth_info *ug_info;
3538 struct ucc_fast_private *uccf;
3540 int howmany; 3539 int howmany;
3541 int rx_work_limit = *budget; 3540 u8 i;
3542 u8 rxQ = 0; 3541 int rx_work_limit;
3542 register u32 uccm;
3543 3543
3544 ug_info = ugeth->ug_info;
3545
3546 rx_work_limit = *budget;
3544 if (rx_work_limit > dev->quota) 3547 if (rx_work_limit > dev->quota)
3545 rx_work_limit = dev->quota; 3548 rx_work_limit = dev->quota;
3546 3549
3547 howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit); 3550 howmany = 0;
3551
3552 for (i = 0; i < ug_info->numQueuesRx; i++) {
3553 howmany += ucc_geth_rx(ugeth, i, rx_work_limit);
3554 }
3548 3555
3549 dev->quota -= howmany; 3556 dev->quota -= howmany;
3550 rx_work_limit -= howmany; 3557 rx_work_limit -= howmany;
3551 *budget -= howmany; 3558 *budget -= howmany;
3552 3559
3553 if (rx_work_limit >= 0) 3560 if (rx_work_limit > 0) {
3554 netif_rx_complete(dev); 3561 netif_rx_complete(dev);
3562 uccf = ugeth->uccf;
3563 uccm = in_be32(uccf->p_uccm);
3564 uccm |= UCCE_RX_EVENTS;
3565 out_be32(uccf->p_uccm, uccm);
3566 }
3555 3567
3556 return (rx_work_limit < 0) ? 1 : 0; 3568 return (rx_work_limit > 0) ? 0 : 1;
3557} 3569}
3558#endif /* CONFIG_UGETH_NAPI */ 3570#endif /* CONFIG_UGETH_NAPI */
3559 3571
@@ -3563,10 +3575,13 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
3563 struct ucc_geth_private *ugeth = netdev_priv(dev); 3575 struct ucc_geth_private *ugeth = netdev_priv(dev);
3564 struct ucc_fast_private *uccf; 3576 struct ucc_fast_private *uccf;
3565 struct ucc_geth_info *ug_info; 3577 struct ucc_geth_info *ug_info;
3566 register u32 ucce = 0; 3578 register u32 ucce;
3567 register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; 3579 register u32 uccm;
3568 register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; 3580#ifndef CONFIG_UGETH_NAPI
3569 register u8 i; 3581 register u32 rx_mask;
3582#endif
3583 register u32 tx_mask;
3584 u8 i;
3570 3585
3571 ugeth_vdbg("%s: IN", __FUNCTION__); 3586 ugeth_vdbg("%s: IN", __FUNCTION__);
3572 3587
@@ -3576,48 +3591,53 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
3576 uccf = ugeth->uccf; 3591 uccf = ugeth->uccf;
3577 ug_info = ugeth->ug_info; 3592 ug_info = ugeth->ug_info;
3578 3593
3579 do { 3594 /* read and clear events */
3580 ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm)); 3595 ucce = (u32) in_be32(uccf->p_ucce);
3581 3596 uccm = (u32) in_be32(uccf->p_uccm);
3582 /* clear event bits for next time */ 3597 ucce &= uccm;
3583 /* Side effect here is to mask ucce variable 3598 out_be32(uccf->p_ucce, ucce);
3584 for future processing below. */
3585 out_be32(uccf->p_ucce, ucce); /* Clear with ones,
3586 but only bits in UCCM */
3587
3588 /* We ignore Tx interrupts because Tx confirmation is
3589 done inside Tx routine */
3590 3599
3600 /* check for receive events that require processing */
3601 if (ucce & UCCE_RX_EVENTS) {
3602#ifdef CONFIG_UGETH_NAPI
3603 if (netif_rx_schedule_prep(dev)) {
3604 uccm &= ~UCCE_RX_EVENTS;
3605 out_be32(uccf->p_uccm, uccm);
3606 __netif_rx_schedule(dev);
3607 }
3608#else
3609 rx_mask = UCCE_RXBF_SINGLE_MASK;
3591 for (i = 0; i < ug_info->numQueuesRx; i++) { 3610 for (i = 0; i < ug_info->numQueuesRx; i++) {
3592 if (ucce & bit_mask) 3611 if (ucce & rx_mask)
3593 ucc_geth_rx(ugeth, i, 3612 ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]);
3594 (int)ugeth->ug_info-> 3613 ucce &= ~rx_mask;
3595 bdRingLenRx[i]); 3614 rx_mask <<= 1;
3596 ucce &= ~bit_mask;
3597 bit_mask <<= 1;
3598 } 3615 }
3616#endif /* CONFIG_UGETH_NAPI */
3617 }
3599 3618
3619 /* Tx event processing */
3620 if (ucce & UCCE_TX_EVENTS) {
3621 spin_lock(&ugeth->lock);
3622 tx_mask = UCCE_TXBF_SINGLE_MASK;
3600 for (i = 0; i < ug_info->numQueuesTx; i++) { 3623 for (i = 0; i < ug_info->numQueuesTx; i++) {
3601 if (ucce & tx_mask) 3624 if (ucce & tx_mask)
3602 ucc_geth_tx(dev, i); 3625 ucc_geth_tx(dev, i);
3603 ucce &= ~tx_mask; 3626 ucce &= ~tx_mask;
3604 tx_mask <<= 1; 3627 tx_mask <<= 1;
3605 } 3628 }
3629 spin_unlock(&ugeth->lock);
3630 }
3606 3631
3607 /* Exceptions */ 3632 /* Errors and other events */
3633 if (ucce & UCCE_OTHER) {
3608 if (ucce & UCCE_BSY) { 3634 if (ucce & UCCE_BSY) {
3609 ugeth_vdbg("Got BUSY irq!!!!");
3610 ugeth->stats.rx_errors++; 3635 ugeth->stats.rx_errors++;
3611 ucce &= ~UCCE_BSY;
3612 } 3636 }
3613 if (ucce & UCCE_OTHER) { 3637 if (ucce & UCCE_TXE) {
3614 ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!", 3638 ugeth->stats.tx_errors++;
3615 ucce);
3616 ugeth->stats.rx_errors++;
3617 ucce &= ~ucce;
3618 } 3639 }
3619 } 3640 }
3620 while (ucce);
3621 3641
3622 return IRQ_HANDLED; 3642 return IRQ_HANDLED;
3623} 3643}
@@ -3677,7 +3697,6 @@ static int ucc_geth_open(struct net_device *dev)
3677 3697
3678 phy_start(ugeth->phydev); 3698 phy_start(ugeth->phydev);
3679 3699
3680#ifndef CONFIG_UGETH_NAPI
3681 err = 3700 err =
3682 request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, 3701 request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
3683 "UCC Geth", dev); 3702 "UCC Geth", dev);
@@ -3687,7 +3706,6 @@ static int ucc_geth_open(struct net_device *dev)
3687 ucc_geth_stop(ugeth); 3706 ucc_geth_stop(ugeth);
3688 return err; 3707 return err;
3689 } 3708 }
3690#endif /* CONFIG_UGETH_NAPI */
3691 3709
3692 err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); 3710 err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
3693 if (err) { 3711 if (err) {
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index 6e97c20b92aa..7cf3dbc9fd4c 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -205,6 +205,9 @@ struct ucc_geth {
205#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ 205#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\
206 UCCE_RXC | UCCE_TXC | UCCE_TXE) 206 UCCE_RXC | UCCE_TXC | UCCE_TXE)
207 207
208#define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY)
209#define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE)
210
208/* UCC GETH UPSMR (Protocol Specific Mode Register) */ 211/* UCC GETH UPSMR (Protocol Specific Mode Register) */
209#define UPSMR_ECM 0x04000000 /* Enable CAM 212#define UPSMR_ECM 0x04000000 /* Enable CAM
210 Miss or 213 Miss or