aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/broadcom-wl/patches/008-fix_virtual_interfaces.patch
blob: 23831df5ba6a9c5b8f4c4df07816b6bc2a297dcd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
--- a/driver/wl_linux.c
+++ b/driver/wl_linux.c
@@ -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;
 	}
 
+	wl_if_setup(wlif->dev);
+
 	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);