aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHante Meuleman <meuleman@broadcom.com>2014-07-30 07:20:06 -0400
committerJohn W. Linville <linville@tuxdriver.com>2014-07-31 13:45:28 -0400
commit17ca5c718414d605f0060336e071fb77359be790 (patch)
tree0a8d5b85e55c907516dd902aa0722bd92ce50f2d
parentbd4f82e3b2899829c7f87dde0d20daeb780ad014 (diff)
brcmfmac: Fix msgbuf flow control.
Msgbuf flow control was using a function to flow off and on which was not supported without proptx enabled. Also flow control needs to be handled per ifidx. Reviewed-by: Arend Van Spriel <arend@broadcom.com> Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com> Signed-off-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.c61
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.h3
3 files changed, 62 insertions, 8 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
index 1825f736fd45..5e4317dbc2b0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h
@@ -121,12 +121,12 @@ struct brcmf_fws_mac_descriptor;
121 * 121 *
122 * @BRCMF_NETIF_STOP_REASON_FWS_FC: 122 * @BRCMF_NETIF_STOP_REASON_FWS_FC:
123 * netif stopped due to firmware signalling flow control. 123 * netif stopped due to firmware signalling flow control.
124 * @BRCMF_NETIF_STOP_REASON_BLOCK_BUS: 124 * @BRCMF_NETIF_STOP_REASON_FLOW:
125 * netif stopped due to bus blocking. 125 * netif stopped due to flowring full.
126 */ 126 */
127enum brcmf_netif_stop_reason { 127enum brcmf_netif_stop_reason {
128 BRCMF_NETIF_STOP_REASON_FWS_FC = 1, 128 BRCMF_NETIF_STOP_REASON_FWS_FC = 1,
129 BRCMF_NETIF_STOP_REASON_BLOCK_BUS = 2 129 BRCMF_NETIF_STOP_REASON_FLOW = 2
130}; 130};
131 131
132/** 132/**
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
index 26cbb7c4ec4c..07009046fda5 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -158,6 +158,51 @@ u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
158} 158}
159 159
160 160
161static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
162 bool blocked)
163{
164 struct brcmf_flowring_ring *ring;
165 struct brcmf_bus *bus_if;
166 struct brcmf_pub *drvr;
167 struct brcmf_if *ifp;
168 bool currently_blocked;
169 int i;
170 u8 ifidx;
171 unsigned long flags;
172
173 spin_lock_irqsave(&flow->block_lock, flags);
174
175 ring = flow->rings[flowid];
176 ifidx = brcmf_flowring_ifidx_get(flow, flowid);
177
178 currently_blocked = false;
179 for (i = 0; i < flow->nrofrings; i++) {
180 if (flow->rings[i]) {
181 ring = flow->rings[i];
182 if ((ring->status == RING_OPEN) &&
183 (brcmf_flowring_ifidx_get(flow, i) == ifidx)) {
184 if (ring->blocked) {
185 currently_blocked = true;
186 break;
187 }
188 }
189 }
190 }
191 ring->blocked = blocked;
192 if (currently_blocked == blocked) {
193 spin_unlock_irqrestore(&flow->block_lock, flags);
194 return;
195 }
196
197 bus_if = dev_get_drvdata(flow->dev);
198 drvr = bus_if->drvr;
199 ifp = drvr->iflist[ifidx];
200 brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW, blocked);
201
202 spin_unlock_irqrestore(&flow->block_lock, flags);
203}
204
205
161void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) 206void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
162{ 207{
163 struct brcmf_flowring_ring *ring; 208 struct brcmf_flowring_ring *ring;
@@ -167,6 +212,7 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
167 ring = flow->rings[flowid]; 212 ring = flow->rings[flowid];
168 if (!ring) 213 if (!ring)
169 return; 214 return;
215 brcmf_flowring_block(flow, flowid, false);
170 hash_idx = ring->hash_id; 216 hash_idx = ring->hash_id;
171 flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX; 217 flow->hash[hash_idx].ifidx = BRCMF_FLOWRING_INVALID_IFIDX;
172 memset(flow->hash[hash_idx].mac, 0, ETH_ALEN); 218 memset(flow->hash[hash_idx].mac, 0, ETH_ALEN);
@@ -193,9 +239,16 @@ void brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
193 239
194 if (!ring->blocked && 240 if (!ring->blocked &&
195 (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) { 241 (skb_queue_len(&ring->skblist) > BRCMF_FLOWRING_HIGH)) {
196 brcmf_txflowblock(flow->dev, true); 242 brcmf_flowring_block(flow, flowid, true);
197 brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid); 243 brcmf_dbg(MSGBUF, "Flowcontrol: BLOCK for ring %d\n", flowid);
198 ring->blocked = 1; 244 /* To prevent (work around) possible race condition, check
245 * queue len again. It is also possible to use locking to
246 * protect, but that is undesirable for every enqueue and
247 * dequeue. This simple check will solve a possible race
248 * condition if it occurs.
249 */
250 if (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)
251 brcmf_flowring_block(flow, flowid, false);
199 } 252 }
200} 253}
201 254
@@ -213,9 +266,8 @@ struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
213 266
214 if (ring->blocked && 267 if (ring->blocked &&
215 (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) { 268 (skb_queue_len(&ring->skblist) < BRCMF_FLOWRING_LOW)) {
216 brcmf_txflowblock(flow->dev, false); 269 brcmf_flowring_block(flow, flowid, false);
217 brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid); 270 brcmf_dbg(MSGBUF, "Flowcontrol: OPEN for ring %d\n", flowid);
218 ring->blocked = 0;
219 } 271 }
220 272
221 return skb; 273 return skb;
@@ -283,6 +335,7 @@ struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings)
283 if (flow) { 335 if (flow) {
284 flow->dev = dev; 336 flow->dev = dev;
285 flow->nrofrings = nrofrings; 337 flow->nrofrings = nrofrings;
338 spin_lock_init(&flow->block_lock);
286 for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++) 339 for (i = 0; i < ARRAY_SIZE(flow->addr_mode); i++)
287 flow->addr_mode[i] = ADDR_INDIRECT; 340 flow->addr_mode[i] = ADDR_INDIRECT;
288 for (i = 0; i < ARRAY_SIZE(flow->hash); i++) 341 for (i = 0; i < ARRAY_SIZE(flow->hash); i++)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
index 677f4b8065f6..cb9644ca6ece 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.h
@@ -35,7 +35,7 @@ enum ring_status {
35 35
36struct brcmf_flowring_ring { 36struct brcmf_flowring_ring {
37 u8 hash_id; 37 u8 hash_id;
38 u8 blocked; 38 bool blocked;
39 enum ring_status status; 39 enum ring_status status;
40 struct sk_buff_head skblist; 40 struct sk_buff_head skblist;
41}; 41};
@@ -44,6 +44,7 @@ struct brcmf_flowring {
44 struct device *dev; 44 struct device *dev;
45 struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE]; 45 struct brcmf_flowring_hash hash[BRCMF_FLOWRING_HASHSIZE];
46 struct brcmf_flowring_ring **rings; 46 struct brcmf_flowring_ring **rings;
47 spinlock_t block_lock;
47 enum proto_addr_mode addr_mode[BRCMF_MAX_IFS]; 48 enum proto_addr_mode addr_mode[BRCMF_MAX_IFS];
48 u16 nrofrings; 49 u16 nrofrings;
49}; 50};