diff options
author | Mark Brown <broonie@sirena.org.uk> | 2006-02-01 19:00:01 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-03-04 12:14:56 -0500 |
commit | b27a16b7c4738ea16f6f0730caf382a3f57317bb (patch) | |
tree | e4e881b1b0e17d3c592073d0e8aa59c0dd2d6e61 /drivers | |
parent | fb15b9dd8b3f44290a7b3b06fdfd4be2ad73f0ac (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.c | 146 |
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) |
184 | static int debug = -1; | 184 | static int debug = -1; |
185 | 185 | ||
186 | /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ | ||
187 | static int max_interrupt_work = 20; | ||
188 | static int mtu; | 186 | static 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>"); | |||
251 | MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver"); | 249 | MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver"); |
252 | MODULE_LICENSE("GPL"); | 250 | MODULE_LICENSE("GPL"); |
253 | 251 | ||
254 | module_param(max_interrupt_work, int, 0); | ||
255 | module_param(mtu, int, 0); | 252 | module_param(mtu, int, 0); |
256 | module_param(debug, int, 0); | 253 | module_param(debug, int, 0); |
257 | module_param(rx_copybreak, int, 0); | 254 | module_param(rx_copybreak, int, 0); |
258 | module_param_array(options, int, NULL, 0); | 255 | module_param_array(options, int, NULL, 0); |
259 | module_param_array(full_duplex, int, NULL, 0); | 256 | module_param_array(full_duplex, int, NULL, 0); |
260 | MODULE_PARM_DESC(max_interrupt_work, | ||
261 | "DP8381x maximum events handled per interrupt"); | ||
262 | MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); | 257 | MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); |
263 | MODULE_PARM_DESC(debug, "DP8381x default debug level"); | 258 | MODULE_PARM_DESC(debug, "DP8381x default debug level"); |
264 | MODULE_PARM_DESC(rx_copybreak, | 259 | MODULE_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); | |||
748 | static int start_tx(struct sk_buff *skb, struct net_device *dev); | 745 | static int start_tx(struct sk_buff *skb, struct net_device *dev); |
749 | static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); | 746 | static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); |
750 | static void netdev_error(struct net_device *dev, int intr_status); | 747 | static void netdev_error(struct net_device *dev, int intr_status); |
751 | static void netdev_rx(struct net_device *dev); | 748 | static int natsemi_poll(struct net_device *dev, int *budget); |
749 | static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do); | ||
752 | static void netdev_tx_done(struct net_device *dev); | 750 | static void netdev_tx_done(struct net_device *dev); |
753 | static int natsemi_change_mtu(struct net_device *dev, int new_mtu); | 751 | static 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 | ||
777 | static 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 | |||
783 | static 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 | |||
779 | static void move_int_phy(struct net_device *dev, int addr) | 789 | static 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. */ |
2163 | static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) | 2177 | static 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 | */ | ||
2211 | static 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. */ |
2222 | static void netdev_rx(struct net_device *dev) | 2260 | static 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); | ||
3238 | out: | 3286 | out: |
3239 | rtnl_unlock(); | 3287 | rtnl_unlock(); |
3240 | return 0; | 3288 | return 0; |