diff options
Diffstat (limited to 'drivers/net/natsemi.c')
-rw-r--r-- | drivers/net/natsemi.c | 192 |
1 files changed, 141 insertions, 51 deletions
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 9d6d2548c2d3..8d4999837b65 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,13 +183,11 @@ | |||
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). |
191 | This chip uses a 512 element hash table based on the Ethernet CRC. */ | 189 | This chip uses a 512 element hash table based on the Ethernet CRC. */ |
192 | static int multicast_filter_limit = 100; | 190 | static const int multicast_filter_limit = 100; |
193 | 191 | ||
194 | /* Set the copy breakpoint for the copy-only-tiny-frames scheme. | 192 | /* Set the copy breakpoint for the copy-only-tiny-frames scheme. |
195 | Setting to > 1518 effectively disables this feature. */ | 193 | Setting to > 1518 effectively disables this feature. */ |
@@ -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, |
@@ -374,7 +369,7 @@ enum pcistuff { | |||
374 | 369 | ||
375 | 370 | ||
376 | /* array of board data directly indexed by pci_tbl[x].driver_data */ | 371 | /* array of board data directly indexed by pci_tbl[x].driver_data */ |
377 | static struct { | 372 | static const struct { |
378 | const char *name; | 373 | const char *name; |
379 | unsigned long flags; | 374 | unsigned long flags; |
380 | } natsemi_pci_info[] __devinitdata = { | 375 | } natsemi_pci_info[] __devinitdata = { |
@@ -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 |
@@ -1484,6 +1498,31 @@ static void natsemi_reset(struct net_device *dev) | |||
1484 | writel(rfcr, ioaddr + RxFilterAddr); | 1498 | writel(rfcr, ioaddr + RxFilterAddr); |
1485 | } | 1499 | } |
1486 | 1500 | ||
1501 | static void reset_rx(struct net_device *dev) | ||
1502 | { | ||
1503 | int i; | ||
1504 | struct netdev_private *np = netdev_priv(dev); | ||
1505 | void __iomem *ioaddr = ns_ioaddr(dev); | ||
1506 | |||
1507 | np->intr_status &= ~RxResetDone; | ||
1508 | |||
1509 | writel(RxReset, ioaddr + ChipCmd); | ||
1510 | |||
1511 | for (i=0;i<NATSEMI_HW_TIMEOUT;i++) { | ||
1512 | np->intr_status |= readl(ioaddr + IntrStatus); | ||
1513 | if (np->intr_status & RxResetDone) | ||
1514 | break; | ||
1515 | udelay(15); | ||
1516 | } | ||
1517 | if (i==NATSEMI_HW_TIMEOUT) { | ||
1518 | printk(KERN_WARNING "%s: RX reset did not complete in %d usec.\n", | ||
1519 | dev->name, i*15); | ||
1520 | } else if (netif_msg_hw(np)) { | ||
1521 | printk(KERN_WARNING "%s: RX reset took %d usec.\n", | ||
1522 | dev->name, i*15); | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1487 | static void natsemi_reload_eeprom(struct net_device *dev) | 1526 | static void natsemi_reload_eeprom(struct net_device *dev) |
1488 | { | 1527 | { |
1489 | struct netdev_private *np = netdev_priv(dev); | 1528 | struct netdev_private *np = netdev_priv(dev); |
@@ -2158,68 +2197,92 @@ static void netdev_tx_done(struct net_device *dev) | |||
2158 | } | 2197 | } |
2159 | } | 2198 | } |
2160 | 2199 | ||
2161 | /* The interrupt handler does all of the Rx thread work and cleans up | 2200 | /* The interrupt handler doesn't actually handle interrupts itself, it |
2162 | after the Tx thread. */ | 2201 | * 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) | 2202 | static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) |
2164 | { | 2203 | { |
2165 | struct net_device *dev = dev_instance; | 2204 | struct net_device *dev = dev_instance; |
2166 | struct netdev_private *np = netdev_priv(dev); | 2205 | struct netdev_private *np = netdev_priv(dev); |
2167 | void __iomem * ioaddr = ns_ioaddr(dev); | 2206 | void __iomem * ioaddr = ns_ioaddr(dev); |
2168 | int boguscnt = max_interrupt_work; | ||
2169 | unsigned int handled = 0; | ||
2170 | 2207 | ||
2171 | if (np->hands_off) | 2208 | if (np->hands_off) |
2172 | return IRQ_NONE; | 2209 | return IRQ_NONE; |
2173 | do { | 2210 | |
2174 | /* Reading automatically acknowledges all int sources. */ | 2211 | /* Reading automatically acknowledges. */ |
2175 | u32 intr_status = readl(ioaddr + IntrStatus); | 2212 | np->intr_status = readl(ioaddr + IntrStatus); |
2176 | 2213 | ||
2177 | if (netif_msg_intr(np)) | 2214 | if (netif_msg_intr(np)) |
2178 | printk(KERN_DEBUG | 2215 | printk(KERN_DEBUG |
2179 | "%s: Interrupt, status %#08x, mask %#08x.\n", | 2216 | "%s: Interrupt, status %#08x, mask %#08x.\n", |
2180 | dev->name, intr_status, | 2217 | dev->name, np->intr_status, |
2181 | readl(ioaddr + IntrMask)); | 2218 | readl(ioaddr + IntrMask)); |
2182 | 2219 | ||
2183 | if (intr_status == 0) | 2220 | if (!np->intr_status) |
2184 | break; | 2221 | return IRQ_NONE; |
2185 | handled = 1; | ||
2186 | 2222 | ||
2187 | if (intr_status & | 2223 | prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); |
2188 | (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | | ||
2189 | IntrRxErr | IntrRxOverrun)) { | ||
2190 | netdev_rx(dev); | ||
2191 | } | ||
2192 | 2224 | ||
2193 | if (intr_status & | 2225 | if (netif_rx_schedule_prep(dev)) { |
2194 | (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { | 2226 | /* Disable interrupts and register for poll */ |
2227 | natsemi_irq_disable(dev); | ||
2228 | __netif_rx_schedule(dev); | ||
2229 | } | ||
2230 | return IRQ_HANDLED; | ||
2231 | } | ||
2232 | |||
2233 | /* This is the NAPI poll routine. As well as the standard RX handling | ||
2234 | * it also handles all other interrupts that the chip might raise. | ||
2235 | */ | ||
2236 | static int natsemi_poll(struct net_device *dev, int *budget) | ||
2237 | { | ||
2238 | struct netdev_private *np = netdev_priv(dev); | ||
2239 | void __iomem * ioaddr = ns_ioaddr(dev); | ||
2240 | |||
2241 | int work_to_do = min(*budget, dev->quota); | ||
2242 | int work_done = 0; | ||
2243 | |||
2244 | do { | ||
2245 | if (np->intr_status & | ||
2246 | (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { | ||
2195 | spin_lock(&np->lock); | 2247 | spin_lock(&np->lock); |
2196 | netdev_tx_done(dev); | 2248 | netdev_tx_done(dev); |
2197 | spin_unlock(&np->lock); | 2249 | spin_unlock(&np->lock); |
2198 | } | 2250 | } |
2199 | 2251 | ||
2200 | /* Abnormal error summary/uncommon events handlers. */ | 2252 | /* Abnormal error summary/uncommon events handlers. */ |
2201 | if (intr_status & IntrAbnormalSummary) | 2253 | if (np->intr_status & IntrAbnormalSummary) |
2202 | netdev_error(dev, intr_status); | 2254 | netdev_error(dev, np->intr_status); |
2203 | 2255 | ||
2204 | if (--boguscnt < 0) { | 2256 | if (np->intr_status & |
2205 | if (netif_msg_intr(np)) | 2257 | (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | |
2206 | printk(KERN_WARNING | 2258 | IntrRxErr | IntrRxOverrun)) { |
2207 | "%s: Too much work at interrupt, " | 2259 | netdev_rx(dev, &work_done, work_to_do); |
2208 | "status=%#08x.\n", | ||
2209 | dev->name, intr_status); | ||
2210 | break; | ||
2211 | } | 2260 | } |
2212 | } while (1); | 2261 | |
2262 | *budget -= work_done; | ||
2263 | dev->quota -= work_done; | ||
2213 | 2264 | ||
2214 | if (netif_msg_intr(np)) | 2265 | if (work_done >= work_to_do) |
2215 | printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); | 2266 | return 1; |
2267 | |||
2268 | np->intr_status = readl(ioaddr + IntrStatus); | ||
2269 | } while (np->intr_status); | ||
2270 | |||
2271 | netif_rx_complete(dev); | ||
2216 | 2272 | ||
2217 | return IRQ_RETVAL(handled); | 2273 | /* Reenable interrupts providing nothing is trying to shut |
2274 | * the chip down. */ | ||
2275 | spin_lock(&np->lock); | ||
2276 | if (!np->hands_off && netif_running(dev)) | ||
2277 | natsemi_irq_enable(dev); | ||
2278 | spin_unlock(&np->lock); | ||
2279 | |||
2280 | return 0; | ||
2218 | } | 2281 | } |
2219 | 2282 | ||
2220 | /* This routine is logically part of the interrupt handler, but separated | 2283 | /* This routine is logically part of the interrupt handler, but separated |
2221 | for clarity and better register allocation. */ | 2284 | for clarity and better register allocation. */ |
2222 | static void netdev_rx(struct net_device *dev) | 2285 | static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) |
2223 | { | 2286 | { |
2224 | struct netdev_private *np = netdev_priv(dev); | 2287 | struct netdev_private *np = netdev_priv(dev); |
2225 | int entry = np->cur_rx % RX_RING_SIZE; | 2288 | int entry = np->cur_rx % RX_RING_SIZE; |
@@ -2237,6 +2300,12 @@ static void netdev_rx(struct net_device *dev) | |||
2237 | entry, desc_status); | 2300 | entry, desc_status); |
2238 | if (--boguscnt < 0) | 2301 | if (--boguscnt < 0) |
2239 | break; | 2302 | break; |
2303 | |||
2304 | if (*work_done >= work_to_do) | ||
2305 | break; | ||
2306 | |||
2307 | (*work_done)++; | ||
2308 | |||
2240 | pkt_len = (desc_status & DescSizeMask) - 4; | 2309 | pkt_len = (desc_status & DescSizeMask) - 4; |
2241 | if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ | 2310 | if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ |
2242 | if (desc_status & DescMore) { | 2311 | if (desc_status & DescMore) { |
@@ -2248,6 +2317,23 @@ static void netdev_rx(struct net_device *dev) | |||
2248 | "status %#08x.\n", dev->name, | 2317 | "status %#08x.\n", dev->name, |
2249 | np->cur_rx, desc_status); | 2318 | np->cur_rx, desc_status); |
2250 | np->stats.rx_length_errors++; | 2319 | np->stats.rx_length_errors++; |
2320 | |||
2321 | /* The RX state machine has probably | ||
2322 | * locked up beneath us. Follow the | ||
2323 | * reset procedure documented in | ||
2324 | * AN-1287. */ | ||
2325 | |||
2326 | spin_lock_irq(&np->lock); | ||
2327 | reset_rx(dev); | ||
2328 | reinit_rx(dev); | ||
2329 | writel(np->ring_dma, ioaddr + RxRingPtr); | ||
2330 | check_link(dev); | ||
2331 | spin_unlock_irq(&np->lock); | ||
2332 | |||
2333 | /* We'll enable RX on exit from this | ||
2334 | * function. */ | ||
2335 | break; | ||
2336 | |||
2251 | } else { | 2337 | } else { |
2252 | /* There was an error. */ | 2338 | /* There was an error. */ |
2253 | np->stats.rx_errors++; | 2339 | np->stats.rx_errors++; |
@@ -2293,7 +2379,7 @@ static void netdev_rx(struct net_device *dev) | |||
2293 | np->rx_skbuff[entry] = NULL; | 2379 | np->rx_skbuff[entry] = NULL; |
2294 | } | 2380 | } |
2295 | skb->protocol = eth_type_trans(skb, dev); | 2381 | skb->protocol = eth_type_trans(skb, dev); |
2296 | netif_rx(skb); | 2382 | netif_receive_skb(skb); |
2297 | dev->last_rx = jiffies; | 2383 | dev->last_rx = jiffies; |
2298 | np->stats.rx_packets++; | 2384 | np->stats.rx_packets++; |
2299 | np->stats.rx_bytes += pkt_len; | 2385 | np->stats.rx_bytes += pkt_len; |
@@ -3074,9 +3160,7 @@ static int netdev_close(struct net_device *dev) | |||
3074 | del_timer_sync(&np->timer); | 3160 | del_timer_sync(&np->timer); |
3075 | disable_irq(dev->irq); | 3161 | disable_irq(dev->irq); |
3076 | spin_lock_irq(&np->lock); | 3162 | spin_lock_irq(&np->lock); |
3077 | /* Disable interrupts, and flush posted writes */ | 3163 | natsemi_irq_disable(dev); |
3078 | writel(0, ioaddr + IntrEnable); | ||
3079 | readl(ioaddr + IntrEnable); | ||
3080 | np->hands_off = 1; | 3164 | np->hands_off = 1; |
3081 | spin_unlock_irq(&np->lock); | 3165 | spin_unlock_irq(&np->lock); |
3082 | enable_irq(dev->irq); | 3166 | enable_irq(dev->irq); |
@@ -3158,6 +3242,9 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) | |||
3158 | * * netdev_timer: timer stopped by natsemi_suspend. | 3242 | * * netdev_timer: timer stopped by natsemi_suspend. |
3159 | * * intr_handler: doesn't acquire the spinlock. suspend calls | 3243 | * * intr_handler: doesn't acquire the spinlock. suspend calls |
3160 | * disable_irq() to enforce synchronization. | 3244 | * disable_irq() to enforce synchronization. |
3245 | * * natsemi_poll: checks before reenabling interrupts. suspend | ||
3246 | * sets hands_off, disables interrupts and then waits with | ||
3247 | * netif_poll_disable(). | ||
3161 | * | 3248 | * |
3162 | * Interrupts must be disabled, otherwise hands_off can cause irq storms. | 3249 | * Interrupts must be disabled, otherwise hands_off can cause irq storms. |
3163 | */ | 3250 | */ |
@@ -3183,6 +3270,8 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) | |||
3183 | spin_unlock_irq(&np->lock); | 3270 | spin_unlock_irq(&np->lock); |
3184 | enable_irq(dev->irq); | 3271 | enable_irq(dev->irq); |
3185 | 3272 | ||
3273 | netif_poll_disable(dev); | ||
3274 | |||
3186 | /* Update the error counts. */ | 3275 | /* Update the error counts. */ |
3187 | __get_stats(dev); | 3276 | __get_stats(dev); |
3188 | 3277 | ||
@@ -3235,6 +3324,7 @@ static int natsemi_resume (struct pci_dev *pdev) | |||
3235 | mod_timer(&np->timer, jiffies + 1*HZ); | 3324 | mod_timer(&np->timer, jiffies + 1*HZ); |
3236 | } | 3325 | } |
3237 | netif_device_attach(dev); | 3326 | netif_device_attach(dev); |
3327 | netif_poll_enable(dev); | ||
3238 | out: | 3328 | out: |
3239 | rtnl_unlock(); | 3329 | rtnl_unlock(); |
3240 | return 0; | 3330 | return 0; |