aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/brcm80211/brcmsmac
diff options
context:
space:
mode:
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_ */