aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211/brcmsmac
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2013-03-23 20:45:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-03-27 13:37:35 -0400
commitaf44e258108058f30d4d4de1f7af0aff88ea3f4b (patch)
tree45bd9d6f36fceefc00bf1b3acf8d7f2570cf4c0b /drivers/net/wireless/brcm80211/brcmsmac
parentee9794ff49d60bb0f363704c4e03f7eed511ed3b (diff)
brcmsmac: add beacon template support
This makes it possible that a beacon template provided by mac80211 is written to the hardware for constant beaconing. This is based on an old version of brcmsmac, on b43 and the spec b43 is based on. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmsmac')
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c13
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.c141
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/main.h7
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/pub.h4
4 files changed, 159 insertions, 6 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index 0e4457c83e4b..e113fb6f3241 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2010 Broadcom Corporation 2 * Copyright (c) 2010 Broadcom Corporation
3 * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
3 * 4 *
4 * Permission to use, copy, modify, and/or distribute this software for any 5 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above 6 * purpose with or without fee is hereby granted, provided that the above
@@ -520,9 +521,17 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
520 brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid); 521 brcms_c_set_addrmatch(wl->wlc, RCM_BSSID_OFFSET, info->bssid);
521 spin_unlock_bh(&wl->lock); 522 spin_unlock_bh(&wl->lock);
522 } 523 }
523 if (changed & BSS_CHANGED_BEACON) 524 if (changed & BSS_CHANGED_BEACON) {
524 /* Beacon data changed, retrieve new beacon (beaconing modes) */ 525 /* Beacon data changed, retrieve new beacon (beaconing modes) */
525 brcms_err(core, "%s: beacon changed\n", __func__); 526 struct sk_buff *beacon;
527 u16 tim_offset = 0;
528
529 spin_lock_bh(&wl->lock);
530 beacon = ieee80211_beacon_get_tim(hw, vif, &tim_offset, NULL);
531 brcms_c_set_new_beacon(wl->wlc, beacon, tim_offset,
532 info->dtim_period);
533 spin_unlock_bh(&wl->lock);
534 }
526 535
527 if (changed & BSS_CHANGED_BEACON_ENABLED) { 536 if (changed & BSS_CHANGED_BEACON_ENABLED) {
528 /* Beaconing should be enabled/disabled (beaconing modes) */ 537 /* Beaconing should be enabled/disabled (beaconing modes) */
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c
index 4ffb0c6d1a0c..60dc2c4bb2f4 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (c) 2010 Broadcom Corporation 2 * Copyright (c) 2010 Broadcom Corporation
3 * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
3 * 4 *
4 * Permission to use, copy, modify, and/or distribute this software for any 5 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above 6 * purpose with or without fee is hereby granted, provided that the above
@@ -448,6 +449,8 @@ static void brcms_c_detach_mfree(struct brcms_c_info *wlc)
448 kfree(wlc->corestate); 449 kfree(wlc->corestate);
449 kfree(wlc->hw->bandstate[0]); 450 kfree(wlc->hw->bandstate[0]);
450 kfree(wlc->hw); 451 kfree(wlc->hw);
452 if (wlc->beacon)
453 dev_kfree_skb_any(wlc->beacon);
451 454
452 /* free the wlc */ 455 /* free the wlc */
453 kfree(wlc); 456 kfree(wlc);
@@ -4084,10 +4087,14 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
4084 *shm_entry++); 4087 *shm_entry++);
4085 } 4088 }
4086 4089
4087 if (suspend) { 4090 if (suspend)
4088 brcms_c_suspend_mac_and_wait(wlc); 4091 brcms_c_suspend_mac_and_wait(wlc);
4092
4093 brcms_c_update_beacon(wlc);
4094 brcms_c_update_probe_resp(wlc, false);
4095
4096 if (suspend)
4089 brcms_c_enable_mac(wlc); 4097 brcms_c_enable_mac(wlc);
4090 }
4091} 4098}
4092 4099
4093static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) 4100static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
@@ -7375,6 +7382,107 @@ int brcms_c_get_header_len(void)
7375 return TXOFF; 7382 return TXOFF;
7376} 7383}
7377 7384
7385static void brcms_c_beacon_write(struct brcms_c_info *wlc,
7386 struct sk_buff *beacon, u16 tim_offset,
7387 u16 dtim_period, bool bcn0, bool bcn1)
7388{
7389 size_t len;
7390 struct ieee80211_tx_info *tx_info;
7391 struct brcms_hardware *wlc_hw = wlc->hw;
7392 struct ieee80211_hw *ieee_hw = brcms_c_pub(wlc)->ieee_hw;
7393
7394 /* Get tx_info */
7395 tx_info = IEEE80211_SKB_CB(beacon);
7396
7397 len = min_t(size_t, beacon->len, BCN_TMPL_LEN);
7398 wlc->bcn_rspec = ieee80211_get_tx_rate(ieee_hw, tx_info)->hw_value;
7399
7400 brcms_c_compute_plcp(wlc, wlc->bcn_rspec,
7401 len + FCS_LEN - D11_PHY_HDR_LEN, beacon->data);
7402
7403 /* "Regular" and 16 MBSS but not for 4 MBSS */
7404 /* Update the phytxctl for the beacon based on the rspec */
7405 brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);
7406
7407 if (bcn0) {
7408 /* write the probe response into the template region */
7409 brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE,
7410 (len + 3) & ~3, beacon->data);
7411
7412 /* write beacon length to SCR */
7413 brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);
7414 }
7415 if (bcn1) {
7416 /* write the probe response into the template region */
7417 brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE,
7418 (len + 3) & ~3, beacon->data);
7419
7420 /* write beacon length to SCR */
7421 brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
7422 }
7423
7424 if (tim_offset != 0) {
7425 brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
7426 tim_offset + D11B_PHY_HDR_LEN);
7427 brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, dtim_period);
7428 } else {
7429 brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,
7430 len + D11B_PHY_HDR_LEN);
7431 brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, 0);
7432 }
7433}
7434
7435static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc,
7436 struct sk_buff *beacon, u16 tim_offset,
7437 u16 dtim_period)
7438{
7439 struct brcms_hardware *wlc_hw = wlc->hw;
7440 struct bcma_device *core = wlc_hw->d11core;
7441
7442 /* Hardware beaconing for this config */
7443 u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;
7444
7445 /* Check if both templates are in use, if so sched. an interrupt
7446 * that will call back into this routine
7447 */
7448 if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid)
7449 /* clear any previous status */
7450 bcma_write32(core, D11REGOFFS(macintstatus), MI_BCNTPL);
7451
7452 if (wlc->beacon_template_virgin) {
7453 wlc->beacon_template_virgin = false;
7454 brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
7455 true);
7456 /* mark beacon0 valid */
7457 bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
7458 return;
7459 }
7460
7461 /* Check that after scheduling the interrupt both of the
7462 * templates are still busy. if not clear the int. & remask
7463 */
7464 if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid) {
7465 wlc->defmacintmask |= MI_BCNTPL;
7466 return;
7467 }
7468
7469 if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN0VLD)) {
7470 brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,
7471 false);
7472 /* mark beacon0 valid */
7473 bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);
7474 return;
7475 }
7476 if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN1VLD)) {
7477 brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period,
7478 false, true);
7479 /* mark beacon0 valid */
7480 bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD);
7481 return;
7482 }
7483 return;
7484}
7485
7378/* 7486/*
7379 * Update all beacons for the system. 7487 * Update all beacons for the system.
7380 */ 7488 */
@@ -7383,9 +7491,31 @@ void brcms_c_update_beacon(struct brcms_c_info *wlc)
7383 struct brcms_bss_cfg *bsscfg = wlc->bsscfg; 7491 struct brcms_bss_cfg *bsscfg = wlc->bsscfg;
7384 7492
7385 if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP || 7493 if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||
7386 bsscfg->type == BRCMS_TYPE_ADHOC)) 7494 bsscfg->type == BRCMS_TYPE_ADHOC)) {
7387 /* Clear the soft intmask */ 7495 /* Clear the soft intmask */
7388 wlc->defmacintmask &= ~MI_BCNTPL; 7496 wlc->defmacintmask &= ~MI_BCNTPL;
7497 if (!wlc->beacon)
7498 return;
7499 brcms_c_update_beacon_hw(wlc, wlc->beacon,
7500 wlc->beacon_tim_offset,
7501 wlc->beacon_dtim_period);
7502 }
7503}
7504
7505void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon,
7506 u16 tim_offset, u16 dtim_period)
7507{
7508 if (!beacon)
7509 return;
7510 if (wlc->beacon)
7511 dev_kfree_skb_any(wlc->beacon);
7512 wlc->beacon = beacon;
7513
7514 /* add PLCP */
7515 skb_push(wlc->beacon, D11_PHY_HDR_LEN);
7516 wlc->beacon_tim_offset = tim_offset;
7517 wlc->beacon_dtim_period = dtim_period;
7518 brcms_c_update_beacon(wlc);
7389} 7519}
7390 7520
7391/* Write ssid into shared memory */ 7521/* Write ssid into shared memory */
@@ -7784,6 +7914,10 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
7784 brcms_rfkill_set_hw_state(wlc->wl); 7914 brcms_rfkill_set_hw_state(wlc->wl);
7785 } 7915 }
7786 7916
7917 /* BCN template is available */
7918 if (macintstatus & MI_BCNTPL)
7919 brcms_c_update_beacon(wlc);
7920
7787 /* it isn't done and needs to be resched if macintstatus is non-zero */ 7921 /* it isn't done and needs to be resched if macintstatus is non-zero */
7788 return wlc->macintstatus != 0; 7922 return wlc->macintstatus != 0;
7789 7923
@@ -7920,6 +8054,7 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
7920 pub->unit = unit; 8054 pub->unit = unit;
7921 pub->_piomode = piomode; 8055 pub->_piomode = piomode;
7922 wlc->bandinit_pending = false; 8056 wlc->bandinit_pending = false;
8057 wlc->beacon_template_virgin = true;
7923 8058
7924 /* populate struct brcms_c_info with default values */ 8059 /* populate struct brcms_c_info with default values */
7925 brcms_c_info_init(wlc, unit); 8060 brcms_c_info_init(wlc, unit);
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.h b/drivers/net/wireless/brcm80211/brcmsmac/main.h
index 397cff3cea57..82382da9a493 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/main.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/main.h
@@ -492,6 +492,8 @@ struct brcms_c_info {
492 bool radio_monitor; 492 bool radio_monitor;
493 bool going_down; 493 bool going_down;
494 494
495 bool beacon_template_virgin;
496
495 struct brcms_timer *wdtimer; 497 struct brcms_timer *wdtimer;
496 struct brcms_timer *radio_timer; 498 struct brcms_timer *radio_timer;
497 499
@@ -561,6 +563,10 @@ struct brcms_c_info {
561 563
562 struct wiphy *wiphy; 564 struct wiphy *wiphy;
563 struct scb pri_scb; 565 struct scb pri_scb;
566
567 struct sk_buff *beacon;
568 u16 beacon_tim_offset;
569 u16 beacon_dtim_period;
564}; 570};
565 571
566/* antsel module specific state */ 572/* antsel module specific state */
@@ -630,7 +636,6 @@ extern u16 brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,
630extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, 636extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,
631 struct ieee80211_sta *sta, 637 struct ieee80211_sta *sta,
632 void (*dma_callback_fn)); 638 void (*dma_callback_fn));
633extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
634extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); 639extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend);
635extern int brcms_c_set_nmode(struct brcms_c_info *wlc); 640extern int brcms_c_set_nmode(struct brcms_c_info *wlc);
636extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, 641extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
index 9dae59c1c13a..8a3071f8f511 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h
+++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h
@@ -332,5 +332,9 @@ extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
332extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); 332extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
333extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); 333extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc);
334extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr); 334extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr);
335extern void brcms_c_update_beacon(struct brcms_c_info *wlc);
336extern void brcms_c_set_new_beacon(struct brcms_c_info *wlc,
337 struct sk_buff *beacon, u16 tim_offset,
338 u16 dtim_period);
335 339
336#endif /* _BRCM_PUB_H_ */ 340#endif /* _BRCM_PUB_H_ */