aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-03 06:40:31 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-03 15:07:04 -0400
commitce814c1bb484f0efd221a05c936eb942657cebb5 (patch)
tree3999747029843fd68a48e1f94e44a10fd0676de0 /drivers
parentbb8c8063f82ce3eb7b44772202ca944f92ac39f5 (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.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c120
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
142struct brcmf_pub; 143struct 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 */
151struct brcmf_fws_mac_descriptor { 152struct 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 {
194struct brcmf_fws_info { 196struct 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
223static 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
236static
237void 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
246static struct brcmf_fws_mac_descriptor *
247brcmf_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
220static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) 266static 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
272static
273int 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
226static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) 324static 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
251int brcmf_fws_init(struct brcmf_pub *drvr) 349int 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
416void brcmf_fws_add_interface(struct brcmf_if *ifp) 512void 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}