aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/typhoon.c
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@linux-foundation.org>2007-10-03 19:41:36 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:47:45 -0400
commitbea3348eef27e6044b6161fd04c3152215f96411 (patch)
treef0990b263e5ce42505d290a4c346fe990bcd4c33 /drivers/net/typhoon.c
parentdde4e47e8fe333a5649a3fa0e7db1fa7c08d6158 (diff)
[NET]: Make NAPI polling independent of struct net_device objects.
Several devices have multiple independant RX queues per net device, and some have a single interrupt doorbell for several queues. In either case, it's easier to support layouts like that if the structure representing the poll is independant from the net device itself. The signature of the ->poll() call back goes from: int foo_poll(struct net_device *dev, int *budget) to int foo_poll(struct napi_struct *napi, int budget) The caller is returned the number of RX packets processed (or the number of "NAPI credits" consumed if you want to get abstract). The callee no longer messes around bumping dev->quota, *budget, etc. because that is all handled in the caller upon return. The napi_struct is to be embedded in the device driver private data structures. Furthermore, it is the driver's responsibility to disable all NAPI instances in it's ->stop() device close handler. Since the napi_struct is privatized into the driver's private data structures, only the driver knows how to get at all of the napi_struct instances it may have per-device. With lots of help and suggestions from Rusty Russell, Roland Dreier, Michael Chan, Jeff Garzik, and Jamal Hadi Salim. Bug fixes from Thomas Graf, Roland Dreier, Peter Zijlstra, Joseph Fannin, Scott Wood, Hans J. Koch, and Michael Chan. [ Ported to current tree and all drivers converted. Integrated Stephen's follow-on kerneldoc additions, and restored poll_list handling to the old style to fix mutual exclusion issues. -DaveM ] Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/typhoon.c')
-rw-r--r--drivers/net/typhoon.c47
1 files changed, 19 insertions, 28 deletions
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 03587205546e..0377b8b64c78 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -284,6 +284,7 @@ struct typhoon {
284 struct basic_ring rxLoRing; 284 struct basic_ring rxLoRing;
285 struct pci_dev * pdev; 285 struct pci_dev * pdev;
286 struct net_device * dev; 286 struct net_device * dev;
287 struct napi_struct napi;
287 spinlock_t state_lock; 288 spinlock_t state_lock;
288 struct vlan_group * vlgrp; 289 struct vlan_group * vlgrp;
289 struct basic_ring rxHiRing; 290 struct basic_ring rxHiRing;
@@ -1759,12 +1760,12 @@ typhoon_fill_free_ring(struct typhoon *tp)
1759} 1760}
1760 1761
1761static int 1762static int
1762typhoon_poll(struct net_device *dev, int *total_budget) 1763typhoon_poll(struct napi_struct *napi, int budget)
1763{ 1764{
1764 struct typhoon *tp = netdev_priv(dev); 1765 struct typhoon *tp = container_of(napi, struct typhoon, napi);
1766 struct net_device *dev = tp->dev;
1765 struct typhoon_indexes *indexes = tp->indexes; 1767 struct typhoon_indexes *indexes = tp->indexes;
1766 int orig_budget = *total_budget; 1768 int work_done;
1767 int budget, work_done, done;
1768 1769
1769 rmb(); 1770 rmb();
1770 if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared) 1771 if(!tp->awaiting_resp && indexes->respReady != indexes->respCleared)
@@ -1773,30 +1774,16 @@ typhoon_poll(struct net_device *dev, int *total_budget)
1773 if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead) 1774 if(le32_to_cpu(indexes->txLoCleared) != tp->txLoRing.lastRead)
1774 typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared); 1775 typhoon_tx_complete(tp, &tp->txLoRing, &indexes->txLoCleared);
1775 1776
1776 if(orig_budget > dev->quota)
1777 orig_budget = dev->quota;
1778
1779 budget = orig_budget;
1780 work_done = 0; 1777 work_done = 0;
1781 done = 1;
1782 1778
1783 if(indexes->rxHiCleared != indexes->rxHiReady) { 1779 if(indexes->rxHiCleared != indexes->rxHiReady) {
1784 work_done = typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady, 1780 work_done += typhoon_rx(tp, &tp->rxHiRing, &indexes->rxHiReady,
1785 &indexes->rxHiCleared, budget); 1781 &indexes->rxHiCleared, budget);
1786 budget -= work_done;
1787 } 1782 }
1788 1783
1789 if(indexes->rxLoCleared != indexes->rxLoReady) { 1784 if(indexes->rxLoCleared != indexes->rxLoReady) {
1790 work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady, 1785 work_done += typhoon_rx(tp, &tp->rxLoRing, &indexes->rxLoReady,
1791 &indexes->rxLoCleared, budget); 1786 &indexes->rxLoCleared, budget - work_done);
1792 }
1793
1794 if(work_done) {
1795 *total_budget -= work_done;
1796 dev->quota -= work_done;
1797
1798 if(work_done >= orig_budget)
1799 done = 0;
1800 } 1787 }
1801 1788
1802 if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) { 1789 if(le32_to_cpu(indexes->rxBuffCleared) == tp->rxBuffRing.lastWrite) {
@@ -1804,14 +1791,14 @@ typhoon_poll(struct net_device *dev, int *total_budget)
1804 typhoon_fill_free_ring(tp); 1791 typhoon_fill_free_ring(tp);
1805 } 1792 }
1806 1793
1807 if(done) { 1794 if (work_done < budget) {
1808 netif_rx_complete(dev); 1795 netif_rx_complete(dev, napi);
1809 iowrite32(TYPHOON_INTR_NONE, 1796 iowrite32(TYPHOON_INTR_NONE,
1810 tp->ioaddr + TYPHOON_REG_INTR_MASK); 1797 tp->ioaddr + TYPHOON_REG_INTR_MASK);
1811 typhoon_post_pci_writes(tp->ioaddr); 1798 typhoon_post_pci_writes(tp->ioaddr);
1812 } 1799 }
1813 1800
1814 return (done ? 0 : 1); 1801 return work_done;
1815} 1802}
1816 1803
1817static irqreturn_t 1804static irqreturn_t
@@ -1828,10 +1815,10 @@ typhoon_interrupt(int irq, void *dev_instance)
1828 1815
1829 iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); 1816 iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS);
1830 1817
1831 if(netif_rx_schedule_prep(dev)) { 1818 if (netif_rx_schedule_prep(dev, &tp->napi)) {
1832 iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); 1819 iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK);
1833 typhoon_post_pci_writes(ioaddr); 1820 typhoon_post_pci_writes(ioaddr);
1834 __netif_rx_schedule(dev); 1821 __netif_rx_schedule(dev, &tp->napi);
1835 } else { 1822 } else {
1836 printk(KERN_ERR "%s: Error, poll already scheduled\n", 1823 printk(KERN_ERR "%s: Error, poll already scheduled\n",
1837 dev->name); 1824 dev->name);
@@ -2119,9 +2106,13 @@ typhoon_open(struct net_device *dev)
2119 if(err < 0) 2106 if(err < 0)
2120 goto out_sleep; 2107 goto out_sleep;
2121 2108
2109 napi_enable(&tp->napi);
2110
2122 err = typhoon_start_runtime(tp); 2111 err = typhoon_start_runtime(tp);
2123 if(err < 0) 2112 if(err < 0) {
2113 napi_disable(&tp->napi);
2124 goto out_irq; 2114 goto out_irq;
2115 }
2125 2116
2126 netif_start_queue(dev); 2117 netif_start_queue(dev);
2127 return 0; 2118 return 0;
@@ -2150,6 +2141,7 @@ typhoon_close(struct net_device *dev)
2150 struct typhoon *tp = netdev_priv(dev); 2141 struct typhoon *tp = netdev_priv(dev);
2151 2142
2152 netif_stop_queue(dev); 2143 netif_stop_queue(dev);
2144 napi_disable(&tp->napi);
2153 2145
2154 if(typhoon_stop_runtime(tp, WaitSleep) < 0) 2146 if(typhoon_stop_runtime(tp, WaitSleep) < 0)
2155 printk(KERN_ERR "%s: unable to stop runtime\n", dev->name); 2147 printk(KERN_ERR "%s: unable to stop runtime\n", dev->name);
@@ -2521,8 +2513,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
2521 dev->stop = typhoon_close; 2513 dev->stop = typhoon_close;
2522 dev->set_multicast_list = typhoon_set_rx_mode; 2514 dev->set_multicast_list = typhoon_set_rx_mode;
2523 dev->tx_timeout = typhoon_tx_timeout; 2515 dev->tx_timeout = typhoon_tx_timeout;
2524 dev->poll = typhoon_poll; 2516 netif_napi_add(dev, &tp->napi, typhoon_poll, 16);
2525 dev->weight = 16;
2526 dev->watchdog_timeo = TX_TIMEOUT; 2517 dev->watchdog_timeo = TX_TIMEOUT;
2527 dev->get_stats = typhoon_get_stats; 2518 dev->get_stats = typhoon_get_stats;
2528 dev->set_mac_address = typhoon_set_mac_address; 2519 dev->set_mac_address = typhoon_set_mac_address;