diff options
author | Arend van Spriel <arend@broadcom.com> | 2013-04-03 06:40:31 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-04-03 15:07:04 -0400 |
commit | ce814c1bb484f0efd221a05c936eb942657cebb5 (patch) | |
tree | 3999747029843fd68a48e1f94e44a10fd0676de0 /drivers | |
parent | bb8c8063f82ce3eb7b44772202ca944f92ac39f5 (diff) |
brcmfmac: handle firmware signal for updating mac descriptor info
Firmware can signal the driver to allocate descriptor info for a given
mac address, which will be used for flow control and host queueing.
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Piotr Haber <phaber@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | 120 |
3 files changed, 112 insertions, 15 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c index ac792499b46a..f0949b1e3073 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c | |||
@@ -141,11 +141,13 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data, | |||
141 | "header_pulls: %u\n" | 141 | "header_pulls: %u\n" |
142 | "header_only_pkt: %u\n" | 142 | "header_only_pkt: %u\n" |
143 | "tlv_parse_failed: %u\n" | 143 | "tlv_parse_failed: %u\n" |
144 | "tlv_invalid_type: %u\n", | 144 | "tlv_invalid_type: %u\n" |
145 | "mac_update_fails: %u\n", | ||
145 | fwstats->header_pulls, | 146 | fwstats->header_pulls, |
146 | fwstats->header_only_pkt, | 147 | fwstats->header_only_pkt, |
147 | fwstats->tlv_parse_failed, | 148 | fwstats->tlv_parse_failed, |
148 | fwstats->tlv_invalid_type); | 149 | fwstats->tlv_invalid_type, |
150 | fwstats->mac_update_failed); | ||
149 | 151 | ||
150 | return simple_read_from_buffer(data, count, ppos, buf, res); | 152 | return simple_read_from_buffer(data, count, ppos, buf, res); |
151 | } | 153 | } |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index 4bc646bde16f..371ae5b546af 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h | |||
@@ -137,6 +137,7 @@ struct brcmf_fws_stats { | |||
137 | u32 tlv_invalid_type; | 137 | u32 tlv_invalid_type; |
138 | u32 header_only_pkt; | 138 | u32 header_only_pkt; |
139 | u32 header_pulls; | 139 | u32 header_pulls; |
140 | u32 mac_update_failed; | ||
140 | }; | 141 | }; |
141 | 142 | ||
142 | struct brcmf_pub; | 143 | struct brcmf_pub; |
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 7ceaceba1845..85fd0ecd720e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c | |||
@@ -141,6 +141,7 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) | |||
141 | * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface | 141 | * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface |
142 | * | 142 | * |
143 | * @occupied: slot is in use. | 143 | * @occupied: slot is in use. |
144 | * @mac_handle: handle for mac entry determined by firmware. | ||
144 | * @interface_id: interface index. | 145 | * @interface_id: interface index. |
145 | * @state: current state. | 146 | * @state: current state. |
146 | * @ac_bitmap: ac queue bitmap. | 147 | * @ac_bitmap: ac queue bitmap. |
@@ -150,6 +151,7 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id) | |||
150 | */ | 151 | */ |
151 | struct brcmf_fws_mac_descriptor { | 152 | struct brcmf_fws_mac_descriptor { |
152 | u8 occupied; | 153 | u8 occupied; |
154 | u8 mac_handle; | ||
153 | u8 interface_id; | 155 | u8 interface_id; |
154 | u8 state; | 156 | u8 state; |
155 | u8 ac_bitmap; | 157 | u8 ac_bitmap; |
@@ -194,6 +196,7 @@ struct brcmf_fws_mac_descriptor { | |||
194 | struct brcmf_fws_info { | 196 | struct brcmf_fws_info { |
195 | struct brcmf_pub *drvr; | 197 | struct brcmf_pub *drvr; |
196 | struct brcmf_fws_stats stats; | 198 | struct brcmf_fws_stats stats; |
199 | struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE]; | ||
197 | }; | 200 | }; |
198 | 201 | ||
199 | /** | 202 | /** |
@@ -217,12 +220,107 @@ static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws, | |||
217 | } | 220 | } |
218 | #undef BRCMF_FWS_TLV_DEF | 221 | #undef BRCMF_FWS_TLV_DEF |
219 | 222 | ||
223 | static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc, | ||
224 | u8 *addr, u8 ifidx) | ||
225 | { | ||
226 | brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u\n", addr, ifidx); | ||
227 | desc->occupied = 1; | ||
228 | desc->state = BRCMF_FWS_STATE_OPEN; | ||
229 | desc->requested_credit = 0; | ||
230 | /* depending on use may need ifp->bssidx instead */ | ||
231 | desc->interface_id = ifidx; | ||
232 | desc->ac_bitmap = 0xff; /* update this when handling APSD */ | ||
233 | memcpy(&desc->ea[0], addr, ETH_ALEN); | ||
234 | } | ||
235 | |||
236 | static | ||
237 | void brcmf_fws_clear_mac_descriptor(struct brcmf_fws_mac_descriptor *desc) | ||
238 | { | ||
239 | brcmf_dbg(TRACE, | ||
240 | "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id); | ||
241 | desc->occupied = 0; | ||
242 | desc->state = BRCMF_FWS_STATE_CLOSE; | ||
243 | desc->requested_credit = 0; | ||
244 | } | ||
245 | |||
246 | static struct brcmf_fws_mac_descriptor * | ||
247 | brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea) | ||
248 | { | ||
249 | struct brcmf_fws_mac_descriptor *entry; | ||
250 | int i; | ||
251 | |||
252 | brcmf_dbg(TRACE, "enter: ea=%pM\n", ea); | ||
253 | if (ea == NULL) | ||
254 | return ERR_PTR(-EINVAL); | ||
255 | |||
256 | entry = &fws->nodes[0]; | ||
257 | for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) { | ||
258 | if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN)) | ||
259 | return entry; | ||
260 | entry++; | ||
261 | } | ||
262 | |||
263 | return ERR_PTR(-ENOENT); | ||
264 | } | ||
265 | |||
220 | static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) | 266 | static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) |
221 | { | 267 | { |
222 | brcmf_dbg(CTL, "rssi %d\n", rssi); | 268 | brcmf_dbg(CTL, "rssi %d\n", rssi); |
223 | return 0; | 269 | return 0; |
224 | } | 270 | } |
225 | 271 | ||
272 | static | ||
273 | int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data) | ||
274 | { | ||
275 | struct brcmf_fws_mac_descriptor *entry, *existing; | ||
276 | u8 mac_handle; | ||
277 | u8 ifidx; | ||
278 | u8 *addr; | ||
279 | |||
280 | mac_handle = *data++; | ||
281 | ifidx = *data++; | ||
282 | addr = data; | ||
283 | |||
284 | entry = &fws->nodes[mac_handle & 0x1F]; | ||
285 | if (type == BRCMF_FWS_TYPE_MACDESC_DEL) { | ||
286 | brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx); | ||
287 | if (entry->occupied) { | ||
288 | entry->occupied = 0; | ||
289 | entry->state = BRCMF_FWS_STATE_CLOSE; | ||
290 | entry->requested_credit = 0; | ||
291 | } else { | ||
292 | fws->stats.mac_update_failed++; | ||
293 | } | ||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | brcmf_dbg(TRACE, "add mac %pM idx %d\n", addr, ifidx); | ||
298 | existing = brcmf_fws_mac_descriptor_lookup(fws, addr); | ||
299 | if (IS_ERR(existing)) { | ||
300 | if (!entry->occupied) { | ||
301 | entry->mac_handle = mac_handle; | ||
302 | brcmf_fws_init_mac_descriptor(entry, addr, ifidx); | ||
303 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, | ||
304 | BRCMF_FWS_PSQ_LEN); | ||
305 | } else { | ||
306 | fws->stats.mac_update_failed++; | ||
307 | } | ||
308 | } else { | ||
309 | if (entry != existing) { | ||
310 | brcmf_dbg(TRACE, "relocate mac\n"); | ||
311 | memcpy(entry, existing, | ||
312 | offsetof(struct brcmf_fws_mac_descriptor, psq)); | ||
313 | entry->mac_handle = mac_handle; | ||
314 | brcmf_fws_clear_mac_descriptor(existing); | ||
315 | } else { | ||
316 | brcmf_dbg(TRACE, "use existing\n"); | ||
317 | WARN_ON(entry->mac_handle != mac_handle); | ||
318 | /* TODO: what should we do here: continue, reinit, .. */ | ||
319 | } | ||
320 | } | ||
321 | return 0; | ||
322 | } | ||
323 | |||
226 | static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) | 324 | static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) |
227 | { | 325 | { |
228 | __le32 timestamp; | 326 | __le32 timestamp; |
@@ -250,11 +348,13 @@ do { \ | |||
250 | 348 | ||
251 | int brcmf_fws_init(struct brcmf_pub *drvr) | 349 | int brcmf_fws_init(struct brcmf_pub *drvr) |
252 | { | 350 | { |
253 | u32 tlv; | 351 | u32 tlv = 0; |
254 | int rc; | 352 | int rc; |
255 | 353 | ||
256 | /* enable rssi signals */ | 354 | /* enable rssi signals */ |
257 | tlv = drvr->fw_signals ? BRCMF_FWS_FLAGS_RSSI_SIGNALS : 0; | 355 | if (drvr->fw_signals) |
356 | tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS | | ||
357 | BRCMF_FWS_FLAGS_XONXOFF_SIGNALS; | ||
258 | 358 | ||
259 | spin_lock_init(&drvr->fws_spinlock); | 359 | spin_lock_init(&drvr->fws_spinlock); |
260 | 360 | ||
@@ -361,8 +461,10 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len, | |||
361 | case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET: | 461 | case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET: |
362 | case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: | 462 | case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: |
363 | case BRCMF_FWS_TYPE_COMP_TXSTATUS: | 463 | case BRCMF_FWS_TYPE_COMP_TXSTATUS: |
464 | break; | ||
364 | case BRCMF_FWS_TYPE_MACDESC_ADD: | 465 | case BRCMF_FWS_TYPE_MACDESC_ADD: |
365 | case BRCMF_FWS_TYPE_MACDESC_DEL: | 466 | case BRCMF_FWS_TYPE_MACDESC_DEL: |
467 | brcmf_fws_macdesc_indicate(fws, type, data); | ||
366 | break; | 468 | break; |
367 | case BRCMF_FWS_TYPE_RSSI: | 469 | case BRCMF_FWS_TYPE_RSSI: |
368 | brcmf_fws_rssi_indicate(fws, *data); | 470 | brcmf_fws_rssi_indicate(fws, *data); |
@@ -404,13 +506,7 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp) | |||
404 | if (!entry) | 506 | if (!entry) |
405 | return; | 507 | return; |
406 | 508 | ||
407 | entry->occupied = 1; | 509 | brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx); |
408 | entry->state = BRCMF_FWS_STATE_OPEN; | ||
409 | entry->requested_credit = 0; | ||
410 | /* depending on use may need ifp->bssidx instead */ | ||
411 | entry->interface_id = ifp->ifidx; | ||
412 | entry->ac_bitmap = 0xff; /* update this when handling APSD */ | ||
413 | memcpy(&entry->ea[0], ifp->mac_addr, ETH_ALEN); | ||
414 | } | 510 | } |
415 | 511 | ||
416 | void brcmf_fws_add_interface(struct brcmf_if *ifp) | 512 | void brcmf_fws_add_interface(struct brcmf_if *ifp) |
@@ -425,7 +521,7 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp) | |||
425 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | 521 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); |
426 | if (entry) { | 522 | if (entry) { |
427 | ifp->fws_desc = entry; | 523 | ifp->fws_desc = entry; |
428 | brcmf_fws_reset_interface(ifp); | 524 | brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx); |
429 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, | 525 | brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, |
430 | BRCMF_FWS_PSQ_LEN); | 526 | BRCMF_FWS_PSQ_LEN); |
431 | } else { | 527 | } else { |
@@ -442,8 +538,6 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp) | |||
442 | return; | 538 | return; |
443 | 539 | ||
444 | ifp->fws_desc = NULL; | 540 | ifp->fws_desc = NULL; |
445 | entry->occupied = 0; | 541 | brcmf_fws_clear_mac_descriptor(entry); |
446 | entry->state = BRCMF_FWS_STATE_CLOSE; | ||
447 | entry->requested_credit = 0; | ||
448 | kfree(entry); | 542 | kfree(entry); |
449 | } | 543 | } |