From: Hauke Mehrtens Date: Mon, 11 Nov 2013 22:04:26 +0000 (+0000) Subject: broadcom-wl: fix crash when starting multiple virtual interfaces X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=697f4a19e52cea8fbd17c8b764a352aab28ba9e1;p=openwrt%2Fstaging%2Fstintel.git 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 SVN-Revision: 38762 --- 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); diff --git a/package/kernel/broadcom-wl/patches/009-fix_compile_3_2.patch b/package/kernel/broadcom-wl/patches/009-fix_compile_3_2.patch index 628f2fdf25..cb388a1125 100644 --- a/package/kernel/broadcom-wl/patches/009-fix_compile_3_2.patch +++ b/package/kernel/broadcom-wl/patches/009-fix_compile_3_2.patch @@ -1,6 +1,6 @@ --- a/driver/wl_linux.c +++ b/driver/wl_linux.c -@@ -462,6 +462,16 @@ wl_schedule_fn(wl_info_t *wl, void (*fn) +@@ -463,6 +463,16 @@ wl_schedule_fn(wl_info_t *wl, void (*fn) } #endif /* DSLCPE_DELAY */ @@ -17,7 +17,7 @@ #define WL_DEFAULT_OPS \ .ndo_open = wl_open, \ .ndo_stop = wl_close, \ -@@ -470,6 +480,7 @@ wl_schedule_fn(wl_info_t *wl, void (*fn) +@@ -471,6 +481,7 @@ wl_schedule_fn(wl_info_t *wl, void (*fn) .ndo_set_mac_address = wl_set_mac_address, \ .ndo_set_multicast_list = wl_set_multicast_list, \ .ndo_do_ioctl = wl_ioctl diff --git a/package/kernel/broadcom-wl/patches/010-remove_irqf_samble_random.patch b/package/kernel/broadcom-wl/patches/010-remove_irqf_samble_random.patch index 27b132d115..4bbbdcaaaa 100644 --- a/package/kernel/broadcom-wl/patches/010-remove_irqf_samble_random.patch +++ b/package/kernel/broadcom-wl/patches/010-remove_irqf_samble_random.patch @@ -1,6 +1,6 @@ --- a/driver/wl_linux.c 2012-09-26 20:51:48.099454971 -0400 +++ b/driver/wl_linux.c 2012-09-26 20:53:24.115453441 -0400 -@@ -691,7 +691,7 @@ +@@ -695,7 +695,7 @@ if (wl->bustype != JTAG_BUS) #endif /* BCMJTAG */ { diff --git a/package/kernel/broadcom-wl/patches/012-compat-3.10.patch b/package/kernel/broadcom-wl/patches/012-compat-3.10.patch index 1ab853967a..e36028a634 100644 --- a/package/kernel/broadcom-wl/patches/012-compat-3.10.patch +++ b/package/kernel/broadcom-wl/patches/012-compat-3.10.patch @@ -9,7 +9,7 @@ static int wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data); #endif /* defined(CONFIG_PROC_FS) */ #ifdef BCMDBG -@@ -516,7 +516,7 @@ wl_attach(uint16 vendor, uint16 device, +@@ -517,7 +517,7 @@ wl_attach(uint16 vendor, uint16 device, struct net_device *dev; wl_if_t *wlif; wl_info_t *wl; @@ -18,7 +18,7 @@ char tmp[128]; #endif osl_t *osh; -@@ -660,7 +660,7 @@ wl_attach(uint16 vendor, uint16 device, +@@ -664,7 +664,7 @@ wl_attach(uint16 vendor, uint16 device, WL_ERROR(("wl%d: Error setting MPC variable to 0\n", unit)); } } @@ -27,7 +27,7 @@ /* create /proc/net/wl */ sprintf(tmp, "net/wl%d", wl->pub->unit); create_proc_read_entry(tmp, 0, 0, wl_read_proc, (void*)wl); -@@ -806,7 +806,7 @@ wl_dbus_disconnect_cb(void *arg) +@@ -810,7 +810,7 @@ wl_dbus_disconnect_cb(void *arg) } #endif /* BCMDBUS */ @@ -36,7 +36,7 @@ static int wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { -@@ -1141,7 +1141,7 @@ wl_free(wl_info_t *wl) +@@ -1149,7 +1149,7 @@ wl_free(wl_info_t *wl) /* free common resources */ if (wl->wlc) { diff --git a/package/kernel/broadcom-wl/patches/013-interface-name.patch b/package/kernel/broadcom-wl/patches/013-interface-name.patch index a19e3a9882..dbe1bdb89a 100644 --- a/package/kernel/broadcom-wl/patches/013-interface-name.patch +++ b/package/kernel/broadcom-wl/patches/013-interface-name.patch @@ -1,6 +1,6 @@ --- a/driver/wl_linux.c +++ b/driver/wl_linux.c -@@ -1560,7 +1560,7 @@ wl_add_if(wl_info_t *wl, struct wlc_if* +@@ -1583,7 +1583,7 @@ wl_add_if(wl_info_t *wl, struct wlc_if* wl_if_setup(wlif->dev); diff --git a/package/kernel/broadcom-wl/patches/110-add_number_to_dev_name.patch b/package/kernel/broadcom-wl/patches/110-add_number_to_dev_name.patch index 28917d912a..95f0beb73c 100644 --- a/package/kernel/broadcom-wl/patches/110-add_number_to_dev_name.patch +++ b/package/kernel/broadcom-wl/patches/110-add_number_to_dev_name.patch @@ -1,6 +1,6 @@ --- a/driver/wl_linux.c +++ b/driver/wl_linux.c -@@ -1416,7 +1416,7 @@ wl_alloc_if(wl_info_t *wl, int iftype, u +@@ -1425,7 +1425,7 @@ wl_alloc_if(wl_info_t *wl, int iftype, u dev = alloc_etherdev(sizeof(wl_if_t)); wlif = netdev_priv(dev); bzero(wlif, sizeof(wl_if_t));