697f4a19e5
When enabling multiple VIFS, the driver sometimes crashes. The frequency of the crash increases as more VIFS are enabled. Signed-off-by: Nathan Hintz <nlhintz@hotmail.com> SVN-Revision: 38762
133 lines
3.3 KiB
Diff
133 lines
3.3 KiB
Diff
--- a/driver/wl_linux.c
|
|
+++ b/driver/wl_linux.c
|
|
@@ -354,6 +354,7 @@ static int wl_read_proc(char *buffer, ch
|
|
static int wl_dump(wl_info_t *wl, struct bcmstrbuf *b);
|
|
#endif /* BCMDBG */
|
|
struct wl_if *wl_alloc_if(wl_info_t *wl, int iftype, uint unit, struct wlc_if* wlc_if);
|
|
+static void wl_link_if(wl_info_t *wl, wl_if_t *wlif);
|
|
static void wl_free_if(wl_info_t *wl, wl_if_t *wlif);
|
|
|
|
|
|
@@ -566,6 +567,9 @@ wl_attach(uint16 vendor, uint16 device,
|
|
wl->dev = dev;
|
|
wl_if_setup(dev);
|
|
|
|
+ /* add the interface to the interface linked list */
|
|
+ wl_link_if(wl, wlif);
|
|
+
|
|
/* map chip registers (47xx: and sprom) */
|
|
dev->base_addr = regs;
|
|
|
|
@@ -1106,10 +1110,14 @@ wl_free(wl_info_t *wl)
|
|
free_irq(wl->dev->irq, wl);
|
|
}
|
|
|
|
- if (wl->dev) {
|
|
- wl_free_if(wl, WL_DEV_IF(wl->dev));
|
|
- wl->dev = NULL;
|
|
+ /* free all interfaces */
|
|
+ while (wl->if_list) {
|
|
+ if ((wl->if_list->dev != wl->dev) || wl->if_list->next == NULL)
|
|
+ wl_free_if(wl, wl->if_list);
|
|
+ else
|
|
+ wl_free_if(wl, wl->if_list->next);
|
|
}
|
|
+ wl->dev = NULL;
|
|
|
|
#ifdef TOE
|
|
wl_toe_detach(wl->toei);
|
|
@@ -1355,10 +1363,12 @@ wl_txflowcontrol(wl_info_t *wl, bool sta
|
|
|
|
ASSERT(prio == ALLPRIO);
|
|
for (wlif = wl->if_list; wlif != NULL; wlif = wlif->next) {
|
|
- if (state == ON)
|
|
- netif_stop_queue(wlif->dev);
|
|
- else
|
|
- netif_wake_queue(wlif->dev);
|
|
+ if (wlif->dev_registed) {
|
|
+ if (state == ON)
|
|
+ netif_stop_queue(wlif->dev);
|
|
+ else
|
|
+ netif_wake_queue(wlif->dev);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -1398,7 +1408,6 @@ wl_alloc_if(wl_info_t *wl, int iftype, u
|
|
{
|
|
struct net_device *dev;
|
|
wl_if_t *wlif;
|
|
- wl_if_t *p;
|
|
|
|
dev = alloc_etherdev(sizeof(wl_if_t));
|
|
wlif = netdev_priv(dev);
|
|
@@ -1411,9 +1420,13 @@ wl_alloc_if(wl_info_t *wl, int iftype, u
|
|
wlif->wlcif = wlcif;
|
|
wlif->subunit = subunit;
|
|
|
|
- /* match current flow control state */
|
|
- if (iftype != WL_IFTYPE_MON && wl->dev && netif_queue_stopped(wl->dev))
|
|
- netif_stop_queue(dev);
|
|
+ return wlif;
|
|
+}
|
|
+
|
|
+static void
|
|
+wl_link_if(wl_info_t *wl, wl_if_t *wlif)
|
|
+{
|
|
+ wl_if_t *p;
|
|
|
|
/* add the interface to the interface linked list */
|
|
if (wl->if_list == NULL)
|
|
@@ -1424,7 +1437,6 @@ wl_alloc_if(wl_info_t *wl, int iftype, u
|
|
p = p->next;
|
|
p->next = wlif;
|
|
}
|
|
- return wlif;
|
|
}
|
|
|
|
static void
|
|
@@ -1504,6 +1516,9 @@ _wl_add_if(wl_task_t *task)
|
|
wl_info_t *wl = wlif->wl;
|
|
struct net_device *dev = wlif->dev;
|
|
|
|
+ /* add the interface to the interface linked list */
|
|
+ wl_link_if(wl, wlif);
|
|
+
|
|
if (wlif->type == WL_IFTYPE_WDS)
|
|
dev->netdev_ops = &wl_wds_ops;
|
|
|
|
@@ -1516,6 +1531,14 @@ _wl_add_if(wl_task_t *task)
|
|
}
|
|
wlif->dev_registed = TRUE;
|
|
|
|
+ /* match current flow control state */
|
|
+ if (wl->dev) {
|
|
+ if (netif_queue_stopped(wl->dev))
|
|
+ netif_stop_queue(dev);
|
|
+ else
|
|
+ netif_wake_queue(dev);
|
|
+ }
|
|
+
|
|
done:
|
|
MFREE(wl->osh, task, sizeof(wl_task_t));
|
|
atomic_dec(&wl->callbacks);
|
|
@@ -1545,6 +1568,8 @@ wl_add_if(wl_info_t *wl, struct wlc_if*
|
|
return NULL;
|
|
}
|
|
|
|
+ wl_if_setup(wlif->dev);
|
|
+
|
|
sprintf(wlif->dev->name, "%s%d.%d", devname, wl->pub->unit, wlif->subunit);
|
|
if (remote)
|
|
bcopy(remote, &wlif->remote, ETHER_ADDR_LEN);
|
|
@@ -2778,6 +2803,9 @@ wl_add_monitor(wl_task_t *task)
|
|
dev = wlif->dev;
|
|
wl->monitor = dev;
|
|
|
|
+ /* add the interface to the interface linked list */
|
|
+ wl_link_if(wl, wlif);
|
|
+
|
|
/* override some fields */
|
|
sprintf(dev->name, "prism%d", wl->pub->unit);
|
|
bcopy(wl->dev->dev_addr, dev->dev_addr, ETHER_ADDR_LEN);
|