aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/spider_net.c
diff options
context:
space:
mode:
authorLinas Vepstas <linas@austin.ibm.com>2006-10-10 17:11:33 -0400
committerJeff Garzik <jeff@garzik.org>2006-10-11 04:04:26 -0400
commit204e5fa17c7ba45a89989f8da6dfe8e54d64b79b (patch)
treee69b3c2989839bac94718c6be16dd1433da30c12 /drivers/net/spider_net.c
parentb21606a773faffc2b3ec326325c433bdf37ecbdf (diff)
[PATCH] powerpc/cell spidernet low watermark patch.
Implement basic low-watermark support for the transmit queue. Hardware low-watermarks allow a properly configured kernel to continously stream data to a device and not have to handle any interrupts at all in doing so. Correct zero-interrupt operation can be actually observed for this driver, when the socket buffer is made large enough. The basic idea of a low-watermark interrupt is as follows. The device driver queues up a bunch of packets for the hardware to transmit, and then kicks the hardware to get it started. As the hardware drains the queue of pending, untransmitted packets, the device driver will want to know when the queue is almost empty, so that it can queue some more packets. If the queue drains down to the low waterark, then an interrupt will be generated. However, if the kernel/driver continues to add enough packets to keep the queue partially filled, no interrupt will actually be generated, and the hardware can continue streaming packets indefinitely in this mode. The impelmentation is done by setting the DESCR_TXDESFLG flag in one of the packets. When the hardware sees this flag, it will interrupt the device driver. Because this flag is on a fixed packet, rather than at fixed location in the queue, the code below needs to move the flag as more packets are queued up. This implementation attempts to keep the flag at about 1/4 from "empty". Signed-off-by: Linas Vepstas <linas@austin.ibm.com> Signed-off-by: James K Lewis <jklewis@us.ibm.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/spider_net.c')
-rw-r--r--drivers/net/spider_net.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index d779a0b9d456..96b5d00c21da 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -684,6 +684,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
684 break; 684 break;
685 } 685 }
686 686
687 /* Chain the bus address, so that the DMA engine finds this descr. */
687 descr->prev->next_descr_addr = descr->bus_addr; 688 descr->prev->next_descr_addr = descr->bus_addr;
688 689
689 card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ 690 card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
@@ -717,6 +718,41 @@ spider_net_release_tx_descr(struct spider_net_card *card)
717 dev_kfree_skb_any(skb); 718 dev_kfree_skb_any(skb);
718} 719}
719 720
721static void
722spider_net_set_low_watermark(struct spider_net_card *card)
723{
724 int status;
725 int cnt=0;
726 int i;
727 struct spider_net_descr *descr = card->tx_chain.tail;
728
729 /* Measure the length of the queue. */
730 while (descr != card->tx_chain.head) {
731 status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
732 if (status == SPIDER_NET_DESCR_NOT_IN_USE)
733 break;
734 descr = descr->next;
735 cnt++;
736 }
737
738 /* If TX queue is short, don't even bother with interrupts */
739 if (cnt < card->tx_desc/4)
740 return;
741
742 /* Set low-watermark 3/4th's of the way into the queue. */
743 descr = card->tx_chain.tail;
744 cnt = (cnt*3)/4;
745 for (i=0;i<cnt; i++)
746 descr = descr->next;
747
748 /* Set the new watermark, clear the old watermark */
749 descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
750 if (card->low_watermark && card->low_watermark != descr)
751 card->low_watermark->dmac_cmd_status =
752 card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
753 card->low_watermark = descr;
754}
755
720/** 756/**
721 * spider_net_release_tx_chain - processes sent tx descriptors 757 * spider_net_release_tx_chain - processes sent tx descriptors
722 * @card: adapter structure 758 * @card: adapter structure
@@ -838,6 +874,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
838 return NETDEV_TX_BUSY; 874 return NETDEV_TX_BUSY;
839 } 875 }
840 876
877 spider_net_set_low_watermark(card);
841 spider_net_kick_tx_dma(card); 878 spider_net_kick_tx_dma(card);
842 card->tx_chain.head = card->tx_chain.head->next; 879 card->tx_chain.head = card->tx_chain.head->next;
843 spin_unlock_irqrestore(&chain->lock, flags); 880 spin_unlock_irqrestore(&chain->lock, flags);
@@ -1467,6 +1504,10 @@ spider_net_interrupt(int irq, void *ptr)
1467 spider_net_rx_irq_off(card); 1504 spider_net_rx_irq_off(card);
1468 netif_rx_schedule(netdev); 1505 netif_rx_schedule(netdev);
1469 } 1506 }
1507 if (status_reg & SPIDER_NET_TXINT ) {
1508 spider_net_cleanup_tx_ring(card);
1509 netif_wake_queue(netdev);
1510 }
1470 1511
1471 if (status_reg & SPIDER_NET_ERRINT ) 1512 if (status_reg & SPIDER_NET_ERRINT )
1472 spider_net_handle_error_irq(card, status_reg); 1513 spider_net_handle_error_irq(card, status_reg);
@@ -1629,6 +1670,8 @@ spider_net_open(struct net_device *netdev)
1629 PCI_DMA_TODEVICE, card->tx_desc)) 1670 PCI_DMA_TODEVICE, card->tx_desc))
1630 goto alloc_tx_failed; 1671 goto alloc_tx_failed;
1631 1672
1673 card->low_watermark = NULL;
1674
1632 /* rx_chain is after tx_chain, so offset is descr + tx_count */ 1675 /* rx_chain is after tx_chain, so offset is descr + tx_count */
1633 if (spider_net_init_chain(card, &card->rx_chain, 1676 if (spider_net_init_chain(card, &card->rx_chain,
1634 card->descr + card->tx_desc, 1677 card->descr + card->tx_desc,