diff options
Diffstat (limited to 'drivers/net/wireless/brcm80211/brcmsmac')
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 13 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/main.c | 141 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/main.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/brcm80211/brcmsmac/pub.h | 4 |
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 | ||
4093 | static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) | 4100 | static 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 | ||
7385 | static 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 | |||
7435 | static 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 | |||
7505 | void 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, | |||
630 | extern void brcms_c_inval_dma_pkts(struct brcms_hardware *hw, | 636 | extern 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)); |
633 | extern void brcms_c_update_beacon(struct brcms_c_info *wlc); | ||
634 | extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); | 639 | extern void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend); |
635 | extern int brcms_c_set_nmode(struct brcms_c_info *wlc); | 640 | extern int brcms_c_set_nmode(struct brcms_c_info *wlc); |
636 | extern void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc, | 641 | extern 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); | |||
332 | extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); | 332 | extern void brcms_c_mute(struct brcms_c_info *wlc, bool on); |
333 | extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); | 333 | extern bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc); |
334 | extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr); | 334 | extern void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr); |
335 | extern void brcms_c_update_beacon(struct brcms_c_info *wlc); | ||
336 | extern 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_ */ |