diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/spider_net.c | 43 | ||||
-rw-r--r-- | drivers/net/spider_net.h | 8 |
2 files changed, 47 insertions, 4 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index d779a0b9d45..96b5d00c21d 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, break; } + /* Chain the bus address, so that the DMA engine finds this descr. */ descr->prev->next_descr_addr = descr->bus_addr; card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ @@ -717,6 +718,41 @@ spider_net_release_tx_descr(struct spider_net_card *card) dev_kfree_skb_any(skb); } +static void +spider_net_set_low_watermark(struct spider_net_card *card) +{ + int status; + int cnt=0; + int i; + struct spider_net_descr *descr = card->tx_chain.tail; + + /* Measure the length of the queue. */ + while (descr != card->tx_chain.head) { + status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; + if (status == SPIDER_NET_DESCR_NOT_IN_USE) + break; + descr = descr->next; + cnt++; + } + + /* If TX queue is short, don't even bother with interrupts */ + if (cnt < card->tx_desc/4) + return; + + /* Set low-watermark 3/4th's of the way into the queue. */ + descr = card->tx_chain.tail; + cnt = (cnt*3)/4; + for (i=0;i<cnt; i++) + descr = descr->next; + + /* Set the new watermark, clear the old watermark */ + descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; + if (card->low_watermark && card->low_watermark != descr) + card->low_watermark->dmac_cmd_status = + card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; + card->low_watermark = descr; +} + /** * spider_net_release_tx_chain - processes sent tx descriptors * @card: adapter structure @@ -838,6 +874,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } + spider_net_set_low_watermark(card); spider_net_kick_tx_dma(card); card->tx_chain.head = card->tx_chain.head->next; spin_unlock_irqrestore(&chain->lock, flags); @@ -1467,6 +1504,10 @@ spider_net_interrupt(int irq, void *ptr) spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } + if (status_reg & SPIDER_NET_TXINT ) { + spider_net_cleanup_tx_ring(card); + netif_wake_queue(netdev); + } if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1629,6 +1670,8 @@ spider_net_open(struct net_device *netdev) PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; + card->low_watermark = NULL; + /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, card->descr + card->tx_desc, diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 6c9d7ce7f73..1f5c9dc806a 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -49,7 +49,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_TX_DESCRIPTORS_MIN 16 #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 -#define SPIDER_NET_TX_TIMER 20 +#define SPIDER_NET_TX_TIMER (HZ/5) #define SPIDER_NET_RX_CSUM_DEFAULT 1 @@ -328,9 +328,7 @@ enum spider_net_int2_status { SPIDER_NET_GRISPDNGINT }; -#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \ - (1 << SPIDER_NET_GDTDCEINT) | \ - (1 << SPIDER_NET_GDTFDCINT) ) +#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GDTFDCINT) ) /* We rely on flagged descriptor interrupts */ #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) @@ -356,6 +354,7 @@ enum spider_net_int2_status { #define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000 +#define SPIDER_NET_DESCR_TXDESFLG 0x00800000 struct spider_net_descr { /* as defined by the hardware */ @@ -440,6 +439,7 @@ struct spider_net_card { struct spider_net_descr_chain tx_chain; struct spider_net_descr_chain rx_chain; + struct spider_net_descr *low_watermark; struct net_device_stats netdev_stats; |