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