aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethoc.c
diff options
context:
space:
mode:
authorJonas Bonn <jonas@southpole.se>2010-11-24 21:30:29 -0500
committerDavid S. Miller <davem@davemloft.net>2010-11-28 14:16:36 -0500
commitfa98eb0e867c6c16e239545d4deb7ad8f40631b3 (patch)
treed07c00d2cd4c2073d92f8d9aebb4cbb4f3a35631 /drivers/net/ethoc.c
parent20f70ddd6558a39a89dba4af675686c5a8dbd7b3 (diff)
ethoc: rework interrupt handling
The old interrupt handling was incorrect in that it did not account for the fact that the interrupt source bits get set irregardless of whether or not their corresponding mask is set. This patch fixes that by masking off the source bits for masked interrupts. Furthermore, the handling of transmission events is moved to the NAPI polling handler alongside the reception handler, thus preventing a whole bunch of interrupts during heavy traffic. Signed-off-by: Jonas Bonn <jonas@southpole.se> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethoc.c')
-rw-r--r--drivers/net/ethoc.c76
1 files changed, 49 insertions, 27 deletions
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index a12a07ea02b6..43431ffcf6c1 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -495,29 +495,42 @@ static int ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
495 return 0; 495 return 0;
496} 496}
497 497
498static void ethoc_tx(struct net_device *dev) 498static int ethoc_tx(struct net_device *dev, int limit)
499{ 499{
500 struct ethoc *priv = netdev_priv(dev); 500 struct ethoc *priv = netdev_priv(dev);
501 int count;
502 struct ethoc_bd bd;
501 503
502 spin_lock(&priv->lock); 504 for (count = 0; count < limit; ++count) {
505 unsigned int entry;
503 506
504 while (priv->dty_tx != priv->cur_tx) { 507 entry = priv->dty_tx % priv->num_tx;
505 unsigned int entry = priv->dty_tx % priv->num_tx;
506 struct ethoc_bd bd;
507 508
508 ethoc_read_bd(priv, entry, &bd); 509 ethoc_read_bd(priv, entry, &bd);
509 if (bd.stat & TX_BD_READY)
510 break;
511 510
512 entry = (++priv->dty_tx) % priv->num_tx; 511 if (bd.stat & TX_BD_READY || (priv->dty_tx == priv->cur_tx)) {
512 ethoc_ack_irq(priv, INT_MASK_TX);
513 /* If interrupt came in between reading in the BD
514 * and clearing the interrupt source, then we risk
515 * missing the event as the TX interrupt won't trigger
516 * right away when we reenable it; hence, check
517 * BD_EMPTY here again to make sure there isn't such an
518 * event pending...
519 */
520 ethoc_read_bd(priv, entry, &bd);
521 if (bd.stat & TX_BD_READY ||
522 (priv->dty_tx == priv->cur_tx))
523 break;
524 }
525
513 (void)ethoc_update_tx_stats(priv, &bd); 526 (void)ethoc_update_tx_stats(priv, &bd);
527 priv->dty_tx++;
514 } 528 }
515 529
516 if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2)) 530 if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2))
517 netif_wake_queue(dev); 531 netif_wake_queue(dev);
518 532
519 ethoc_ack_irq(priv, INT_MASK_TX); 533 return count;
520 spin_unlock(&priv->lock);
521} 534}
522 535
523static irqreturn_t ethoc_interrupt(int irq, void *dev_id) 536static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
@@ -525,32 +538,38 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
525 struct net_device *dev = dev_id; 538 struct net_device *dev = dev_id;
526 struct ethoc *priv = netdev_priv(dev); 539 struct ethoc *priv = netdev_priv(dev);
527 u32 pending; 540 u32 pending;
528 541 u32 mask;
529 ethoc_disable_irq(priv, INT_MASK_ALL); 542
543 /* Figure out what triggered the interrupt...
544 * The tricky bit here is that the interrupt source bits get
545 * set in INT_SOURCE for an event irregardless of whether that
546 * event is masked or not. Thus, in order to figure out what
547 * triggered the interrupt, we need to remove the sources
548 * for all events that are currently masked. This behaviour
549 * is not particularly well documented but reasonable...
550 */
551 mask = ethoc_read(priv, INT_MASK);
530 pending = ethoc_read(priv, INT_SOURCE); 552 pending = ethoc_read(priv, INT_SOURCE);
553 pending &= mask;
554
531 if (unlikely(pending == 0)) { 555 if (unlikely(pending == 0)) {
532 ethoc_enable_irq(priv, INT_MASK_ALL);
533 return IRQ_NONE; 556 return IRQ_NONE;
534 } 557 }
535 558
536 ethoc_ack_irq(priv, pending); 559 ethoc_ack_irq(priv, pending);
537 560
561 /* We always handle the dropped packet interrupt */
538 if (pending & INT_MASK_BUSY) { 562 if (pending & INT_MASK_BUSY) {
539 dev_err(&dev->dev, "packet dropped\n"); 563 dev_err(&dev->dev, "packet dropped\n");
540 dev->stats.rx_dropped++; 564 dev->stats.rx_dropped++;
541 } 565 }
542 566
543 if (pending & INT_MASK_RX) { 567 /* Handle receive/transmit event by switching to polling */
544 if (napi_schedule_prep(&priv->napi)) 568 if (pending & (INT_MASK_TX | INT_MASK_RX)) {
545 __napi_schedule(&priv->napi); 569 ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX);
546 } else { 570 napi_schedule(&priv->napi);
547 ethoc_enable_irq(priv, INT_MASK_RX);
548 } 571 }
549 572
550 if (pending & INT_MASK_TX)
551 ethoc_tx(dev);
552
553 ethoc_enable_irq(priv, INT_MASK_ALL & ~INT_MASK_RX);
554 return IRQ_HANDLED; 573 return IRQ_HANDLED;
555} 574}
556 575
@@ -576,15 +595,18 @@ static int ethoc_get_mac_address(struct net_device *dev, void *addr)
576static int ethoc_poll(struct napi_struct *napi, int budget) 595static int ethoc_poll(struct napi_struct *napi, int budget)
577{ 596{
578 struct ethoc *priv = container_of(napi, struct ethoc, napi); 597 struct ethoc *priv = container_of(napi, struct ethoc, napi);
579 int work_done = 0; 598 int rx_work_done = 0;
599 int tx_work_done = 0;
600
601 rx_work_done = ethoc_rx(priv->netdev, budget);
602 tx_work_done = ethoc_tx(priv->netdev, budget);
580 603
581 work_done = ethoc_rx(priv->netdev, budget); 604 if (rx_work_done < budget && tx_work_done < budget) {
582 if (work_done < budget) {
583 napi_complete(napi); 605 napi_complete(napi);
584 ethoc_enable_irq(priv, INT_MASK_RX); 606 ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX);
585 } 607 }
586 608
587 return work_done; 609 return rx_work_done;
588} 610}
589 611
590static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg) 612static int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)