aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMark Brown <broonie@sirena.org.uk>2006-02-01 19:00:01 -0500
committerJeff Garzik <jeff@garzik.org>2006-03-04 12:14:56 -0500
commitb27a16b7c4738ea16f6f0730caf382a3f57317bb (patch)
treee4e881b1b0e17d3c592073d0e8aa59c0dd2d6e61 /drivers
parentfb15b9dd8b3f44290a7b3b06fdfd4be2ad73f0ac (diff)
[PATCH] natsemi: NAPI and a bugfix
This patch converts the natsemi driver to use NAPI. It was originally based on one written by Harald Welte, though it has since been modified quite a bit, most extensively in order to remove the ability to disable NAPI since none of the other drivers seem to provide that functionality any more. Signed-off-by: Mark Brown <broonie@sirena.org.uk> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/natsemi.c146
1 files changed, 97 insertions, 49 deletions
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 01920648fc38..e363f9bb35ea 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -3,6 +3,7 @@
3 Written/copyright 1999-2001 by Donald Becker. 3 Written/copyright 1999-2001 by Donald Becker.
4 Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) 4 Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com)
5 Portions copyright 2001,2002 Manfred Spraul (manfred@colorfullife.com) 5 Portions copyright 2001,2002 Manfred Spraul (manfred@colorfullife.com)
6 Portions copyright 2004 Harald Welte <laforge@gnumonks.org>
6 7
7 This software may be used and distributed according to the terms of 8 This software may be used and distributed according to the terms of
8 the GNU General Public License (GPL), incorporated herein by reference. 9 the GNU General Public License (GPL), incorporated herein by reference.
@@ -135,8 +136,6 @@
135 136
136 TODO: 137 TODO:
137 * big endian support with CFG:BEM instead of cpu_to_le32 138 * big endian support with CFG:BEM instead of cpu_to_le32
138 * support for an external PHY
139 * NAPI
140*/ 139*/
141 140
142#include <linux/config.h> 141#include <linux/config.h>
@@ -160,6 +159,7 @@
160#include <linux/mii.h> 159#include <linux/mii.h>
161#include <linux/crc32.h> 160#include <linux/crc32.h>
162#include <linux/bitops.h> 161#include <linux/bitops.h>
162#include <linux/prefetch.h>
163#include <asm/processor.h> /* Processor type for cache alignment. */ 163#include <asm/processor.h> /* Processor type for cache alignment. */
164#include <asm/io.h> 164#include <asm/io.h>
165#include <asm/irq.h> 165#include <asm/irq.h>
@@ -183,8 +183,6 @@
183 NETIF_MSG_TX_ERR) 183 NETIF_MSG_TX_ERR)
184static int debug = -1; 184static int debug = -1;
185 185
186/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
187static int max_interrupt_work = 20;
188static int mtu; 186static int mtu;
189 187
190/* Maximum number of multicast addresses to filter (vs. rx-all-multicast). 188/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
@@ -251,14 +249,11 @@ MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
251MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver"); 249MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver");
252MODULE_LICENSE("GPL"); 250MODULE_LICENSE("GPL");
253 251
254module_param(max_interrupt_work, int, 0);
255module_param(mtu, int, 0); 252module_param(mtu, int, 0);
256module_param(debug, int, 0); 253module_param(debug, int, 0);
257module_param(rx_copybreak, int, 0); 254module_param(rx_copybreak, int, 0);
258module_param_array(options, int, NULL, 0); 255module_param_array(options, int, NULL, 0);
259module_param_array(full_duplex, int, NULL, 0); 256module_param_array(full_duplex, int, NULL, 0);
260MODULE_PARM_DESC(max_interrupt_work,
261 "DP8381x maximum events handled per interrupt");
262MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); 257MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
263MODULE_PARM_DESC(debug, "DP8381x default debug level"); 258MODULE_PARM_DESC(debug, "DP8381x default debug level");
264MODULE_PARM_DESC(rx_copybreak, 259MODULE_PARM_DESC(rx_copybreak,
@@ -691,6 +686,8 @@ struct netdev_private {
691 /* Based on MTU+slack. */ 686 /* Based on MTU+slack. */
692 unsigned int rx_buf_sz; 687 unsigned int rx_buf_sz;
693 int oom; 688 int oom;
689 /* Interrupt status */
690 u32 intr_status;
694 /* Do not touch the nic registers */ 691 /* Do not touch the nic registers */
695 int hands_off; 692 int hands_off;
696 /* external phy that is used: only valid if dev->if_port != PORT_TP */ 693 /* external phy that is used: only valid if dev->if_port != PORT_TP */
@@ -748,7 +745,8 @@ static void init_registers(struct net_device *dev);
748static int start_tx(struct sk_buff *skb, struct net_device *dev); 745static int start_tx(struct sk_buff *skb, struct net_device *dev);
749static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); 746static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
750static void netdev_error(struct net_device *dev, int intr_status); 747static void netdev_error(struct net_device *dev, int intr_status);
751static void netdev_rx(struct net_device *dev); 748static int natsemi_poll(struct net_device *dev, int *budget);
749static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
752static void netdev_tx_done(struct net_device *dev); 750static void netdev_tx_done(struct net_device *dev);
753static int natsemi_change_mtu(struct net_device *dev, int new_mtu); 751static int natsemi_change_mtu(struct net_device *dev, int new_mtu);
754#ifdef CONFIG_NET_POLL_CONTROLLER 752#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -776,6 +774,18 @@ static inline void __iomem *ns_ioaddr(struct net_device *dev)
776 return (void __iomem *) dev->base_addr; 774 return (void __iomem *) dev->base_addr;
777} 775}
778 776
777static inline void natsemi_irq_enable(struct net_device *dev)
778{
779 writel(1, ns_ioaddr(dev) + IntrEnable);
780 readl(ns_ioaddr(dev) + IntrEnable);
781}
782
783static inline void natsemi_irq_disable(struct net_device *dev)
784{
785 writel(0, ns_ioaddr(dev) + IntrEnable);
786 readl(ns_ioaddr(dev) + IntrEnable);
787}
788
779static void move_int_phy(struct net_device *dev, int addr) 789static void move_int_phy(struct net_device *dev, int addr)
780{ 790{
781 struct netdev_private *np = netdev_priv(dev); 791 struct netdev_private *np = netdev_priv(dev);
@@ -879,6 +889,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
879 spin_lock_init(&np->lock); 889 spin_lock_init(&np->lock);
880 np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG; 890 np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
881 np->hands_off = 0; 891 np->hands_off = 0;
892 np->intr_status = 0;
882 893
883 /* Initial port: 894 /* Initial port:
884 * - If the nic was configured to use an external phy and if find_mii 895 * - If the nic was configured to use an external phy and if find_mii
@@ -932,6 +943,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
932 dev->do_ioctl = &netdev_ioctl; 943 dev->do_ioctl = &netdev_ioctl;
933 dev->tx_timeout = &tx_timeout; 944 dev->tx_timeout = &tx_timeout;
934 dev->watchdog_timeo = TX_TIMEOUT; 945 dev->watchdog_timeo = TX_TIMEOUT;
946 dev->poll = natsemi_poll;
947 dev->weight = 64;
948
935#ifdef CONFIG_NET_POLL_CONTROLLER 949#ifdef CONFIG_NET_POLL_CONTROLLER
936 dev->poll_controller = &natsemi_poll_controller; 950 dev->poll_controller = &natsemi_poll_controller;
937#endif 951#endif
@@ -2158,68 +2172,92 @@ static void netdev_tx_done(struct net_device *dev)
2158 } 2172 }
2159} 2173}
2160 2174
2161/* The interrupt handler does all of the Rx thread work and cleans up 2175/* The interrupt handler doesn't actually handle interrupts itself, it
2162 after the Tx thread. */ 2176 * schedules a NAPI poll if there is anything to do. */
2163static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) 2177static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
2164{ 2178{
2165 struct net_device *dev = dev_instance; 2179 struct net_device *dev = dev_instance;
2166 struct netdev_private *np = netdev_priv(dev); 2180 struct netdev_private *np = netdev_priv(dev);
2167 void __iomem * ioaddr = ns_ioaddr(dev); 2181 void __iomem * ioaddr = ns_ioaddr(dev);
2168 int boguscnt = max_interrupt_work;
2169 unsigned int handled = 0;
2170 2182
2171 if (np->hands_off) 2183 if (np->hands_off)
2172 return IRQ_NONE; 2184 return IRQ_NONE;
2173 do { 2185
2174 /* Reading automatically acknowledges all int sources. */ 2186 /* Reading automatically acknowledges. */
2175 u32 intr_status = readl(ioaddr + IntrStatus); 2187 np->intr_status = readl(ioaddr + IntrStatus);
2176 2188
2177 if (netif_msg_intr(np)) 2189 if (netif_msg_intr(np))
2178 printk(KERN_DEBUG 2190 printk(KERN_DEBUG
2179 "%s: Interrupt, status %#08x, mask %#08x.\n", 2191 "%s: Interrupt, status %#08x, mask %#08x.\n",
2180 dev->name, intr_status, 2192 dev->name, np->intr_status,
2181 readl(ioaddr + IntrMask)); 2193 readl(ioaddr + IntrMask));
2182 2194
2183 if (intr_status == 0) 2195 if (!np->intr_status)
2184 break; 2196 return IRQ_NONE;
2185 handled = 1;
2186 2197
2187 if (intr_status & 2198 prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
2188 (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | 2199
2189 IntrRxErr | IntrRxOverrun)) { 2200 if (netif_rx_schedule_prep(dev)) {
2190 netdev_rx(dev); 2201 /* Disable interrupts and register for poll */
2191 } 2202 natsemi_irq_disable(dev);
2203 __netif_rx_schedule(dev);
2204 }
2205 return IRQ_HANDLED;
2206}
2207
2208/* This is the NAPI poll routine. As well as the standard RX handling
2209 * it also handles all other interrupts that the chip might raise.
2210 */
2211static int natsemi_poll(struct net_device *dev, int *budget)
2212{
2213 struct netdev_private *np = netdev_priv(dev);
2214 void __iomem * ioaddr = ns_ioaddr(dev);
2192 2215
2193 if (intr_status & 2216 int work_to_do = min(*budget, dev->quota);
2194 (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { 2217 int work_done = 0;
2218
2219 do {
2220 if (np->intr_status &
2221 (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) {
2195 spin_lock(&np->lock); 2222 spin_lock(&np->lock);
2196 netdev_tx_done(dev); 2223 netdev_tx_done(dev);
2197 spin_unlock(&np->lock); 2224 spin_unlock(&np->lock);
2198 } 2225 }
2199 2226
2200 /* Abnormal error summary/uncommon events handlers. */ 2227 /* Abnormal error summary/uncommon events handlers. */
2201 if (intr_status & IntrAbnormalSummary) 2228 if (np->intr_status & IntrAbnormalSummary)
2202 netdev_error(dev, intr_status); 2229 netdev_error(dev, np->intr_status);
2203 2230
2204 if (--boguscnt < 0) { 2231 if (np->intr_status &
2205 if (netif_msg_intr(np)) 2232 (IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
2206 printk(KERN_WARNING 2233 IntrRxErr | IntrRxOverrun)) {
2207 "%s: Too much work at interrupt, " 2234 netdev_rx(dev, &work_done, work_to_do);
2208 "status=%#08x.\n",
2209 dev->name, intr_status);
2210 break;
2211 } 2235 }
2212 } while (1); 2236
2237 *budget -= work_done;
2238 dev->quota -= work_done;
2213 2239
2214 if (netif_msg_intr(np)) 2240 if (work_done >= work_to_do)
2215 printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); 2241 return 1;
2242
2243 np->intr_status = readl(ioaddr + IntrStatus);
2244 } while (np->intr_status);
2216 2245
2217 return IRQ_RETVAL(handled); 2246 netif_rx_complete(dev);
2247
2248 /* Reenable interrupts providing nothing is trying to shut
2249 * the chip down. */
2250 spin_lock(&np->lock);
2251 if (!np->hands_off && netif_running(dev))
2252 natsemi_irq_enable(dev);
2253 spin_unlock(&np->lock);
2254
2255 return 0;
2218} 2256}
2219 2257
2220/* This routine is logically part of the interrupt handler, but separated 2258/* This routine is logically part of the interrupt handler, but separated
2221 for clarity and better register allocation. */ 2259 for clarity and better register allocation. */
2222static void netdev_rx(struct net_device *dev) 2260static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do)
2223{ 2261{
2224 struct netdev_private *np = netdev_priv(dev); 2262 struct netdev_private *np = netdev_priv(dev);
2225 int entry = np->cur_rx % RX_RING_SIZE; 2263 int entry = np->cur_rx % RX_RING_SIZE;
@@ -2237,6 +2275,12 @@ static void netdev_rx(struct net_device *dev)
2237 entry, desc_status); 2275 entry, desc_status);
2238 if (--boguscnt < 0) 2276 if (--boguscnt < 0)
2239 break; 2277 break;
2278
2279 if (*work_done >= work_to_do)
2280 break;
2281
2282 (*work_done)++;
2283
2240 pkt_len = (desc_status & DescSizeMask) - 4; 2284 pkt_len = (desc_status & DescSizeMask) - 4;
2241 if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ 2285 if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){
2242 if (desc_status & DescMore) { 2286 if (desc_status & DescMore) {
@@ -2293,7 +2337,7 @@ static void netdev_rx(struct net_device *dev)
2293 np->rx_skbuff[entry] = NULL; 2337 np->rx_skbuff[entry] = NULL;
2294 } 2338 }
2295 skb->protocol = eth_type_trans(skb, dev); 2339 skb->protocol = eth_type_trans(skb, dev);
2296 netif_rx(skb); 2340 netif_receive_skb(skb);
2297 dev->last_rx = jiffies; 2341 dev->last_rx = jiffies;
2298 np->stats.rx_packets++; 2342 np->stats.rx_packets++;
2299 np->stats.rx_bytes += pkt_len; 2343 np->stats.rx_bytes += pkt_len;
@@ -3074,9 +3118,7 @@ static int netdev_close(struct net_device *dev)
3074 del_timer_sync(&np->timer); 3118 del_timer_sync(&np->timer);
3075 disable_irq(dev->irq); 3119 disable_irq(dev->irq);
3076 spin_lock_irq(&np->lock); 3120 spin_lock_irq(&np->lock);
3077 /* Disable interrupts, and flush posted writes */ 3121 natsemi_irq_disable(dev);
3078 writel(0, ioaddr + IntrEnable);
3079 readl(ioaddr + IntrEnable);
3080 np->hands_off = 1; 3122 np->hands_off = 1;
3081 spin_unlock_irq(&np->lock); 3123 spin_unlock_irq(&np->lock);
3082 enable_irq(dev->irq); 3124 enable_irq(dev->irq);
@@ -3158,6 +3200,9 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev)
3158 * * netdev_timer: timer stopped by natsemi_suspend. 3200 * * netdev_timer: timer stopped by natsemi_suspend.
3159 * * intr_handler: doesn't acquire the spinlock. suspend calls 3201 * * intr_handler: doesn't acquire the spinlock. suspend calls
3160 * disable_irq() to enforce synchronization. 3202 * disable_irq() to enforce synchronization.
3203 * * natsemi_poll: checks before reenabling interrupts. suspend
3204 * sets hands_off, disables interrupts and then waits with
3205 * netif_poll_disable().
3161 * 3206 *
3162 * Interrupts must be disabled, otherwise hands_off can cause irq storms. 3207 * Interrupts must be disabled, otherwise hands_off can cause irq storms.
3163 */ 3208 */
@@ -3183,6 +3228,8 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state)
3183 spin_unlock_irq(&np->lock); 3228 spin_unlock_irq(&np->lock);
3184 enable_irq(dev->irq); 3229 enable_irq(dev->irq);
3185 3230
3231 netif_poll_disable(dev);
3232
3186 /* Update the error counts. */ 3233 /* Update the error counts. */
3187 __get_stats(dev); 3234 __get_stats(dev);
3188 3235
@@ -3235,6 +3282,7 @@ static int natsemi_resume (struct pci_dev *pdev)
3235 mod_timer(&np->timer, jiffies + 1*HZ); 3282 mod_timer(&np->timer, jiffies + 1*HZ);
3236 } 3283 }
3237 netif_device_attach(dev); 3284 netif_device_attach(dev);
3285 netif_poll_enable(dev);
3238out: 3286out:
3239 rtnl_unlock(); 3287 rtnl_unlock();
3240 return 0; 3288 return 0;