mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	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> SVN-Revision: 38762
This commit is contained in:
		
							parent
							
								
									b98f77f3d9
								
							
						
					
					
						commit
						697f4a19e5
					
				@ -1,6 +1,117 @@
 | 
				
			|||||||
--- a/driver/wl_linux.c
 | 
					--- a/driver/wl_linux.c
 | 
				
			||||||
+++ b/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;
 | 
					 		return NULL;
 | 
				
			||||||
 	}
 | 
					 	}
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
@ -9,3 +120,13 @@
 | 
				
			|||||||
 	sprintf(wlif->dev->name, "%s%d.%d", devname, wl->pub->unit, wlif->subunit);
 | 
					 	sprintf(wlif->dev->name, "%s%d.%d", devname, wl->pub->unit, wlif->subunit);
 | 
				
			||||||
 	if (remote)
 | 
					 	if (remote)
 | 
				
			||||||
 		bcopy(remote, &wlif->remote, ETHER_ADDR_LEN);
 | 
					 		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);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
--- a/driver/wl_linux.c
 | 
					--- a/driver/wl_linux.c
 | 
				
			||||||
+++ b/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 */
 | 
					 #endif /* DSLCPE_DELAY */
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
@ -17,7 +17,7 @@
 | 
				
			|||||||
 #define WL_DEFAULT_OPS \
 | 
					 #define WL_DEFAULT_OPS \
 | 
				
			||||||
 	.ndo_open = wl_open, \
 | 
					 	.ndo_open = wl_open, \
 | 
				
			||||||
 	.ndo_stop = wl_close, \
 | 
					 	.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_mac_address = wl_set_mac_address, \
 | 
				
			||||||
 	.ndo_set_multicast_list = wl_set_multicast_list, \
 | 
					 	.ndo_set_multicast_list = wl_set_multicast_list, \
 | 
				
			||||||
 	.ndo_do_ioctl = wl_ioctl
 | 
					 	.ndo_do_ioctl = wl_ioctl
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
--- a/driver/wl_linux.c	2012-09-26 20:51:48.099454971 -0400
 | 
					--- 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
 | 
					+++ 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)
 | 
					 	if (wl->bustype != JTAG_BUS)
 | 
				
			||||||
 #endif	/* BCMJTAG */
 | 
					 #endif	/* BCMJTAG */
 | 
				
			||||||
 	{
 | 
					 	{
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@
 | 
				
			|||||||
 static int wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 | 
					 static int wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 | 
				
			||||||
 #endif /* defined(CONFIG_PROC_FS) */
 | 
					 #endif /* defined(CONFIG_PROC_FS) */
 | 
				
			||||||
 #ifdef BCMDBG
 | 
					 #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;
 | 
					 	struct net_device *dev;
 | 
				
			||||||
 	wl_if_t *wlif;
 | 
					 	wl_if_t *wlif;
 | 
				
			||||||
 	wl_info_t *wl;
 | 
					 	wl_info_t *wl;
 | 
				
			||||||
@ -18,7 +18,7 @@
 | 
				
			|||||||
 	char tmp[128];
 | 
					 	char tmp[128];
 | 
				
			||||||
 #endif
 | 
					 #endif
 | 
				
			||||||
 	osl_t *osh;
 | 
					 	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));
 | 
					 			WL_ERROR(("wl%d: Error setting MPC variable to 0\n", unit));
 | 
				
			||||||
 		}
 | 
					 		}
 | 
				
			||||||
 	}
 | 
					 	}
 | 
				
			||||||
@ -27,7 +27,7 @@
 | 
				
			|||||||
 	/* create /proc/net/wl<unit> */
 | 
					 	/* create /proc/net/wl<unit> */
 | 
				
			||||||
 	sprintf(tmp, "net/wl%d", wl->pub->unit);
 | 
					 	sprintf(tmp, "net/wl%d", wl->pub->unit);
 | 
				
			||||||
 	create_proc_read_entry(tmp, 0, 0, wl_read_proc, (void*)wl);
 | 
					 	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 */
 | 
					 #endif /* BCMDBUS */
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
@ -36,7 +36,7 @@
 | 
				
			|||||||
 static int
 | 
					 static int
 | 
				
			||||||
 wl_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
 | 
					 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 */
 | 
					 	/* free common resources */
 | 
				
			||||||
 	if (wl->wlc) {
 | 
					 	if (wl->wlc) {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
--- a/driver/wl_linux.c
 | 
					--- a/driver/wl_linux.c
 | 
				
			||||||
+++ b/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);
 | 
					 	wl_if_setup(wlif->dev);
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
--- a/driver/wl_linux.c
 | 
					--- a/driver/wl_linux.c
 | 
				
			||||||
+++ b/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));
 | 
					 	dev = alloc_etherdev(sizeof(wl_if_t));
 | 
				
			||||||
 	wlif = netdev_priv(dev);
 | 
					 	wlif = netdev_priv(dev);
 | 
				
			||||||
 	bzero(wlif, sizeof(wl_if_t));
 | 
					 	bzero(wlif, sizeof(wl_if_t));
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user