diff options
Diffstat (limited to 'arch/um/drivers/net_kern.c')
-rw-r--r-- | arch/um/drivers/net_kern.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index fb1f9fb9b871..8ebb2241ad42 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -68,6 +68,11 @@ static int uml_net_rx(struct net_device *dev) | |||
68 | return pkt_len; | 68 | return pkt_len; |
69 | } | 69 | } |
70 | 70 | ||
71 | static void uml_dev_close(void* dev) | ||
72 | { | ||
73 | dev_close( (struct net_device *) dev); | ||
74 | } | ||
75 | |||
71 | irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 76 | irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
72 | { | 77 | { |
73 | struct net_device *dev = dev_id; | 78 | struct net_device *dev = dev_id; |
@@ -80,15 +85,21 @@ irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
80 | spin_lock(&lp->lock); | 85 | spin_lock(&lp->lock); |
81 | while((err = uml_net_rx(dev)) > 0) ; | 86 | while((err = uml_net_rx(dev)) > 0) ; |
82 | if(err < 0) { | 87 | if(err < 0) { |
88 | DECLARE_WORK(close_work, uml_dev_close, dev); | ||
83 | printk(KERN_ERR | 89 | printk(KERN_ERR |
84 | "Device '%s' read returned %d, shutting it down\n", | 90 | "Device '%s' read returned %d, shutting it down\n", |
85 | dev->name, err); | 91 | dev->name, err); |
86 | dev_close(dev); | 92 | /* dev_close can't be called in interrupt context, and takes |
93 | * again lp->lock. | ||
94 | * And dev_close() can be safely called multiple times on the | ||
95 | * same device, since it tests for (dev->flags & IFF_UP). So | ||
96 | * there's no harm in delaying the device shutdown. */ | ||
97 | schedule_work(&close_work); | ||
87 | goto out; | 98 | goto out; |
88 | } | 99 | } |
89 | reactivate_fd(lp->fd, UM_ETH_IRQ); | 100 | reactivate_fd(lp->fd, UM_ETH_IRQ); |
90 | 101 | ||
91 | out: | 102 | out: |
92 | spin_unlock(&lp->lock); | 103 | spin_unlock(&lp->lock); |
93 | return(IRQ_HANDLED); | 104 | return(IRQ_HANDLED); |
94 | } | 105 | } |
@@ -317,6 +328,11 @@ static int eth_configure(int n, void *init, char *mac, | |||
317 | return 1; | 328 | return 1; |
318 | } | 329 | } |
319 | 330 | ||
331 | lp = dev->priv; | ||
332 | /* This points to the transport private data. It's still clear, but we | ||
333 | * must memset it to 0 *now*. Let's help the drivers. */ | ||
334 | memset(lp, 0, size); | ||
335 | |||
320 | /* sysfs register */ | 336 | /* sysfs register */ |
321 | if (!driver_registered) { | 337 | if (!driver_registered) { |
322 | platform_driver_register(¨_net_driver); | 338 | platform_driver_register(¨_net_driver); |
@@ -358,7 +374,6 @@ static int eth_configure(int n, void *init, char *mac, | |||
358 | free_netdev(dev); | 374 | free_netdev(dev); |
359 | return 1; | 375 | return 1; |
360 | } | 376 | } |
361 | lp = dev->priv; | ||
362 | 377 | ||
363 | /* lp.user is the first four bytes of the transport data, which | 378 | /* lp.user is the first four bytes of the transport data, which |
364 | * has already been initialized. This structure assignment will | 379 | * has already been initialized. This structure assignment will |