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:
		| @@ -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)); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Hauke Mehrtens
					Hauke Mehrtens