summaryrefslogtreecommitdiff
path: root/package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch
diff options
context:
space:
mode:
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>2013-11-11 22:04:26 +0000
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>2013-11-11 22:04:26 +0000
commit16ddac3ea40a027a1c98582cc2ea631ed560a2f6 (patch)
tree14e9b755aebdaab987e0cefcc464be79be47d135 /package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch
parente2687447c5ebc6179859ca95c50150651a4411f7 (diff)
broadcom-wl: fix crash when starting multiple virtual interfaces
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> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@38762 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch')
-rw-r--r--package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch123
1 files changed, 122 insertions, 1 deletions
diff --git a/package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch b/package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch
index 360593115b..23831df5ba 100644
--- a/package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch
+++ b/package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch
@@ -1,6 +1,117 @@
--- a/driver/wl_linux.c
+++ b/driver/wl_linux.c
-@@ -1545,6 +1545,8 @@ wl_add_if(wl_info_t *wl, struct wlc_if*
+@@ -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;
}
@@ -9,3 +120,13 @@
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);