Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmsmac/main.c
178665 views
/*1* Copyright (c) 2010 Broadcom Corporation2* Copyright (c) 2013 Hauke Mehrtens <[email protected]>3*4* Permission to use, copy, modify, and/or distribute this software for any5* purpose with or without fee is hereby granted, provided that the above6* copyright notice and this permission notice appear in all copies.7*8* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY11* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION13* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN14* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15*/1617#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt1819#include <linux/pci_ids.h>20#include <linux/if_ether.h>21#include <net/cfg80211.h>22#include <net/mac80211.h>23#include <brcm_hw_ids.h>24#include <aiutils.h>25#include <chipcommon.h>26#include "rate.h"27#include "scb.h"28#include "phy/phy_hal.h"29#include "channel.h"30#include "antsel.h"31#include "stf.h"32#include "ampdu.h"33#include "mac80211_if.h"34#include "ucode_loader.h"35#include "main.h"36#include "soc.h"37#include "dma.h"38#include "debug.h"39#include "brcms_trace_events.h"4041/* watchdog timer, in unit of ms */42#define TIMER_INTERVAL_WATCHDOG 100043/* radio monitor timer, in unit of ms */44#define TIMER_INTERVAL_RADIOCHK 8004546/* beacon interval, in unit of 1024TU */47#define BEACON_INTERVAL_DEFAULT 1004849/* n-mode support capability */50/* 2x2 includes both 1x1 & 2x2 devices51* reserved #define 2 for future when we want to separate 1x1 & 2x2 and52* control it independently53*/54#define WL_11N_2x2 155#define WL_11N_3x3 356#define WL_11N_4x4 45758#define EDCF_ACI_MASK 0x6059#define EDCF_ACI_SHIFT 560#define EDCF_ECWMIN_MASK 0x0f61#define EDCF_ECWMAX_SHIFT 462#define EDCF_AIFSN_MASK 0x0f63#define EDCF_AIFSN_MAX 1564#define EDCF_ECWMAX_MASK 0xf06566#define EDCF_AC_BE_TXOP_STA 0x000067#define EDCF_AC_BK_TXOP_STA 0x000068#define EDCF_AC_VO_ACI_STA 0x6269#define EDCF_AC_VO_ECW_STA 0x3270#define EDCF_AC_VI_ACI_STA 0x4271#define EDCF_AC_VI_ECW_STA 0x4372#define EDCF_AC_BK_ECW_STA 0xA473#define EDCF_AC_VI_TXOP_STA 0x005e74#define EDCF_AC_VO_TXOP_STA 0x002f75#define EDCF_AC_BE_ACI_STA 0x0376#define EDCF_AC_BE_ECW_STA 0xA477#define EDCF_AC_BK_ACI_STA 0x2778#define EDCF_AC_VO_TXOP_AP 0x002f7980#define EDCF_TXOP2USEC(txop) ((txop) << 5)81#define EDCF_ECW2CW(exp) ((1 << (exp)) - 1)8283#define APHY_SYMBOL_TIME 484#define APHY_PREAMBLE_TIME 1685#define APHY_SIGNAL_TIME 486#define APHY_SIFS_TIME 1687#define APHY_SERVICE_NBITS 1688#define APHY_TAIL_NBITS 689#define BPHY_SIFS_TIME 1090#define BPHY_PLCP_SHORT_TIME 969192#define PREN_PREAMBLE 2493#define PREN_MM_EXT 1294#define PREN_PREAMBLE_EXT 49596#define DOT11_MAC_HDR_LEN 2497#define DOT11_ACK_LEN 1098#define DOT11_BA_LEN 499#define DOT11_OFDM_SIGNAL_EXTENSION 6100#define DOT11_MIN_FRAG_LEN 256101#define DOT11_RTS_LEN 16102#define DOT11_CTS_LEN 10103#define DOT11_BA_BITMAP_LEN 128104#define DOT11_MAXNUMFRAGS 16105#define DOT11_MAX_FRAG_LEN 2346106107#define BPHY_PLCP_TIME 192108#define RIFS_11N_TIME 2109110/* length of the BCN template area */111#define BCN_TMPL_LEN 512112113/* brcms_bss_info flag bit values */114#define BRCMS_BSS_HT 0x0020 /* BSS is HT (MIMO) capable */115116/* chip rx buffer offset */117#define BRCMS_HWRXOFF 38118119/* rfdisable delay timer 500 ms, runs of ALP clock */120#define RFDISABLE_DEFAULT 10000000121122#define BRCMS_TEMPSENSE_PERIOD 10 /* 10 second timeout */123124/* synthpu_dly times in us */125#define SYNTHPU_DLY_APHY_US 3700126#define SYNTHPU_DLY_BPHY_US 1050127#define SYNTHPU_DLY_NPHY_US 2048128#define SYNTHPU_DLY_LPPHY_US 300129130#define ANTCNT 10 /* vanilla M_MAX_ANTCNT val */131132/* Per-AC retry limit register definitions; uses defs.h bitfield macros */133#define EDCF_SHORT_S 0134#define EDCF_SFB_S 4135#define EDCF_LONG_S 8136#define EDCF_LFB_S 12137#define EDCF_SHORT_M BITFIELD_MASK(4)138#define EDCF_SFB_M BITFIELD_MASK(4)139#define EDCF_LONG_M BITFIELD_MASK(4)140#define EDCF_LFB_M BITFIELD_MASK(4)141142#define RETRY_SHORT_DEF 7 /* Default Short retry Limit */143#define RETRY_SHORT_MAX 255 /* Maximum Short retry Limit */144#define RETRY_LONG_DEF 4 /* Default Long retry count */145#define RETRY_SHORT_FB 3 /* Short count for fb rate */146#define RETRY_LONG_FB 2 /* Long count for fb rate */147148#define APHY_CWMIN 15149#define PHY_CWMAX 1023150151#define EDCF_AIFSN_MIN 1152153#define FRAGNUM_MASK 0xF154155#define APHY_SLOT_TIME 9156#define BPHY_SLOT_TIME 20157158#define WL_SPURAVOID_OFF 0159#define WL_SPURAVOID_ON1 1160#define WL_SPURAVOID_ON2 2161162/* invalid core flags, use the saved coreflags */163#define BRCMS_USE_COREFLAGS 0xffffffff164165/* values for PLCPHdr_override */166#define BRCMS_PLCP_AUTO -1167#define BRCMS_PLCP_SHORT 0168#define BRCMS_PLCP_LONG 1169170/* values for g_protection_override and n_protection_override */171#define BRCMS_PROTECTION_AUTO -1172#define BRCMS_PROTECTION_OFF 0173#define BRCMS_PROTECTION_ON 1174#define BRCMS_PROTECTION_MMHDR_ONLY 2175#define BRCMS_PROTECTION_CTS_ONLY 3176177/* values for g_protection_control and n_protection_control */178#define BRCMS_PROTECTION_CTL_OFF 0179#define BRCMS_PROTECTION_CTL_LOCAL 1180#define BRCMS_PROTECTION_CTL_OVERLAP 2181182/* values for n_protection */183#define BRCMS_N_PROTECTION_OFF 0184#define BRCMS_N_PROTECTION_OPTIONAL 1185#define BRCMS_N_PROTECTION_20IN40 2186#define BRCMS_N_PROTECTION_MIXEDMODE 3187188/* values for band specific 40MHz capabilities */189#define BRCMS_N_BW_20ALL 0190#define BRCMS_N_BW_40ALL 1191#define BRCMS_N_BW_20IN2G_40IN5G 2192193/* bitflags for SGI support (sgi_rx iovar) */194#define BRCMS_N_SGI_20 0x01195#define BRCMS_N_SGI_40 0x02196197/* defines used by the nrate iovar */198/* MSC in use,indicates b0-6 holds an mcs */199#define NRATE_MCS_INUSE 0x00000080200/* rate/mcs value */201#define NRATE_RATE_MASK 0x0000007f202/* stf mode mask: siso, cdd, stbc, sdm */203#define NRATE_STF_MASK 0x0000ff00204/* stf mode shift */205#define NRATE_STF_SHIFT 8206/* bit indicate to override mcs only */207#define NRATE_OVERRIDE_MCS_ONLY 0x40000000208#define NRATE_SGI_MASK 0x00800000 /* sgi mode */209#define NRATE_SGI_SHIFT 23 /* sgi mode */210#define NRATE_LDPC_CODING 0x00400000 /* adv coding in use */211#define NRATE_LDPC_SHIFT 22 /* ldpc shift */212213#define NRATE_STF_SISO 0 /* stf mode SISO */214#define NRATE_STF_CDD 1 /* stf mode CDD */215#define NRATE_STF_STBC 2 /* stf mode STBC */216#define NRATE_STF_SDM 3 /* stf mode SDM */217218#define MAX_DMA_SEGS 4219220/* # of entries in Tx FIFO */221#define NTXD 64222/* Max # of entries in Rx FIFO based on 4kb page size */223#define NRXD 256224225/* Amount of headroom to leave in Tx FIFO */226#define TX_HEADROOM 4227228/* try to keep this # rbufs posted to the chip */229#define NRXBUFPOST 32230231/* max # frames to process in brcms_c_recv() */232#define RXBND 8233/* max # tx status to process in wlc_txstatus() */234#define TXSBND 8235236/*237* The following table lists the buffer memory allocated to xmt fifos in HW.238* the size is in units of 256bytes(one block), total size is HW dependent239* ucode has default fifo partition, sw can overwrite if necessary240*241* This is documented in twiki under the topic UcodeTxFifo. Please ensure242* the twiki is updated before making changes.243*/244245/* Starting corerev for the fifo size table */246#define XMTFIFOTBL_STARTREV 17247248struct d11init {249__le16 addr;250__le16 size;251__le32 value;252};253254struct edcf_acparam {255u8 ACI;256u8 ECW;257u16 TXOP;258} __packed;259260/* debug/trace */261uint brcm_msg_level;262263/* TX FIFO number to WME/802.1E Access Category */264static const u8 wme_fifo2ac[] = {265IEEE80211_AC_BK,266IEEE80211_AC_BE,267IEEE80211_AC_VI,268IEEE80211_AC_VO,269IEEE80211_AC_BE,270IEEE80211_AC_BE271};272273/* ieee80211 Access Category to TX FIFO number */274static const u8 wme_ac2fifo[] = {275TX_AC_VO_FIFO,276TX_AC_VI_FIFO,277TX_AC_BE_FIFO,278TX_AC_BK_FIFO279};280281static const u16 xmtfifo_sz[][NFIFO] = {282/* corerev 17: 5120, 49152, 49152, 5376, 4352, 1280 */283{20, 192, 192, 21, 17, 5},284/* corerev 18: */285{0, 0, 0, 0, 0, 0},286/* corerev 19: */287{0, 0, 0, 0, 0, 0},288/* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */289{20, 192, 192, 21, 17, 5},290/* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */291{9, 58, 22, 14, 14, 5},292/* corerev 22: 5120, 49152, 49152, 5376, 4352, 1280 */293{20, 192, 192, 21, 17, 5},294/* corerev 23: 5120, 49152, 49152, 5376, 4352, 1280 */295{20, 192, 192, 21, 17, 5},296/* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */297{9, 58, 22, 14, 14, 5},298/* corerev 25: */299{0, 0, 0, 0, 0, 0},300/* corerev 26: */301{0, 0, 0, 0, 0, 0},302/* corerev 27: */303{0, 0, 0, 0, 0, 0},304/* corerev 28: 2304, 14848, 5632, 3584, 3584, 1280 */305{9, 58, 22, 14, 14, 5},306};307308#ifdef DEBUG309static const char * const fifo_names[] = {310"AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };311#else312static const char fifo_names[6][1];313#endif314315#ifdef DEBUG316/* pointer to most recently allocated wl/wlc */317static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);318#endif319320/* Mapping of ieee80211 AC numbers to tx fifos */321static const u8 ac_to_fifo_mapping[IEEE80211_NUM_ACS] = {322[IEEE80211_AC_VO] = TX_AC_VO_FIFO,323[IEEE80211_AC_VI] = TX_AC_VI_FIFO,324[IEEE80211_AC_BE] = TX_AC_BE_FIFO,325[IEEE80211_AC_BK] = TX_AC_BK_FIFO,326};327328/* Mapping of tx fifos to ieee80211 AC numbers */329static const u8 fifo_to_ac_mapping[IEEE80211_NUM_ACS] = {330[TX_AC_BK_FIFO] = IEEE80211_AC_BK,331[TX_AC_BE_FIFO] = IEEE80211_AC_BE,332[TX_AC_VI_FIFO] = IEEE80211_AC_VI,333[TX_AC_VO_FIFO] = IEEE80211_AC_VO,334};335336static u8 brcms_ac_to_fifo(u8 ac)337{338if (ac >= ARRAY_SIZE(ac_to_fifo_mapping))339return TX_AC_BE_FIFO;340return ac_to_fifo_mapping[ac];341}342343static u8 brcms_fifo_to_ac(u8 fifo)344{345if (fifo >= ARRAY_SIZE(fifo_to_ac_mapping))346return IEEE80211_AC_BE;347return fifo_to_ac_mapping[fifo];348}349350/* Find basic rate for a given rate */351static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)352{353if (is_mcs_rate(rspec))354return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]355.leg_ofdm];356return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];357}358359static u16 frametype(u32 rspec, u8 mimoframe)360{361if (is_mcs_rate(rspec))362return mimoframe;363return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;364}365366/* currently the best mechanism for determining SIFS is the band in use */367static u16 get_sifs(struct brcms_band *band)368{369return band->bandtype == BRCM_BAND_5G ? APHY_SIFS_TIME :370BPHY_SIFS_TIME;371}372373/*374* Detect Card removed.375* Even checking an sbconfig register read will not false trigger when the core376* is in reset it breaks CF address mechanism. Accessing gphy phyversion will377* cause SB error if aphy is in reset on 4306B0-DB. Need a simple accessible378* reg with fixed 0/1 pattern (some platforms return all 0).379* If clocks are present, call the sb routine which will figure out if the380* device is removed.381*/382static bool brcms_deviceremoved(struct brcms_c_info *wlc)383{384u32 macctrl;385386if (!wlc->hw->clk)387return ai_deviceremoved(wlc->hw->sih);388macctrl = bcma_read32(wlc->hw->d11core,389D11REGOFFS(maccontrol));390return (macctrl & (MCTL_PSM_JMP_0 | MCTL_IHR_EN)) != MCTL_IHR_EN;391}392393/* sum the individual fifo tx pending packet counts */394static int brcms_txpktpendtot(struct brcms_c_info *wlc)395{396int i;397int pending = 0;398399for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)400if (wlc->hw->di[i])401pending += dma_txpending(wlc->hw->di[i]);402return pending;403}404405static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)406{407return wlc->pub->_nbands > 1 && !wlc->bandlocked;408}409410static int brcms_chspec_bw(u16 chanspec)411{412if (CHSPEC_IS40(chanspec))413return BRCMS_40_MHZ;414if (CHSPEC_IS20(chanspec))415return BRCMS_20_MHZ;416417return BRCMS_10_MHZ;418}419420static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)421{422if (cfg == NULL)423return;424425kfree(cfg->current_bss);426kfree(cfg);427}428429static void brcms_c_detach_mfree(struct brcms_c_info *wlc)430{431if (wlc == NULL)432return;433434brcms_c_bsscfg_mfree(wlc->bsscfg);435kfree(wlc->pub);436kfree(wlc->modulecb);437kfree(wlc->default_bss);438kfree(wlc->protection);439kfree(wlc->stf);440kfree(wlc->bandstate[0]);441if (wlc->corestate)442kfree(wlc->corestate->macstat_snapshot);443kfree(wlc->corestate);444if (wlc->hw)445kfree(wlc->hw->bandstate[0]);446kfree(wlc->hw);447if (wlc->beacon)448dev_kfree_skb_any(wlc->beacon);449if (wlc->probe_resp)450dev_kfree_skb_any(wlc->probe_resp);451452kfree(wlc);453}454455static struct brcms_bss_cfg *brcms_c_bsscfg_malloc(uint unit)456{457struct brcms_bss_cfg *cfg;458459cfg = kzalloc(sizeof(*cfg), GFP_ATOMIC);460if (cfg == NULL)461goto fail;462463cfg->current_bss = kzalloc(sizeof(*cfg->current_bss), GFP_ATOMIC);464if (cfg->current_bss == NULL)465goto fail;466467return cfg;468469fail:470brcms_c_bsscfg_mfree(cfg);471return NULL;472}473474static struct brcms_c_info *475brcms_c_attach_malloc(uint unit, uint *err, uint devid)476{477struct brcms_c_info *wlc;478479wlc = kzalloc(sizeof(*wlc), GFP_ATOMIC);480if (wlc == NULL) {481*err = 1002;482goto fail;483}484485/* allocate struct brcms_c_pub state structure */486wlc->pub = kzalloc(sizeof(*wlc->pub), GFP_ATOMIC);487if (wlc->pub == NULL) {488*err = 1003;489goto fail;490}491wlc->pub->wlc = wlc;492493/* allocate struct brcms_hardware state structure */494495wlc->hw = kzalloc(sizeof(*wlc->hw), GFP_ATOMIC);496if (wlc->hw == NULL) {497*err = 1005;498goto fail;499}500wlc->hw->wlc = wlc;501502wlc->hw->bandstate[0] =503kcalloc(MAXBANDS, sizeof(struct brcms_hw_band), GFP_ATOMIC);504if (wlc->hw->bandstate[0] == NULL) {505*err = 1006;506goto fail;507} else {508int i;509510for (i = 1; i < MAXBANDS; i++)511wlc->hw->bandstate[i] = (struct brcms_hw_band *)512((unsigned long)wlc->hw->bandstate[0] +513(sizeof(struct brcms_hw_band) * i));514}515516wlc->modulecb =517kcalloc(BRCMS_MAXMODULES, sizeof(struct modulecb),518GFP_ATOMIC);519if (wlc->modulecb == NULL) {520*err = 1009;521goto fail;522}523524wlc->default_bss = kzalloc(sizeof(*wlc->default_bss), GFP_ATOMIC);525if (wlc->default_bss == NULL) {526*err = 1010;527goto fail;528}529530wlc->bsscfg = brcms_c_bsscfg_malloc(unit);531if (wlc->bsscfg == NULL) {532*err = 1011;533goto fail;534}535536wlc->protection = kzalloc(sizeof(*wlc->protection), GFP_ATOMIC);537if (wlc->protection == NULL) {538*err = 1016;539goto fail;540}541542wlc->stf = kzalloc(sizeof(*wlc->stf), GFP_ATOMIC);543if (wlc->stf == NULL) {544*err = 1017;545goto fail;546}547548wlc->bandstate[0] =549kcalloc(MAXBANDS, sizeof(*wlc->bandstate[0]), GFP_ATOMIC);550if (wlc->bandstate[0] == NULL) {551*err = 1025;552goto fail;553} else {554int i;555556for (i = 1; i < MAXBANDS; i++)557wlc->bandstate[i] = (struct brcms_band *)558((unsigned long)wlc->bandstate[0]559+ (sizeof(struct brcms_band)*i));560}561562wlc->corestate = kzalloc(sizeof(*wlc->corestate), GFP_ATOMIC);563if (wlc->corestate == NULL) {564*err = 1026;565goto fail;566}567568wlc->corestate->macstat_snapshot =569kzalloc(sizeof(*wlc->corestate->macstat_snapshot), GFP_ATOMIC);570if (wlc->corestate->macstat_snapshot == NULL) {571*err = 1027;572goto fail;573}574575return wlc;576577fail:578brcms_c_detach_mfree(wlc);579return NULL;580}581582/*583* Update the slot timing for standard 11b/g (20us slots)584* or shortslot 11g (9us slots)585* The PSM needs to be suspended for this call.586*/587static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,588bool shortslot)589{590struct bcma_device *core = wlc_hw->d11core;591592if (shortslot) {593/* 11g short slot: 11a timing */594bcma_write16(core, D11REGOFFS(ifs_slot), 0x0207);595brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, APHY_SLOT_TIME);596} else {597/* 11g long slot: 11b timing */598bcma_write16(core, D11REGOFFS(ifs_slot), 0x0212);599brcms_b_write_shm(wlc_hw, M_DOT11_SLOT, BPHY_SLOT_TIME);600}601}602603/*604* calculate frame duration of a given rate and length, return605* time in usec unit606*/607static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,608u8 preamble_type, uint mac_len)609{610uint nsyms, dur = 0, Ndps, kNdps;611uint rate = rspec2rate(ratespec);612613if (rate == 0) {614brcms_err(wlc->hw->d11core, "wl%d: WAR: using rate of 1 mbps\n",615wlc->pub->unit);616rate = BRCM_RATE_1M;617}618619if (is_mcs_rate(ratespec)) {620uint mcs = ratespec & RSPEC_RATE_MASK;621int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);622623dur = PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);624if (preamble_type == BRCMS_MM_PREAMBLE)625dur += PREN_MM_EXT;626/* 1000Ndbps = kbps * 4 */627kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),628rspec_issgi(ratespec)) * 4;629630if (rspec_stc(ratespec) == 0)631nsyms =632CEIL((APHY_SERVICE_NBITS + 8 * mac_len +633APHY_TAIL_NBITS) * 1000, kNdps);634else635/* STBC needs to have even number of symbols */636nsyms =6372 *638CEIL((APHY_SERVICE_NBITS + 8 * mac_len +639APHY_TAIL_NBITS) * 1000, 2 * kNdps);640641dur += APHY_SYMBOL_TIME * nsyms;642if (wlc->band->bandtype == BRCM_BAND_2G)643dur += DOT11_OFDM_SIGNAL_EXTENSION;644} else if (is_ofdm_rate(rate)) {645dur = APHY_PREAMBLE_TIME;646dur += APHY_SIGNAL_TIME;647/* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */648Ndps = rate * 2;649/* NSyms = CEILING((SERVICE + 8*NBytes + TAIL) / Ndbps) */650nsyms =651CEIL((APHY_SERVICE_NBITS + 8 * mac_len + APHY_TAIL_NBITS),652Ndps);653dur += APHY_SYMBOL_TIME * nsyms;654if (wlc->band->bandtype == BRCM_BAND_2G)655dur += DOT11_OFDM_SIGNAL_EXTENSION;656} else {657/*658* calc # bits * 2 so factor of 2 in rate (1/2 mbps)659* will divide out660*/661mac_len = mac_len * 8 * 2;662/* calc ceiling of bits/rate = microseconds of air time */663dur = (mac_len + rate - 1) / rate;664if (preamble_type & BRCMS_SHORT_PREAMBLE)665dur += BPHY_PLCP_SHORT_TIME;666else667dur += BPHY_PLCP_TIME;668}669return dur;670}671672static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,673const struct d11init *inits)674{675struct bcma_device *core = wlc_hw->d11core;676int i;677uint offset;678u16 size;679u32 value;680681brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);682683for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) {684size = le16_to_cpu(inits[i].size);685offset = le16_to_cpu(inits[i].addr);686value = le32_to_cpu(inits[i].value);687if (size == 2)688bcma_write16(core, offset, value);689else if (size == 4)690bcma_write32(core, offset, value);691else692break;693}694}695696static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)697{698u8 idx;699static const u16 addr[] = {700M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,701M_HOST_FLAGS5702};703704for (idx = 0; idx < MHFMAX; idx++)705brcms_b_write_shm(wlc_hw, addr[idx], mhfs[idx]);706}707708static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)709{710struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;711712/* init microcode host flags */713brcms_c_write_mhf(wlc_hw, wlc_hw->band->mhfs);714715/* do band-specific ucode IHR, SHM, and SCR inits */716if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {717if (BRCMS_ISNPHY(wlc_hw->band))718brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);719else720brcms_err(wlc_hw->d11core,721"%s: wl%d: unsupported phy in corerev %d\n",722__func__, wlc_hw->unit,723wlc_hw->corerev);724} else {725if (D11REV_IS(wlc_hw->corerev, 24)) {726if (BRCMS_ISLCNPHY(wlc_hw->band))727brcms_c_write_inits(wlc_hw,728ucode->d11lcn0bsinitvals24);729else730brcms_err(wlc_hw->d11core,731"%s: wl%d: unsupported phy in core rev %d\n",732__func__, wlc_hw->unit,733wlc_hw->corerev);734} else {735brcms_err(wlc_hw->d11core,736"%s: wl%d: unsupported corerev %d\n",737__func__, wlc_hw->unit, wlc_hw->corerev);738}739}740}741742static void brcms_b_core_ioctl(struct brcms_hardware *wlc_hw, u32 m, u32 v)743{744struct bcma_device *core = wlc_hw->d11core;745u32 ioctl = bcma_aread32(core, BCMA_IOCTL) & ~m;746747bcma_awrite32(core, BCMA_IOCTL, ioctl | v);748}749750static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)751{752brcms_dbg_info(wlc_hw->d11core, "wl%d: clk %d\n", wlc_hw->unit, clk);753754wlc_hw->phyclk = clk;755756if (OFF == clk) { /* clear gmode bit, put phy into reset */757758brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC | SICF_GMODE),759(SICF_PRST | SICF_FGC));760udelay(1);761brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_PRST);762udelay(1);763764} else { /* take phy out of reset */765766brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_FGC), SICF_FGC);767udelay(1);768brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0);769udelay(1);770771}772}773774/* low-level band switch utility routine */775static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)776{777brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit,778bandunit);779780wlc_hw->band = wlc_hw->bandstate[bandunit];781782/*783* BMAC_NOTE:784* until we eliminate need for wlc->band refs in low level code785*/786wlc_hw->wlc->band = wlc_hw->wlc->bandstate[bandunit];787788/* set gmode core flag */789if (wlc_hw->sbclk && !wlc_hw->noreset) {790u32 gmode = 0;791792if (bandunit == 0)793gmode = SICF_GMODE;794795brcms_b_core_ioctl(wlc_hw, SICF_GMODE, gmode);796}797}798799/* switch to new band but leave it inactive */800static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)801{802struct brcms_hardware *wlc_hw = wlc->hw;803u32 macintmask;804u32 macctrl;805806brcms_dbg_mac80211(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);807macctrl = bcma_read32(wlc_hw->d11core,808D11REGOFFS(maccontrol));809WARN_ON((macctrl & MCTL_EN_MAC) != 0);810811/* disable interrupts */812macintmask = brcms_intrsoff(wlc->wl);813814/* radio off */815wlc_phy_switch_radio(wlc_hw->band->pi, OFF);816817brcms_b_core_phy_clk(wlc_hw, OFF);818819brcms_c_setxband(wlc_hw, bandunit);820821return macintmask;822}823824/* process an individual struct tx_status */825static bool826brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)827{828struct sk_buff *p = NULL;829uint queue = NFIFO;830struct dma_pub *dma = NULL;831struct d11txh *txh = NULL;832struct scb *scb = NULL;833int tx_frame_count;834uint supr_status;835bool lastframe;836struct ieee80211_hdr *h;837struct ieee80211_tx_info *tx_info;838struct ieee80211_tx_rate *txrate;839int i;840bool fatal = true;841842trace_brcms_txstatus(&wlc->hw->d11core->dev, txs->framelen,843txs->frameid, txs->status, txs->lasttxtime,844txs->sequence, txs->phyerr, txs->ackphyrxsh);845846/* discard intermediate indications for ucode with one legitimate case:847* e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,848* but the subsequent tx of DATA failed. so it will start rts/cts849* from the beginning (resetting the rts transmission count)850*/851if (!(txs->status & TX_STATUS_AMPDU)852&& (txs->status & TX_STATUS_INTERMEDIATE)) {853brcms_dbg_tx(wlc->hw->d11core, "INTERMEDIATE but not AMPDU\n");854fatal = false;855goto out;856}857858queue = txs->frameid & TXFID_QUEUE_MASK;859if (queue >= NFIFO) {860brcms_err(wlc->hw->d11core, "queue %u >= NFIFO\n", queue);861goto out;862}863864dma = wlc->hw->di[queue];865866p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);867if (p == NULL) {868brcms_err(wlc->hw->d11core, "dma_getnexttxp returned null!\n");869goto out;870}871872txh = (struct d11txh *) (p->data);873874if (txs->phyerr)875brcms_dbg_tx(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",876txs->phyerr, txh->MainRates);877878if (txs->frameid != le16_to_cpu(txh->TxFrameID)) {879brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n");880goto out;881}882tx_info = IEEE80211_SKB_CB(p);883h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);884885if (tx_info->rate_driver_data[0])886scb = &wlc->pri_scb;887888if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {889brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);890fatal = false;891goto out;892}893894/*895* brcms_c_ampdu_dotxstatus() will trace tx descriptors for AMPDU896* frames; this traces them for the rest.897*/898trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));899900supr_status = txs->status & TX_STATUS_SUPR_MASK;901if (supr_status == TX_STATUS_SUPR_BADCH) {902unsigned xfts = le16_to_cpu(txh->XtraFrameTypes);903brcms_dbg_tx(wlc->hw->d11core,904"Pkt tx suppressed, dest chan %u, current %d\n",905(xfts >> XFTS_CHANNEL_SHIFT) & 0xff,906CHSPEC_CHANNEL(wlc->default_bss->chanspec));907}908909tx_frame_count =910(txs->status & TX_STATUS_FRM_RTX_MASK) >> TX_STATUS_FRM_RTX_SHIFT;911912lastframe = !ieee80211_has_morefrags(h->frame_control);913914if (!lastframe) {915brcms_err(wlc->hw->d11core, "Not last frame!\n");916} else {917/*918* Set information to be consumed by Minstrel ht.919*920* The "fallback limit" is the number of tx attempts a given921* MPDU is sent at the "primary" rate. Tx attempts beyond that922* limit are sent at the "secondary" rate.923* A 'short frame' does not exceed RTS threshold.924*/925u16 sfbl, /* Short Frame Rate Fallback Limit */926lfbl, /* Long Frame Rate Fallback Limit */927fbl;928929if (queue < IEEE80211_NUM_ACS) {930sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],931EDCF_SFB);932lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],933EDCF_LFB);934} else {935sfbl = wlc->SFBL;936lfbl = wlc->LFBL;937}938939txrate = tx_info->status.rates;940if (txrate[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)941fbl = lfbl;942else943fbl = sfbl;944945ieee80211_tx_info_clear_status(tx_info);946947if ((tx_frame_count > fbl) && (txrate[1].idx >= 0)) {948/*949* rate selection requested a fallback rate950* and we used it951*/952txrate[0].count = fbl;953txrate[1].count = tx_frame_count - fbl;954} else {955/*956* rate selection did not request fallback rate, or957* we didn't need it958*/959txrate[0].count = tx_frame_count;960/*961* rc80211_minstrel.c:minstrel_tx_status() expects962* unused rates to be marked with idx = -1963*/964txrate[1].idx = -1;965txrate[1].count = 0;966}967968/* clear the rest of the rates */969for (i = 2; i < IEEE80211_TX_MAX_RATES; i++) {970txrate[i].idx = -1;971txrate[i].count = 0;972}973974if (txs->status & TX_STATUS_ACK_RCV)975tx_info->flags |= IEEE80211_TX_STAT_ACK;976}977978if (lastframe) {979/* remove PLCP & Broadcom tx descriptor header */980skb_pull(p, D11_PHY_HDR_LEN);981skb_pull(p, D11_TXH_LEN);982ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);983} else {984brcms_err(wlc->hw->d11core,985"%s: Not last frame => not calling tx_status\n",986__func__);987}988989fatal = false;990991out:992if (fatal) {993if (txh)994trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,995sizeof(*txh));996brcmu_pkt_buf_free_skb(p);997}998999if (dma && queue < NFIFO) {1000u16 ac_queue = brcms_fifo_to_ac(queue);1001if (dma->txavail > TX_HEADROOM && queue < TX_BCMC_FIFO &&1002ieee80211_queue_stopped(wlc->pub->ieee_hw, ac_queue))1003ieee80211_wake_queue(wlc->pub->ieee_hw, ac_queue);1004dma_kick_tx(dma);1005}10061007return fatal;1008}10091010/* process tx completion events in BMAC1011* Return true if more tx status need to be processed. false otherwise.1012*/1013static bool1014brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)1015{1016struct bcma_device *core;1017struct tx_status txstatus, *txs;1018u32 s1, s2;1019uint n = 0;1020/*1021* Param 'max_tx_num' indicates max. # tx status to process before1022* break out.1023*/1024uint max_tx_num = bound ? TXSBND : -1;10251026txs = &txstatus;1027core = wlc_hw->d11core;1028*fatal = false;10291030while (n < max_tx_num) {1031s1 = bcma_read32(core, D11REGOFFS(frmtxstatus));1032if (s1 == 0xffffffff) {1033brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,1034__func__);1035*fatal = true;1036return false;1037}1038/* only process when valid */1039if (!(s1 & TXS_V))1040break;10411042s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));1043txs->status = s1 & TXS_STATUS_MASK;1044txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;1045txs->sequence = s2 & TXS_SEQ_MASK;1046txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;1047txs->lasttxtime = 0;10481049*fatal = brcms_c_dotxstatus(wlc_hw->wlc, txs);1050if (*fatal)1051return false;1052n++;1053}10541055return n >= max_tx_num;1056}10571058static void brcms_c_tbtt(struct brcms_c_info *wlc)1059{1060if (wlc->bsscfg->type == BRCMS_TYPE_ADHOC)1061/*1062* DirFrmQ is now valid...defer setting until end1063* of ATIM window1064*/1065wlc->qvalid |= MCMD_DIRFRMQVAL;1066}10671068/* set initial host flags value */1069static void1070brcms_c_mhfdef(struct brcms_c_info *wlc, u16 *mhfs, u16 mhf2_init)1071{1072struct brcms_hardware *wlc_hw = wlc->hw;10731074memset(mhfs, 0, MHFMAX * sizeof(u16));10751076mhfs[MHF2] |= mhf2_init;10771078/* prohibit use of slowclock on multifunction boards */1079if (wlc_hw->boardflags & BFL_NOPLLDOWN)1080mhfs[MHF1] |= MHF1_FORCEFASTCLK;10811082if (BRCMS_ISNPHY(wlc_hw->band) && NREV_LT(wlc_hw->band->phyrev, 2)) {1083mhfs[MHF2] |= MHF2_NPHY40MHZ_WAR;1084mhfs[MHF1] |= MHF1_IQSWAP_WAR;1085}1086}10871088static uint1089dmareg(uint direction, uint fifonum)1090{1091if (direction == DMA_TX)1092return offsetof(struct d11regs, fifo64regs[fifonum].dmaxmt);1093return offsetof(struct d11regs, fifo64regs[fifonum].dmarcv);1094}10951096static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)1097{1098uint i;1099char name[8];1100/*1101* ucode host flag 2 needed for pio mode, independent of band and fifo1102*/1103u16 pio_mhf2 = 0;1104struct brcms_hardware *wlc_hw = wlc->hw;1105uint unit = wlc_hw->unit;11061107/* name and offsets for dma_attach */1108snprintf(name, sizeof(name), "wl%d", unit);11091110if (wlc_hw->di[0] == NULL) { /* Init FIFOs */1111int dma_attach_err = 0;11121113/*1114* FIFO 01115* TX: TX_AC_BK_FIFO (TX AC Background data packets)1116* RX: RX_FIFO (RX data packets)1117*/1118wlc_hw->di[0] = dma_attach(name, wlc,1119(wme ? dmareg(DMA_TX, 0) : 0),1120dmareg(DMA_RX, 0),1121(wme ? NTXD : 0), NRXD,1122RXBUFSZ, -1, NRXBUFPOST,1123BRCMS_HWRXOFF);1124dma_attach_err |= (NULL == wlc_hw->di[0]);11251126/*1127* FIFO 11128* TX: TX_AC_BE_FIFO (TX AC Best-Effort data packets)1129* (legacy) TX_DATA_FIFO (TX data packets)1130* RX: UNUSED1131*/1132wlc_hw->di[1] = dma_attach(name, wlc,1133dmareg(DMA_TX, 1), 0,1134NTXD, 0, 0, -1, 0, 0);1135dma_attach_err |= (NULL == wlc_hw->di[1]);11361137/*1138* FIFO 21139* TX: TX_AC_VI_FIFO (TX AC Video data packets)1140* RX: UNUSED1141*/1142wlc_hw->di[2] = dma_attach(name, wlc,1143dmareg(DMA_TX, 2), 0,1144NTXD, 0, 0, -1, 0, 0);1145dma_attach_err |= (NULL == wlc_hw->di[2]);1146/*1147* FIFO 31148* TX: TX_AC_VO_FIFO (TX AC Voice data packets)1149* (legacy) TX_CTL_FIFO (TX control & mgmt packets)1150*/1151wlc_hw->di[3] = dma_attach(name, wlc,1152dmareg(DMA_TX, 3),11530, NTXD, 0, 0, -1,11540, 0);1155dma_attach_err |= (NULL == wlc_hw->di[3]);1156/* Cleaner to leave this as if with AP defined */11571158if (dma_attach_err) {1159brcms_err(wlc_hw->d11core,1160"wl%d: wlc_attach: dma_attach failed\n",1161unit);1162return false;1163}11641165/* get pointer to dma engine tx flow control variable */1166for (i = 0; i < NFIFO; i++)1167if (wlc_hw->di[i])1168wlc_hw->txavail[i] =1169(uint *) dma_getvar(wlc_hw->di[i],1170"&txavail");1171}11721173/* initial ucode host flags */1174brcms_c_mhfdef(wlc, wlc_hw->band->mhfs, pio_mhf2);11751176return true;1177}11781179static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)1180{1181uint j;11821183for (j = 0; j < NFIFO; j++) {1184if (wlc_hw->di[j]) {1185dma_detach(wlc_hw->di[j]);1186wlc_hw->di[j] = NULL;1187}1188}1189}11901191/*1192* Initialize brcms_c_info default values ...1193* may get overrides later in this function1194* BMAC_NOTES, move low out and resolve the dangling ones1195*/1196static void brcms_b_info_init(struct brcms_hardware *wlc_hw)1197{1198struct brcms_c_info *wlc = wlc_hw->wlc;11991200/* set default sw macintmask value */1201wlc->defmacintmask = DEF_MACINTMASK;12021203/* various 802.11g modes */1204wlc_hw->shortslot = false;12051206wlc_hw->SFBL = RETRY_SHORT_FB;1207wlc_hw->LFBL = RETRY_LONG_FB;12081209/* default mac retry limits */1210wlc_hw->SRL = RETRY_SHORT_DEF;1211wlc_hw->LRL = RETRY_LONG_DEF;1212wlc_hw->chanspec = ch20mhz_chspec(1);1213}12141215static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)1216{1217/* delay before first read of ucode state */1218udelay(40);12191220/* wait until ucode is no longer asleep */1221SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==1222DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);1223}12241225/* control chip clock to save power, enable dynamic clock or force fast clock */1226static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)1227{1228if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) {1229/* new chips with PMU, CCS_FORCEHT will distribute the HT clock1230* on backplane, but mac core will still run on ALP(not HT) when1231* it enters powersave mode, which means the FCA bit may not be1232* set. Should wakeup mac if driver wants it to run on HT.1233*/12341235if (wlc_hw->clk) {1236if (mode == BCMA_CLKMODE_FAST) {1237bcma_set32(wlc_hw->d11core,1238D11REGOFFS(clk_ctl_st),1239CCS_FORCEHT);12401241udelay(64);12421243SPINWAIT(1244((bcma_read32(wlc_hw->d11core,1245D11REGOFFS(clk_ctl_st)) &1246CCS_HTAVAIL) == 0),1247PMU_MAX_TRANSITION_DLY);1248WARN_ON(!(bcma_read32(wlc_hw->d11core,1249D11REGOFFS(clk_ctl_st)) &1250CCS_HTAVAIL));1251} else {1252if ((ai_get_pmurev(wlc_hw->sih) == 0) &&1253(bcma_read32(wlc_hw->d11core,1254D11REGOFFS(clk_ctl_st)) &1255(CCS_FORCEHT | CCS_HTAREQ)))1256SPINWAIT(1257((bcma_read32(wlc_hw->d11core,1258offsetof(struct d11regs,1259clk_ctl_st)) &1260CCS_HTAVAIL) == 0),1261PMU_MAX_TRANSITION_DLY);1262bcma_mask32(wlc_hw->d11core,1263D11REGOFFS(clk_ctl_st),1264~CCS_FORCEHT);1265}1266}1267wlc_hw->forcefastclk = (mode == BCMA_CLKMODE_FAST);1268} else {12691270/* old chips w/o PMU, force HT through cc,1271* then use FCA to verify mac is running fast clock1272*/12731274wlc_hw->forcefastclk = ai_clkctl_cc(wlc_hw->sih, mode);12751276/* check fast clock is available (if core is not in reset) */1277if (wlc_hw->forcefastclk && wlc_hw->clk)1278WARN_ON(!(bcma_aread32(wlc_hw->d11core, BCMA_IOST) &1279SISF_FCLKA));12801281/*1282* keep the ucode wake bit on if forcefastclk is on since we1283* do not want ucode to put us back to slow clock when it dozes1284* for PM mode. Code below matches the wake override bit with1285* current forcefastclk state. Only setting bit in wake_override1286* instead of waking ucode immediately since old code had this1287* behavior. Older code set wlc->forcefastclk but only had the1288* wake happen if the wakup_ucode work (protected by an up1289* check) was executed just below.1290*/1291if (wlc_hw->forcefastclk)1292mboolset(wlc_hw->wake_override,1293BRCMS_WAKE_OVERRIDE_FORCEFAST);1294else1295mboolclr(wlc_hw->wake_override,1296BRCMS_WAKE_OVERRIDE_FORCEFAST);1297}1298}12991300/* set or clear ucode host flag bits1301* it has an optimization for no-change write1302* it only writes through shared memory when the core has clock;1303* pre-CLK changes should use wlc_write_mhf to get around the optimization1304*1305*1306* bands values are: BRCM_BAND_AUTO <--- Current band only1307* BRCM_BAND_5G <--- 5G band only1308* BRCM_BAND_2G <--- 2G band only1309* BRCM_BAND_ALL <--- All bands1310*/1311void1312brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,1313int bands)1314{1315u16 save;1316u16 addr[MHFMAX] = {1317M_HOST_FLAGS1, M_HOST_FLAGS2, M_HOST_FLAGS3, M_HOST_FLAGS4,1318M_HOST_FLAGS51319};1320struct brcms_hw_band *band;13211322if ((val & ~mask) || idx >= MHFMAX)1323return; /* error condition */13241325switch (bands) {1326/* Current band only or all bands,1327* then set the band to current band1328*/1329case BRCM_BAND_AUTO:1330case BRCM_BAND_ALL:1331band = wlc_hw->band;1332break;1333case BRCM_BAND_5G:1334band = wlc_hw->bandstate[BAND_5G_INDEX];1335break;1336case BRCM_BAND_2G:1337band = wlc_hw->bandstate[BAND_2G_INDEX];1338break;1339default:1340band = NULL; /* error condition */1341}13421343if (band) {1344save = band->mhfs[idx];1345band->mhfs[idx] = (band->mhfs[idx] & ~mask) | val;13461347/* optimization: only write through if changed, and1348* changed band is the current band1349*/1350if (wlc_hw->clk && (band->mhfs[idx] != save)1351&& (band == wlc_hw->band))1352brcms_b_write_shm(wlc_hw, addr[idx],1353(u16) band->mhfs[idx]);1354}13551356if (bands == BRCM_BAND_ALL) {1357wlc_hw->bandstate[0]->mhfs[idx] =1358(wlc_hw->bandstate[0]->mhfs[idx] & ~mask) | val;1359wlc_hw->bandstate[1]->mhfs[idx] =1360(wlc_hw->bandstate[1]->mhfs[idx] & ~mask) | val;1361}1362}13631364/* set the maccontrol register to desired reset state and1365* initialize the sw cache of the register1366*/1367static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw)1368{1369/* IHR accesses are always enabled, PSM disabled, HPS off and WAKE on */1370wlc_hw->maccontrol = 0;1371wlc_hw->suspended_fifos = 0;1372wlc_hw->wake_override = 0;1373wlc_hw->mute_override = 0;1374brcms_b_mctrl(wlc_hw, ~0, MCTL_IHR_EN | MCTL_WAKE);1375}13761377/*1378* write the software state of maccontrol and1379* overrides to the maccontrol register1380*/1381static void brcms_c_mctrl_write(struct brcms_hardware *wlc_hw)1382{1383u32 maccontrol = wlc_hw->maccontrol;13841385/* OR in the wake bit if overridden */1386if (wlc_hw->wake_override)1387maccontrol |= MCTL_WAKE;13881389/* set AP and INFRA bits for mute if needed */1390if (wlc_hw->mute_override) {1391maccontrol &= ~(MCTL_AP);1392maccontrol |= MCTL_INFRA;1393}13941395bcma_write32(wlc_hw->d11core, D11REGOFFS(maccontrol),1396maccontrol);1397}13981399/* set or clear maccontrol bits */1400void brcms_b_mctrl(struct brcms_hardware *wlc_hw, u32 mask, u32 val)1401{1402u32 maccontrol;1403u32 new_maccontrol;14041405if (val & ~mask)1406return; /* error condition */1407maccontrol = wlc_hw->maccontrol;1408new_maccontrol = (maccontrol & ~mask) | val;14091410/* if the new maccontrol value is the same as the old, nothing to do */1411if (new_maccontrol == maccontrol)1412return;14131414/* something changed, cache the new value */1415wlc_hw->maccontrol = new_maccontrol;14161417/* write the new values with overrides applied */1418brcms_c_mctrl_write(wlc_hw);1419}14201421void brcms_c_ucode_wake_override_set(struct brcms_hardware *wlc_hw,1422u32 override_bit)1423{1424if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE)) {1425mboolset(wlc_hw->wake_override, override_bit);1426return;1427}14281429mboolset(wlc_hw->wake_override, override_bit);14301431brcms_c_mctrl_write(wlc_hw);1432brcms_b_wait_for_wake(wlc_hw);1433}14341435void brcms_c_ucode_wake_override_clear(struct brcms_hardware *wlc_hw,1436u32 override_bit)1437{1438mboolclr(wlc_hw->wake_override, override_bit);14391440if (wlc_hw->wake_override || (wlc_hw->maccontrol & MCTL_WAKE))1441return;14421443brcms_c_mctrl_write(wlc_hw);1444}14451446/* When driver needs ucode to stop beaconing, it has to make sure that1447* MCTL_AP is clear and MCTL_INFRA is set1448* Mode MCTL_AP MCTL_INFRA1449* AP 1 11450* STA 0 1 <--- This will ensure no beacons1451* IBSS 0 01452*/1453static void brcms_c_ucode_mute_override_set(struct brcms_hardware *wlc_hw)1454{1455wlc_hw->mute_override = 1;14561457/* if maccontrol already has AP == 0 and INFRA == 1 without this1458* override, then there is no change to write1459*/1460if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)1461return;14621463brcms_c_mctrl_write(wlc_hw);1464}14651466/* Clear the override on AP and INFRA bits */1467static void brcms_c_ucode_mute_override_clear(struct brcms_hardware *wlc_hw)1468{1469if (wlc_hw->mute_override == 0)1470return;14711472wlc_hw->mute_override = 0;14731474/* if maccontrol already has AP == 0 and INFRA == 1 without this1475* override, then there is no change to write1476*/1477if ((wlc_hw->maccontrol & (MCTL_AP | MCTL_INFRA)) == MCTL_INFRA)1478return;14791480brcms_c_mctrl_write(wlc_hw);1481}14821483/*1484* Write a MAC address to the given match reg offset in the RXE match engine.1485*/1486static void1487brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,1488const u8 *addr)1489{1490struct bcma_device *core = wlc_hw->d11core;1491u16 mac_l;1492u16 mac_m;1493u16 mac_h;14941495brcms_dbg_rx(core, "wl%d: brcms_b_set_addrmatch\n", wlc_hw->unit);14961497mac_l = addr[0] | (addr[1] << 8);1498mac_m = addr[2] | (addr[3] << 8);1499mac_h = addr[4] | (addr[5] << 8);15001501/* enter the MAC addr into the RXE match registers */1502bcma_write16(core, D11REGOFFS(rcm_ctl),1503RCM_INC_DATA | match_reg_offset);1504bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_l);1505bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_m);1506bcma_write16(core, D11REGOFFS(rcm_mat_data), mac_h);1507}15081509void1510brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,1511void *buf)1512{1513struct bcma_device *core = wlc_hw->d11core;1514u32 word;1515__le32 word_le;1516__be32 word_be;1517bool be_bit;1518brcms_dbg_info(core, "wl%d\n", wlc_hw->unit);15191520bcma_write32(core, D11REGOFFS(tplatewrptr), offset);15211522/* if MCTL_BIGEND bit set in mac control register,1523* the chip swaps data in fifo, as well as data in1524* template ram1525*/1526be_bit = (bcma_read32(core, D11REGOFFS(maccontrol)) & MCTL_BIGEND) != 0;15271528while (len > 0) {1529memcpy(&word, buf, sizeof(u32));15301531if (be_bit) {1532word_be = cpu_to_be32(word);1533word = *(u32 *)&word_be;1534} else {1535word_le = cpu_to_le32(word);1536word = *(u32 *)&word_le;1537}15381539bcma_write32(core, D11REGOFFS(tplatewrdata), word);15401541buf = (u8 *) buf + sizeof(u32);1542len -= sizeof(u32);1543}1544}15451546static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin)1547{1548wlc_hw->band->CWmin = newmin;15491550bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),1551OBJADDR_SCR_SEL | S_DOT11_CWMIN);1552(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));1553bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmin);1554}15551556static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax)1557{1558wlc_hw->band->CWmax = newmax;15591560bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),1561OBJADDR_SCR_SEL | S_DOT11_CWMAX);1562(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));1563bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), newmax);1564}15651566void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)1567{1568bool fastclk;15691570/* request FAST clock if not on */1571fastclk = wlc_hw->forcefastclk;1572if (!fastclk)1573brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);15741575wlc_phy_bw_state_set(wlc_hw->band->pi, bw);15761577brcms_b_phy_reset(wlc_hw);1578wlc_phy_init(wlc_hw->band->pi, wlc_phy_chanspec_get(wlc_hw->band->pi));15791580/* restore the clk */1581if (!fastclk)1582brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);1583}15841585static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)1586{1587u16 v;1588struct brcms_c_info *wlc = wlc_hw->wlc;1589/* update SYNTHPU_DLY */15901591if (BRCMS_ISLCNPHY(wlc->band))1592v = SYNTHPU_DLY_LPPHY_US;1593else if (BRCMS_ISNPHY(wlc->band) && (NREV_GE(wlc->band->phyrev, 3)))1594v = SYNTHPU_DLY_NPHY_US;1595else1596v = SYNTHPU_DLY_BPHY_US;15971598brcms_b_write_shm(wlc_hw, M_SYNTHPU_DLY, v);1599}16001601static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw)1602{1603u16 phyctl;1604u16 phytxant = wlc_hw->bmac_phytxant;1605u16 mask = PHY_TXC_ANT_MASK;16061607/* set the Probe Response frame phy control word */1608phyctl = brcms_b_read_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS);1609phyctl = (phyctl & ~mask) | phytxant;1610brcms_b_write_shm(wlc_hw, M_CTXPRS_BLK + C_CTX_PCTLWD_POS, phyctl);16111612/* set the Response (ACK/CTS) frame phy control word */1613phyctl = brcms_b_read_shm(wlc_hw, M_RSP_PCTLWD);1614phyctl = (phyctl & ~mask) | phytxant;1615brcms_b_write_shm(wlc_hw, M_RSP_PCTLWD, phyctl);1616}16171618static u16 brcms_b_ofdm_ratetable_offset(struct brcms_hardware *wlc_hw,1619u8 rate)1620{1621uint i;1622u8 plcp_rate = 0;1623struct plcp_signal_rate_lookup {1624u8 rate;1625u8 signal_rate;1626};1627/* OFDM RATE sub-field of PLCP SIGNAL field, per 802.11 sec 17.3.4.1 */1628const struct plcp_signal_rate_lookup rate_lookup[] = {1629{BRCM_RATE_6M, 0xB},1630{BRCM_RATE_9M, 0xF},1631{BRCM_RATE_12M, 0xA},1632{BRCM_RATE_18M, 0xE},1633{BRCM_RATE_24M, 0x9},1634{BRCM_RATE_36M, 0xD},1635{BRCM_RATE_48M, 0x8},1636{BRCM_RATE_54M, 0xC}1637};16381639for (i = 0; i < ARRAY_SIZE(rate_lookup); i++) {1640if (rate == rate_lookup[i].rate) {1641plcp_rate = rate_lookup[i].signal_rate;1642break;1643}1644}16451646/* Find the SHM pointer to the rate table entry by looking in the1647* Direct-map Table1648*/1649return 2 * brcms_b_read_shm(wlc_hw, M_RT_DIRMAP_A + (plcp_rate * 2));1650}16511652static void brcms_upd_ofdm_pctl1_table(struct brcms_hardware *wlc_hw)1653{1654u8 rate;1655u8 rates[8] = {1656BRCM_RATE_6M, BRCM_RATE_9M, BRCM_RATE_12M, BRCM_RATE_18M,1657BRCM_RATE_24M, BRCM_RATE_36M, BRCM_RATE_48M, BRCM_RATE_54M1658};1659u16 entry_ptr;1660u16 pctl1;1661uint i;16621663if (!BRCMS_PHY_11N_CAP(wlc_hw->band))1664return;16651666/* walk the phy rate table and update the entries */1667for (i = 0; i < ARRAY_SIZE(rates); i++) {1668rate = rates[i];16691670entry_ptr = brcms_b_ofdm_ratetable_offset(wlc_hw, rate);16711672/* read the SHM Rate Table entry OFDM PCTL1 values */1673pctl1 =1674brcms_b_read_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS);16751676/* modify the value */1677pctl1 &= ~PHY_TXC1_MODE_MASK;1678pctl1 |= (wlc_hw->hw_stf_ss_opmode << PHY_TXC1_MODE_SHIFT);16791680/* Update the SHM Rate Table entry OFDM PCTL1 values */1681brcms_b_write_shm(wlc_hw, entry_ptr + M_RT_OFDM_PCTL1_POS,1682pctl1);1683}1684}16851686/* band-specific init */1687static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)1688{1689struct brcms_hardware *wlc_hw = wlc->hw;16901691brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit,1692wlc_hw->band->bandunit);16931694brcms_c_ucode_bsinit(wlc_hw);16951696wlc_phy_init(wlc_hw->band->pi, chanspec);16971698brcms_c_ucode_txant_set(wlc_hw);16991700/*1701* cwmin is band-specific, update hardware1702* with value for current band1703*/1704brcms_b_set_cwmin(wlc_hw, wlc_hw->band->CWmin);1705brcms_b_set_cwmax(wlc_hw, wlc_hw->band->CWmax);17061707brcms_b_update_slot_timing(wlc_hw,1708wlc_hw->band->bandtype == BRCM_BAND_5G ?1709true : wlc_hw->shortslot);17101711/* write phytype and phyvers */1712brcms_b_write_shm(wlc_hw, M_PHYTYPE, (u16) wlc_hw->band->phytype);1713brcms_b_write_shm(wlc_hw, M_PHYVER, (u16) wlc_hw->band->phyrev);17141715/*1716* initialize the txphyctl1 rate table since1717* shmem is shared between bands1718*/1719brcms_upd_ofdm_pctl1_table(wlc_hw);17201721brcms_b_upd_synthpu(wlc_hw);1722}17231724/* Perform a soft reset of the PHY PLL */1725void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)1726{1727ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_addr),1728~0, 0);1729udelay(1);1730ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),17310x4, 0);1732udelay(1);1733ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),17340x4, 4);1735udelay(1);1736ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_data),17370x4, 0);1738udelay(1);1739}17401741/* light way to turn on phy clock without reset for NPHY only1742* refer to brcms_b_core_phy_clk for full version1743*/1744void brcms_b_phyclk_fgc(struct brcms_hardware *wlc_hw, bool clk)1745{1746/* support(necessary for NPHY and HYPHY) only */1747if (!BRCMS_ISNPHY(wlc_hw->band))1748return;17491750if (ON == clk)1751brcms_b_core_ioctl(wlc_hw, SICF_FGC, SICF_FGC);1752else1753brcms_b_core_ioctl(wlc_hw, SICF_FGC, 0);17541755}17561757void brcms_b_macphyclk_set(struct brcms_hardware *wlc_hw, bool clk)1758{1759if (ON == clk)1760brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, SICF_MPCLKE);1761else1762brcms_b_core_ioctl(wlc_hw, SICF_MPCLKE, 0);1763}17641765void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)1766{1767struct brcms_phy_pub *pih = wlc_hw->band->pi;1768u32 phy_bw_clkbits;17691770brcms_dbg_info(wlc_hw->d11core, "wl%d: reset phy\n", wlc_hw->unit);17711772if (pih == NULL)1773return;17741775phy_bw_clkbits = wlc_phy_clk_bwbits(wlc_hw->band->pi);17761777/* Specific reset sequence required for NPHY rev 3 and 4 */1778if (BRCMS_ISNPHY(wlc_hw->band) && NREV_GE(wlc_hw->band->phyrev, 3) &&1779NREV_LE(wlc_hw->band->phyrev, 4)) {1780/* Set the PHY bandwidth */1781brcms_b_core_ioctl(wlc_hw, SICF_BWMASK, phy_bw_clkbits);17821783udelay(1);17841785/* Perform a soft reset of the PHY PLL */1786brcms_b_core_phypll_reset(wlc_hw);17871788/* reset the PHY */1789brcms_b_core_ioctl(wlc_hw, (SICF_PRST | SICF_PCLKE),1790(SICF_PRST | SICF_PCLKE));1791} else {1792brcms_b_core_ioctl(wlc_hw,1793(SICF_PRST | SICF_PCLKE | SICF_BWMASK),1794(SICF_PRST | SICF_PCLKE | phy_bw_clkbits));1795}17961797udelay(2);1798brcms_b_core_phy_clk(wlc_hw, ON);17991800wlc_phy_anacore(pih, ON);1801}18021803/* switch to and initialize new band */1804static void brcms_b_setband(struct brcms_hardware *wlc_hw, uint bandunit,1805u16 chanspec) {1806struct brcms_c_info *wlc = wlc_hw->wlc;1807u32 macintmask;18081809/* Enable the d11 core before accessing it */1810if (!bcma_core_is_enabled(wlc_hw->d11core)) {1811bcma_core_enable(wlc_hw->d11core, 0);1812brcms_c_mctrl_reset(wlc_hw);1813}18141815macintmask = brcms_c_setband_inact(wlc, bandunit);18161817if (!wlc_hw->up)1818return;18191820brcms_b_core_phy_clk(wlc_hw, ON);18211822/* band-specific initializations */1823brcms_b_bsinit(wlc, chanspec);18241825/*1826* If there are any pending software interrupt bits,1827* then replace these with a harmless nonzero value1828* so brcms_c_dpc() will re-enable interrupts when done.1829*/1830if (wlc->macintstatus)1831wlc->macintstatus = MI_DMAINT;18321833/* restore macintmask */1834brcms_intrsrestore(wlc->wl, macintmask);18351836/* ucode should still be suspended.. */1837WARN_ON((bcma_read32(wlc_hw->d11core, D11REGOFFS(maccontrol)) &1838MCTL_EN_MAC) != 0);1839}18401841static bool brcms_c_isgoodchip(struct brcms_hardware *wlc_hw)1842{18431844/* reject unsupported corerev */1845if (!CONF_HAS(D11CONF, wlc_hw->corerev)) {1846wiphy_err(wlc_hw->wlc->wiphy, "unsupported core rev %d\n",1847wlc_hw->corerev);1848return false;1849}18501851return true;1852}18531854/* Validate some board info parameters */1855static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)1856{1857uint boardrev = wlc_hw->boardrev;18581859/* 4 bits each for board type, major, minor, and tiny version */1860uint brt = (boardrev & 0xf000) >> 12;1861uint b0 = (boardrev & 0xf00) >> 8;1862uint b1 = (boardrev & 0xf0) >> 4;1863uint b2 = boardrev & 0xf;18641865/* voards from other vendors are always considered valid */1866if (ai_get_boardvendor(wlc_hw->sih) != PCI_VENDOR_ID_BROADCOM)1867return true;18681869/* do some boardrev sanity checks when boardvendor is Broadcom */1870if (boardrev == 0)1871return false;18721873if (boardrev <= 0xff)1874return true;18751876if ((brt > 2) || (brt == 0) || (b0 > 9) || (b0 == 0) || (b1 > 9)1877|| (b2 > 9))1878return false;18791880return true;1881}18821883static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ALEN])1884{1885struct ssb_sprom *sprom = &wlc_hw->d11core->bus->sprom;18861887/* If macaddr exists, use it (Sromrev4, CIS, ...). */1888if (!is_zero_ether_addr(sprom->il0mac)) {1889memcpy(etheraddr, sprom->il0mac, ETH_ALEN);1890return;1891}18921893if (wlc_hw->_nbands > 1)1894memcpy(etheraddr, sprom->et1mac, ETH_ALEN);1895else1896memcpy(etheraddr, sprom->il0mac, ETH_ALEN);1897}18981899/* power both the pll and external oscillator on/off */1900static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)1901{1902brcms_dbg_info(wlc_hw->d11core, "wl%d: want %d\n", wlc_hw->unit, want);19031904/*1905* dont power down if plldown is false or1906* we must poll hw radio disable1907*/1908if (!want && wlc_hw->pllreq)1909return;19101911wlc_hw->sbclk = want;1912if (!wlc_hw->sbclk) {1913wlc_hw->clk = false;1914if (wlc_hw->band && wlc_hw->band->pi)1915wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);1916}1917}19181919/*1920* Return true if radio is disabled, otherwise false.1921* hw radio disable signal is an external pin, users activate it asynchronously1922* this function could be called when driver is down and w/o clock1923* it operates on different registers depending on corerev and boardflag.1924*/1925static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)1926{1927bool v, clk, xtal;1928u32 flags = 0;19291930xtal = wlc_hw->sbclk;1931if (!xtal)1932brcms_b_xtal(wlc_hw, ON);19331934/* may need to take core out of reset first */1935clk = wlc_hw->clk;1936if (!clk) {1937/*1938* mac no longer enables phyclk automatically when driver1939* accesses phyreg throughput mac. This can be skipped since1940* only mac reg is accessed below1941*/1942if (D11REV_GE(wlc_hw->corerev, 18))1943flags |= SICF_PCLKE;19441945/*1946* TODO: test suspend/resume1947*1948* AI chip doesn't restore bar0win2 on1949* hibernation/resume, need sw fixup1950*/19511952bcma_core_enable(wlc_hw->d11core, flags);1953brcms_c_mctrl_reset(wlc_hw);1954}19551956v = ((bcma_read32(wlc_hw->d11core,1957D11REGOFFS(phydebug)) & PDBG_RFD) != 0);19581959/* put core back into reset */1960if (!clk)1961bcma_core_disable(wlc_hw->d11core, 0);19621963if (!xtal)1964brcms_b_xtal(wlc_hw, OFF);19651966return v;1967}19681969static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)1970{1971struct dma_pub *di = wlc_hw->di[fifo];1972return dma_rxreset(di);1973}19741975/* d11 core reset1976* ensure fask clock during reset1977* reset dma1978* reset d11(out of reset)1979* reset phy(out of reset)1980* clear software macintstatus for fresh new start1981* one testing hack wlc_hw->noreset will bypass the d11/phy reset1982*/1983void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)1984{1985uint i;1986bool fastclk;19871988if (flags == BRCMS_USE_COREFLAGS)1989flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);19901991brcms_dbg_info(wlc_hw->d11core, "wl%d: core reset\n", wlc_hw->unit);19921993/* request FAST clock if not on */1994fastclk = wlc_hw->forcefastclk;1995if (!fastclk)1996brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);19971998/* reset the dma engines except first time thru */1999if (bcma_core_is_enabled(wlc_hw->d11core)) {2000for (i = 0; i < NFIFO; i++)2001if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i])))2002brcms_err(wlc_hw->d11core, "wl%d: %s: "2003"dma_txreset[%d]: cannot stop dma\n",2004wlc_hw->unit, __func__, i);20052006if ((wlc_hw->di[RX_FIFO])2007&& (!wlc_dma_rxreset(wlc_hw, RX_FIFO)))2008brcms_err(wlc_hw->d11core, "wl%d: %s: dma_rxreset"2009"[%d]: cannot stop dma\n",2010wlc_hw->unit, __func__, RX_FIFO);2011}2012/* if noreset, just stop the psm and return */2013if (wlc_hw->noreset) {2014wlc_hw->wlc->macintstatus = 0; /* skip wl_dpc after down */2015brcms_b_mctrl(wlc_hw, MCTL_PSM_RUN | MCTL_EN_MAC, 0);2016return;2017}20182019/*2020* mac no longer enables phyclk automatically when driver accesses2021* phyreg throughput mac, AND phy_reset is skipped at early stage when2022* band->pi is invalid. need to enable PHY CLK2023*/2024if (D11REV_GE(wlc_hw->corerev, 18))2025flags |= SICF_PCLKE;20262027/*2028* reset the core2029* In chips with PMU, the fastclk request goes through d11 core2030* reg 0x1e0, which is cleared by the core_reset. have to re-request it.2031*2032* This adds some delay and we can optimize it by also requesting2033* fastclk through chipcommon during this period if necessary. But2034* that has to work coordinate with other driver like mips/arm since2035* they may touch chipcommon as well.2036*/2037wlc_hw->clk = false;2038bcma_core_enable(wlc_hw->d11core, flags);2039wlc_hw->clk = true;2040if (wlc_hw->band && wlc_hw->band->pi)2041wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, true);20422043brcms_c_mctrl_reset(wlc_hw);20442045if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU)2046brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);20472048brcms_b_phy_reset(wlc_hw);20492050/* turn on PHY_PLL */2051brcms_b_core_phypll_ctl(wlc_hw, true);20522053/* clear sw intstatus */2054wlc_hw->wlc->macintstatus = 0;20552056/* restore the clk setting */2057if (!fastclk)2058brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);2059}20602061/* txfifo sizes needs to be modified(increased) since the newer cores2062* have more memory.2063*/2064static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)2065{2066struct bcma_device *core = wlc_hw->d11core;2067u16 fifo_nu;2068u16 txfifo_startblk = TXFIFO_START_BLK, txfifo_endblk;2069u16 txfifo_def, txfifo_def1;2070u16 txfifo_cmd;20712072/* tx fifos start at TXFIFO_START_BLK from the Base address */2073txfifo_startblk = TXFIFO_START_BLK;20742075/* sequence of operations: reset fifo, set fifo size, reset fifo */2076for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {20772078txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];2079txfifo_def = (txfifo_startblk & 0xff) |2080(((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);2081txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |2082((((txfifo_endblk -20831) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);2084txfifo_cmd =2085TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);20862087bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd);2088bcma_write16(core, D11REGOFFS(xmtfifodef), txfifo_def);2089bcma_write16(core, D11REGOFFS(xmtfifodef1), txfifo_def1);20902091bcma_write16(core, D11REGOFFS(xmtfifocmd), txfifo_cmd);20922093txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];2094}2095/*2096* need to propagate to shm location to be in sync since ucode/hw won't2097* do this2098*/2099brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,2100wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);2101brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,2102wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);2103brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,2104((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->2105xmtfifo_sz[TX_AC_BK_FIFO]));2106brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,2107((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->2108xmtfifo_sz[TX_BCMC_FIFO]));2109}21102111/* This function is used for changing the tsf frac register2112* If spur avoidance mode is off, the mac freq will be 80/120/160Mhz2113* If spur avoidance mode is on1, the mac freq will be 82/123/164Mhz2114* If spur avoidance mode is on2, the mac freq will be 84/126/168Mhz2115* HTPHY Formula is 2^26/freq(MHz) e.g.2116* For spuron2 - 126MHz -> 2^26/126 = 532610.02117* - 532610 = 0x82082 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x20822118* For spuron: 123MHz -> 2^26/123 = 545600.52119* - 545601 = 0x85341 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x53412120* For spur off: 120MHz -> 2^26/120 = 559240.52121* - 559241 = 0x88889 => tsf_clk_frac_h = 0x8, tsf_clk_frac_l = 0x88892122*/21232124void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode)2125{2126struct bcma_device *core = wlc_hw->d11core;21272128if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43224) ||2129(ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225)) {2130if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */2131bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082);2132bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);2133} else if (spurmode == WL_SPURAVOID_ON1) { /* 123Mhz */2134bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x5341);2135bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);2136} else { /* 120Mhz */2137bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x8889);2138bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8);2139}2140} else if (BRCMS_ISLCNPHY(wlc_hw->band)) {2141if (spurmode == WL_SPURAVOID_ON1) { /* 82Mhz */2142bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x7CE0);2143bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC);2144} else { /* 80Mhz */2145bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0xCCCD);2146bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0xC);2147}2148}2149}21502151void brcms_c_start_station(struct brcms_c_info *wlc, u8 *addr)2152{2153memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));2154wlc->bsscfg->type = BRCMS_TYPE_STATION;2155}21562157void brcms_c_start_ap(struct brcms_c_info *wlc, u8 *addr, const u8 *bssid,2158u8 *ssid, size_t ssid_len)2159{2160brcms_c_set_ssid(wlc, ssid, ssid_len);21612162memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));2163memcpy(wlc->bsscfg->BSSID, bssid, sizeof(wlc->bsscfg->BSSID));2164wlc->bsscfg->type = BRCMS_TYPE_AP;21652166brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, MCTL_AP | MCTL_INFRA);2167}21682169void brcms_c_start_adhoc(struct brcms_c_info *wlc, u8 *addr)2170{2171memcpy(wlc->pub->cur_etheraddr, addr, sizeof(wlc->pub->cur_etheraddr));2172wlc->bsscfg->type = BRCMS_TYPE_ADHOC;21732174brcms_b_mctrl(wlc->hw, MCTL_AP | MCTL_INFRA, 0);2175}21762177/* Initialize GPIOs that are controlled by D11 core */2178static void brcms_c_gpio_init(struct brcms_c_info *wlc)2179{2180struct brcms_hardware *wlc_hw = wlc->hw;2181u32 gc, gm;21822183/* use GPIO select 0 to get all gpio signals from the gpio out reg */2184brcms_b_mctrl(wlc_hw, MCTL_GPOUT_SEL_MASK, 0);21852186/*2187* Common GPIO setup:2188* G0 = LED 0 = WLAN Activity2189* G1 = LED 1 = WLAN 2.4 GHz Radio State2190* G2 = LED 2 = WLAN 5 GHz Radio State2191* G4 = radio disable input (HI enabled, LO disabled)2192*/21932194gc = gm = 0;21952196/* Allocate GPIOs for mimo antenna diversity feature */2197if (wlc_hw->antsel_type == ANTSEL_2x3) {2198/* Enable antenna diversity, use 2x3 mode */2199brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,2200MHF3_ANTSEL_EN, BRCM_BAND_ALL);2201brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE,2202MHF3_ANTSEL_MODE, BRCM_BAND_ALL);22032204/* init superswitch control */2205wlc_phy_antsel_init(wlc_hw->band->pi, false);22062207} else if (wlc_hw->antsel_type == ANTSEL_2x4) {2208gm |= gc |= (BOARD_GPIO_12 | BOARD_GPIO_13);2209/*2210* The board itself is powered by these GPIOs2211* (when not sending pattern) so set them high2212*/2213bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_oe),2214(BOARD_GPIO_12 | BOARD_GPIO_13));2215bcma_set16(wlc_hw->d11core, D11REGOFFS(psm_gpio_out),2216(BOARD_GPIO_12 | BOARD_GPIO_13));22172218/* Enable antenna diversity, use 2x4 mode */2219brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_EN,2220MHF3_ANTSEL_EN, BRCM_BAND_ALL);2221brcms_b_mhf(wlc_hw, MHF3, MHF3_ANTSEL_MODE, 0,2222BRCM_BAND_ALL);22232224/* Configure the desired clock to be 4Mhz */2225brcms_b_write_shm(wlc_hw, M_ANTSEL_CLKDIV,2226ANTSEL_CLKDIV_4MHZ);2227}22282229/*2230* gpio 9 controls the PA. ucode is responsible2231* for wiggling out and oe2232*/2233if (wlc_hw->boardflags & BFL_PACTRL)2234gm |= gc |= BOARD_GPIO_PACTRL;22352236/* apply to gpiocontrol register */2237bcma_chipco_gpio_control(&wlc_hw->d11core->bus->drv_cc, gm, gc);2238}22392240static void brcms_ucode_write(struct brcms_hardware *wlc_hw,2241const __le32 ucode[], const size_t nbytes)2242{2243struct bcma_device *core = wlc_hw->d11core;2244uint i;2245uint count;22462247brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);22482249count = (nbytes / sizeof(u32));22502251bcma_write32(core, D11REGOFFS(objaddr),2252OBJADDR_AUTO_INC | OBJADDR_UCM_SEL);2253(void)bcma_read32(core, D11REGOFFS(objaddr));2254for (i = 0; i < count; i++)2255bcma_write32(core, D11REGOFFS(objdata), le32_to_cpu(ucode[i]));22562257}22582259static void brcms_ucode_download(struct brcms_hardware *wlc_hw)2260{2261struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;22622263if (wlc_hw->ucode_loaded)2264return;22652266if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {2267if (BRCMS_ISNPHY(wlc_hw->band)) {2268brcms_ucode_write(wlc_hw, ucode->bcm43xx_16_mimo,2269ucode->bcm43xx_16_mimosz);2270wlc_hw->ucode_loaded = true;2271} else2272brcms_err(wlc_hw->d11core,2273"%s: wl%d: unsupported phy in corerev %d\n",2274__func__, wlc_hw->unit, wlc_hw->corerev);2275} else if (D11REV_IS(wlc_hw->corerev, 24)) {2276if (BRCMS_ISLCNPHY(wlc_hw->band)) {2277brcms_ucode_write(wlc_hw, ucode->bcm43xx_24_lcn,2278ucode->bcm43xx_24_lcnsz);2279wlc_hw->ucode_loaded = true;2280} else {2281brcms_err(wlc_hw->d11core,2282"%s: wl%d: unsupported phy in corerev %d\n",2283__func__, wlc_hw->unit, wlc_hw->corerev);2284}2285}2286}22872288void brcms_b_txant_set(struct brcms_hardware *wlc_hw, u16 phytxant)2289{2290/* update sw state */2291wlc_hw->bmac_phytxant = phytxant;22922293/* push to ucode if up */2294if (!wlc_hw->up)2295return;2296brcms_c_ucode_txant_set(wlc_hw);22972298}22992300u16 brcms_b_get_txant(struct brcms_hardware *wlc_hw)2301{2302return (u16) wlc_hw->wlc->stf->txant;2303}23042305void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)2306{2307wlc_hw->antsel_type = antsel_type;23082309/* Update the antsel type for phy module to use */2310wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);2311}23122313static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)2314{2315bool fatal = false;2316uint unit;2317uint intstatus, idx;2318struct bcma_device *core = wlc_hw->d11core;23192320unit = wlc_hw->unit;23212322for (idx = 0; idx < NFIFO; idx++) {2323/* read intstatus register and ignore any non-error bits */2324intstatus =2325bcma_read32(core,2326D11REGOFFS(intctrlregs[idx].intstatus)) &2327I_ERRORS;2328if (!intstatus)2329continue;23302331brcms_dbg_int(core, "wl%d: intstatus%d 0x%x\n",2332unit, idx, intstatus);23332334if (intstatus & I_RO) {2335brcms_err(core, "wl%d: fifo %d: receive fifo "2336"overflow\n", unit, idx);2337fatal = true;2338}23392340if (intstatus & I_PC) {2341brcms_err(core, "wl%d: fifo %d: descriptor error\n",2342unit, idx);2343fatal = true;2344}23452346if (intstatus & I_PD) {2347brcms_err(core, "wl%d: fifo %d: data error\n", unit,2348idx);2349fatal = true;2350}23512352if (intstatus & I_DE) {2353brcms_err(core, "wl%d: fifo %d: descriptor protocol "2354"error\n", unit, idx);2355fatal = true;2356}23572358if (intstatus & I_RU)2359brcms_err(core, "wl%d: fifo %d: receive descriptor "2360"underflow\n", idx, unit);23612362if (intstatus & I_XU) {2363brcms_err(core, "wl%d: fifo %d: transmit fifo "2364"underflow\n", idx, unit);2365fatal = true;2366}23672368if (fatal) {2369brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */2370break;2371} else2372bcma_write32(core,2373D11REGOFFS(intctrlregs[idx].intstatus),2374intstatus);2375}2376}23772378void brcms_c_intrson(struct brcms_c_info *wlc)2379{2380struct brcms_hardware *wlc_hw = wlc->hw;2381wlc->macintmask = wlc->defmacintmask;2382bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask);2383}23842385u32 brcms_c_intrsoff(struct brcms_c_info *wlc)2386{2387struct brcms_hardware *wlc_hw = wlc->hw;2388u32 macintmask;23892390if (!wlc_hw->clk)2391return 0;23922393macintmask = wlc->macintmask; /* isr can still happen */23942395bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), 0);2396(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(macintmask));2397udelay(1); /* ensure int line is no longer driven */2398wlc->macintmask = 0;23992400/* return previous macintmask; resolve race between us and our isr */2401return wlc->macintstatus ? 0 : macintmask;2402}24032404void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)2405{2406struct brcms_hardware *wlc_hw = wlc->hw;2407if (!wlc_hw->clk)2408return;24092410wlc->macintmask = macintmask;2411bcma_write32(wlc_hw->d11core, D11REGOFFS(macintmask), wlc->macintmask);2412}24132414/* assumes that the d11 MAC is enabled */2415static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,2416uint tx_fifo)2417{2418u8 fifo = 1 << tx_fifo;24192420/* Two clients of this code, 11h Quiet period and scanning. */24212422/* only suspend if not already suspended */2423if ((wlc_hw->suspended_fifos & fifo) == fifo)2424return;24252426/* force the core awake only if not already */2427if (wlc_hw->suspended_fifos == 0)2428brcms_c_ucode_wake_override_set(wlc_hw,2429BRCMS_WAKE_OVERRIDE_TXFIFO);24302431wlc_hw->suspended_fifos |= fifo;24322433if (wlc_hw->di[tx_fifo]) {2434/*2435* Suspending AMPDU transmissions in the middle can cause2436* underflow which may result in mismatch between ucode and2437* driver so suspend the mac before suspending the FIFO2438*/2439if (BRCMS_PHY_11N_CAP(wlc_hw->band))2440brcms_c_suspend_mac_and_wait(wlc_hw->wlc);24412442dma_txsuspend(wlc_hw->di[tx_fifo]);24432444if (BRCMS_PHY_11N_CAP(wlc_hw->band))2445brcms_c_enable_mac(wlc_hw->wlc);2446}2447}24482449static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,2450uint tx_fifo)2451{2452/* BMAC_NOTE: BRCMS_TX_FIFO_ENAB is done in brcms_c_dpc() for DMA case2453* but need to be done here for PIO otherwise the watchdog will catch2454* the inconsistency and fire2455*/2456/* Two clients of this code, 11h Quiet period and scanning. */2457if (wlc_hw->di[tx_fifo])2458dma_txresume(wlc_hw->di[tx_fifo]);24592460/* allow core to sleep again */2461if (wlc_hw->suspended_fifos == 0)2462return;2463else {2464wlc_hw->suspended_fifos &= ~(1 << tx_fifo);2465if (wlc_hw->suspended_fifos == 0)2466brcms_c_ucode_wake_override_clear(wlc_hw,2467BRCMS_WAKE_OVERRIDE_TXFIFO);2468}2469}24702471/* precondition: requires the mac core to be enabled */2472static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)2473{2474static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};2475u8 *ethaddr = wlc_hw->wlc->pub->cur_etheraddr;24762477if (mute_tx) {2478/* suspend tx fifos */2479brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);2480brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);2481brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_BK_FIFO);2482brcms_b_tx_fifo_suspend(wlc_hw, TX_AC_VI_FIFO);24832484/* zero the address match register so we do not send ACKs */2485brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, null_ether_addr);2486} else {2487/* resume tx fifos */2488brcms_b_tx_fifo_resume(wlc_hw, TX_DATA_FIFO);2489brcms_b_tx_fifo_resume(wlc_hw, TX_CTL_FIFO);2490brcms_b_tx_fifo_resume(wlc_hw, TX_AC_BK_FIFO);2491brcms_b_tx_fifo_resume(wlc_hw, TX_AC_VI_FIFO);24922493/* Restore address */2494brcms_b_set_addrmatch(wlc_hw, RCM_MAC_OFFSET, ethaddr);2495}24962497wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);24982499if (mute_tx)2500brcms_c_ucode_mute_override_set(wlc_hw);2501else2502brcms_c_ucode_mute_override_clear(wlc_hw);2503}25042505void2506brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx)2507{2508brcms_b_mute(wlc->hw, mute_tx);2509}25102511/*2512* Read and clear macintmask and macintstatus and intstatus registers.2513* This routine should be called with interrupts off2514* Return:2515* -1 if brcms_deviceremoved(wlc) evaluates to true;2516* 0 if the interrupt is not for us, or we are in some special cases;2517* device interrupt status bits otherwise.2518*/2519static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)2520{2521struct brcms_hardware *wlc_hw = wlc->hw;2522struct bcma_device *core = wlc_hw->d11core;2523u32 macintstatus, mask;25242525/* macintstatus includes a DMA interrupt summary bit */2526macintstatus = bcma_read32(core, D11REGOFFS(macintstatus));2527mask = in_isr ? wlc->macintmask : wlc->defmacintmask;25282529trace_brcms_macintstatus(&core->dev, in_isr, macintstatus, mask);25302531/* detect cardbus removed, in power down(suspend) and in reset */2532if (brcms_deviceremoved(wlc))2533return -1;25342535/* brcms_deviceremoved() succeeds even when the core is still resetting,2536* handle that case here.2537*/2538if (macintstatus == 0xffffffff)2539return 0;25402541/* defer unsolicited interrupts */2542macintstatus &= mask;25432544/* if not for us */2545if (macintstatus == 0)2546return 0;25472548/* turn off the interrupts */2549bcma_write32(core, D11REGOFFS(macintmask), 0);2550(void)bcma_read32(core, D11REGOFFS(macintmask));2551wlc->macintmask = 0;25522553/* clear device interrupts */2554bcma_write32(core, D11REGOFFS(macintstatus), macintstatus);25552556/* MI_DMAINT is indication of non-zero intstatus */2557if (macintstatus & MI_DMAINT)2558/*2559* only fifo interrupt enabled is I_RI in2560* RX_FIFO. If MI_DMAINT is set, assume it2561* is set and clear the interrupt.2562*/2563bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intstatus),2564DEF_RXINTMASK);25652566return macintstatus;2567}25682569/* Update wlc->macintstatus and wlc->intstatus[]. */2570/* Return true if they are updated successfully. false otherwise */2571bool brcms_c_intrsupd(struct brcms_c_info *wlc)2572{2573u32 macintstatus;25742575/* read and clear macintstatus and intstatus registers */2576macintstatus = wlc_intstatus(wlc, false);25772578/* device is removed */2579if (macintstatus == 0xffffffff)2580return false;25812582/* update interrupt status in software */2583wlc->macintstatus |= macintstatus;25842585return true;2586}25872588/*2589* First-level interrupt processing.2590* Return true if this was our interrupt2591* and if further brcms_c_dpc() processing is required,2592* false otherwise.2593*/2594bool brcms_c_isr(struct brcms_c_info *wlc)2595{2596struct brcms_hardware *wlc_hw = wlc->hw;2597u32 macintstatus;25982599if (!wlc_hw->up || !wlc->macintmask)2600return false;26012602/* read and clear macintstatus and intstatus registers */2603macintstatus = wlc_intstatus(wlc, true);26042605if (macintstatus == 0xffffffff) {2606brcms_err(wlc_hw->d11core,2607"DEVICEREMOVED detected in the ISR code path\n");2608return false;2609}26102611/* it is not for us */2612if (macintstatus == 0)2613return false;26142615/* save interrupt status bits */2616wlc->macintstatus = macintstatus;26172618return true;26192620}26212622void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)2623{2624struct brcms_hardware *wlc_hw = wlc->hw;2625struct bcma_device *core = wlc_hw->d11core;2626u32 mc, mi;26272628brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit,2629wlc_hw->band->bandunit);26302631/*2632* Track overlapping suspend requests2633*/2634wlc_hw->mac_suspend_depth++;2635if (wlc_hw->mac_suspend_depth > 1)2636return;26372638/* force the core awake */2639brcms_c_ucode_wake_override_set(wlc_hw, BRCMS_WAKE_OVERRIDE_MACSUSPEND);26402641mc = bcma_read32(core, D11REGOFFS(maccontrol));26422643if (mc == 0xffffffff) {2644brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,2645__func__);2646brcms_down(wlc->wl);2647return;2648}2649WARN_ON(mc & MCTL_PSM_JMP_0);2650WARN_ON(!(mc & MCTL_PSM_RUN));2651WARN_ON(!(mc & MCTL_EN_MAC));26522653mi = bcma_read32(core, D11REGOFFS(macintstatus));2654if (mi == 0xffffffff) {2655brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,2656__func__);2657brcms_down(wlc->wl);2658return;2659}2660WARN_ON(mi & MI_MACSSPNDD);26612662brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, 0);26632664SPINWAIT(!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD),2665BRCMS_MAX_MAC_SUSPEND);26662667if (!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD)) {2668brcms_err(core, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"2669" and MI_MACSSPNDD is still not on.\n",2670wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);2671brcms_err(core, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "2672"psm_brc 0x%04x\n", wlc_hw->unit,2673bcma_read32(core, D11REGOFFS(psmdebug)),2674bcma_read32(core, D11REGOFFS(phydebug)),2675bcma_read16(core, D11REGOFFS(psm_brc)));2676}26772678mc = bcma_read32(core, D11REGOFFS(maccontrol));2679if (mc == 0xffffffff) {2680brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,2681__func__);2682brcms_down(wlc->wl);2683return;2684}2685WARN_ON(mc & MCTL_PSM_JMP_0);2686WARN_ON(!(mc & MCTL_PSM_RUN));2687WARN_ON(mc & MCTL_EN_MAC);2688}26892690void brcms_c_enable_mac(struct brcms_c_info *wlc)2691{2692struct brcms_hardware *wlc_hw = wlc->hw;2693struct bcma_device *core = wlc_hw->d11core;2694u32 mc, mi;26952696brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit,2697wlc->band->bandunit);26982699/*2700* Track overlapping suspend requests2701*/2702wlc_hw->mac_suspend_depth--;2703if (wlc_hw->mac_suspend_depth > 0)2704return;27052706mc = bcma_read32(core, D11REGOFFS(maccontrol));2707WARN_ON(mc & MCTL_PSM_JMP_0);2708WARN_ON(mc & MCTL_EN_MAC);2709WARN_ON(!(mc & MCTL_PSM_RUN));27102711brcms_b_mctrl(wlc_hw, MCTL_EN_MAC, MCTL_EN_MAC);2712bcma_write32(core, D11REGOFFS(macintstatus), MI_MACSSPNDD);27132714mc = bcma_read32(core, D11REGOFFS(maccontrol));2715WARN_ON(mc & MCTL_PSM_JMP_0);2716WARN_ON(!(mc & MCTL_EN_MAC));2717WARN_ON(!(mc & MCTL_PSM_RUN));27182719mi = bcma_read32(core, D11REGOFFS(macintstatus));2720WARN_ON(mi & MI_MACSSPNDD);27212722brcms_c_ucode_wake_override_clear(wlc_hw,2723BRCMS_WAKE_OVERRIDE_MACSUSPEND);2724}27252726void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)2727{2728wlc_hw->hw_stf_ss_opmode = stf_mode;27292730if (wlc_hw->clk)2731brcms_upd_ofdm_pctl1_table(wlc_hw);2732}27332734static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)2735{2736struct bcma_device *core = wlc_hw->d11core;2737u32 w, val;2738struct wiphy *wiphy = wlc_hw->wlc->wiphy;27392740/* Validate dchip register access */27412742bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);2743(void)bcma_read32(core, D11REGOFFS(objaddr));2744w = bcma_read32(core, D11REGOFFS(objdata));27452746/* Can we write and read back a 32bit register? */2747bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);2748(void)bcma_read32(core, D11REGOFFS(objaddr));2749bcma_write32(core, D11REGOFFS(objdata), (u32) 0xaa5555aa);27502751bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);2752(void)bcma_read32(core, D11REGOFFS(objaddr));2753val = bcma_read32(core, D11REGOFFS(objdata));2754if (val != (u32) 0xaa5555aa) {2755wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "2756"expected 0xaa5555aa\n", wlc_hw->unit, val);2757return false;2758}27592760bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);2761(void)bcma_read32(core, D11REGOFFS(objaddr));2762bcma_write32(core, D11REGOFFS(objdata), (u32) 0x55aaaa55);27632764bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);2765(void)bcma_read32(core, D11REGOFFS(objaddr));2766val = bcma_read32(core, D11REGOFFS(objdata));2767if (val != (u32) 0x55aaaa55) {2768wiphy_err(wiphy, "wl%d: validate_chip_access: SHM = 0x%x, "2769"expected 0x55aaaa55\n", wlc_hw->unit, val);2770return false;2771}27722773bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);2774(void)bcma_read32(core, D11REGOFFS(objaddr));2775bcma_write32(core, D11REGOFFS(objdata), w);27762777/* clear CFPStart */2778bcma_write32(core, D11REGOFFS(tsf_cfpstart), 0);27792780w = bcma_read32(core, D11REGOFFS(maccontrol));2781if ((w != (MCTL_IHR_EN | MCTL_WAKE)) &&2782(w != (MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE))) {2783wiphy_err(wiphy, "wl%d: validate_chip_access: maccontrol = "2784"0x%x, expected 0x%x or 0x%x\n", wlc_hw->unit, w,2785(MCTL_IHR_EN | MCTL_WAKE),2786(MCTL_IHR_EN | MCTL_GMODE | MCTL_WAKE));2787return false;2788}27892790return true;2791}27922793#define PHYPLL_WAIT_US 10000027942795void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)2796{2797struct bcma_device *core = wlc_hw->d11core;2798u32 tmp;27992800brcms_dbg_info(core, "wl%d\n", wlc_hw->unit);28012802tmp = 0;28032804if (on) {2805if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) {2806bcma_set32(core, D11REGOFFS(clk_ctl_st),2807CCS_ERSRC_REQ_HT |2808CCS_ERSRC_REQ_D11PLL |2809CCS_ERSRC_REQ_PHYPLL);2810SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) &2811CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT,2812PHYPLL_WAIT_US);28132814tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));2815if ((tmp & CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT)2816brcms_err(core, "%s: turn on PHY PLL failed\n",2817__func__);2818} else {2819bcma_set32(core, D11REGOFFS(clk_ctl_st),2820tmp | CCS_ERSRC_REQ_D11PLL |2821CCS_ERSRC_REQ_PHYPLL);2822SPINWAIT((bcma_read32(core, D11REGOFFS(clk_ctl_st)) &2823(CCS_ERSRC_AVAIL_D11PLL |2824CCS_ERSRC_AVAIL_PHYPLL)) !=2825(CCS_ERSRC_AVAIL_D11PLL |2826CCS_ERSRC_AVAIL_PHYPLL), PHYPLL_WAIT_US);28272828tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));2829if ((tmp &2830(CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))2831!=2832(CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))2833brcms_err(core, "%s: turn on PHY PLL failed\n",2834__func__);2835}2836} else {2837/*2838* Since the PLL may be shared, other cores can still2839* be requesting it; so we'll deassert the request but2840* not wait for status to comply.2841*/2842bcma_mask32(core, D11REGOFFS(clk_ctl_st),2843~CCS_ERSRC_REQ_PHYPLL);2844(void)bcma_read32(core, D11REGOFFS(clk_ctl_st));2845}2846}28472848static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)2849{2850bool dev_gone;28512852brcms_dbg_info(wlc_hw->d11core, "wl%d: disable core\n", wlc_hw->unit);28532854dev_gone = brcms_deviceremoved(wlc_hw->wlc);28552856if (dev_gone)2857return;28582859if (wlc_hw->noreset)2860return;28612862/* radio off */2863wlc_phy_switch_radio(wlc_hw->band->pi, OFF);28642865/* turn off analog core */2866wlc_phy_anacore(wlc_hw->band->pi, OFF);28672868/* turn off PHYPLL to save power */2869brcms_b_core_phypll_ctl(wlc_hw, false);28702871wlc_hw->clk = false;2872bcma_core_disable(wlc_hw->d11core, 0);2873wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);2874}28752876static void brcms_c_flushqueues(struct brcms_c_info *wlc)2877{2878struct brcms_hardware *wlc_hw = wlc->hw;2879uint i;28802881/* free any posted tx packets */2882for (i = 0; i < NFIFO; i++) {2883if (wlc_hw->di[i]) {2884dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);2885if (i < TX_BCMC_FIFO)2886ieee80211_wake_queue(wlc->pub->ieee_hw,2887brcms_fifo_to_ac(i));2888}2889}28902891/* free any posted rx packets */2892dma_rxreclaim(wlc_hw->di[RX_FIFO]);2893}28942895static u162896brcms_b_read_objmem(struct brcms_hardware *wlc_hw, uint offset, u32 sel)2897{2898struct bcma_device *core = wlc_hw->d11core;2899u16 objoff = D11REGOFFS(objdata);29002901bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2));2902(void)bcma_read32(core, D11REGOFFS(objaddr));2903if (offset & 2)2904objoff += 2;29052906return bcma_read16(core, objoff);2907}29082909static void2910brcms_b_write_objmem(struct brcms_hardware *wlc_hw, uint offset, u16 v,2911u32 sel)2912{2913struct bcma_device *core = wlc_hw->d11core;2914u16 objoff = D11REGOFFS(objdata);29152916bcma_write32(core, D11REGOFFS(objaddr), sel | (offset >> 2));2917(void)bcma_read32(core, D11REGOFFS(objaddr));2918if (offset & 2)2919objoff += 2;29202921bcma_wflush16(core, objoff, v);2922}29232924/*2925* Read a single u16 from shared memory.2926* SHM 'offset' needs to be an even address2927*/2928u16 brcms_b_read_shm(struct brcms_hardware *wlc_hw, uint offset)2929{2930return brcms_b_read_objmem(wlc_hw, offset, OBJADDR_SHM_SEL);2931}29322933/*2934* Write a single u16 to shared memory.2935* SHM 'offset' needs to be an even address2936*/2937void brcms_b_write_shm(struct brcms_hardware *wlc_hw, uint offset, u16 v)2938{2939brcms_b_write_objmem(wlc_hw, offset, v, OBJADDR_SHM_SEL);2940}29412942/*2943* Copy a buffer to shared memory of specified type .2944* SHM 'offset' needs to be an even address and2945* Buffer length 'len' must be an even number of bytes2946* 'sel' selects the type of memory2947*/2948void2949brcms_b_copyto_objmem(struct brcms_hardware *wlc_hw, uint offset,2950const void *buf, int len, u32 sel)2951{2952u16 v;2953const u8 *p = (const u8 *)buf;2954int i;29552956if (len <= 0 || (offset & 1) || (len & 1))2957return;29582959for (i = 0; i < len; i += 2) {2960v = p[i] | (p[i + 1] << 8);2961brcms_b_write_objmem(wlc_hw, offset + i, v, sel);2962}2963}29642965/*2966* Copy a piece of shared memory of specified type to a buffer .2967* SHM 'offset' needs to be an even address and2968* Buffer length 'len' must be an even number of bytes2969* 'sel' selects the type of memory2970*/2971void2972brcms_b_copyfrom_objmem(struct brcms_hardware *wlc_hw, uint offset, void *buf,2973int len, u32 sel)2974{2975u16 v;2976u8 *p = (u8 *) buf;2977int i;29782979if (len <= 0 || (offset & 1) || (len & 1))2980return;29812982for (i = 0; i < len; i += 2) {2983v = brcms_b_read_objmem(wlc_hw, offset + i, sel);2984p[i] = v & 0xFF;2985p[i + 1] = (v >> 8) & 0xFF;2986}2987}29882989/* Copy a buffer to shared memory.2990* SHM 'offset' needs to be an even address and2991* Buffer length 'len' must be an even number of bytes2992*/2993static void brcms_c_copyto_shm(struct brcms_c_info *wlc, uint offset,2994const void *buf, int len)2995{2996brcms_b_copyto_objmem(wlc->hw, offset, buf, len, OBJADDR_SHM_SEL);2997}29982999static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw,3000u16 SRL, u16 LRL)3001{3002wlc_hw->SRL = SRL;3003wlc_hw->LRL = LRL;30043005/* write retry limit to SCR, shouldn't need to suspend */3006if (wlc_hw->up) {3007bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),3008OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);3009(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));3010bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->SRL);3011bcma_write32(wlc_hw->d11core, D11REGOFFS(objaddr),3012OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);3013(void)bcma_read32(wlc_hw->d11core, D11REGOFFS(objaddr));3014bcma_write32(wlc_hw->d11core, D11REGOFFS(objdata), wlc_hw->LRL);3015}3016}30173018static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, u32 req_bit)3019{3020if (set) {3021if (mboolisset(wlc_hw->pllreq, req_bit))3022return;30233024mboolset(wlc_hw->pllreq, req_bit);30253026if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {3027if (!wlc_hw->sbclk)3028brcms_b_xtal(wlc_hw, ON);3029}3030} else {3031if (!mboolisset(wlc_hw->pllreq, req_bit))3032return;30333034mboolclr(wlc_hw->pllreq, req_bit);30353036if (mboolisset(wlc_hw->pllreq, BRCMS_PLLREQ_FLIP)) {3037if (wlc_hw->sbclk)3038brcms_b_xtal(wlc_hw, OFF);3039}3040}3041}30423043static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)3044{3045wlc_hw->antsel_avail = antsel_avail;3046}30473048/*3049* conditions under which the PM bit should be set in outgoing frames3050* and STAY_AWAKE is meaningful3051*/3052static bool brcms_c_ps_allowed(struct brcms_c_info *wlc)3053{3054/* not supporting PS so always return false for now */3055return false;3056}30573058static void brcms_c_statsupd(struct brcms_c_info *wlc)3059{3060int i;3061struct macstat *macstats;3062#ifdef DEBUG3063u16 delta;3064u16 rxf0ovfl;3065u16 txfunfl[NFIFO];3066#endif /* DEBUG */30673068/* if driver down, make no sense to update stats */3069if (!wlc->pub->up)3070return;30713072macstats = wlc->core->macstat_snapshot;30733074#ifdef DEBUG3075/* save last rx fifo 0 overflow count */3076rxf0ovfl = macstats->rxf0ovfl;30773078/* save last tx fifo underflow count */3079for (i = 0; i < NFIFO; i++)3080txfunfl[i] = macstats->txfunfl[i];3081#endif /* DEBUG */30823083/* Read mac stats from contiguous shared memory */3084brcms_b_copyfrom_objmem(wlc->hw, M_UCODE_MACSTAT, macstats,3085sizeof(*macstats), OBJADDR_SHM_SEL);30863087#ifdef DEBUG3088/* check for rx fifo 0 overflow */3089delta = (u16)(macstats->rxf0ovfl - rxf0ovfl);3090if (delta)3091brcms_err(wlc->hw->d11core, "wl%d: %u rx fifo 0 overflows!\n",3092wlc->pub->unit, delta);30933094/* check for tx fifo underflows */3095for (i = 0; i < NFIFO; i++) {3096delta = macstats->txfunfl[i] - txfunfl[i];3097if (delta)3098brcms_err(wlc->hw->d11core,3099"wl%d: %u tx fifo %d underflows!\n",3100wlc->pub->unit, delta, i);3101}3102#endif /* DEBUG */31033104/* merge counters from dma module */3105for (i = 0; i < NFIFO; i++) {3106if (wlc->hw->di[i])3107dma_counterreset(wlc->hw->di[i]);3108}3109}31103111static void brcms_b_reset(struct brcms_hardware *wlc_hw)3112{3113/* reset the core */3114if (!brcms_deviceremoved(wlc_hw->wlc))3115brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);31163117/* purge the dma rings */3118brcms_c_flushqueues(wlc_hw->wlc);3119}31203121void brcms_c_reset(struct brcms_c_info *wlc)3122{3123brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);31243125/* slurp up hw mac counters before core reset */3126brcms_c_statsupd(wlc);31273128/* reset our snapshot of macstat counters */3129memset(wlc->core->macstat_snapshot, 0, sizeof(struct macstat));31303131brcms_b_reset(wlc->hw);3132}31333134void brcms_c_init_scb(struct scb *scb)3135{3136int i;31373138memset(scb, 0, sizeof(struct scb));3139scb->flags = SCB_WMECAP | SCB_HTCAP;3140for (i = 0; i < NUMPRIO; i++) {3141scb->seqnum[i] = 0;3142}31433144scb->magic = SCB_MAGIC;3145}31463147/* d11 core init3148* reset PSM3149* download ucode/PCM3150* let ucode run to suspended3151* download ucode inits3152* config other core registers3153* init dma3154*/3155static void brcms_b_coreinit(struct brcms_c_info *wlc)3156{3157struct brcms_hardware *wlc_hw = wlc->hw;3158struct bcma_device *core = wlc_hw->d11core;3159u32 bcnint_us;3160uint i = 0;3161bool fifosz_fixup = false;3162int err = 0;3163u16 buf[NFIFO];3164struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;31653166brcms_dbg_info(core, "wl%d: core init\n", wlc_hw->unit);31673168/* reset PSM */3169brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));31703171brcms_ucode_download(wlc_hw);3172/*3173* FIFOSZ fixup. driver wants to controls the fifo allocation.3174*/3175fifosz_fixup = true;31763177/* let the PSM run to the suspended state, set mode to BSS STA */3178bcma_write32(core, D11REGOFFS(macintstatus), -1);3179brcms_b_mctrl(wlc_hw, ~0,3180(MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));31813182/* wait for ucode to self-suspend after auto-init */3183SPINWAIT(((bcma_read32(core, D11REGOFFS(macintstatus)) &3184MI_MACSSPNDD) == 0), 1000 * 1000);3185if ((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0)3186brcms_err(core, "wl%d: wlc_coreinit: ucode did not self-"3187"suspend!\n", wlc_hw->unit);31883189brcms_c_gpio_init(wlc);31903191bcma_aread32(core, BCMA_IOST);31923193if (D11REV_IS(wlc_hw->corerev, 17) || D11REV_IS(wlc_hw->corerev, 23)) {3194if (BRCMS_ISNPHY(wlc_hw->band))3195brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);3196else3197brcms_err(core, "%s: wl%d: unsupported phy in corerev"3198" %d\n", __func__, wlc_hw->unit,3199wlc_hw->corerev);3200} else if (D11REV_IS(wlc_hw->corerev, 24)) {3201if (BRCMS_ISLCNPHY(wlc_hw->band))3202brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24);3203else3204brcms_err(core, "%s: wl%d: unsupported phy in corerev"3205" %d\n", __func__, wlc_hw->unit,3206wlc_hw->corerev);3207} else {3208brcms_err(core, "%s: wl%d: unsupported corerev %d\n",3209__func__, wlc_hw->unit, wlc_hw->corerev);3210}32113212/* For old ucode, txfifo sizes needs to be modified(increased) */3213if (fifosz_fixup)3214brcms_b_corerev_fifofixup(wlc_hw);32153216/* check txfifo allocations match between ucode and driver */3217buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);3218if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {3219i = TX_AC_BE_FIFO;3220err = -1;3221}3222buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);3223if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {3224i = TX_AC_VI_FIFO;3225err = -1;3226}3227buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);3228buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;3229buf[TX_AC_BK_FIFO] &= 0xff;3230if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {3231i = TX_AC_BK_FIFO;3232err = -1;3233}3234if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {3235i = TX_AC_VO_FIFO;3236err = -1;3237}3238buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);3239buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;3240buf[TX_BCMC_FIFO] &= 0xff;3241if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {3242i = TX_BCMC_FIFO;3243err = -1;3244}3245if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {3246i = TX_ATIM_FIFO;3247err = -1;3248}3249if (err != 0)3250brcms_err(core, "wlc_coreinit: txfifo mismatch: ucode size %d"3251" driver size %d index %d\n", buf[i],3252wlc_hw->xmtfifo_sz[i], i);32533254/* make sure we can still talk to the mac */3255WARN_ON(bcma_read32(core, D11REGOFFS(maccontrol)) == 0xffffffff);32563257/* band-specific inits done by wlc_bsinit() */32583259/* Set up frame burst size and antenna swap threshold init values */3260brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);3261brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);32623263/* enable one rx interrupt per received frame */3264bcma_write32(core, D11REGOFFS(intrcvlazy[0]), (1 << IRL_FC_SHIFT));32653266/* set the station mode (BSS STA) */3267brcms_b_mctrl(wlc_hw,3268(MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),3269(MCTL_INFRA | MCTL_DISCARD_PMQ));32703271/* set up Beacon interval */3272bcnint_us = 0x8000 << 10;3273bcma_write32(core, D11REGOFFS(tsf_cfprep),3274(bcnint_us << CFPREP_CBI_SHIFT));3275bcma_write32(core, D11REGOFFS(tsf_cfpstart), bcnint_us);3276bcma_write32(core, D11REGOFFS(macintstatus), MI_GP1);32773278/* write interrupt mask */3279bcma_write32(core, D11REGOFFS(intctrlregs[RX_FIFO].intmask),3280DEF_RXINTMASK);32813282/* allow the MAC to control the PHY clock (dynamic on/off) */3283brcms_b_macphyclk_set(wlc_hw, ON);32843285/* program dynamic clock control fast powerup delay register */3286wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);3287bcma_write16(core, D11REGOFFS(scc_fastpwrup_dly), wlc->fastpwrup_dly);32883289/* tell the ucode the corerev */3290brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);32913292/* tell the ucode MAC capabilities */3293brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,3294(u16) (wlc_hw->machwcap & 0xffff));3295brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,3296(u16) ((wlc_hw->3297machwcap >> 16) & 0xffff));32983299/* write retry limits to SCR, this done after PSM init */3300bcma_write32(core, D11REGOFFS(objaddr),3301OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);3302(void)bcma_read32(core, D11REGOFFS(objaddr));3303bcma_write32(core, D11REGOFFS(objdata), wlc_hw->SRL);3304bcma_write32(core, D11REGOFFS(objaddr),3305OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);3306(void)bcma_read32(core, D11REGOFFS(objaddr));3307bcma_write32(core, D11REGOFFS(objdata), wlc_hw->LRL);33083309/* write rate fallback retry limits */3310brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);3311brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);33123313bcma_mask16(core, D11REGOFFS(ifs_ctl), 0x0FFF);3314bcma_write16(core, D11REGOFFS(ifs_aifsn), EDCF_AIFSN_MIN);33153316/* init the tx dma engines */3317for (i = 0; i < NFIFO; i++) {3318if (wlc_hw->di[i])3319dma_txinit(wlc_hw->di[i]);3320}33213322/* init the rx dma engine(s) and post receive buffers */3323dma_rxinit(wlc_hw->di[RX_FIFO]);3324dma_rxfill(wlc_hw->di[RX_FIFO]);3325}33263327static void brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec)3328{3329u32 macintmask;3330bool fastclk;3331struct brcms_c_info *wlc = wlc_hw->wlc;33323333/* request FAST clock if not on */3334fastclk = wlc_hw->forcefastclk;3335if (!fastclk)3336brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);33373338/* disable interrupts */3339macintmask = brcms_intrsoff(wlc->wl);33403341/* set up the specified band and chanspec */3342brcms_c_setxband(wlc_hw, chspec_bandunit(chanspec));3343wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);33443345/* do one-time phy inits and calibration */3346wlc_phy_cal_init(wlc_hw->band->pi);33473348/* core-specific initialization */3349brcms_b_coreinit(wlc);33503351/* band-specific inits */3352brcms_b_bsinit(wlc, chanspec);33533354/* restore macintmask */3355brcms_intrsrestore(wlc->wl, macintmask);33563357/* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac3358* is suspended and brcms_c_enable_mac() will clear this override bit.3359*/3360mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);33613362/*3363* initialize mac_suspend_depth to 1 to match ucode3364* initial suspended state3365*/3366wlc_hw->mac_suspend_depth = 1;33673368/* restore the clk */3369if (!fastclk)3370brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);3371}33723373static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,3374u16 chanspec)3375{3376/* Save our copy of the chanspec */3377wlc->chanspec = chanspec;33783379/* Set the chanspec and power limits for this locale */3380brcms_c_channel_set_chanspec(wlc->cmi, chanspec, BRCMS_TXPWR_MAX);33813382if (wlc->stf->ss_algosel_auto)3383brcms_c_stf_ss_algo_channel_get(wlc, &wlc->stf->ss_algo_channel,3384chanspec);33853386brcms_c_stf_ss_update(wlc, wlc->band);3387}33883389static void3390brcms_default_rateset(struct brcms_c_info *wlc, struct brcms_c_rateset *rs)3391{3392brcms_c_rateset_default(rs, NULL, wlc->band->phytype,3393wlc->band->bandtype, false, BRCMS_RATE_MASK_FULL,3394(bool) (wlc->pub->_n_enab & SUPPORT_11N),3395brcms_chspec_bw(wlc->default_bss->chanspec),3396wlc->stf->txstreams);3397}33983399/* derive wlc->band->basic_rate[] table from 'rateset' */3400static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,3401struct brcms_c_rateset *rateset)3402{3403u8 rate;3404u8 mandatory;3405u8 cck_basic = 0;3406u8 ofdm_basic = 0;3407u8 *br = wlc->band->basic_rate;3408uint i;34093410/* incoming rates are in 500kbps units as in 802.11 Supported Rates */3411memset(br, 0, BRCM_MAXRATE + 1);34123413/* For each basic rate in the rates list, make an entry in the3414* best basic lookup.3415*/3416for (i = 0; i < rateset->count; i++) {3417/* only make an entry for a basic rate */3418if (!(rateset->rates[i] & BRCMS_RATE_FLAG))3419continue;34203421/* mask off basic bit */3422rate = (rateset->rates[i] & BRCMS_RATE_MASK);34233424if (rate > BRCM_MAXRATE) {3425brcms_err(wlc->hw->d11core, "brcms_c_rate_lookup_init: "3426"invalid rate 0x%X in rate set\n",3427rateset->rates[i]);3428continue;3429}34303431br[rate] = rate;3432}34333434/* The rate lookup table now has non-zero entries for each3435* basic rate, equal to the basic rate: br[basicN] = basicN3436*3437* To look up the best basic rate corresponding to any3438* particular rate, code can use the basic_rate table3439* like this3440*3441* basic_rate = wlc->band->basic_rate[tx_rate]3442*3443* Make sure there is a best basic rate entry for3444* every rate by walking up the table from low rates3445* to high, filling in holes in the lookup table3446*/34473448for (i = 0; i < wlc->band->hw_rateset.count; i++) {3449rate = wlc->band->hw_rateset.rates[i];34503451if (br[rate] != 0) {3452/* This rate is a basic rate.3453* Keep track of the best basic rate so far by3454* modulation type.3455*/3456if (is_ofdm_rate(rate))3457ofdm_basic = rate;3458else3459cck_basic = rate;34603461continue;3462}34633464/* This rate is not a basic rate so figure out the3465* best basic rate less than this rate and fill in3466* the hole in the table3467*/34683469br[rate] = is_ofdm_rate(rate) ? ofdm_basic : cck_basic;34703471if (br[rate] != 0)3472continue;34733474if (is_ofdm_rate(rate)) {3475/*3476* In 11g and 11a, the OFDM mandatory rates3477* are 6, 12, and 24 Mbps3478*/3479if (rate >= BRCM_RATE_24M)3480mandatory = BRCM_RATE_24M;3481else if (rate >= BRCM_RATE_12M)3482mandatory = BRCM_RATE_12M;3483else3484mandatory = BRCM_RATE_6M;3485} else {3486/* In 11b, all CCK rates are mandatory 1 - 11 Mbps */3487mandatory = rate;3488}34893490br[rate] = mandatory;3491}3492}34933494static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,3495u16 chanspec)3496{3497struct brcms_c_rateset default_rateset;3498uint parkband;3499uint i, band_order[2];35003501/*3502* We might have been bandlocked during down and the chip3503* power-cycled (hibernate). Figure out the right band to park on3504*/3505if (wlc->bandlocked || wlc->pub->_nbands == 1) {3506/* updated in brcms_c_bandlock() */3507parkband = wlc->band->bandunit;3508band_order[0] = band_order[1] = parkband;3509} else {3510/* park on the band of the specified chanspec */3511parkband = chspec_bandunit(chanspec);35123513/* order so that parkband initialize last */3514band_order[0] = parkband ^ 1;3515band_order[1] = parkband;3516}35173518/* make each band operational, software state init */3519for (i = 0; i < wlc->pub->_nbands; i++) {3520uint j = band_order[i];35213522wlc->band = wlc->bandstate[j];35233524brcms_default_rateset(wlc, &default_rateset);35253526/* fill in hw_rate */3527brcms_c_rateset_filter(&default_rateset, &wlc->band->hw_rateset,3528false, BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,3529(bool) (wlc->pub->_n_enab & SUPPORT_11N));35303531/* init basic rate lookup */3532brcms_c_rate_lookup_init(wlc, &default_rateset);3533}35343535/* sync up phy/radio chanspec */3536brcms_c_set_phy_chanspec(wlc, chanspec);3537}35383539/*3540* Set or clear filtering related maccontrol bits based on3541* specified filter flags3542*/3543void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags)3544{3545u32 promisc_bits = 0;35463547wlc->filter_flags = filter_flags;35483549if (filter_flags & FIF_OTHER_BSS)3550promisc_bits |= MCTL_PROMISC;35513552if (filter_flags & FIF_BCN_PRBRESP_PROMISC)3553promisc_bits |= MCTL_BCNS_PROMISC;35543555if (filter_flags & FIF_FCSFAIL)3556promisc_bits |= MCTL_KEEPBADFCS;35573558if (filter_flags & (FIF_CONTROL | FIF_PSPOLL))3559promisc_bits |= MCTL_KEEPCONTROL;35603561brcms_b_mctrl(wlc->hw,3562MCTL_PROMISC | MCTL_BCNS_PROMISC |3563MCTL_KEEPCONTROL | MCTL_KEEPBADFCS,3564promisc_bits);3565}35663567/*3568* ucode, hwmac update3569* Channel dependent updates for ucode and hw3570*/3571static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)3572{3573/* enable or disable any active IBSSs depending on whether or not3574* we are on the home channel3575*/3576if (wlc->home_chanspec == wlc_phy_chanspec_get(wlc->band->pi)) {3577if (wlc->pub->associated) {3578/*3579* BMAC_NOTE: This is something that should be fixed3580* in ucode inits. I think that the ucode inits set3581* up the bcn templates and shm values with a bogus3582* beacon. This should not be done in the inits. If3583* ucode needs to set up a beacon for testing, the3584* test routines should write it down, not expect the3585* inits to populate a bogus beacon.3586*/3587if (BRCMS_PHY_11N_CAP(wlc->band))3588brcms_b_write_shm(wlc->hw,3589M_BCN_TXTSF_OFFSET, 0);3590}3591} else {3592/* disable an active IBSS if we are not on the home channel */3593}3594}35953596static void brcms_c_write_rate_shm(struct brcms_c_info *wlc, u8 rate,3597u8 basic_rate)3598{3599u8 phy_rate, index;3600u8 basic_phy_rate, basic_index;3601u16 dir_table, basic_table;3602u16 basic_ptr;36033604/* Shared memory address for the table we are reading */3605dir_table = is_ofdm_rate(basic_rate) ? M_RT_DIRMAP_A : M_RT_DIRMAP_B;36063607/* Shared memory address for the table we are writing */3608basic_table = is_ofdm_rate(rate) ? M_RT_BBRSMAP_A : M_RT_BBRSMAP_B;36093610/*3611* for a given rate, the LS-nibble of the PLCP SIGNAL field is3612* the index into the rate table.3613*/3614phy_rate = rate_info[rate] & BRCMS_RATE_MASK;3615basic_phy_rate = rate_info[basic_rate] & BRCMS_RATE_MASK;3616index = phy_rate & 0xf;3617basic_index = basic_phy_rate & 0xf;36183619/* Find the SHM pointer to the ACK rate entry by looking in the3620* Direct-map Table3621*/3622basic_ptr = brcms_b_read_shm(wlc->hw, (dir_table + basic_index * 2));36233624/* Update the SHM BSS-basic-rate-set mapping table with the pointer3625* to the correct basic rate for the given incoming rate3626*/3627brcms_b_write_shm(wlc->hw, (basic_table + index * 2), basic_ptr);3628}36293630static const struct brcms_c_rateset *3631brcms_c_rateset_get_hwrs(struct brcms_c_info *wlc)3632{3633const struct brcms_c_rateset *rs_dflt;36343635if (BRCMS_PHY_11N_CAP(wlc->band)) {3636if (wlc->band->bandtype == BRCM_BAND_5G)3637rs_dflt = &ofdm_mimo_rates;3638else3639rs_dflt = &cck_ofdm_mimo_rates;3640} else if (wlc->band->gmode)3641rs_dflt = &cck_ofdm_rates;3642else3643rs_dflt = &cck_rates;36443645return rs_dflt;3646}36473648static void brcms_c_set_ratetable(struct brcms_c_info *wlc)3649{3650const struct brcms_c_rateset *rs_dflt;3651struct brcms_c_rateset rs;3652u8 rate, basic_rate;3653uint i;36543655rs_dflt = brcms_c_rateset_get_hwrs(wlc);36563657brcms_c_rateset_copy(rs_dflt, &rs);3658brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);36593660/* walk the phy rate table and update SHM basic rate lookup table */3661for (i = 0; i < rs.count; i++) {3662rate = rs.rates[i] & BRCMS_RATE_MASK;36633664/* for a given rate brcms_basic_rate returns the rate at3665* which a response ACK/CTS should be sent.3666*/3667basic_rate = brcms_basic_rate(wlc, rate);3668if (basic_rate == 0)3669/* This should only happen if we are using a3670* restricted rateset.3671*/3672basic_rate = rs.rates[0] & BRCMS_RATE_MASK;36733674brcms_c_write_rate_shm(wlc, rate, basic_rate);3675}3676}36773678/* band-specific init */3679static void brcms_c_bsinit(struct brcms_c_info *wlc)3680{3681brcms_dbg_info(wlc->hw->d11core, "wl%d: bandunit %d\n",3682wlc->pub->unit, wlc->band->bandunit);36833684/* write ucode ACK/CTS rate table */3685brcms_c_set_ratetable(wlc);36863687/* update some band specific mac configuration */3688brcms_c_ucode_mac_upd(wlc);36893690/* init antenna selection */3691brcms_c_antsel_init(wlc->asi);36923693}36943695/* formula: IDLE_BUSY_RATIO_X_16 = (100-duty_cycle)/duty_cycle*16 */3696static int3697brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,3698bool writeToShm)3699{3700int idle_busy_ratio_x_16 = 0;3701uint offset =3702isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :3703M_TX_IDLE_BUSY_RATIO_X_16_CCK;3704if (duty_cycle > 100 || duty_cycle < 0) {3705brcms_err(wlc->hw->d11core,3706"wl%d: duty cycle value off limit\n",3707wlc->pub->unit);3708return -EINVAL;3709}3710if (duty_cycle)3711idle_busy_ratio_x_16 = (100 - duty_cycle) * 16 / duty_cycle;3712/* Only write to shared memory when wl is up */3713if (writeToShm)3714brcms_b_write_shm(wlc->hw, offset, (u16) idle_busy_ratio_x_16);37153716if (isOFDM)3717wlc->tx_duty_cycle_ofdm = (u16) duty_cycle;3718else3719wlc->tx_duty_cycle_cck = (u16) duty_cycle;37203721return 0;3722}37233724/* push sw hps and wake state through hardware */3725static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)3726{3727u32 v1, v2;3728bool hps;3729bool awake_before;37303731hps = brcms_c_ps_allowed(wlc);37323733brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,3734hps);37353736v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));3737v2 = MCTL_WAKE;3738if (hps)3739v2 |= MCTL_HPS;37403741brcms_b_mctrl(wlc->hw, MCTL_WAKE | MCTL_HPS, v2);37423743awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0));37443745if (!awake_before)3746brcms_b_wait_for_wake(wlc->hw);3747}37483749/*3750* Write this BSS config's MAC address to core.3751* Updates RXE match engine.3752*/3753static void brcms_c_set_mac(struct brcms_bss_cfg *bsscfg)3754{3755struct brcms_c_info *wlc = bsscfg->wlc;37563757/* enter the MAC addr into the RXE match registers */3758brcms_c_set_addrmatch(wlc, RCM_MAC_OFFSET, wlc->pub->cur_etheraddr);37593760brcms_c_ampdu_macaddr_upd(wlc);3761}37623763/* Write the BSS config's BSSID address to core (set_bssid in d11procs.tcl).3764* Updates RXE match engine.3765*/3766static void brcms_c_set_bssid(struct brcms_bss_cfg *bsscfg)3767{3768/* we need to update BSSID in RXE match registers */3769brcms_c_set_addrmatch(bsscfg->wlc, RCM_BSSID_OFFSET, bsscfg->BSSID);3770}37713772void brcms_c_set_ssid(struct brcms_c_info *wlc, u8 *ssid, size_t ssid_len)3773{3774u8 len = min_t(u8, sizeof(wlc->bsscfg->SSID), ssid_len);3775memset(wlc->bsscfg->SSID, 0, sizeof(wlc->bsscfg->SSID));37763777memcpy(wlc->bsscfg->SSID, ssid, len);3778wlc->bsscfg->SSID_len = len;3779}37803781static void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)3782{3783wlc_hw->shortslot = shortslot;37843785if (wlc_hw->band->bandtype == BRCM_BAND_2G && wlc_hw->up) {3786brcms_c_suspend_mac_and_wait(wlc_hw->wlc);3787brcms_b_update_slot_timing(wlc_hw, shortslot);3788brcms_c_enable_mac(wlc_hw->wlc);3789}3790}37913792/*3793* Suspend the MAC and update the slot timing3794* for standard 11b/g (20us slots) or shortslot 11g (9us slots).3795*/3796static void brcms_c_switch_shortslot(struct brcms_c_info *wlc, bool shortslot)3797{3798/* use the override if it is set */3799if (wlc->shortslot_override != BRCMS_SHORTSLOT_AUTO)3800shortslot = (wlc->shortslot_override == BRCMS_SHORTSLOT_ON);38013802if (wlc->shortslot == shortslot)3803return;38043805wlc->shortslot = shortslot;38063807brcms_b_set_shortslot(wlc->hw, shortslot);3808}38093810static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)3811{3812if (wlc->home_chanspec != chanspec) {3813wlc->home_chanspec = chanspec;38143815if (wlc->pub->associated)3816wlc->bsscfg->current_bss->chanspec = chanspec;3817}3818}38193820void3821brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,3822bool mute_tx, struct txpwr_limits *txpwr)3823{3824uint bandunit;38253826brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: 0x%x\n", wlc_hw->unit,3827chanspec);38283829wlc_hw->chanspec = chanspec;38303831/* Switch bands if necessary */3832if (wlc_hw->_nbands > 1) {3833bandunit = chspec_bandunit(chanspec);3834if (wlc_hw->band->bandunit != bandunit) {3835/* brcms_b_setband disables other bandunit,3836* use light band switch if not up yet3837*/3838if (wlc_hw->up) {3839wlc_phy_chanspec_radio_set(wlc_hw->3840bandstate[bandunit]->3841pi, chanspec);3842brcms_b_setband(wlc_hw, bandunit, chanspec);3843} else {3844brcms_c_setxband(wlc_hw, bandunit);3845}3846}3847}38483849wlc_phy_initcal_enable(wlc_hw->band->pi, !mute_tx);38503851if (!wlc_hw->up) {3852if (wlc_hw->clk)3853wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,3854chanspec);3855wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);3856} else {3857wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);3858wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);38593860/* Update muting of the channel */3861brcms_b_mute(wlc_hw, mute_tx);3862}3863}38643865/* switch to and initialize new band */3866static void brcms_c_setband(struct brcms_c_info *wlc,3867uint bandunit)3868{3869wlc->band = wlc->bandstate[bandunit];38703871if (!wlc->pub->up)3872return;38733874/* wait for at least one beacon before entering sleeping state */3875brcms_c_set_ps_ctrl(wlc);38763877/* band-specific initializations */3878brcms_c_bsinit(wlc);3879}38803881static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)3882{3883uint bandunit;3884u16 old_chanspec = wlc->chanspec;38853886if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) {3887brcms_err(wlc->hw->d11core, "wl%d: %s: Bad channel %d\n",3888wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec));3889return;3890}38913892/* Switch bands if necessary */3893if (wlc->pub->_nbands > 1) {3894bandunit = chspec_bandunit(chanspec);3895if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {3896if (wlc->bandlocked) {3897brcms_err(wlc->hw->d11core,3898"wl%d: %s: chspec %d band is locked!\n",3899wlc->pub->unit, __func__,3900CHSPEC_CHANNEL(chanspec));3901return;3902}3903/*3904* should the setband call come after the3905* brcms_b_chanspec() ? if the setband updates3906* (brcms_c_bsinit) use low level calls to inspect and3907* set state, the state inspected may be from the wrong3908* band, or the following brcms_b_set_chanspec() may3909* undo the work.3910*/3911brcms_c_setband(wlc, bandunit);3912}3913}39143915/* sync up phy/radio chanspec */3916brcms_c_set_phy_chanspec(wlc, chanspec);39173918/* init antenna selection */3919if (brcms_chspec_bw(old_chanspec) != brcms_chspec_bw(chanspec)) {3920brcms_c_antsel_init(wlc->asi);39213922/* Fix the hardware rateset based on bw.3923* Mainly add MCS32 for 40Mhz, remove MCS 32 for 20Mhz3924*/3925brcms_c_rateset_bw_mcs_filter(&wlc->band->hw_rateset,3926wlc->band->mimo_cap_40 ? brcms_chspec_bw(chanspec) : 0);3927}39283929/* update some mac configuration since chanspec changed */3930brcms_c_ucode_mac_upd(wlc);3931}39323933/*3934* This function changes the phytxctl for beacon based on current3935* beacon ratespec AND txant setting as per this table:3936* ratespec CCK ant = wlc->stf->txant3937* OFDM ant = 33938*/3939void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,3940u32 bcn_rspec)3941{3942u16 phyctl;3943u16 phytxant = wlc->stf->phytxant;3944u16 mask = PHY_TXC_ANT_MASK;39453946/* for non-siso rates or default setting, use the available chains */3947if (BRCMS_PHY_11N_CAP(wlc->band))3948phytxant = brcms_c_stf_phytxchain_sel(wlc, bcn_rspec);39493950phyctl = brcms_b_read_shm(wlc->hw, M_BCN_PCTLWD);3951phyctl = (phyctl & ~mask) | phytxant;3952brcms_b_write_shm(wlc->hw, M_BCN_PCTLWD, phyctl);3953}39543955/*3956* centralized protection config change function to simplify debugging, no3957* consistency checking this should be called only on changes to avoid overhead3958* in periodic function3959*/3960void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)3961{3962/*3963* Cannot use brcms_dbg_* here because this function is called3964* before wlc is sufficiently initialized.3965*/3966BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val);39673968switch (idx) {3969case BRCMS_PROT_G_SPEC:3970wlc->protection->_g = (bool) val;3971break;3972case BRCMS_PROT_G_OVR:3973wlc->protection->g_override = (s8) val;3974break;3975case BRCMS_PROT_G_USER:3976wlc->protection->gmode_user = (u8) val;3977break;3978case BRCMS_PROT_OVERLAP:3979wlc->protection->overlap = (s8) val;3980break;3981case BRCMS_PROT_N_USER:3982wlc->protection->nmode_user = (s8) val;3983break;3984case BRCMS_PROT_N_CFG:3985wlc->protection->n_cfg = (s8) val;3986break;3987case BRCMS_PROT_N_CFG_OVR:3988wlc->protection->n_cfg_override = (s8) val;3989break;3990case BRCMS_PROT_N_NONGF:3991wlc->protection->nongf = (bool) val;3992break;3993case BRCMS_PROT_N_NONGF_OVR:3994wlc->protection->nongf_override = (s8) val;3995break;3996case BRCMS_PROT_N_PAM_OVR:3997wlc->protection->n_pam_override = (s8) val;3998break;3999case BRCMS_PROT_N_OBSS:4000wlc->protection->n_obss = (bool) val;4001break;40024003default:4004break;4005}40064007}40084009static void brcms_c_ht_update_sgi_rx(struct brcms_c_info *wlc, int val)4010{4011if (wlc->pub->up) {4012brcms_c_update_beacon(wlc);4013brcms_c_update_probe_resp(wlc, true);4014}4015}40164017static void brcms_c_ht_update_ldpc(struct brcms_c_info *wlc, s8 val)4018{4019wlc->stf->ldpc = val;40204021if (wlc->pub->up) {4022brcms_c_update_beacon(wlc);4023brcms_c_update_probe_resp(wlc, true);4024wlc_phy_ldpc_override_set(wlc->band->pi, (val ? true : false));4025}4026}40274028void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,4029const struct ieee80211_tx_queue_params *params,4030bool suspend)4031{4032int i;4033struct shm_acparams acp_shm;4034u16 *shm_entry;40354036/* Only apply params if the core is out of reset and has clocks */4037if (!wlc->clk) {4038brcms_err(wlc->hw->d11core, "wl%d: %s : no-clock\n",4039wlc->pub->unit, __func__);4040return;4041}40424043memset(&acp_shm, 0, sizeof(struct shm_acparams));4044/* fill in shm ac params struct */4045acp_shm.txop = params->txop;4046/* convert from units of 32us to us for ucode */4047wlc->edcf_txop[aci & 0x3] = acp_shm.txop =4048EDCF_TXOP2USEC(acp_shm.txop);4049acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);40504051if (aci == IEEE80211_AC_VI && acp_shm.txop == 04052&& acp_shm.aifs < EDCF_AIFSN_MAX)4053acp_shm.aifs++;40544055if (acp_shm.aifs < EDCF_AIFSN_MIN4056|| acp_shm.aifs > EDCF_AIFSN_MAX) {4057brcms_err(wlc->hw->d11core, "wl%d: edcf_setparams: bad "4058"aifs %d\n", wlc->pub->unit, acp_shm.aifs);4059} else {4060acp_shm.cwmin = params->cw_min;4061acp_shm.cwmax = params->cw_max;4062acp_shm.cwcur = acp_shm.cwmin;4063acp_shm.bslots =4064bcma_read16(wlc->hw->d11core, D11REGOFFS(tsf_random)) &4065acp_shm.cwcur;4066acp_shm.reggap = acp_shm.bslots + acp_shm.aifs;4067/* Indicate the new params to the ucode */4068acp_shm.status = brcms_b_read_shm(wlc->hw, (M_EDCF_QINFO +4069wme_ac2fifo[aci] *4070M_EDCF_QLEN +4071M_EDCF_STATUS_OFF));4072acp_shm.status |= WME_STATUS_NEWAC;40734074/* Fill in shm acparam table */4075shm_entry = (u16 *) &acp_shm;4076for (i = 0; i < (int)sizeof(struct shm_acparams); i += 2)4077brcms_b_write_shm(wlc->hw,4078M_EDCF_QINFO +4079wme_ac2fifo[aci] * M_EDCF_QLEN + i,4080*shm_entry++);4081}40824083if (suspend)4084brcms_c_suspend_mac_and_wait(wlc);40854086brcms_c_update_beacon(wlc);4087brcms_c_update_probe_resp(wlc, false);40884089if (suspend)4090brcms_c_enable_mac(wlc);4091}40924093static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)4094{4095u16 aci;4096int i_ac;4097struct ieee80211_tx_queue_params txq_pars;4098static const struct edcf_acparam default_edcf_acparams[] = {4099{EDCF_AC_BE_ACI_STA, EDCF_AC_BE_ECW_STA, EDCF_AC_BE_TXOP_STA},4100{EDCF_AC_BK_ACI_STA, EDCF_AC_BK_ECW_STA, EDCF_AC_BK_TXOP_STA},4101{EDCF_AC_VI_ACI_STA, EDCF_AC_VI_ECW_STA, EDCF_AC_VI_TXOP_STA},4102{EDCF_AC_VO_ACI_STA, EDCF_AC_VO_ECW_STA, EDCF_AC_VO_TXOP_STA}4103}; /* ucode needs these parameters during its initialization */4104const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];41054106for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) {4107/* find out which ac this set of params applies to */4108aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;41094110/* fill in shm ac params struct */4111txq_pars.txop = edcf_acp->TXOP;4112txq_pars.aifs = edcf_acp->ACI;41134114/* CWmin = 2^(ECWmin) - 1 */4115txq_pars.cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);4116/* CWmax = 2^(ECWmax) - 1 */4117txq_pars.cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)4118>> EDCF_ECWMAX_SHIFT);4119brcms_c_wme_setparams(wlc, aci, &txq_pars, suspend);4120}41214122if (suspend) {4123brcms_c_suspend_mac_and_wait(wlc);4124brcms_c_enable_mac(wlc);4125}4126}41274128static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)4129{4130/* Don't start the timer if HWRADIO feature is disabled */4131if (wlc->radio_monitor)4132return;41334134wlc->radio_monitor = true;4135brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_RADIO_MON);4136brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);4137}41384139static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)4140{4141if (!wlc->radio_monitor)4142return true;41434144wlc->radio_monitor = false;4145brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_RADIO_MON);4146return brcms_del_timer(wlc->radio_timer);4147}41484149/* read hwdisable state and propagate to wlc flag */4150static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)4151{4152if (wlc->pub->hw_off)4153return;41544155if (brcms_b_radio_read_hwdisabled(wlc->hw))4156mboolset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);4157else4158mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);4159}41604161/* update hwradio status and return it */4162bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)4163{4164brcms_c_radio_hwdisable_upd(wlc);41654166return mboolisset(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE) ?4167true : false;4168}41694170/* periodical query hw radio button while driver is "down" */4171static void brcms_c_radio_timer(void *arg)4172{4173struct brcms_c_info *wlc = (struct brcms_c_info *) arg;41744175if (brcms_deviceremoved(wlc)) {4176brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n",4177wlc->pub->unit, __func__);4178brcms_down(wlc->wl);4179return;4180}41814182brcms_c_radio_hwdisable_upd(wlc);4183}41844185/* common low-level watchdog code */4186static void brcms_b_watchdog(struct brcms_c_info *wlc)4187{4188struct brcms_hardware *wlc_hw = wlc->hw;41894190if (!wlc_hw->up)4191return;41924193/* increment second count */4194wlc_hw->now++;41954196/* Check for FIFO error interrupts */4197brcms_b_fifoerrors(wlc_hw);41984199/* make sure RX dma has buffers */4200dma_rxfill(wlc->hw->di[RX_FIFO]);42014202wlc_phy_watchdog(wlc_hw->band->pi);4203}42044205/* common watchdog code */4206static void brcms_c_watchdog(struct brcms_c_info *wlc)4207{4208brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);42094210if (!wlc->pub->up)4211return;42124213if (brcms_deviceremoved(wlc)) {4214brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n",4215wlc->pub->unit, __func__);4216brcms_down(wlc->wl);4217return;4218}42194220/* increment second count */4221wlc->pub->now++;42224223brcms_c_radio_hwdisable_upd(wlc);4224/* if radio is disable, driver may be down, quit here */4225if (wlc->pub->radio_disabled)4226return;42274228brcms_b_watchdog(wlc);42294230/*4231* occasionally sample mac stat counters to4232* detect 16-bit counter wrap4233*/4234if ((wlc->pub->now % SW_TIMER_MAC_STAT_UPD) == 0)4235brcms_c_statsupd(wlc);42364237if (BRCMS_ISNPHY(wlc->band) &&4238((wlc->pub->now - wlc->tempsense_lasttime) >=4239BRCMS_TEMPSENSE_PERIOD)) {4240wlc->tempsense_lasttime = wlc->pub->now;4241brcms_c_tempsense_upd(wlc);4242}4243}42444245static void brcms_c_watchdog_by_timer(void *arg)4246{4247struct brcms_c_info *wlc = (struct brcms_c_info *) arg;42484249brcms_c_watchdog(wlc);4250}42514252static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)4253{4254wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,4255wlc, "watchdog");4256if (!wlc->wdtimer) {4257wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer "4258"failed\n", unit);4259goto fail;4260}42614262wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,4263wlc, "radio");4264if (!wlc->radio_timer) {4265wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer "4266"failed\n", unit);4267goto fail;4268}42694270return true;42714272fail:4273return false;4274}42754276/*4277* Initialize brcms_c_info default values ...4278* may get overrides later in this function4279*/4280static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)4281{4282int i;42834284/* Save our copy of the chanspec */4285wlc->chanspec = ch20mhz_chspec(1);42864287/* various 802.11g modes */4288wlc->shortslot = false;4289wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;42904291brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);4292brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);42934294brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,4295BRCMS_PROTECTION_AUTO);4296brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);4297brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,4298BRCMS_PROTECTION_AUTO);4299brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);4300brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);43014302brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,4303BRCMS_PROTECTION_CTL_OVERLAP);43044305/* 802.11g draft 4.0 NonERP elt advertisement */4306wlc->include_legacy_erp = true;43074308wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;4309wlc->stf->txant = ANT_TX_DEF;43104311wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;43124313wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;4314for (i = 0; i < NFIFO; i++)4315wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN;4316wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;43174318/* default rate fallback retry limits */4319wlc->SFBL = RETRY_SHORT_FB;4320wlc->LFBL = RETRY_LONG_FB;43214322/* default mac retry limits */4323wlc->SRL = RETRY_SHORT_DEF;4324wlc->LRL = RETRY_LONG_DEF;43254326/* WME QoS mode is Auto by default */4327wlc->pub->_ampdu = AMPDU_AGG_HOST;4328}43294330static uint brcms_c_attach_module(struct brcms_c_info *wlc)4331{4332uint err = 0;4333uint unit;4334unit = wlc->pub->unit;43354336wlc->asi = brcms_c_antsel_attach(wlc);4337if (wlc->asi == NULL) {4338wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach "4339"failed\n", unit);4340err = 44;4341goto fail;4342}43434344wlc->ampdu = brcms_c_ampdu_attach(wlc);4345if (wlc->ampdu == NULL) {4346wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach "4347"failed\n", unit);4348err = 50;4349goto fail;4350}43514352if ((brcms_c_stf_attach(wlc) != 0)) {4353wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach "4354"failed\n", unit);4355err = 68;4356goto fail;4357}4358fail:4359return err;4360}43614362struct brcms_pub *brcms_c_pub(struct brcms_c_info *wlc)4363{4364return wlc->pub;4365}43664367/* low level attach4368* run backplane attach, init nvram4369* run phy attach4370* initialize software state for each core and band4371* put the whole chip in reset(driver down state), no clock4372*/4373static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,4374uint unit, bool piomode)4375{4376struct brcms_hardware *wlc_hw;4377uint err = 0;4378uint j;4379bool wme = false;4380struct shared_phy_params sha_params;4381struct wiphy *wiphy = wlc->wiphy;4382struct pci_dev *pcidev = core->bus->host_pci;4383struct ssb_sprom *sprom = &core->bus->sprom;43844385if (core->bus->hosttype == BCMA_HOSTTYPE_PCI)4386brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit,4387pcidev->vendor,4388pcidev->device);4389else4390brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit,4391core->bus->boardinfo.vendor,4392core->bus->boardinfo.type);43934394wme = true;43954396wlc_hw = wlc->hw;4397wlc_hw->wlc = wlc;4398wlc_hw->unit = unit;4399wlc_hw->band = wlc_hw->bandstate[0];4400wlc_hw->_piomode = piomode;44014402/* populate struct brcms_hardware with default values */4403brcms_b_info_init(wlc_hw);44044405/*4406* Do the hardware portion of the attach. Also initialize software4407* state that depends on the particular hardware we are running.4408*/4409wlc_hw->sih = ai_attach(core->bus);4410if (wlc_hw->sih == NULL) {4411wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",4412unit);4413err = 11;4414goto fail;4415}44164417/* verify again the device is supported */4418if (!brcms_c_chipmatch(core)) {4419wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported device\n",4420unit);4421err = 12;4422goto fail;4423}44244425if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {4426wlc_hw->vendorid = pcidev->vendor;4427wlc_hw->deviceid = pcidev->device;4428} else {4429wlc_hw->vendorid = core->bus->boardinfo.vendor;4430wlc_hw->deviceid = core->bus->boardinfo.type;4431}44324433wlc_hw->d11core = core;4434wlc_hw->corerev = core->id.rev;44354436/* validate chip, chiprev and corerev */4437if (!brcms_c_isgoodchip(wlc_hw)) {4438err = 13;4439goto fail;4440}44414442/* initialize power control registers */4443ai_clkctl_init(wlc_hw->sih);44444445/* request fastclock and force fastclock for the rest of attach4446* bring the d11 core out of reset.4447* For PMU chips, the first wlc_clkctl_clk is no-op since core-clk4448* is still false; But it will be called again inside wlc_corereset,4449* after d11 is out of reset.4450*/4451brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);4452brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);44534454if (!brcms_b_validate_chip_access(wlc_hw)) {4455wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "4456"failed\n", unit);4457err = 14;4458goto fail;4459}44604461/* get the board rev, used just below */4462j = sprom->board_rev;4463/* promote srom boardrev of 0xFF to 1 */4464if (j == BOARDREV_PROMOTABLE)4465j = BOARDREV_PROMOTED;4466wlc_hw->boardrev = (u16) j;4467if (!brcms_c_validboardtype(wlc_hw)) {4468wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "4469"board type (0x%x)" " or revision level (0x%x)\n",4470unit, ai_get_boardtype(wlc_hw->sih),4471wlc_hw->boardrev);4472err = 15;4473goto fail;4474}4475wlc_hw->sromrev = sprom->revision;4476wlc_hw->boardflags = sprom->boardflags_lo + (sprom->boardflags_hi << 16);4477wlc_hw->boardflags2 = sprom->boardflags2_lo + (sprom->boardflags2_hi << 16);44784479if (wlc_hw->boardflags & BFL_NOPLLDOWN)4480brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);44814482/* check device id(srom, nvram etc.) to set bands */4483if (wlc_hw->deviceid == BCM43224_D11N_ID ||4484wlc_hw->deviceid == BCM43224_D11N_ID_VEN1 ||4485wlc_hw->deviceid == BCM43224_CHIP_ID)4486/* Dualband boards */4487wlc_hw->_nbands = 2;4488else4489wlc_hw->_nbands = 1;44904491if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225))4492wlc_hw->_nbands = 1;44934494/* BMAC_NOTE: remove init of pub values when brcms_c_attach()4495* unconditionally does the init of these values4496*/4497wlc->vendorid = wlc_hw->vendorid;4498wlc->deviceid = wlc_hw->deviceid;4499wlc->pub->sih = wlc_hw->sih;4500wlc->pub->corerev = wlc_hw->corerev;4501wlc->pub->sromrev = wlc_hw->sromrev;4502wlc->pub->boardrev = wlc_hw->boardrev;4503wlc->pub->boardflags = wlc_hw->boardflags;4504wlc->pub->boardflags2 = wlc_hw->boardflags2;4505wlc->pub->_nbands = wlc_hw->_nbands;45064507wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);45084509if (wlc_hw->physhim == NULL) {4510wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "4511"failed\n", unit);4512err = 25;4513goto fail;4514}45154516/* pass all the parameters to wlc_phy_shared_attach in one struct */4517sha_params.sih = wlc_hw->sih;4518sha_params.physhim = wlc_hw->physhim;4519sha_params.unit = unit;4520sha_params.corerev = wlc_hw->corerev;4521sha_params.vid = wlc_hw->vendorid;4522sha_params.did = wlc_hw->deviceid;4523sha_params.chip = ai_get_chip_id(wlc_hw->sih);4524sha_params.chiprev = ai_get_chiprev(wlc_hw->sih);4525sha_params.chippkg = ai_get_chippkg(wlc_hw->sih);4526sha_params.sromrev = wlc_hw->sromrev;4527sha_params.boardtype = ai_get_boardtype(wlc_hw->sih);4528sha_params.boardrev = wlc_hw->boardrev;4529sha_params.boardflags = wlc_hw->boardflags;4530sha_params.boardflags2 = wlc_hw->boardflags2;45314532/* alloc and save pointer to shared phy state area */4533wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);4534if (!wlc_hw->phy_sh) {4535err = 16;4536goto fail;4537}45384539/* initialize software state for each core and band */4540for (j = 0; j < wlc_hw->_nbands; j++) {4541/*4542* band0 is always 2.4Ghz4543* band1, if present, is 5Ghz4544*/45454546brcms_c_setxband(wlc_hw, j);45474548wlc_hw->band->bandunit = j;4549wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;4550wlc->band->bandunit = j;4551wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;4552wlc->core->coreidx = core->core_index;45534554wlc_hw->machwcap = bcma_read32(core, D11REGOFFS(machwcap));4555wlc_hw->machwcap_backup = wlc_hw->machwcap;45564557/* init tx fifo size */4558WARN_ON(wlc_hw->corerev < XMTFIFOTBL_STARTREV ||4559(wlc_hw->corerev - XMTFIFOTBL_STARTREV) >4560ARRAY_SIZE(xmtfifo_sz));4561wlc_hw->xmtfifo_sz =4562xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];4563WARN_ON(!wlc_hw->xmtfifo_sz[0]);45644565/* Get a phy for this band */4566wlc_hw->band->pi =4567wlc_phy_attach(wlc_hw->phy_sh, core,4568wlc_hw->band->bandtype,4569wlc->wiphy);4570if (wlc_hw->band->pi == NULL) {4571wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"4572"attach failed\n", unit);4573err = 17;4574goto fail;4575}45764577wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);45784579wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,4580&wlc_hw->band->phyrev,4581&wlc_hw->band->radioid,4582&wlc_hw->band->radiorev);4583wlc_hw->band->abgphy_encore =4584wlc_phy_get_encore(wlc_hw->band->pi);4585wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);4586wlc_hw->band->core_flags =4587wlc_phy_get_coreflags(wlc_hw->band->pi);45884589/* verify good phy_type & supported phy revision */4590if (BRCMS_ISNPHY(wlc_hw->band)) {4591if (NCONF_HAS(wlc_hw->band->phyrev))4592goto good_phy;4593else4594goto bad_phy;4595} else if (BRCMS_ISLCNPHY(wlc_hw->band)) {4596if (LCNCONF_HAS(wlc_hw->band->phyrev))4597goto good_phy;4598else4599goto bad_phy;4600} else {4601bad_phy:4602wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "4603"phy type/rev (%d/%d)\n", unit,4604wlc_hw->band->phytype, wlc_hw->band->phyrev);4605err = 18;4606goto fail;4607}46084609good_phy:4610/*4611* BMAC_NOTE: wlc->band->pi should not be set below and should4612* be done in the high level attach. However we can not make4613* that change until all low level access is changed to4614* wlc_hw->band->pi. Instead do the wlc->band->pi init below,4615* keeping wlc_hw->band->pi as well for incremental update of4616* low level fns, and cut over low only init when all fns4617* updated.4618*/4619wlc->band->pi = wlc_hw->band->pi;4620wlc->band->phytype = wlc_hw->band->phytype;4621wlc->band->phyrev = wlc_hw->band->phyrev;4622wlc->band->radioid = wlc_hw->band->radioid;4623wlc->band->radiorev = wlc_hw->band->radiorev;4624brcms_dbg_info(core, "wl%d: phy %u/%u radio %x/%u\n", unit,4625wlc->band->phytype, wlc->band->phyrev,4626wlc->band->radioid, wlc->band->radiorev);4627/* default contention windows size limits */4628wlc_hw->band->CWmin = APHY_CWMIN;4629wlc_hw->band->CWmax = PHY_CWMAX;46304631if (!brcms_b_attach_dmapio(wlc, j, wme)) {4632err = 19;4633goto fail;4634}4635}46364637/* disable core to match driver "down" state */4638brcms_c_coredisable(wlc_hw);46394640/* Match driver "down" state */4641bcma_host_pci_down(wlc_hw->d11core->bus);46424643/* turn off pll and xtal to match driver "down" state */4644brcms_b_xtal(wlc_hw, OFF);46454646/* *******************************************************************4647* The hardware is in the DOWN state at this point. D11 core4648* or cores are in reset with clocks off, and the board PLLs4649* are off if possible.4650*4651* Beyond this point, wlc->sbclk == false and chip registers4652* should not be touched.4653*********************************************************************4654*/46554656/* init etheraddr state variables */4657brcms_c_get_macaddr(wlc_hw, wlc_hw->etheraddr);46584659if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||4660is_zero_ether_addr(wlc_hw->etheraddr)) {4661wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr\n",4662unit);4663err = 22;4664goto fail;4665}46664667brcms_dbg_info(wlc_hw->d11core, "deviceid 0x%x nbands %d board 0x%x\n",4668wlc_hw->deviceid, wlc_hw->_nbands,4669ai_get_boardtype(wlc_hw->sih));46704671return err;46724673fail:4674wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,4675err);4676return err;4677}46784679static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)4680{4681int aa;4682uint unit;4683int bandtype;4684struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;46854686unit = wlc->pub->unit;4687bandtype = wlc->band->bandtype;46884689/* get antennas available */4690if (bandtype == BRCM_BAND_5G)4691aa = sprom->ant_available_a;4692else4693aa = sprom->ant_available_bg;46944695if ((aa < 1) || (aa > 15)) {4696wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"4697" srom (0x%x), using 3\n", unit, __func__, aa);4698aa = 3;4699}47004701/* reset the defaults if we have a single antenna */4702if (aa == 1) {4703wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_0;4704wlc->stf->txant = ANT_TX_FORCE_0;4705} else if (aa == 2) {4706wlc->stf->ant_rx_ovr = ANT_RX_DIV_FORCE_1;4707wlc->stf->txant = ANT_TX_FORCE_1;4708} else {4709}47104711/* Compute Antenna Gain */4712if (bandtype == BRCM_BAND_5G)4713wlc->band->antgain = sprom->antenna_gain.a1;4714else4715wlc->band->antgain = sprom->antenna_gain.a0;47164717return true;4718}47194720static void brcms_c_bss_default_init(struct brcms_c_info *wlc)4721{4722u16 chanspec;4723struct brcms_band *band;4724struct brcms_bss_info *bi = wlc->default_bss;47254726/* init default and target BSS with some sane initial values */4727memset(bi, 0, sizeof(*bi));4728bi->beacon_period = BEACON_INTERVAL_DEFAULT;47294730/* fill the default channel as the first valid channel4731* starting from the 2G channels4732*/4733chanspec = ch20mhz_chspec(1);4734wlc->home_chanspec = bi->chanspec = chanspec;47354736/* find the band of our default channel */4737band = wlc->band;4738if (wlc->pub->_nbands > 1 &&4739band->bandunit != chspec_bandunit(chanspec))4740band = wlc->bandstate[OTHERBANDUNIT(wlc)];47414742/* init bss rates to the band specific default rate set */4743brcms_c_rateset_default(&bi->rateset, NULL, band->phytype,4744band->bandtype, false, BRCMS_RATE_MASK_FULL,4745(bool) (wlc->pub->_n_enab & SUPPORT_11N),4746brcms_chspec_bw(chanspec), wlc->stf->txstreams);47474748if (wlc->pub->_n_enab & SUPPORT_11N)4749bi->flags |= BRCMS_BSS_HT;4750}47514752static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)4753{4754uint i;4755struct brcms_band *band;47564757for (i = 0; i < wlc->pub->_nbands; i++) {4758band = wlc->bandstate[i];4759if (band->bandtype == BRCM_BAND_5G) {4760if ((bwcap == BRCMS_N_BW_40ALL)4761|| (bwcap == BRCMS_N_BW_20IN2G_40IN5G))4762band->mimo_cap_40 = true;4763else4764band->mimo_cap_40 = false;4765} else {4766if (bwcap == BRCMS_N_BW_40ALL)4767band->mimo_cap_40 = true;4768else4769band->mimo_cap_40 = false;4770}4771}4772}47734774static void brcms_c_timers_deinit(struct brcms_c_info *wlc)4775{4776/* free timer state */4777if (wlc->wdtimer) {4778brcms_free_timer(wlc->wdtimer);4779wlc->wdtimer = NULL;4780}4781if (wlc->radio_timer) {4782brcms_free_timer(wlc->radio_timer);4783wlc->radio_timer = NULL;4784}4785}47864787static void brcms_c_detach_module(struct brcms_c_info *wlc)4788{4789if (wlc->asi) {4790brcms_c_antsel_detach(wlc->asi);4791wlc->asi = NULL;4792}47934794if (wlc->ampdu) {4795brcms_c_ampdu_detach(wlc->ampdu);4796wlc->ampdu = NULL;4797}47984799brcms_c_stf_detach(wlc);4800}48014802/*4803* low level detach4804*/4805static void brcms_b_detach(struct brcms_c_info *wlc)4806{4807uint i;4808struct brcms_hw_band *band;4809struct brcms_hardware *wlc_hw = wlc->hw;48104811brcms_b_detach_dmapio(wlc_hw);48124813band = wlc_hw->band;4814for (i = 0; i < wlc_hw->_nbands; i++) {4815if (band->pi) {4816/* Detach this band's phy */4817wlc_phy_detach(band->pi);4818band->pi = NULL;4819}4820band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];4821}48224823/* Free shared phy state */4824kfree(wlc_hw->phy_sh);48254826wlc_phy_shim_detach(wlc_hw->physhim);48274828if (wlc_hw->sih) {4829ai_detach(wlc_hw->sih);4830wlc_hw->sih = NULL;4831}4832}48334834/*4835* Return a count of the number of driver callbacks still pending.4836*4837* General policy is that brcms_c_detach can only dealloc/free software states.4838* It can NOT touch hardware registers since the d11core may be in reset and4839* clock may not be available.4840* One exception is sb register access, which is possible if crystal is turned4841* on after "down" state, driver should avoid software timer with the exception4842* of radio_monitor.4843*/4844uint brcms_c_detach(struct brcms_c_info *wlc)4845{4846uint callbacks;48474848if (wlc == NULL)4849return 0;48504851brcms_b_detach(wlc);48524853/* delete software timers */4854callbacks = 0;4855if (!brcms_c_radio_monitor_stop(wlc))4856callbacks++;48574858brcms_c_channel_mgr_detach(wlc->cmi);48594860brcms_c_timers_deinit(wlc);48614862brcms_c_detach_module(wlc);48634864brcms_c_detach_mfree(wlc);4865return callbacks;4866}48674868/* update state that depends on the current value of "ap" */4869static void brcms_c_ap_upd(struct brcms_c_info *wlc)4870{4871/* STA-BSS; short capable */4872wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;4873}48744875/* Initialize just the hardware when coming out of POR or S3/S5 system states */4876static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)4877{4878if (wlc_hw->wlc->pub->hw_up)4879return;48804881brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);48824883/*4884* Enable pll and xtal, initialize the power control registers,4885* and force fastclock for the remainder of brcms_c_up().4886*/4887brcms_b_xtal(wlc_hw, ON);4888ai_clkctl_init(wlc_hw->sih);4889brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);48904891/*4892* TODO: test suspend/resume4893*4894* AI chip doesn't restore bar0win2 on4895* hibernation/resume, need sw fixup4896*/48974898/*4899* Inform phy that a POR reset has occurred so4900* it does a complete phy init4901*/4902wlc_phy_por_inform(wlc_hw->band->pi);49034904wlc_hw->ucode_loaded = false;4905wlc_hw->wlc->pub->hw_up = true;49064907if ((wlc_hw->boardflags & BFL_FEM)4908&& (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) {4909if (!4910(wlc_hw->boardrev >= 0x12504911&& (wlc_hw->boardflags & BFL_FEM_BT)))4912ai_epa_4313war(wlc_hw->sih);4913}4914}49154916static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)4917{4918brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);49194920/*4921* Enable pll and xtal, initialize the power control registers,4922* and force fastclock for the remainder of brcms_c_up().4923*/4924brcms_b_xtal(wlc_hw, ON);4925ai_clkctl_init(wlc_hw->sih);4926brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);49274928/*4929* Configure pci/pcmcia here instead of in brcms_c_attach()4930* to allow mfg hotswap: down, hotswap (chip power cycle), up.4931*/4932bcma_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,4933true);49344935/*4936* Need to read the hwradio status here to cover the case where the4937* system is loaded with the hw radio disabled. We do not want to4938* bring the driver up in this case.4939*/4940if (brcms_b_radio_read_hwdisabled(wlc_hw)) {4941/* put SB PCI in down state again */4942bcma_host_pci_down(wlc_hw->d11core->bus);4943brcms_b_xtal(wlc_hw, OFF);4944return -ENOMEDIUM;4945}49464947bcma_host_pci_up(wlc_hw->d11core->bus);49484949/* reset the d11 core */4950brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);49514952return 0;4953}49544955static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)4956{4957wlc_hw->up = true;4958wlc_phy_hw_state_upd(wlc_hw->band->pi, true);49594960/* FULLY enable dynamic power control and d11 core interrupt */4961brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);4962brcms_intrson(wlc_hw->wlc->wl);4963return 0;4964}49654966/*4967* Write WME tunable parameters for retransmit/max rate4968* from wlc struct to ucode4969*/4970static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)4971{4972int ac;49734974/* Need clock to do this */4975if (!wlc->clk)4976return;49774978for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)4979brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),4980wlc->wme_retries[ac]);4981}49824983/* make interface operational */4984int brcms_c_up(struct brcms_c_info *wlc)4985{4986struct ieee80211_channel *ch;49874988brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);49894990/* HW is turned off so don't try to access it */4991if (wlc->pub->hw_off || brcms_deviceremoved(wlc))4992return -ENOMEDIUM;49934994if (!wlc->pub->hw_up) {4995brcms_b_hw_up(wlc->hw);4996wlc->pub->hw_up = true;4997}49984999if ((wlc->pub->boardflags & BFL_FEM)5000&& (ai_get_chip_id(wlc->hw->sih) == BCMA_CHIP_ID_BCM4313)) {5001if (wlc->pub->boardrev >= 0x12505002&& (wlc->pub->boardflags & BFL_FEM_BT))5003brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL,5004MHF5_4313_GPIOCTRL, BRCM_BAND_ALL);5005else5006brcms_b_mhf(wlc->hw, MHF4, MHF4_EXTPA_ENABLE,5007MHF4_EXTPA_ENABLE, BRCM_BAND_ALL);5008}50095010/*5011* Need to read the hwradio status here to cover the case where the5012* system is loaded with the hw radio disabled. We do not want to bring5013* the driver up in this case. If radio is disabled, abort up, lower5014* power, start radio timer and return 0(for NDIS) don't call5015* radio_update to avoid looping brcms_c_up.5016*5017* brcms_b_up_prep() returns either 0 or -BCME_RADIOOFF only5018*/5019if (!wlc->pub->radio_disabled) {5020int status = brcms_b_up_prep(wlc->hw);5021if (status == -ENOMEDIUM) {5022if (!mboolisset5023(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE)) {5024struct brcms_bss_cfg *bsscfg = wlc->bsscfg;5025mboolset(wlc->pub->radio_disabled,5026WL_RADIO_HW_DISABLE);5027if (bsscfg->type == BRCMS_TYPE_STATION ||5028bsscfg->type == BRCMS_TYPE_ADHOC)5029brcms_err(wlc->hw->d11core,5030"wl%d: up: rfdisable -> "5031"bsscfg_disable()\n",5032wlc->pub->unit);5033}5034}5035}50365037if (wlc->pub->radio_disabled) {5038brcms_c_radio_monitor_start(wlc);5039return 0;5040}50415042/* brcms_b_up_prep has done brcms_c_corereset(). so clk is on, set it */5043wlc->clk = true;50445045brcms_c_radio_monitor_stop(wlc);50465047/* Set EDCF hostflags */5048brcms_b_mhf(wlc->hw, MHF1, MHF1_EDCF, MHF1_EDCF, BRCM_BAND_ALL);50495050brcms_init(wlc->wl);5051wlc->pub->up = true;50525053if (wlc->bandinit_pending) {5054ch = wlc->pub->ieee_hw->conf.chandef.chan;5055brcms_c_suspend_mac_and_wait(wlc);5056brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value));5057wlc->bandinit_pending = false;5058brcms_c_enable_mac(wlc);5059}50605061brcms_b_up_finish(wlc->hw);50625063/* Program the TX wme params with the current settings */5064brcms_c_wme_retries_write(wlc);50655066/* start one second watchdog timer */5067brcms_add_timer(wlc->wdtimer, TIMER_INTERVAL_WATCHDOG, true);5068wlc->WDarmed = true;50695070/* ensure antenna config is up to date */5071brcms_c_stf_phy_txant_upd(wlc);5072/* ensure LDPC config is in sync */5073brcms_c_ht_update_ldpc(wlc, wlc->stf->ldpc);50745075return 0;5076}50775078static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)5079{5080bool dev_gone;5081uint callbacks = 0;50825083if (!wlc_hw->up)5084return callbacks;50855086dev_gone = brcms_deviceremoved(wlc_hw->wlc);50875088/* disable interrupts */5089if (dev_gone)5090wlc_hw->wlc->macintmask = 0;5091else {5092/* now disable interrupts */5093brcms_intrsoff(wlc_hw->wlc->wl);50945095/* ensure we're running on the pll clock again */5096brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);5097}5098/* down phy at the last of this stage */5099callbacks += wlc_phy_down(wlc_hw->band->pi);51005101return callbacks;5102}51035104static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)5105{5106uint callbacks = 0;5107bool dev_gone;51085109if (!wlc_hw->up)5110return callbacks;51115112wlc_hw->up = false;5113wlc_phy_hw_state_upd(wlc_hw->band->pi, false);51145115dev_gone = brcms_deviceremoved(wlc_hw->wlc);51165117if (dev_gone) {5118wlc_hw->sbclk = false;5119wlc_hw->clk = false;5120wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);51215122/* reclaim any posted packets */5123brcms_c_flushqueues(wlc_hw->wlc);5124} else {51255126/* Reset and disable the core */5127if (bcma_core_is_enabled(wlc_hw->d11core)) {5128if (bcma_read32(wlc_hw->d11core,5129D11REGOFFS(maccontrol)) & MCTL_EN_MAC)5130brcms_c_suspend_mac_and_wait(wlc_hw->wlc);5131callbacks += brcms_reset(wlc_hw->wlc->wl);5132brcms_c_coredisable(wlc_hw);5133}51345135/* turn off primary xtal and pll */5136if (!wlc_hw->noreset) {5137bcma_host_pci_down(wlc_hw->d11core->bus);5138brcms_b_xtal(wlc_hw, OFF);5139}5140}51415142return callbacks;5143}51445145/*5146* Mark the interface nonoperational, stop the software mechanisms,5147* disable the hardware, free any transient buffer state.5148* Return a count of the number of driver callbacks still pending.5149*/5150uint brcms_c_down(struct brcms_c_info *wlc)5151{51525153uint callbacks = 0;5154int i;51555156brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);51575158/* check if we are already in the going down path */5159if (wlc->going_down) {5160brcms_err(wlc->hw->d11core,5161"wl%d: %s: Driver going down so return\n",5162wlc->pub->unit, __func__);5163return 0;5164}5165if (!wlc->pub->up)5166return callbacks;51675168wlc->going_down = true;51695170callbacks += brcms_b_bmac_down_prep(wlc->hw);51715172brcms_deviceremoved(wlc);51735174/* Call any registered down handlers */5175for (i = 0; i < BRCMS_MAXMODULES; i++) {5176if (wlc->modulecb[i].down_fn)5177callbacks +=5178wlc->modulecb[i].down_fn(wlc->modulecb[i].hdl);5179}51805181/* cancel the watchdog timer */5182if (wlc->WDarmed) {5183if (!brcms_del_timer(wlc->wdtimer))5184callbacks++;5185wlc->WDarmed = false;5186}51875188wlc->pub->up = false;51895190wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL);51915192callbacks += brcms_b_down_finish(wlc->hw);51935194/* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */5195wlc->clk = false;51965197wlc->going_down = false;5198return callbacks;5199}52005201/* Set the current gmode configuration */5202int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)5203{5204int ret = 0;5205uint i;5206struct brcms_c_rateset rs;5207/* Default to 54g Auto */5208/* Advertise and use shortslot (-1/0/1 Auto/Off/On) */5209s8 shortslot = BRCMS_SHORTSLOT_AUTO;5210bool ofdm_basic = false; /* Make 6, 12, and 24 basic rates */5211struct brcms_band *band;52125213/* if N-support is enabled, allow Gmode set as long as requested5214* Gmode is not GMODE_LEGACY_B5215*/5216if ((wlc->pub->_n_enab & SUPPORT_11N) && gmode == GMODE_LEGACY_B)5217return -ENOTSUPP;52185219/* verify that we are dealing with 2G band and grab the band pointer */5220if (wlc->band->bandtype == BRCM_BAND_2G)5221band = wlc->band;5222else if ((wlc->pub->_nbands > 1) &&5223(wlc->bandstate[OTHERBANDUNIT(wlc)]->bandtype == BRCM_BAND_2G))5224band = wlc->bandstate[OTHERBANDUNIT(wlc)];5225else5226return -EINVAL;52275228/* update configuration value */5229if (config)5230brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode);52315232/* Clear rateset override */5233memset(&rs, 0, sizeof(rs));52345235switch (gmode) {5236case GMODE_LEGACY_B:5237shortslot = BRCMS_SHORTSLOT_OFF;5238brcms_c_rateset_copy(&gphy_legacy_rates, &rs);52395240break;52415242case GMODE_LRS:5243break;52445245case GMODE_AUTO:5246/* Accept defaults */5247break;52485249case GMODE_ONLY:5250ofdm_basic = true;5251break;52525253case GMODE_PERFORMANCE:5254shortslot = BRCMS_SHORTSLOT_ON;5255ofdm_basic = true;5256break;52575258default:5259/* Error */5260brcms_err(wlc->hw->d11core, "wl%d: %s: invalid gmode %d\n",5261wlc->pub->unit, __func__, gmode);5262return -ENOTSUPP;5263}52645265band->gmode = gmode;52665267wlc->shortslot_override = shortslot;52685269/* Use the default 11g rateset */5270if (!rs.count)5271brcms_c_rateset_copy(&cck_ofdm_rates, &rs);52725273if (ofdm_basic) {5274for (i = 0; i < rs.count; i++) {5275if (rs.rates[i] == BRCM_RATE_6M5276|| rs.rates[i] == BRCM_RATE_12M5277|| rs.rates[i] == BRCM_RATE_24M)5278rs.rates[i] |= BRCMS_RATE_FLAG;5279}5280}52815282/* Set default bss rateset */5283wlc->default_bss->rateset.count = rs.count;5284memcpy(wlc->default_bss->rateset.rates, rs.rates,5285sizeof(wlc->default_bss->rateset.rates));52865287return ret;5288}52895290int brcms_c_set_nmode(struct brcms_c_info *wlc)5291{5292uint i;5293s32 nmode = AUTO;52945295if (wlc->stf->txstreams == WL_11N_3x3)5296nmode = WL_11N_3x3;5297else5298nmode = WL_11N_2x2;52995300/* force GMODE_AUTO if NMODE is ON */5301brcms_c_set_gmode(wlc, GMODE_AUTO, true);5302if (nmode == WL_11N_3x3)5303wlc->pub->_n_enab = SUPPORT_HT;5304else5305wlc->pub->_n_enab = SUPPORT_11N;5306wlc->default_bss->flags |= BRCMS_BSS_HT;5307/* add the mcs rates to the default and hw ratesets */5308brcms_c_rateset_mcs_build(&wlc->default_bss->rateset,5309wlc->stf->txstreams);5310for (i = 0; i < wlc->pub->_nbands; i++)5311memcpy(wlc->bandstate[i]->hw_rateset.mcs,5312wlc->default_bss->rateset.mcs, MCSSET_LEN);53135314return 0;5315}53165317static int5318brcms_c_set_internal_rateset(struct brcms_c_info *wlc,5319struct brcms_c_rateset *rs_arg)5320{5321struct brcms_c_rateset rs, new;5322uint bandunit;53235324memcpy(&rs, rs_arg, sizeof(struct brcms_c_rateset));53255326/* check for bad count value */5327if ((rs.count == 0) || (rs.count > BRCMS_NUMRATES))5328return -EINVAL;53295330/* try the current band */5331bandunit = wlc->band->bandunit;5332memcpy(&new, &rs, sizeof(struct brcms_c_rateset));5333if (brcms_c_rate_hwrs_filter_sort_validate5334(&new, &wlc->bandstate[bandunit]->hw_rateset, true,5335wlc->stf->txstreams))5336goto good;53375338/* try the other band */5339if (brcms_is_mband_unlocked(wlc)) {5340bandunit = OTHERBANDUNIT(wlc);5341memcpy(&new, &rs, sizeof(struct brcms_c_rateset));5342if (brcms_c_rate_hwrs_filter_sort_validate(&new,5343&wlc->5344bandstate[bandunit]->5345hw_rateset, true,5346wlc->stf->txstreams))5347goto good;5348}53495350return -EBADE;53515352good:5353/* apply new rateset */5354memcpy(&wlc->default_bss->rateset, &new,5355sizeof(struct brcms_c_rateset));5356memcpy(&wlc->bandstate[bandunit]->defrateset, &new,5357sizeof(struct brcms_c_rateset));5358return 0;5359}53605361static void brcms_c_ofdm_rateset_war(struct brcms_c_info *wlc)5362{5363wlc_phy_ofdm_rateset_war(wlc->band->pi, false);5364}53655366int brcms_c_set_channel(struct brcms_c_info *wlc, u16 channel)5367{5368u16 chspec = ch20mhz_chspec(channel);53695370if (channel > MAXCHANNEL)5371return -EINVAL;53725373if (!brcms_c_valid_chanspec_db(wlc->cmi, chspec))5374return -EINVAL;537553765377if (!wlc->pub->up && brcms_is_mband_unlocked(wlc)) {5378if (wlc->band->bandunit != chspec_bandunit(chspec))5379wlc->bandinit_pending = true;5380else5381wlc->bandinit_pending = false;5382}53835384wlc->default_bss->chanspec = chspec;5385/* brcms_c_BSSinit() will sanitize the rateset before5386* using it.. */5387if (wlc->pub->up && (wlc_phy_chanspec_get(wlc->band->pi) != chspec)) {5388brcms_c_set_home_chanspec(wlc, chspec);5389brcms_c_suspend_mac_and_wait(wlc);5390brcms_c_set_chanspec(wlc, chspec);5391brcms_c_enable_mac(wlc);5392}5393return 0;5394}53955396int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)5397{5398int ac;53995400if (srl < 1 || srl > RETRY_SHORT_MAX ||5401lrl < 1 || lrl > RETRY_SHORT_MAX)5402return -EINVAL;54035404wlc->SRL = srl;5405wlc->LRL = lrl;54065407brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);54085409for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {5410wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],5411EDCF_SHORT, wlc->SRL);5412wlc->wme_retries[ac] = SFIELD(wlc->wme_retries[ac],5413EDCF_LONG, wlc->LRL);5414}5415brcms_c_wme_retries_write(wlc);54165417return 0;5418}54195420void brcms_c_get_current_rateset(struct brcms_c_info *wlc,5421struct brcm_rateset *currs)5422{5423struct brcms_c_rateset *rs;54245425if (wlc->pub->associated)5426rs = &wlc->bsscfg->current_bss->rateset;5427else5428rs = &wlc->default_bss->rateset;54295430/* Copy only legacy rateset section */5431currs->count = rs->count;5432memcpy(&currs->rates, &rs->rates, rs->count);5433}54345435int brcms_c_set_rateset(struct brcms_c_info *wlc, struct brcm_rateset *rs)5436{5437struct brcms_c_rateset internal_rs;5438int bcmerror;54395440if (rs->count > BRCMS_NUMRATES)5441return -ENOBUFS;54425443memset(&internal_rs, 0, sizeof(internal_rs));54445445/* Copy only legacy rateset section */5446internal_rs.count = rs->count;5447memcpy(&internal_rs.rates, &rs->rates, internal_rs.count);54485449/* merge rateset coming in with the current mcsset */5450if (wlc->pub->_n_enab & SUPPORT_11N) {5451struct brcms_bss_info *mcsset_bss;5452if (wlc->pub->associated)5453mcsset_bss = wlc->bsscfg->current_bss;5454else5455mcsset_bss = wlc->default_bss;5456memcpy(internal_rs.mcs, &mcsset_bss->rateset.mcs[0],5457MCSSET_LEN);5458}54595460bcmerror = brcms_c_set_internal_rateset(wlc, &internal_rs);5461if (!bcmerror)5462brcms_c_ofdm_rateset_war(wlc);54635464return bcmerror;5465}54665467static void brcms_c_time_lock(struct brcms_c_info *wlc)5468{5469bcma_set32(wlc->hw->d11core, D11REGOFFS(maccontrol), MCTL_TBTTHOLD);5470/* Commit the write */5471bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));5472}54735474static void brcms_c_time_unlock(struct brcms_c_info *wlc)5475{5476bcma_mask32(wlc->hw->d11core, D11REGOFFS(maccontrol), ~MCTL_TBTTHOLD);5477/* Commit the write */5478bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));5479}54805481int brcms_c_set_beacon_period(struct brcms_c_info *wlc, u16 period)5482{5483u32 bcnint_us;54845485if (period == 0)5486return -EINVAL;54875488wlc->default_bss->beacon_period = period;54895490bcnint_us = period << 10;5491brcms_c_time_lock(wlc);5492bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfprep),5493(bcnint_us << CFPREP_CBI_SHIFT));5494bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_cfpstart), bcnint_us);5495brcms_c_time_unlock(wlc);54965497return 0;5498}54995500u16 brcms_c_get_phy_type(struct brcms_c_info *wlc, int phyidx)5501{5502return wlc->band->phytype;5503}55045505void brcms_c_set_shortslot_override(struct brcms_c_info *wlc, s8 sslot_override)5506{5507wlc->shortslot_override = sslot_override;55085509/*5510* shortslot is an 11g feature, so no more work if we are5511* currently on the 5G band5512*/5513if (wlc->band->bandtype == BRCM_BAND_5G)5514return;55155516if (wlc->pub->up && wlc->pub->associated) {5517/* let watchdog or beacon processing update shortslot */5518} else if (wlc->pub->up) {5519/* unassociated shortslot is off */5520brcms_c_switch_shortslot(wlc, false);5521} else {5522/* driver is down, so just update the brcms_c_info5523* value */5524if (wlc->shortslot_override == BRCMS_SHORTSLOT_AUTO)5525wlc->shortslot = false;5526else5527wlc->shortslot =5528(wlc->shortslot_override ==5529BRCMS_SHORTSLOT_ON);5530}5531}55325533/*5534* register watchdog and down handlers.5535*/5536int brcms_c_module_register(struct brcms_pub *pub,5537const char *name, struct brcms_info *hdl,5538int (*d_fn)(void *handle))5539{5540struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;5541int i;55425543/* find an empty entry and just add, no duplication check! */5544for (i = 0; i < BRCMS_MAXMODULES; i++) {5545if (wlc->modulecb[i].name[0] == '\0') {5546strscpy(wlc->modulecb[i].name, name,5547sizeof(wlc->modulecb[i].name));5548wlc->modulecb[i].hdl = hdl;5549wlc->modulecb[i].down_fn = d_fn;5550return 0;5551}5552}55535554return -ENOSR;5555}55565557/* unregister module callbacks */5558int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,5559struct brcms_info *hdl)5560{5561struct brcms_c_info *wlc = (struct brcms_c_info *) pub->wlc;5562int i;55635564if (wlc == NULL)5565return -ENODATA;55665567for (i = 0; i < BRCMS_MAXMODULES; i++) {5568if (!strcmp(wlc->modulecb[i].name, name) &&5569(wlc->modulecb[i].hdl == hdl)) {5570memset(&wlc->modulecb[i], 0, sizeof(wlc->modulecb[i]));5571return 0;5572}5573}55745575/* table not found! */5576return -ENODATA;5577}55785579static bool brcms_c_chipmatch_pci(struct bcma_device *core)5580{5581struct pci_dev *pcidev = core->bus->host_pci;5582u16 vendor = pcidev->vendor;5583u16 device = pcidev->device;55845585if (vendor != PCI_VENDOR_ID_BROADCOM) {5586pr_err("unknown vendor id %04x\n", vendor);5587return false;5588}55895590if (device == BCM43224_D11N_ID_VEN1 || device == BCM43224_CHIP_ID)5591return true;5592if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))5593return true;5594if (device == BCM4313_D11N2G_ID || device == BCM4313_CHIP_ID)5595return true;5596if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))5597return true;55985599pr_err("unknown device id %04x\n", device);5600return false;5601}56025603static bool brcms_c_chipmatch_soc(struct bcma_device *core)5604{5605struct bcma_chipinfo *chipinfo = &core->bus->chipinfo;56065607if (chipinfo->id == BCMA_CHIP_ID_BCM4716)5608return true;56095610pr_err("unknown chip id %04x\n", chipinfo->id);5611return false;5612}56135614bool brcms_c_chipmatch(struct bcma_device *core)5615{5616switch (core->bus->hosttype) {5617case BCMA_HOSTTYPE_PCI:5618return brcms_c_chipmatch_pci(core);5619case BCMA_HOSTTYPE_SOC:5620return brcms_c_chipmatch_soc(core);5621default:5622pr_err("unknown host type: %i\n", core->bus->hosttype);5623return false;5624}5625}56265627u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)5628{5629u16 table_ptr;5630u8 phy_rate, index;56315632/* get the phy specific rate encoding for the PLCP SIGNAL field */5633if (is_ofdm_rate(rate))5634table_ptr = M_RT_DIRMAP_A;5635else5636table_ptr = M_RT_DIRMAP_B;56375638/* for a given rate, the LS-nibble of the PLCP SIGNAL field is5639* the index into the rate table.5640*/5641phy_rate = rate_info[rate] & BRCMS_RATE_MASK;5642index = phy_rate & 0xf;56435644/* Find the SHM pointer to the rate table entry by looking in the5645* Direct-map Table5646*/5647return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));5648}56495650/*5651* bcmc_fid_generate:5652* Generate frame ID for a BCMC packet. The frag field is not used5653* for MC frames so is used as part of the sequence number.5654*/5655static inline u165656bcmc_fid_generate(struct brcms_c_info *wlc, struct brcms_bss_cfg *bsscfg,5657struct d11txh *txh)5658{5659u16 frameid;56605661frameid = le16_to_cpu(txh->TxFrameID) & ~(TXFID_SEQ_MASK |5662TXFID_QUEUE_MASK);5663frameid |=5664(((wlc->5665mc_fid_counter++) << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |5666TX_BCMC_FIFO;56675668return frameid;5669}56705671static uint5672brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,5673u8 preamble_type)5674{5675uint dur = 0;56765677/*5678* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that5679* is less than or equal to the rate of the immediately previous5680* frame in the FES5681*/5682rspec = brcms_basic_rate(wlc, rspec);5683/* ACK frame len == 14 == 2(fc) + 2(dur) + 6(ra) + 4(fcs) */5684dur =5685brcms_c_calc_frame_time(wlc, rspec, preamble_type,5686(DOT11_ACK_LEN + FCS_LEN));5687return dur;5688}56895690static uint5691brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,5692u8 preamble_type)5693{5694return brcms_c_calc_ack_time(wlc, rspec, preamble_type);5695}56965697static uint5698brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,5699u8 preamble_type)5700{5701/*5702* Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that5703* is less than or equal to the rate of the immediately previous5704* frame in the FES5705*/5706rspec = brcms_basic_rate(wlc, rspec);5707/* BA len == 32 == 16(ctl hdr) + 4(ba len) + 8(bitmap) + 4(fcs) */5708return brcms_c_calc_frame_time(wlc, rspec, preamble_type,5709(DOT11_BA_LEN + DOT11_BA_BITMAP_LEN +5710FCS_LEN));5711}57125713/* brcms_c_compute_frame_dur()5714*5715* Calculate the 802.11 MAC header DUR field for MPDU5716* DUR for a single frame = 1 SIFS + 1 ACK5717* DUR for a frame with following frags = 3 SIFS + 2 ACK + next frag time5718*5719* rate MPDU rate in unit of 500kbps5720* next_frag_len next MPDU length in bytes5721* preamble_type use short/GF or long/MM PLCP header5722*/5723static u165724brcms_c_compute_frame_dur(struct brcms_c_info *wlc, u32 rate,5725u8 preamble_type, uint next_frag_len)5726{5727u16 dur, sifs;57285729sifs = get_sifs(wlc->band);57305731dur = sifs;5732dur += (u16) brcms_c_calc_ack_time(wlc, rate, preamble_type);57335734if (next_frag_len) {5735/* Double the current DUR to get 2 SIFS + 2 ACKs */5736dur *= 2;5737/* add another SIFS and the frag time */5738dur += sifs;5739dur +=5740(u16) brcms_c_calc_frame_time(wlc, rate, preamble_type,5741next_frag_len);5742}5743return dur;5744}57455746/* The opposite of brcms_c_calc_frame_time */5747static uint5748brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,5749u8 preamble_type, uint dur)5750{5751uint nsyms, mac_len, Ndps, kNdps;5752uint rate = rspec2rate(ratespec);57535754if (is_mcs_rate(ratespec)) {5755uint mcs = ratespec & RSPEC_RATE_MASK;5756int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);5757dur -= PREN_PREAMBLE + (tot_streams * PREN_PREAMBLE_EXT);5758/* payload calculation matches that of regular ofdm */5759if (wlc->band->bandtype == BRCM_BAND_2G)5760dur -= DOT11_OFDM_SIGNAL_EXTENSION;5761/* kNdbps = kbps * 4 */5762kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),5763rspec_issgi(ratespec)) * 4;5764nsyms = dur / APHY_SYMBOL_TIME;5765mac_len =5766((nsyms * kNdps) -5767((APHY_SERVICE_NBITS + APHY_TAIL_NBITS) * 1000)) / 8000;5768} else if (is_ofdm_rate(ratespec)) {5769dur -= APHY_PREAMBLE_TIME;5770dur -= APHY_SIGNAL_TIME;5771/* Ndbps = Mbps * 4 = rate(500Kbps) * 2 */5772Ndps = rate * 2;5773nsyms = dur / APHY_SYMBOL_TIME;5774mac_len =5775((nsyms * Ndps) -5776(APHY_SERVICE_NBITS + APHY_TAIL_NBITS)) / 8;5777} else {5778if (preamble_type & BRCMS_SHORT_PREAMBLE)5779dur -= BPHY_PLCP_SHORT_TIME;5780else5781dur -= BPHY_PLCP_TIME;5782mac_len = dur * rate;5783/* divide out factor of 2 in rate (1/2 mbps) */5784mac_len = mac_len / 8 / 2;5785}5786return mac_len;5787}57885789/*5790* Return true if the specified rate is supported by the specified band.5791* BRCM_BAND_AUTO indicates the current band.5792*/5793static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,5794bool verbose)5795{5796struct brcms_c_rateset *hw_rateset;5797uint i;57985799if ((band == BRCM_BAND_AUTO) || (band == wlc->band->bandtype))5800hw_rateset = &wlc->band->hw_rateset;5801else if (wlc->pub->_nbands > 1)5802hw_rateset = &wlc->bandstate[OTHERBANDUNIT(wlc)]->hw_rateset;5803else5804/* other band specified and we are a single band device */5805return false;58065807/* check if this is a mimo rate */5808if (is_mcs_rate(rspec)) {5809if ((rspec & RSPEC_RATE_MASK) >= MCS_TABLE_SIZE)5810goto error;58115812return isset(hw_rateset->mcs, (rspec & RSPEC_RATE_MASK));5813}58145815for (i = 0; i < hw_rateset->count; i++)5816if (hw_rateset->rates[i] == rspec2rate(rspec))5817return true;5818error:5819if (verbose)5820brcms_err(wlc->hw->d11core, "wl%d: valid_rate: rate spec 0x%x "5821"not in hw_rateset\n", wlc->pub->unit, rspec);58225823return false;5824}58255826static u325827mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,5828u32 int_val)5829{5830struct bcma_device *core = wlc->hw->d11core;5831u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;5832u8 rate = int_val & NRATE_RATE_MASK;5833u32 rspec;5834bool ismcs = ((int_val & NRATE_MCS_INUSE) == NRATE_MCS_INUSE);5835bool issgi = ((int_val & NRATE_SGI_MASK) >> NRATE_SGI_SHIFT);5836bool override_mcs_only = ((int_val & NRATE_OVERRIDE_MCS_ONLY)5837== NRATE_OVERRIDE_MCS_ONLY);58385839if (!ismcs)5840return (u32) rate;58415842/* validate the combination of rate/mcs/stf is allowed */5843if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) {5844/* mcs only allowed when nmode */5845if (stf > PHY_TXC1_MODE_SDM) {5846brcms_err(core, "wl%d: %s: Invalid stf\n",5847wlc->pub->unit, __func__);5848goto done;5849}58505851/* mcs 32 is a special case, DUP mode 40 only */5852if (rate == 32) {5853if (!CHSPEC_IS40(wlc->home_chanspec) ||5854((stf != PHY_TXC1_MODE_SISO)5855&& (stf != PHY_TXC1_MODE_CDD))) {5856brcms_err(core, "wl%d: %s: Invalid mcs 32\n",5857wlc->pub->unit, __func__);5858goto done;5859}5860/* mcs > 7 must use stf SDM */5861} else if (rate > HIGHEST_SINGLE_STREAM_MCS) {5862/* mcs > 7 must use stf SDM */5863if (stf != PHY_TXC1_MODE_SDM) {5864brcms_dbg_mac80211(core, "wl%d: enabling "5865"SDM mode for mcs %d\n",5866wlc->pub->unit, rate);5867stf = PHY_TXC1_MODE_SDM;5868}5869} else {5870/*5871* MCS 0-7 may use SISO, CDD, and for5872* phy_rev >= 3 STBC5873*/5874if ((stf > PHY_TXC1_MODE_STBC) ||5875(!BRCMS_STBC_CAP_PHY(wlc)5876&& (stf == PHY_TXC1_MODE_STBC))) {5877brcms_err(core, "wl%d: %s: Invalid STBC\n",5878wlc->pub->unit, __func__);5879goto done;5880}5881}5882} else if (is_ofdm_rate(rate)) {5883if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {5884brcms_err(core, "wl%d: %s: Invalid OFDM\n",5885wlc->pub->unit, __func__);5886goto done;5887}5888} else if (is_cck_rate(rate)) {5889if ((cur_band->bandtype != BRCM_BAND_2G)5890|| (stf != PHY_TXC1_MODE_SISO)) {5891brcms_err(core, "wl%d: %s: Invalid CCK\n",5892wlc->pub->unit, __func__);5893goto done;5894}5895} else {5896brcms_err(core, "wl%d: %s: Unknown rate type\n",5897wlc->pub->unit, __func__);5898goto done;5899}5900/* make sure multiple antennae are available for non-siso rates */5901if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {5902brcms_err(core, "wl%d: %s: SISO antenna but !SISO "5903"request\n", wlc->pub->unit, __func__);5904goto done;5905}59065907rspec = rate;5908if (ismcs) {5909rspec |= RSPEC_MIMORATE;5910/* For STBC populate the STC field of the ratespec */5911if (stf == PHY_TXC1_MODE_STBC) {5912u8 stc;5913stc = 1; /* Nss for single stream is always 1 */5914rspec |= (stc << RSPEC_STC_SHIFT);5915}5916}59175918rspec |= (stf << RSPEC_STF_SHIFT);59195920if (override_mcs_only)5921rspec |= RSPEC_OVERRIDE_MCS_ONLY;59225923if (issgi)5924rspec |= RSPEC_SHORT_GI;59255926if ((rate != 0)5927&& !brcms_c_valid_rate(wlc, rspec, cur_band->bandtype, true))5928return rate;59295930return rspec;5931done:5932return rate;5933}59345935/*5936* Compute PLCP, but only requires actual rate and length of pkt.5937* Rate is given in the driver standard multiple of 500 kbps.5938* le is set for 11 Mbps rate if necessary.5939* Broken out for PRQ.5940*/59415942static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,5943uint length, u8 *plcp)5944{5945u16 usec = 0;5946u8 le = 0;59475948switch (rate_500) {5949case BRCM_RATE_1M:5950usec = length << 3;5951break;5952case BRCM_RATE_2M:5953usec = length << 2;5954break;5955case BRCM_RATE_5M5:5956usec = (length << 4) / 11;5957if ((length << 4) - (usec * 11) > 0)5958usec++;5959break;5960case BRCM_RATE_11M:5961usec = (length << 3) / 11;5962if ((length << 3) - (usec * 11) > 0) {5963usec++;5964if ((usec * 11) - (length << 3) >= 8)5965le = D11B_PLCP_SIGNAL_LE;5966}5967break;59685969default:5970brcms_err(wlc->hw->d11core,5971"brcms_c_cck_plcp_set: unsupported rate %d\n",5972rate_500);5973rate_500 = BRCM_RATE_1M;5974usec = length << 3;5975break;5976}5977/* PLCP signal byte */5978plcp[0] = rate_500 * 5; /* r (500kbps) * 5 == r (100kbps) */5979/* PLCP service byte */5980plcp[1] = (u8) (le | D11B_PLCP_SIGNAL_LOCKED);5981/* PLCP length u16, little endian */5982plcp[2] = usec & 0xff;5983plcp[3] = (usec >> 8) & 0xff;5984/* PLCP CRC16 */5985plcp[4] = 0;5986plcp[5] = 0;5987}59885989/* Rate: 802.11 rate code, length: PSDU length in octets */5990static void brcms_c_compute_mimo_plcp(u32 rspec, uint length, u8 *plcp)5991{5992u8 mcs = (u8) (rspec & RSPEC_RATE_MASK);5993plcp[0] = mcs;5994if (rspec_is40mhz(rspec) || (mcs == 32))5995plcp[0] |= MIMO_PLCP_40MHZ;5996BRCMS_SET_MIMO_PLCP_LEN(plcp, length);5997plcp[3] = rspec_mimoplcp3(rspec); /* rspec already holds this byte */5998plcp[3] |= 0x7; /* set smoothing, not sounding ppdu & reserved */5999plcp[4] = 0; /* number of extension spatial streams bit 0 & 1 */6000plcp[5] = 0;6001}60026003/* Rate: 802.11 rate code, length: PSDU length in octets */6004static void6005brcms_c_compute_ofdm_plcp(u32 rspec, u32 length, u8 *plcp)6006{6007u8 rate_signal;6008u32 tmp = 0;6009int rate = rspec2rate(rspec);60106011/*6012* encode rate per 802.11a-1999 sec 17.3.4.1, with lsb6013* transmitted first6014*/6015rate_signal = rate_info[rate] & BRCMS_RATE_MASK;6016memset(plcp, 0, D11_PHY_HDR_LEN);6017D11A_PHY_HDR_SRATE((struct ofdm_phy_hdr *) plcp, rate_signal);60186019tmp = (length & 0xfff) << 5;6020plcp[2] |= (tmp >> 16) & 0xff;6021plcp[1] |= (tmp >> 8) & 0xff;6022plcp[0] |= tmp & 0xff;6023}60246025/* Rate: 802.11 rate code, length: PSDU length in octets */6026static void brcms_c_compute_cck_plcp(struct brcms_c_info *wlc, u32 rspec,6027uint length, u8 *plcp)6028{6029int rate = rspec2rate(rspec);60306031brcms_c_cck_plcp_set(wlc, rate, length, plcp);6032}60336034static void6035brcms_c_compute_plcp(struct brcms_c_info *wlc, u32 rspec,6036uint length, u8 *plcp)6037{6038if (is_mcs_rate(rspec))6039brcms_c_compute_mimo_plcp(rspec, length, plcp);6040else if (is_ofdm_rate(rspec))6041brcms_c_compute_ofdm_plcp(rspec, length, plcp);6042else6043brcms_c_compute_cck_plcp(wlc, rspec, length, plcp);6044}60456046/* brcms_c_compute_rtscts_dur()6047*6048* Calculate the 802.11 MAC header DUR field for an RTS or CTS frame6049* DUR for normal RTS/CTS w/ frame = 3 SIFS + 1 CTS + next frame time + 1 ACK6050* DUR for CTS-TO-SELF w/ frame = 2 SIFS + next frame time + 1 ACK6051*6052* cts cts-to-self or rts/cts6053* rts_rate rts or cts rate in unit of 500kbps6054* rate next MPDU rate in unit of 500kbps6055* frame_len next MPDU frame length in bytes6056*/6057u166058brcms_c_compute_rtscts_dur(struct brcms_c_info *wlc, bool cts_only,6059u32 rts_rate,6060u32 frame_rate, u8 rts_preamble_type,6061u8 frame_preamble_type, uint frame_len, bool ba)6062{6063u16 dur, sifs;60646065sifs = get_sifs(wlc->band);60666067if (!cts_only) {6068/* RTS/CTS */6069dur = 3 * sifs;6070dur +=6071(u16) brcms_c_calc_cts_time(wlc, rts_rate,6072rts_preamble_type);6073} else {6074/* CTS-TO-SELF */6075dur = 2 * sifs;6076}60776078dur +=6079(u16) brcms_c_calc_frame_time(wlc, frame_rate, frame_preamble_type,6080frame_len);6081if (ba)6082dur +=6083(u16) brcms_c_calc_ba_time(wlc, frame_rate,6084BRCMS_SHORT_PREAMBLE);6085else6086dur +=6087(u16) brcms_c_calc_ack_time(wlc, frame_rate,6088frame_preamble_type);6089return dur;6090}60916092static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)6093{6094u16 phyctl1 = 0;6095u16 bw;60966097if (BRCMS_ISLCNPHY(wlc->band)) {6098bw = PHY_TXC1_BW_20MHZ;6099} else {6100bw = rspec_get_bw(rspec);6101/* 10Mhz is not supported yet */6102if (bw < PHY_TXC1_BW_20MHZ) {6103brcms_err(wlc->hw->d11core, "phytxctl1_calc: bw %d is "6104"not supported yet, set to 20L\n", bw);6105bw = PHY_TXC1_BW_20MHZ;6106}6107}61086109if (is_mcs_rate(rspec)) {6110uint mcs = rspec & RSPEC_RATE_MASK;61116112/* bw, stf, coding-type is part of rspec_phytxbyte2 returns */6113phyctl1 = rspec_phytxbyte2(rspec);6114/* set the upper byte of phyctl1 */6115phyctl1 |= (mcs_table[mcs].tx_phy_ctl3 << 8);6116} else if (is_cck_rate(rspec) && !BRCMS_ISLCNPHY(wlc->band)6117&& !BRCMS_ISSSLPNPHY(wlc->band)) {6118/*6119* In CCK mode LPPHY overloads OFDM Modulation bits with CCK6120* Data Rate. Eventually MIMOPHY would also be converted to6121* this format6122*/6123/* 0 = 1Mbps; 1 = 2Mbps; 2 = 5.5Mbps; 3 = 11Mbps */6124phyctl1 = (bw | (rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));6125} else { /* legacy OFDM/CCK */6126s16 phycfg;6127/* get the phyctl byte from rate phycfg table */6128phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));6129if (phycfg == -1) {6130brcms_err(wlc->hw->d11core, "phytxctl1_calc: wrong "6131"legacy OFDM/CCK rate\n");6132phycfg = 0;6133}6134/* set the upper byte of phyctl1 */6135phyctl1 =6136(bw | (phycfg << 8) |6137(rspec_stf(rspec) << PHY_TXC1_MODE_SHIFT));6138}6139return phyctl1;6140}61416142/*6143* Add struct d11txh, struct cck_phy_hdr.6144*6145* 'p' data must start with 802.11 MAC header6146* 'p' must allow enough bytes of local headers to be "pushed" onto the packet6147*6148* headroom == D11_PHY_HDR_LEN + D11_TXH_LEN (D11_TXH_LEN is now 104 bytes)6149*6150*/6151static u166152brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,6153struct sk_buff *p, struct scb *scb, uint frag,6154uint nfrags, uint queue, uint next_frag_len)6155{6156struct ieee80211_hdr *h;6157struct d11txh *txh;6158u8 *plcp, plcp_fallback[D11_PHY_HDR_LEN];6159int len, phylen, rts_phylen;6160u16 mch, phyctl, xfts, mainrates;6161u16 seq = 0, mcl = 0, status = 0, frameid = 0;6162u32 rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };6163u32 rts_rspec[2] = { BRCM_RATE_1M, BRCM_RATE_1M };6164bool use_rts = false;6165bool use_cts = false;6166bool use_rifs = false;6167u8 preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };6168u8 rts_preamble_type[2] = { BRCMS_LONG_PREAMBLE, BRCMS_LONG_PREAMBLE };6169u8 *rts_plcp, rts_plcp_fallback[D11_PHY_HDR_LEN];6170struct ieee80211_rts *rts = NULL;6171bool qos;6172uint ac;6173bool hwtkmic = false;6174u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;6175#define ANTCFG_NONE 0xFF6176u8 antcfg = ANTCFG_NONE;6177u8 fbantcfg = ANTCFG_NONE;6178uint phyctl1_stf = 0;6179u16 durid = 0;6180struct ieee80211_tx_rate *txrate[2];6181int k;6182struct ieee80211_tx_info *tx_info;6183bool is_mcs;6184u16 mimo_txbw;6185u8 mimo_preamble_type;61866187/* locate 802.11 MAC header */6188h = (struct ieee80211_hdr *)(p->data);6189qos = ieee80211_is_data_qos(h->frame_control);61906191/* compute length of frame in bytes for use in PLCP computations */6192len = p->len;6193phylen = len + FCS_LEN;61946195/* Get tx_info */6196tx_info = IEEE80211_SKB_CB(p);61976198/* add PLCP */6199plcp = skb_push(p, D11_PHY_HDR_LEN);62006201/* add Broadcom tx descriptor header */6202txh = (struct d11txh *) skb_push(p, D11_TXH_LEN);6203memset(txh, 0, D11_TXH_LEN);62046205/* setup frameid */6206if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {6207/* non-AP STA should never use BCMC queue */6208if (queue == TX_BCMC_FIFO) {6209brcms_err(wlc->hw->d11core,6210"wl%d: %s: ASSERT queue == TX_BCMC!\n",6211wlc->pub->unit, __func__);6212frameid = bcmc_fid_generate(wlc, NULL, txh);6213} else {6214/* Increment the counter for first fragment */6215if (tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)6216scb->seqnum[p->priority]++;62176218/* extract fragment number from frame first */6219seq = le16_to_cpu(h->seq_ctrl) & FRAGNUM_MASK;6220seq |= (scb->seqnum[p->priority] << SEQNUM_SHIFT);6221h->seq_ctrl = cpu_to_le16(seq);62226223frameid = ((seq << TXFID_SEQ_SHIFT) & TXFID_SEQ_MASK) |6224(queue & TXFID_QUEUE_MASK);6225}6226}6227frameid |= queue & TXFID_QUEUE_MASK;62286229/* set the ignpmq bit for all pkts tx'd in PS mode and for beacons */6230if (ieee80211_is_beacon(h->frame_control))6231mcl |= TXC_IGNOREPMQ;62326233txrate[0] = tx_info->control.rates;6234txrate[1] = txrate[0] + 1;62356236/*6237* if rate control algorithm didn't give us a fallback6238* rate, use the primary rate6239*/6240if (txrate[1]->idx < 0)6241txrate[1] = txrate[0];62426243for (k = 0; k < hw->max_rates; k++) {6244is_mcs = txrate[k]->flags & IEEE80211_TX_RC_MCS ? true : false;6245if (!is_mcs) {6246if ((txrate[k]->idx >= 0)6247&& (txrate[k]->idx <6248hw->wiphy->bands[tx_info->band]->n_bitrates)) {6249rspec[k] =6250hw->wiphy->bands[tx_info->band]->6251bitrates[txrate[k]->idx].hw_value;6252} else {6253rspec[k] = BRCM_RATE_1M;6254}6255} else {6256rspec[k] = mac80211_wlc_set_nrate(wlc, wlc->band,6257NRATE_MCS_INUSE | txrate[k]->idx);6258}62596260/*6261* Currently only support same setting for primary and6262* fallback rates. Unify flags for each rate into a6263* single value for the frame6264*/6265use_rts |=6266txrate[k]->6267flags & IEEE80211_TX_RC_USE_RTS_CTS ? true : false;6268use_cts |=6269txrate[k]->6270flags & IEEE80211_TX_RC_USE_CTS_PROTECT ? true : false;627162726273/*6274* (1) RATE:6275* determine and validate primary rate6276* and fallback rates6277*/6278if (!rspec_active(rspec[k])) {6279rspec[k] = BRCM_RATE_1M;6280} else {6281if (!is_multicast_ether_addr(h->addr1)) {6282/* set tx antenna config */6283brcms_c_antsel_antcfg_get(wlc->asi, false,6284false, 0, 0, &antcfg, &fbantcfg);6285}6286}6287}62886289phyctl1_stf = wlc->stf->ss_opmode;62906291if (wlc->pub->_n_enab & SUPPORT_11N) {6292for (k = 0; k < hw->max_rates; k++) {6293/*6294* apply siso/cdd to single stream mcs's or ofdm6295* if rspec is auto selected6296*/6297if (((is_mcs_rate(rspec[k]) &&6298is_single_stream(rspec[k] & RSPEC_RATE_MASK)) ||6299is_ofdm_rate(rspec[k]))6300&& ((rspec[k] & RSPEC_OVERRIDE_MCS_ONLY)6301|| !(rspec[k] & RSPEC_OVERRIDE))) {6302rspec[k] &= ~(RSPEC_STF_MASK | RSPEC_STC_MASK);63036304/* For SISO MCS use STBC if possible */6305if (is_mcs_rate(rspec[k])6306&& BRCMS_STF_SS_STBC_TX(wlc, scb)) {6307u8 stc;63086309/* Nss for single stream is always 1 */6310stc = 1;6311rspec[k] |= (PHY_TXC1_MODE_STBC <<6312RSPEC_STF_SHIFT) |6313(stc << RSPEC_STC_SHIFT);6314} else6315rspec[k] |=6316(phyctl1_stf << RSPEC_STF_SHIFT);6317}63186319/*6320* Is the phy configured to use 40MHZ frames? If6321* so then pick the desired txbw6322*/6323if (brcms_chspec_bw(wlc->chanspec) == BRCMS_40_MHZ) {6324/* default txbw is 20in40 SB */6325mimo_ctlchbw = mimo_txbw =6326CHSPEC_SB_UPPER(wlc_phy_chanspec_get(6327wlc->band->pi))6328? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;63296330if (is_mcs_rate(rspec[k])) {6331/* mcs 32 must be 40b/w DUP */6332if ((rspec[k] & RSPEC_RATE_MASK)6333== 32) {6334mimo_txbw =6335PHY_TXC1_BW_40MHZ_DUP;6336/* use override */6337} else if (wlc->mimo_40txbw != AUTO)6338mimo_txbw = wlc->mimo_40txbw;6339/* else check if dst is using 40 Mhz */6340else if (scb->flags & SCB_IS40)6341mimo_txbw = PHY_TXC1_BW_40MHZ;6342} else if (is_ofdm_rate(rspec[k])) {6343if (wlc->ofdm_40txbw != AUTO)6344mimo_txbw = wlc->ofdm_40txbw;6345} else if (wlc->cck_40txbw != AUTO) {6346mimo_txbw = wlc->cck_40txbw;6347}6348} else {6349/*6350* mcs32 is 40 b/w only.6351* This is possible for probe packets on6352* a STA during SCAN6353*/6354if ((rspec[k] & RSPEC_RATE_MASK) == 32)6355/* mcs 0 */6356rspec[k] = RSPEC_MIMORATE;63576358mimo_txbw = PHY_TXC1_BW_20MHZ;6359}63606361/* Set channel width */6362rspec[k] &= ~RSPEC_BW_MASK;6363if ((k == 0) || ((k > 0) && is_mcs_rate(rspec[k])))6364rspec[k] |= (mimo_txbw << RSPEC_BW_SHIFT);6365else6366rspec[k] |= (mimo_ctlchbw << RSPEC_BW_SHIFT);63676368/* Disable short GI, not supported yet */6369rspec[k] &= ~RSPEC_SHORT_GI;63706371mimo_preamble_type = BRCMS_MM_PREAMBLE;6372if (txrate[k]->flags & IEEE80211_TX_RC_GREEN_FIELD)6373mimo_preamble_type = BRCMS_GF_PREAMBLE;63746375if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)6376&& (!is_mcs_rate(rspec[k]))) {6377brcms_warn(wlc->hw->d11core,6378"wl%d: %s: IEEE80211_TX_RC_MCS != is_mcs_rate(rspec)\n",6379wlc->pub->unit, __func__);6380}63816382if (is_mcs_rate(rspec[k])) {6383preamble_type[k] = mimo_preamble_type;63846385/*6386* if SGI is selected, then forced mm6387* for single stream6388*/6389if ((rspec[k] & RSPEC_SHORT_GI)6390&& is_single_stream(rspec[k] &6391RSPEC_RATE_MASK))6392preamble_type[k] = BRCMS_MM_PREAMBLE;6393}63946395/* should be better conditionalized */6396if (!is_mcs_rate(rspec[0])6397&& (tx_info->control.rates[0].6398flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE))6399preamble_type[k] = BRCMS_SHORT_PREAMBLE;6400}6401} else {6402for (k = 0; k < hw->max_rates; k++) {6403/* Set ctrlchbw as 20Mhz */6404rspec[k] &= ~RSPEC_BW_MASK;6405rspec[k] |= (PHY_TXC1_BW_20MHZ << RSPEC_BW_SHIFT);64066407/* for nphy, stf of ofdm frames must follow policies */6408if (BRCMS_ISNPHY(wlc->band) && is_ofdm_rate(rspec[k])) {6409rspec[k] &= ~RSPEC_STF_MASK;6410rspec[k] |= phyctl1_stf << RSPEC_STF_SHIFT;6411}6412}6413}64146415/* Reset these for use with AMPDU's */6416txrate[0]->count = 0;6417txrate[1]->count = 0;64186419/* (2) PROTECTION, may change rspec */6420if ((ieee80211_is_data(h->frame_control) ||6421ieee80211_is_mgmt(h->frame_control)) &&6422(phylen > wlc->RTSThresh) && !is_multicast_ether_addr(h->addr1))6423use_rts = true;64246425/* (3) PLCP: determine PLCP header and MAC duration,6426* fill struct d11txh */6427brcms_c_compute_plcp(wlc, rspec[0], phylen, plcp);6428brcms_c_compute_plcp(wlc, rspec[1], phylen, plcp_fallback);6429memcpy(&txh->FragPLCPFallback,6430plcp_fallback, sizeof(txh->FragPLCPFallback));64316432/* Length field now put in CCK FBR CRC field */6433if (is_cck_rate(rspec[1])) {6434txh->FragPLCPFallback[4] = phylen & 0xff;6435txh->FragPLCPFallback[5] = (phylen & 0xff00) >> 8;6436}64376438/* MIMO-RATE: need validation ?? */6439mainrates = is_ofdm_rate(rspec[0]) ?6440D11A_PHY_HDR_GRATE((struct ofdm_phy_hdr *) plcp) :6441plcp[0];64426443/* DUR field for main rate */6444if (!ieee80211_is_pspoll(h->frame_control) &&6445!is_multicast_ether_addr(h->addr1) && !use_rifs) {6446durid =6447brcms_c_compute_frame_dur(wlc, rspec[0], preamble_type[0],6448next_frag_len);6449h->duration_id = cpu_to_le16(durid);6450} else if (use_rifs) {6451/* NAV protect to end of next max packet size */6452durid =6453(u16) brcms_c_calc_frame_time(wlc, rspec[0],6454preamble_type[0],6455DOT11_MAX_FRAG_LEN);6456durid += RIFS_11N_TIME;6457h->duration_id = cpu_to_le16(durid);6458}64596460/* DUR field for fallback rate */6461if (ieee80211_is_pspoll(h->frame_control))6462txh->FragDurFallback = h->duration_id;6463else if (is_multicast_ether_addr(h->addr1) || use_rifs)6464txh->FragDurFallback = 0;6465else {6466durid = brcms_c_compute_frame_dur(wlc, rspec[1],6467preamble_type[1], next_frag_len);6468txh->FragDurFallback = cpu_to_le16(durid);6469}64706471/* (4) MAC-HDR: MacTxControlLow */6472if (frag == 0)6473mcl |= TXC_STARTMSDU;64746475if (!is_multicast_ether_addr(h->addr1))6476mcl |= TXC_IMMEDACK;64776478if (wlc->band->bandtype == BRCM_BAND_5G)6479mcl |= TXC_FREQBAND_5G;64806481if (CHSPEC_IS40(wlc_phy_chanspec_get(wlc->band->pi)))6482mcl |= TXC_BW_40;64836484/* set AMIC bit if using hardware TKIP MIC */6485if (hwtkmic)6486mcl |= TXC_AMIC;64876488txh->MacTxControlLow = cpu_to_le16(mcl);64896490/* MacTxControlHigh */6491mch = 0;64926493/* Set fallback rate preamble type */6494if ((preamble_type[1] == BRCMS_SHORT_PREAMBLE) ||6495(preamble_type[1] == BRCMS_GF_PREAMBLE)) {6496if (rspec2rate(rspec[1]) != BRCM_RATE_1M)6497mch |= TXC_PREAMBLE_DATA_FB_SHORT;6498}64996500/* MacFrameControl */6501memcpy(&txh->MacFrameControl, &h->frame_control, sizeof(u16));6502txh->TxFesTimeNormal = cpu_to_le16(0);65036504txh->TxFesTimeFallback = cpu_to_le16(0);65056506/* TxFrameRA */6507memcpy(&txh->TxFrameRA, &h->addr1, ETH_ALEN);65086509/* TxFrameID */6510txh->TxFrameID = cpu_to_le16(frameid);65116512/*6513* TxStatus, Note the case of recreating the first frag of a suppressed6514* frame then we may need to reset the retry cnt's via the status reg6515*/6516txh->TxStatus = cpu_to_le16(status);65176518/*6519* extra fields for ucode AMPDU aggregation, the new fields are added to6520* the END of previous structure so that it's compatible in driver.6521*/6522txh->MaxNMpdus = cpu_to_le16(0);6523txh->MaxABytes_MRT = cpu_to_le16(0);6524txh->MaxABytes_FBR = cpu_to_le16(0);6525txh->MinMBytes = cpu_to_le16(0);65266527/* (5) RTS/CTS: determine RTS/CTS PLCP header and MAC duration,6528* furnish struct d11txh */6529/* RTS PLCP header and RTS frame */6530if (use_rts || use_cts) {6531if (use_rts && use_cts)6532use_cts = false;65336534for (k = 0; k < 2; k++) {6535rts_rspec[k] = brcms_c_rspec_to_rts_rspec(wlc, rspec[k],6536false,6537mimo_ctlchbw);6538}65396540if (!is_ofdm_rate(rts_rspec[0]) &&6541!((rspec2rate(rts_rspec[0]) == BRCM_RATE_1M) ||6542(wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {6543rts_preamble_type[0] = BRCMS_SHORT_PREAMBLE;6544mch |= TXC_PREAMBLE_RTS_MAIN_SHORT;6545}65466547if (!is_ofdm_rate(rts_rspec[1]) &&6548!((rspec2rate(rts_rspec[1]) == BRCM_RATE_1M) ||6549(wlc->PLCPHdr_override == BRCMS_PLCP_LONG))) {6550rts_preamble_type[1] = BRCMS_SHORT_PREAMBLE;6551mch |= TXC_PREAMBLE_RTS_FB_SHORT;6552}65536554/* RTS/CTS additions to MacTxControlLow */6555if (use_cts) {6556txh->MacTxControlLow |= cpu_to_le16(TXC_SENDCTS);6557} else {6558txh->MacTxControlLow |= cpu_to_le16(TXC_SENDRTS);6559txh->MacTxControlLow |= cpu_to_le16(TXC_LONGFRAME);6560}65616562/* RTS PLCP header */6563rts_plcp = txh->RTSPhyHeader;6564if (use_cts)6565rts_phylen = DOT11_CTS_LEN + FCS_LEN;6566else6567rts_phylen = DOT11_RTS_LEN + FCS_LEN;65686569brcms_c_compute_plcp(wlc, rts_rspec[0], rts_phylen, rts_plcp);65706571/* fallback rate version of RTS PLCP header */6572brcms_c_compute_plcp(wlc, rts_rspec[1], rts_phylen,6573rts_plcp_fallback);6574memcpy(&txh->RTSPLCPFallback, rts_plcp_fallback,6575sizeof(txh->RTSPLCPFallback));65766577/* RTS frame fields... */6578rts = (struct ieee80211_rts *)&txh->rts_frame;65796580durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec[0],6581rspec[0], rts_preamble_type[0],6582preamble_type[0], phylen, false);6583rts->duration = cpu_to_le16(durid);6584/* fallback rate version of RTS DUR field */6585durid = brcms_c_compute_rtscts_dur(wlc, use_cts,6586rts_rspec[1], rspec[1],6587rts_preamble_type[1],6588preamble_type[1], phylen, false);6589txh->RTSDurFallback = cpu_to_le16(durid);65906591if (use_cts) {6592rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |6593IEEE80211_STYPE_CTS);65946595memcpy(&rts->ra, &h->addr2, ETH_ALEN);6596} else {6597rts->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL |6598IEEE80211_STYPE_RTS);65996600memcpy(&rts->ra, &h->addr1, ETH_ALEN);6601memcpy(&rts->ta, &h->addr2, ETH_ALEN);6602}66036604/* mainrate6605* low 8 bits: main frag rate/mcs,6606* high 8 bits: rts/cts rate/mcs6607*/6608mainrates |= (is_ofdm_rate(rts_rspec[0]) ?6609D11A_PHY_HDR_GRATE(6610(struct ofdm_phy_hdr *) rts_plcp) :6611rts_plcp[0]) << 8;6612} else {6613memset(txh->RTSPhyHeader, 0, D11_PHY_HDR_LEN);6614memset(&txh->rts_frame, 0, sizeof(struct ieee80211_rts));6615memset(txh->RTSPLCPFallback, 0, sizeof(txh->RTSPLCPFallback));6616txh->RTSDurFallback = 0;6617}66186619#ifdef SUPPORT_40MHZ6620/* add null delimiter count */6621if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && is_mcs_rate(rspec))6622txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] =6623brcm_c_ampdu_null_delim_cnt(wlc->ampdu, scb, rspec, phylen);66246625#endif66266627/*6628* Now that RTS/RTS FB preamble types are updated, write6629* the final value6630*/6631txh->MacTxControlHigh = cpu_to_le16(mch);66326633/*6634* MainRates (both the rts and frag plcp rates have6635* been calculated now)6636*/6637txh->MainRates = cpu_to_le16(mainrates);66386639/* XtraFrameTypes */6640xfts = frametype(rspec[1], wlc->mimoft);6641xfts |= (frametype(rts_rspec[0], wlc->mimoft) << XFTS_RTS_FT_SHIFT);6642xfts |= (frametype(rts_rspec[1], wlc->mimoft) << XFTS_FBRRTS_FT_SHIFT);6643xfts |= CHSPEC_CHANNEL(wlc_phy_chanspec_get(wlc->band->pi)) <<6644XFTS_CHANNEL_SHIFT;6645txh->XtraFrameTypes = cpu_to_le16(xfts);66466647/* PhyTxControlWord */6648phyctl = frametype(rspec[0], wlc->mimoft);6649if ((preamble_type[0] == BRCMS_SHORT_PREAMBLE) ||6650(preamble_type[0] == BRCMS_GF_PREAMBLE)) {6651if (rspec2rate(rspec[0]) != BRCM_RATE_1M)6652phyctl |= PHY_TXC_SHORT_HDR;6653}66546655/* phytxant is properly bit shifted */6656phyctl |= brcms_c_stf_d11hdrs_phyctl_txant(wlc, rspec[0]);6657txh->PhyTxControlWord = cpu_to_le16(phyctl);66586659/* PhyTxControlWord_1 */6660if (BRCMS_PHY_11N_CAP(wlc->band)) {6661u16 phyctl1 = 0;66626663phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[0]);6664txh->PhyTxControlWord_1 = cpu_to_le16(phyctl1);6665phyctl1 = brcms_c_phytxctl1_calc(wlc, rspec[1]);6666txh->PhyTxControlWord_1_Fbr = cpu_to_le16(phyctl1);66676668if (use_rts || use_cts) {6669phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[0]);6670txh->PhyTxControlWord_1_Rts = cpu_to_le16(phyctl1);6671phyctl1 = brcms_c_phytxctl1_calc(wlc, rts_rspec[1]);6672txh->PhyTxControlWord_1_FbrRts = cpu_to_le16(phyctl1);6673}66746675/*6676* For mcs frames, if mixedmode(overloaded with long preamble)6677* is going to be set, fill in non-zero MModeLen and/or6678* MModeFbrLen it will be unnecessary if they are separated6679*/6680if (is_mcs_rate(rspec[0]) &&6681(preamble_type[0] == BRCMS_MM_PREAMBLE)) {6682u16 mmodelen =6683brcms_c_calc_lsig_len(wlc, rspec[0], phylen);6684txh->MModeLen = cpu_to_le16(mmodelen);6685}66866687if (is_mcs_rate(rspec[1]) &&6688(preamble_type[1] == BRCMS_MM_PREAMBLE)) {6689u16 mmodefbrlen =6690brcms_c_calc_lsig_len(wlc, rspec[1], phylen);6691txh->MModeFbrLen = cpu_to_le16(mmodefbrlen);6692}6693}66946695ac = skb_get_queue_mapping(p);6696if ((scb->flags & SCB_WMECAP) && qos && wlc->edcf_txop[ac]) {6697uint frag_dur, dur, dur_fallback;66986699/* WME: Update TXOP threshold */6700if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) && frag == 0) {6701frag_dur =6702brcms_c_calc_frame_time(wlc, rspec[0],6703preamble_type[0], phylen);67046705if (rts) {6706/* 1 RTS or CTS-to-self frame */6707dur =6708brcms_c_calc_cts_time(wlc, rts_rspec[0],6709rts_preamble_type[0]);6710dur_fallback =6711brcms_c_calc_cts_time(wlc, rts_rspec[1],6712rts_preamble_type[1]);6713/* (SIFS + CTS) + SIFS + frame + SIFS + ACK */6714dur += le16_to_cpu(rts->duration);6715dur_fallback +=6716le16_to_cpu(txh->RTSDurFallback);6717} else if (use_rifs) {6718dur = frag_dur;6719dur_fallback = 0;6720} else {6721/* frame + SIFS + ACK */6722dur = frag_dur;6723dur +=6724brcms_c_compute_frame_dur(wlc, rspec[0],6725preamble_type[0], 0);67266727dur_fallback =6728brcms_c_calc_frame_time(wlc, rspec[1],6729preamble_type[1],6730phylen);6731dur_fallback +=6732brcms_c_compute_frame_dur(wlc, rspec[1],6733preamble_type[1], 0);6734}6735/* NEED to set TxFesTimeNormal (hard) */6736txh->TxFesTimeNormal = cpu_to_le16((u16) dur);6737/*6738* NEED to set fallback rate version of6739* TxFesTimeNormal (hard)6740*/6741txh->TxFesTimeFallback =6742cpu_to_le16((u16) dur_fallback);67436744/*6745* update txop byte threshold (txop minus intraframe6746* overhead)6747*/6748if (wlc->edcf_txop[ac] >= (dur - frag_dur)) {6749uint newfragthresh;67506751newfragthresh =6752brcms_c_calc_frame_len(wlc,6753rspec[0], preamble_type[0],6754(wlc->edcf_txop[ac] -6755(dur - frag_dur)));6756/* range bound the fragthreshold */6757if (newfragthresh < DOT11_MIN_FRAG_LEN)6758newfragthresh =6759DOT11_MIN_FRAG_LEN;6760else if (newfragthresh >6761wlc->usr_fragthresh)6762newfragthresh =6763wlc->usr_fragthresh;6764/* update the fragthresh and do txc update */6765if (wlc->fragthresh[queue] !=6766(u16) newfragthresh)6767wlc->fragthresh[queue] =6768(u16) newfragthresh;6769} else {6770brcms_warn(wlc->hw->d11core,6771"wl%d: %s txop invalid for rate %d\n",6772wlc->pub->unit, fifo_names[queue],6773rspec2rate(rspec[0]));6774}67756776if (dur > wlc->edcf_txop[ac])6777brcms_warn(wlc->hw->d11core,6778"wl%d: %s: %s txop exceeded phylen %d/%d dur %d/%d\n",6779wlc->pub->unit, __func__,6780fifo_names[queue],6781phylen, wlc->fragthresh[queue],6782dur, wlc->edcf_txop[ac]);6783}6784}67856786return 0;6787}67886789static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)6790{6791struct dma_pub *dma;6792int fifo, ret = -ENOSPC;6793struct d11txh *txh;6794u16 frameid = INVALIDFID;67956796fifo = brcms_ac_to_fifo(skb_get_queue_mapping(skb));6797dma = wlc->hw->di[fifo];6798txh = (struct d11txh *)(skb->data);67996800if (dma->txavail == 0) {6801/*6802* We sometimes get a frame from mac80211 after stopping6803* the queues. This only ever seems to be a single frame6804* and is seems likely to be a race. TX_HEADROOM should6805* ensure that we have enough space to handle these stray6806* packets, so warn if there isn't. If we're out of space6807* in the tx ring and the tx queue isn't stopped then6808* we've really got a bug; warn loudly if that happens.6809*/6810brcms_warn(wlc->hw->d11core,6811"Received frame for tx with no space in DMA ring\n");6812WARN_ON(!ieee80211_queue_stopped(wlc->pub->ieee_hw,6813skb_get_queue_mapping(skb)));6814return -ENOSPC;6815}68166817/* When a BC/MC frame is being committed to the BCMC fifo6818* via DMA (NOT PIO), update ucode or BSS info as appropriate.6819*/6820if (fifo == TX_BCMC_FIFO)6821frameid = le16_to_cpu(txh->TxFrameID);68226823/* Commit BCMC sequence number in the SHM frame ID location */6824if (frameid != INVALIDFID) {6825/*6826* To inform the ucode of the last mcast frame posted6827* so that it can clear moredata bit6828*/6829brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);6830}68316832ret = brcms_c_txfifo(wlc, fifo, skb);6833/*6834* The only reason for brcms_c_txfifo to fail is because6835* there weren't any DMA descriptors, but we've already6836* checked for that. So if it does fail yell loudly.6837*/6838WARN_ON_ONCE(ret);68396840return ret;6841}68426843bool brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,6844struct ieee80211_hw *hw)6845{6846uint fifo;6847struct scb *scb = &wlc->pri_scb;68486849fifo = brcms_ac_to_fifo(skb_get_queue_mapping(sdu));6850brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0);6851if (!brcms_c_tx(wlc, sdu))6852return true;68536854/* packet discarded */6855dev_kfree_skb_any(sdu);6856return false;6857}68586859int6860brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p)6861{6862struct dma_pub *dma = wlc->hw->di[fifo];6863int ret;6864u16 queue;68656866ret = dma_txfast(wlc, dma, p);6867if (ret < 0)6868wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");68696870/*6871* Stop queue if DMA ring is full. Reserve some free descriptors,6872* as we sometimes receive a frame from mac80211 after the queues6873* are stopped.6874*/6875queue = skb_get_queue_mapping(p);6876if (dma->txavail <= TX_HEADROOM && fifo < TX_BCMC_FIFO &&6877!ieee80211_queue_stopped(wlc->pub->ieee_hw, queue))6878ieee80211_stop_queue(wlc->pub->ieee_hw, queue);68796880return ret;6881}68826883u326884brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,6885bool use_rspec, u16 mimo_ctlchbw)6886{6887u32 rts_rspec = 0;68886889if (use_rspec)6890/* use frame rate as rts rate */6891rts_rspec = rspec;6892else if (wlc->band->gmode && wlc->protection->_g && !is_cck_rate(rspec))6893/* Use 11Mbps as the g protection RTS target rate and fallback.6894* Use the brcms_basic_rate() lookup to find the best basic rate6895* under the target in case 11 Mbps is not Basic.6896* 6 and 9 Mbps are not usually selected by rate selection, but6897* even if the OFDM rate we are protecting is 6 or 9 Mbps, 116898* is more robust.6899*/6900rts_rspec = brcms_basic_rate(wlc, BRCM_RATE_11M);6901else6902/* calculate RTS rate and fallback rate based on the frame rate6903* RTS must be sent at a basic rate since it is a6904* control frame, sec 9.6 of 802.11 spec6905*/6906rts_rspec = brcms_basic_rate(wlc, rspec);69076908if (BRCMS_PHY_11N_CAP(wlc->band)) {6909/* set rts txbw to correct side band */6910rts_rspec &= ~RSPEC_BW_MASK;69116912/*6913* if rspec/rspec_fallback is 40MHz, then send RTS on both6914* 20MHz channel (DUP), otherwise send RTS on control channel6915*/6916if (rspec_is40mhz(rspec) && !is_cck_rate(rts_rspec))6917rts_rspec |= (PHY_TXC1_BW_40MHZ_DUP << RSPEC_BW_SHIFT);6918else6919rts_rspec |= (mimo_ctlchbw << RSPEC_BW_SHIFT);69206921/* pick siso/cdd as default for ofdm */6922if (is_ofdm_rate(rts_rspec)) {6923rts_rspec &= ~RSPEC_STF_MASK;6924rts_rspec |= (wlc->stf->ss_opmode << RSPEC_STF_SHIFT);6925}6926}6927return rts_rspec;6928}69296930/* Update beacon listen interval in shared memory */6931static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)6932{6933/* wake up every DTIM is the default */6934if (wlc->bcn_li_dtim == 1)6935brcms_b_write_shm(wlc->hw, M_BCN_LI, 0);6936else6937brcms_b_write_shm(wlc->hw, M_BCN_LI,6938(wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);6939}69406941static void6942brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,6943u32 *tsf_h_ptr)6944{6945struct bcma_device *core = wlc_hw->d11core;69466947/* read the tsf timer low, then high to get an atomic read */6948*tsf_l_ptr = bcma_read32(core, D11REGOFFS(tsf_timerlow));6949*tsf_h_ptr = bcma_read32(core, D11REGOFFS(tsf_timerhigh));6950}69516952/*6953* recover 64bit TSF value from the 16bit TSF value in the rx header6954* given the assumption that the TSF passed in header is within 65ms6955* of the current tsf.6956*6957* 6 5 4 4 3 2 16958* 3.......6.......8.......0.......2.......4.......6.......8......06959* |<---------- tsf_h ----------->||<--- tsf_l -->||<-RxTSFTime ->|6960*6961* The RxTSFTime are the lowest 16 bits and provided by the ucode. The6962* tsf_l is filled in by brcms_b_recv, which is done earlier in the6963* receive call sequence after rx interrupt. Only the higher 16 bits6964* are used. Finally, the tsf_h is read from the tsf register.6965*/6966static u64 brcms_c_recover_tsf64(struct brcms_c_info *wlc,6967struct d11rxhdr *rxh)6968{6969u32 tsf_h, tsf_l;6970u16 rx_tsf_0_15, rx_tsf_16_31;69716972brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);69736974rx_tsf_16_31 = (u16)(tsf_l >> 16);6975rx_tsf_0_15 = rxh->RxTSFTime;69766977/*6978* a greater tsf time indicates the low 16 bits of6979* tsf_l wrapped, so decrement the high 16 bits.6980*/6981if ((u16)tsf_l < rx_tsf_0_15) {6982rx_tsf_16_31 -= 1;6983if (rx_tsf_16_31 == 0xffff)6984tsf_h -= 1;6985}69866987return ((u64)tsf_h << 32) | (((u32)rx_tsf_16_31 << 16) + rx_tsf_0_15);6988}69896990static void6991prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,6992struct sk_buff *p,6993struct ieee80211_rx_status *rx_status)6994{6995int channel;6996u32 rspec;6997unsigned char *plcp;69986999/* fill in TSF and flag its presence */7000rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh);7001rx_status->flag |= RX_FLAG_MACTIME_START;70027003channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);70047005rx_status->band =7006channel > 14 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ;7007rx_status->freq =7008ieee80211_channel_to_frequency(channel, rx_status->band);70097010rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);70117012/* noise */7013/* qual */7014rx_status->antenna =7015(rxh->PhyRxStatus_0 & PRXS0_RXANT_UPSUBBAND) ? 1 : 0;70167017plcp = p->data;70187019rspec = brcms_c_compute_rspec(rxh, plcp);7020if (is_mcs_rate(rspec)) {7021rx_status->rate_idx = rspec & RSPEC_RATE_MASK;7022rx_status->encoding = RX_ENC_HT;7023if (rspec_is40mhz(rspec))7024rx_status->bw = RATE_INFO_BW_40;7025} else {7026switch (rspec2rate(rspec)) {7027case BRCM_RATE_1M:7028rx_status->rate_idx = 0;7029break;7030case BRCM_RATE_2M:7031rx_status->rate_idx = 1;7032break;7033case BRCM_RATE_5M5:7034rx_status->rate_idx = 2;7035break;7036case BRCM_RATE_11M:7037rx_status->rate_idx = 3;7038break;7039case BRCM_RATE_6M:7040rx_status->rate_idx = 4;7041break;7042case BRCM_RATE_9M:7043rx_status->rate_idx = 5;7044break;7045case BRCM_RATE_12M:7046rx_status->rate_idx = 6;7047break;7048case BRCM_RATE_18M:7049rx_status->rate_idx = 7;7050break;7051case BRCM_RATE_24M:7052rx_status->rate_idx = 8;7053break;7054case BRCM_RATE_36M:7055rx_status->rate_idx = 9;7056break;7057case BRCM_RATE_48M:7058rx_status->rate_idx = 10;7059break;7060case BRCM_RATE_54M:7061rx_status->rate_idx = 11;7062break;7063default:7064brcms_err(wlc->hw->d11core,7065"%s: Unknown rate\n", __func__);7066}70677068/*7069* For 5GHz, we should decrease the index as it is7070* a subset of the 2.4G rates. See bitrates field7071* of brcms_band_5GHz_nphy (in mac80211_if.c).7072*/7073if (rx_status->band == NL80211_BAND_5GHZ)7074rx_status->rate_idx -= BRCMS_LEGACY_5G_RATE_OFFSET;70757076/* Determine short preamble and rate_idx */7077if (is_cck_rate(rspec)) {7078if (rxh->PhyRxStatus_0 & PRXS0_SHORTH)7079rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;7080} else if (is_ofdm_rate(rspec)) {7081rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE;7082} else {7083brcms_err(wlc->hw->d11core, "%s: Unknown modulation\n",7084__func__);7085}7086}70877088if (plcp3_issgi(plcp[3]))7089rx_status->enc_flags |= RX_ENC_FLAG_SHORT_GI;70907091if (rxh->RxStatus1 & RXS_DECERR) {7092rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;7093brcms_err(wlc->hw->d11core, "%s: RX_FLAG_FAILED_PLCP_CRC\n",7094__func__);7095}7096if (rxh->RxStatus1 & RXS_FCSERR) {7097rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;7098brcms_err(wlc->hw->d11core, "%s: RX_FLAG_FAILED_FCS_CRC\n",7099__func__);7100}7101}71027103static void7104brcms_c_recvctl(struct brcms_c_info *wlc, struct d11rxhdr *rxh,7105struct sk_buff *p)7106{7107int len_mpdu;7108struct ieee80211_rx_status rx_status;7109struct ieee80211_hdr *hdr;71107111memset(&rx_status, 0, sizeof(rx_status));7112prep_mac80211_status(wlc, rxh, p, &rx_status);71137114/* mac header+body length, exclude CRC and plcp header */7115len_mpdu = p->len - D11_PHY_HDR_LEN - FCS_LEN;7116skb_pull(p, D11_PHY_HDR_LEN);7117__skb_trim(p, len_mpdu);71187119/* unmute transmit */7120if (wlc->hw->suspended_fifos) {7121hdr = (struct ieee80211_hdr *)p->data;7122if (ieee80211_is_beacon(hdr->frame_control))7123brcms_b_mute(wlc->hw, false);7124}71257126memcpy(IEEE80211_SKB_RXCB(p), &rx_status, sizeof(rx_status));7127ieee80211_rx_irqsafe(wlc->pub->ieee_hw, p);7128}71297130/* calculate frame duration for Mixed-mode L-SIG spoofing, return7131* number of bytes goes in the length field7132*7133* Formula given by HT PHY Spec v 1.137134* len = 3(nsyms + nstream + 3) - 37135*/7136u167137brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,7138uint mac_len)7139{7140uint nsyms, len = 0, kNdps;71417142if (is_mcs_rate(ratespec)) {7143uint mcs = ratespec & RSPEC_RATE_MASK;7144int tot_streams = (mcs_2_txstreams(mcs) + 1) +7145rspec_stc(ratespec);71467147/*7148* the payload duration calculation matches that7149* of regular ofdm7150*/7151/* 1000Ndbps = kbps * 4 */7152kNdps = mcs_2_rate(mcs, rspec_is40mhz(ratespec),7153rspec_issgi(ratespec)) * 4;71547155if (rspec_stc(ratespec) == 0)7156nsyms =7157CEIL((APHY_SERVICE_NBITS + 8 * mac_len +7158APHY_TAIL_NBITS) * 1000, kNdps);7159else7160/* STBC needs to have even number of symbols */7161nsyms =71622 *7163CEIL((APHY_SERVICE_NBITS + 8 * mac_len +7164APHY_TAIL_NBITS) * 1000, 2 * kNdps);71657166/* (+3) account for HT-SIG(2) and HT-STF(1) */7167nsyms += (tot_streams + 3);7168/*7169* 3 bytes/symbol @ legacy 6Mbps rate7170* (-3) excluding service bits and tail bits7171*/7172len = (3 * nsyms) - 3;7173}71747175return (u16) len;7176}71777178static void7179brcms_c_mod_prb_rsp_rate_table(struct brcms_c_info *wlc, uint frame_len)7180{7181const struct brcms_c_rateset *rs_dflt;7182struct brcms_c_rateset rs;7183u8 rate;7184u16 entry_ptr;7185u8 plcp[D11_PHY_HDR_LEN];7186u16 dur, sifs;7187uint i;71887189sifs = get_sifs(wlc->band);71907191rs_dflt = brcms_c_rateset_get_hwrs(wlc);71927193brcms_c_rateset_copy(rs_dflt, &rs);7194brcms_c_rateset_mcs_upd(&rs, wlc->stf->txstreams);71957196/*7197* walk the phy rate table and update MAC core SHM7198* basic rate table entries7199*/7200for (i = 0; i < rs.count; i++) {7201rate = rs.rates[i] & BRCMS_RATE_MASK;72027203entry_ptr = brcms_b_rate_shm_offset(wlc->hw, rate);72047205/* Calculate the Probe Response PLCP for the given rate */7206brcms_c_compute_plcp(wlc, rate, frame_len, plcp);72077208/*7209* Calculate the duration of the Probe Response7210* frame plus SIFS for the MAC7211*/7212dur = (u16) brcms_c_calc_frame_time(wlc, rate,7213BRCMS_LONG_PREAMBLE, frame_len);7214dur += sifs;72157216/* Update the SHM Rate Table entry Probe Response values */7217brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS,7218(u16) (plcp[0] + (plcp[1] << 8)));7219brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_PLCP_POS + 2,7220(u16) (plcp[2] + (plcp[3] << 8)));7221brcms_b_write_shm(wlc->hw, entry_ptr + M_RT_PRS_DUR_POS, dur);7222}7223}72247225int brcms_c_get_header_len(void)7226{7227return TXOFF;7228}72297230static void brcms_c_beacon_write(struct brcms_c_info *wlc,7231struct sk_buff *beacon, u16 tim_offset,7232u16 dtim_period, bool bcn0, bool bcn1)7233{7234size_t len;7235struct ieee80211_tx_info *tx_info;7236struct brcms_hardware *wlc_hw = wlc->hw;7237struct ieee80211_hw *ieee_hw = brcms_c_pub(wlc)->ieee_hw;72387239/* Get tx_info */7240tx_info = IEEE80211_SKB_CB(beacon);72417242len = min_t(size_t, beacon->len, BCN_TMPL_LEN);7243wlc->bcn_rspec = ieee80211_get_tx_rate(ieee_hw, tx_info)->hw_value;72447245brcms_c_compute_plcp(wlc, wlc->bcn_rspec,7246len + FCS_LEN - D11_PHY_HDR_LEN, beacon->data);72477248/* "Regular" and 16 MBSS but not for 4 MBSS */7249/* Update the phytxctl for the beacon based on the rspec */7250brcms_c_beacon_phytxctl_txant_upd(wlc, wlc->bcn_rspec);72517252if (bcn0) {7253/* write the probe response into the template region */7254brcms_b_write_template_ram(wlc_hw, T_BCN0_TPL_BASE,7255(len + 3) & ~3, beacon->data);72567257/* write beacon length to SCR */7258brcms_b_write_shm(wlc_hw, M_BCN0_FRM_BYTESZ, (u16) len);7259}7260if (bcn1) {7261/* write the probe response into the template region */7262brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE,7263(len + 3) & ~3, beacon->data);72647265/* write beacon length to SCR */7266brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);7267}72687269if (tim_offset != 0) {7270brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,7271tim_offset + D11B_PHY_HDR_LEN);7272brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, dtim_period);7273} else {7274brcms_b_write_shm(wlc_hw, M_TIMBPOS_INBEACON,7275len + D11B_PHY_HDR_LEN);7276brcms_b_write_shm(wlc_hw, M_DOT11_DTIMPERIOD, 0);7277}7278}72797280static void brcms_c_update_beacon_hw(struct brcms_c_info *wlc,7281struct sk_buff *beacon, u16 tim_offset,7282u16 dtim_period)7283{7284struct brcms_hardware *wlc_hw = wlc->hw;7285struct bcma_device *core = wlc_hw->d11core;72867287/* Hardware beaconing for this config */7288u32 both_valid = MCMD_BCN0VLD | MCMD_BCN1VLD;72897290/* Check if both templates are in use, if so sched. an interrupt7291* that will call back into this routine7292*/7293if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid)7294/* clear any previous status */7295bcma_write32(core, D11REGOFFS(macintstatus), MI_BCNTPL);72967297if (wlc->beacon_template_virgin) {7298wlc->beacon_template_virgin = false;7299brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,7300true);7301/* mark beacon0 valid */7302bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);7303return;7304}73057306/* Check that after scheduling the interrupt both of the7307* templates are still busy. if not clear the int. & remask7308*/7309if ((bcma_read32(core, D11REGOFFS(maccommand)) & both_valid) == both_valid) {7310wlc->defmacintmask |= MI_BCNTPL;7311return;7312}73137314if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN0VLD)) {7315brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period, true,7316false);7317/* mark beacon0 valid */7318bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN0VLD);7319return;7320}7321if (!(bcma_read32(core, D11REGOFFS(maccommand)) & MCMD_BCN1VLD)) {7322brcms_c_beacon_write(wlc, beacon, tim_offset, dtim_period,7323false, true);7324/* mark beacon0 valid */7325bcma_set32(core, D11REGOFFS(maccommand), MCMD_BCN1VLD);7326}7327}73287329/*7330* Update all beacons for the system.7331*/7332void brcms_c_update_beacon(struct brcms_c_info *wlc)7333{7334struct brcms_bss_cfg *bsscfg = wlc->bsscfg;73357336if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||7337bsscfg->type == BRCMS_TYPE_ADHOC)) {7338/* Clear the soft intmask */7339wlc->defmacintmask &= ~MI_BCNTPL;7340if (!wlc->beacon)7341return;7342brcms_c_update_beacon_hw(wlc, wlc->beacon,7343wlc->beacon_tim_offset,7344wlc->beacon_dtim_period);7345}7346}73477348void brcms_c_set_new_beacon(struct brcms_c_info *wlc, struct sk_buff *beacon,7349u16 tim_offset, u16 dtim_period)7350{7351if (!beacon)7352return;7353if (wlc->beacon)7354dev_kfree_skb_any(wlc->beacon);7355wlc->beacon = beacon;73567357/* add PLCP */7358skb_push(wlc->beacon, D11_PHY_HDR_LEN);7359wlc->beacon_tim_offset = tim_offset;7360wlc->beacon_dtim_period = dtim_period;7361brcms_c_update_beacon(wlc);7362}73637364void brcms_c_set_new_probe_resp(struct brcms_c_info *wlc,7365struct sk_buff *probe_resp)7366{7367if (!probe_resp)7368return;7369if (wlc->probe_resp)7370dev_kfree_skb_any(wlc->probe_resp);7371wlc->probe_resp = probe_resp;73727373/* add PLCP */7374skb_push(wlc->probe_resp, D11_PHY_HDR_LEN);7375brcms_c_update_probe_resp(wlc, false);7376}73777378void brcms_c_enable_probe_resp(struct brcms_c_info *wlc, bool enable)7379{7380/*7381* prevent ucode from sending probe responses by setting the timeout7382* to 1, it can not send it in that time frame.7383*/7384wlc->prb_resp_timeout = enable ? BRCMS_PRB_RESP_TIMEOUT : 1;7385brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);7386/* TODO: if (enable) => also deactivate receiving of probe request */7387}73887389/* Write ssid into shared memory */7390static void7391brcms_c_shm_ssid_upd(struct brcms_c_info *wlc, struct brcms_bss_cfg *cfg)7392{7393u8 *ssidptr = cfg->SSID;7394u16 base = M_SSID;7395u8 ssidbuf[IEEE80211_MAX_SSID_LEN];73967397/* padding the ssid with zero and copy it into shm */7398memset(ssidbuf, 0, IEEE80211_MAX_SSID_LEN);7399memcpy(ssidbuf, ssidptr, cfg->SSID_len);74007401brcms_c_copyto_shm(wlc, base, ssidbuf, IEEE80211_MAX_SSID_LEN);7402brcms_b_write_shm(wlc->hw, M_SSIDLEN, (u16) cfg->SSID_len);7403}74047405static void7406brcms_c_bss_update_probe_resp(struct brcms_c_info *wlc,7407struct brcms_bss_cfg *cfg,7408struct sk_buff *probe_resp,7409bool suspend)7410{7411int len;74127413len = min_t(size_t, probe_resp->len, BCN_TMPL_LEN);74147415if (suspend)7416brcms_c_suspend_mac_and_wait(wlc);74177418/* write the probe response into the template region */7419brcms_b_write_template_ram(wlc->hw, T_PRS_TPL_BASE,7420(len + 3) & ~3, probe_resp->data);74217422/* write the length of the probe response frame (+PLCP/-FCS) */7423brcms_b_write_shm(wlc->hw, M_PRB_RESP_FRM_LEN, (u16) len);74247425/* write the SSID and SSID length */7426brcms_c_shm_ssid_upd(wlc, cfg);74277428/*7429* Write PLCP headers and durations for probe response frames7430* at all rates. Use the actual frame length covered by the7431* PLCP header for the call to brcms_c_mod_prb_rsp_rate_table()7432* by subtracting the PLCP len and adding the FCS.7433*/7434brcms_c_mod_prb_rsp_rate_table(wlc,7435(u16)len + FCS_LEN - D11_PHY_HDR_LEN);74367437if (suspend)7438brcms_c_enable_mac(wlc);7439}74407441void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)7442{7443struct brcms_bss_cfg *bsscfg = wlc->bsscfg;74447445/* update AP or IBSS probe responses */7446if (wlc->pub->up && (bsscfg->type == BRCMS_TYPE_AP ||7447bsscfg->type == BRCMS_TYPE_ADHOC)) {7448if (!wlc->probe_resp)7449return;7450brcms_c_bss_update_probe_resp(wlc, bsscfg, wlc->probe_resp,7451suspend);7452}7453}74547455int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,7456uint *blocks)7457{7458if (fifo >= NFIFO)7459return -EINVAL;74607461*blocks = wlc_hw->xmtfifo_sz[fifo];74627463return 0;7464}74657466void7467brcms_c_set_addrmatch(struct brcms_c_info *wlc, int match_reg_offset,7468const u8 *addr)7469{7470brcms_b_set_addrmatch(wlc->hw, match_reg_offset, addr);7471if (match_reg_offset == RCM_BSSID_OFFSET)7472memcpy(wlc->bsscfg->BSSID, addr, ETH_ALEN);7473}74747475/*7476* Flag 'scan in progress' to withhold dynamic phy calibration7477*/7478void brcms_c_scan_start(struct brcms_c_info *wlc)7479{7480wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, true);7481}74827483void brcms_c_scan_stop(struct brcms_c_info *wlc)7484{7485wlc_phy_hold_upd(wlc->band->pi, PHY_HOLD_FOR_SCAN, false);7486}74877488void brcms_c_associate_upd(struct brcms_c_info *wlc, bool state)7489{7490wlc->pub->associated = state;7491}74927493/*7494* When a remote STA/AP is removed by Mac80211, or when it can no longer accept7495* AMPDU traffic, packets pending in hardware have to be invalidated so that7496* when later on hardware releases them, they can be handled appropriately.7497*/7498void brcms_c_inval_dma_pkts(struct brcms_hardware *hw,7499struct ieee80211_sta *sta,7500void (*dma_callback_fn))7501{7502struct dma_pub *dmah;7503int i;7504for (i = 0; i < NFIFO; i++) {7505dmah = hw->di[i];7506if (dmah != NULL)7507dma_walk_packets(dmah, dma_callback_fn, sta);7508}7509}75107511int brcms_c_get_curband(struct brcms_c_info *wlc)7512{7513return wlc->band->bandunit;7514}75157516bool brcms_c_tx_flush_completed(struct brcms_c_info *wlc)7517{7518int i;75197520/* Kick DMA to send any pending AMPDU */7521for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)7522if (wlc->hw->di[i])7523dma_kick_tx(wlc->hw->di[i]);75247525return !brcms_txpktpendtot(wlc);7526}75277528void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc, u8 interval)7529{7530wlc->bcn_li_bcn = interval;7531if (wlc->pub->up)7532brcms_c_bcn_li_upd(wlc);7533}75347535u64 brcms_c_tsf_get(struct brcms_c_info *wlc)7536{7537u32 tsf_h, tsf_l;7538u64 tsf;75397540brcms_b_read_tsf(wlc->hw, &tsf_l, &tsf_h);75417542tsf = tsf_h;7543tsf <<= 32;7544tsf |= tsf_l;75457546return tsf;7547}75487549void brcms_c_tsf_set(struct brcms_c_info *wlc, u64 tsf)7550{7551u32 tsf_h, tsf_l;75527553brcms_c_time_lock(wlc);75547555tsf_l = tsf;7556tsf_h = (tsf >> 32);75577558/* read the tsf timer low, then high to get an atomic read */7559bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerlow), tsf_l);7560bcma_write32(wlc->hw->d11core, D11REGOFFS(tsf_timerhigh), tsf_h);75617562brcms_c_time_unlock(wlc);7563}75647565int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr)7566{7567uint qdbm;75687569/* Remove override bit and clip to max qdbm value */7570qdbm = min_t(uint, txpwr * BRCMS_TXPWR_DB_FACTOR, 0xff);7571return wlc_phy_txpower_set(wlc->band->pi, qdbm, false);7572}75737574int brcms_c_get_tx_power(struct brcms_c_info *wlc)7575{7576uint qdbm;7577bool override;75787579wlc_phy_txpower_get(wlc->band->pi, &qdbm, &override);75807581/* Return qdbm units */7582return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);7583}75847585/* Process received frames */7586/*7587* Return true if more frames need to be processed. false otherwise.7588* Param 'bound' indicates max. # frames to process before break out.7589*/7590static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)7591{7592struct d11rxhdr *rxh;7593struct ieee80211_hdr *h;7594uint len;7595bool is_amsdu;75967597/* frame starts with rxhdr */7598rxh = (struct d11rxhdr *) (p->data);75997600/* strip off rxhdr */7601skb_pull(p, BRCMS_HWRXOFF);76027603/* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */7604if (rxh->RxStatus1 & RXS_PBPRES) {7605if (p->len < 2) {7606brcms_err(wlc->hw->d11core,7607"wl%d: recv: rcvd runt of len %d\n",7608wlc->pub->unit, p->len);7609goto toss;7610}7611skb_pull(p, 2);7612}76137614h = (struct ieee80211_hdr *)(p->data + D11_PHY_HDR_LEN);7615len = p->len;76167617if (rxh->RxStatus1 & RXS_FCSERR) {7618if (!(wlc->filter_flags & FIF_FCSFAIL))7619goto toss;7620}76217622/* check received pkt has at least frame control field */7623if (len < D11_PHY_HDR_LEN + sizeof(h->frame_control))7624goto toss;76257626/* not supporting A-MSDU */7627is_amsdu = rxh->RxStatus2 & RXS_AMSDU_MASK;7628if (is_amsdu)7629goto toss;76307631brcms_c_recvctl(wlc, rxh, p);7632return;76337634toss:7635brcmu_pkt_buf_free_skb(p);7636}76377638/* Process received frames */7639/*7640* Return true if more frames need to be processed. false otherwise.7641* Param 'bound' indicates max. # frames to process before break out.7642*/7643static bool7644brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)7645{7646struct sk_buff *p;7647struct sk_buff *next = NULL;7648struct sk_buff_head recv_frames;76497650uint n = 0;7651uint bound_limit = bound ? RXBND : -1;7652bool morepending = false;76537654skb_queue_head_init(&recv_frames);76557656/* gather received frames */7657do {7658/* !give others some time to run! */7659if (n >= bound_limit)7660break;76617662morepending = dma_rx(wlc_hw->di[fifo], &recv_frames);7663n++;7664} while (morepending);76657666/* post more rbufs */7667dma_rxfill(wlc_hw->di[fifo]);76687669/* process each frame */7670skb_queue_walk_safe(&recv_frames, p, next) {7671struct d11rxhdr_le *rxh_le;7672struct d11rxhdr *rxh;76737674skb_unlink(p, &recv_frames);7675rxh_le = (struct d11rxhdr_le *)p->data;7676rxh = (struct d11rxhdr *)p->data;76777678/* fixup rx header endianness */7679rxh->RxFrameSize = le16_to_cpu(rxh_le->RxFrameSize);7680rxh->PhyRxStatus_0 = le16_to_cpu(rxh_le->PhyRxStatus_0);7681rxh->PhyRxStatus_1 = le16_to_cpu(rxh_le->PhyRxStatus_1);7682rxh->PhyRxStatus_2 = le16_to_cpu(rxh_le->PhyRxStatus_2);7683rxh->PhyRxStatus_3 = le16_to_cpu(rxh_le->PhyRxStatus_3);7684rxh->PhyRxStatus_4 = le16_to_cpu(rxh_le->PhyRxStatus_4);7685rxh->PhyRxStatus_5 = le16_to_cpu(rxh_le->PhyRxStatus_5);7686rxh->RxStatus1 = le16_to_cpu(rxh_le->RxStatus1);7687rxh->RxStatus2 = le16_to_cpu(rxh_le->RxStatus2);7688rxh->RxTSFTime = le16_to_cpu(rxh_le->RxTSFTime);7689rxh->RxChan = le16_to_cpu(rxh_le->RxChan);76907691brcms_c_recv(wlc_hw->wlc, p);7692}76937694return morepending;7695}76967697/* second-level interrupt processing7698* Return true if another dpc needs to be re-scheduled. false otherwise.7699* Param 'bounded' indicates if applicable loops should be bounded.7700*/7701bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)7702{7703u32 macintstatus;7704struct brcms_hardware *wlc_hw = wlc->hw;7705struct bcma_device *core = wlc_hw->d11core;77067707if (brcms_deviceremoved(wlc)) {7708brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,7709__func__);7710brcms_down(wlc->wl);7711return false;7712}77137714/* grab and clear the saved software intstatus bits */7715macintstatus = wlc->macintstatus;7716wlc->macintstatus = 0;77177718brcms_dbg_int(core, "wl%d: macintstatus 0x%x\n",7719wlc_hw->unit, macintstatus);77207721WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */77227723/* tx status */7724if (macintstatus & MI_TFS) {7725bool fatal;7726if (brcms_b_txstatus(wlc->hw, bounded, &fatal))7727wlc->macintstatus |= MI_TFS;7728if (fatal) {7729brcms_err(core, "MI_TFS: fatal\n");7730goto fatal;7731}7732}77337734if (macintstatus & (MI_TBTT | MI_DTIM_TBTT))7735brcms_c_tbtt(wlc);77367737/* ATIM window end */7738if (macintstatus & MI_ATIMWINEND) {7739brcms_dbg_info(core, "end of ATIM window\n");7740bcma_set32(core, D11REGOFFS(maccommand), wlc->qvalid);7741wlc->qvalid = 0;7742}77437744/*7745* received data or control frame, MI_DMAINT is7746* indication of RX_FIFO interrupt7747*/7748if (macintstatus & MI_DMAINT)7749if (brcms_b_recv(wlc_hw, RX_FIFO, bounded))7750wlc->macintstatus |= MI_DMAINT;77517752/* noise sample collected */7753if (macintstatus & MI_BG_NOISE)7754wlc_phy_noise_sample_intr(wlc_hw->band->pi);77557756if (macintstatus & MI_GP0) {7757brcms_err(core, "wl%d: PSM microcode watchdog fired at %d "7758"(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);77597760printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",7761__func__, ai_get_chip_id(wlc_hw->sih),7762ai_get_chiprev(wlc_hw->sih));7763brcms_fatal_error(wlc_hw->wlc->wl);7764}77657766/* gptimer timeout */7767if (macintstatus & MI_TO)7768bcma_write32(core, D11REGOFFS(gptimer), 0);77697770if (macintstatus & MI_RFDISABLE) {7771brcms_dbg_info(core, "wl%d: BMAC Detected a change on the"7772" RF Disable Input\n", wlc_hw->unit);7773brcms_rfkill_set_hw_state(wlc->wl);7774}77757776/* BCN template is available */7777if (macintstatus & MI_BCNTPL)7778brcms_c_update_beacon(wlc);77797780/* it isn't done and needs to be resched if macintstatus is non-zero */7781return wlc->macintstatus != 0;77827783fatal:7784brcms_fatal_error(wlc_hw->wlc->wl);7785return wlc->macintstatus != 0;7786}77877788void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)7789{7790struct bcma_device *core = wlc->hw->d11core;7791struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.chandef.chan;7792u16 chanspec;77937794brcms_dbg_info(core, "wl%d\n", wlc->pub->unit);77957796chanspec = ch20mhz_chspec(ch->hw_value);77977798brcms_b_init(wlc->hw, chanspec);77997800/* update beacon listen interval */7801brcms_c_bcn_li_upd(wlc);78027803/* write ethernet address to core */7804brcms_c_set_mac(wlc->bsscfg);7805brcms_c_set_bssid(wlc->bsscfg);78067807/* Update tsf_cfprep if associated and up */7808if (wlc->pub->associated && wlc->pub->up) {7809u32 bi;78107811/* get beacon period and convert to uS */7812bi = wlc->bsscfg->current_bss->beacon_period << 10;7813/*7814* update since init path would reset7815* to default value7816*/7817bcma_write32(core, D11REGOFFS(tsf_cfprep),7818bi << CFPREP_CBI_SHIFT);78197820/* Update maccontrol PM related bits */7821brcms_c_set_ps_ctrl(wlc);7822}78237824brcms_c_bandinit_ordered(wlc, chanspec);78257826/* init probe response timeout */7827brcms_b_write_shm(wlc->hw, M_PRS_MAXTIME, wlc->prb_resp_timeout);78287829/* init max burst txop (framebursting) */7830brcms_b_write_shm(wlc->hw, M_MBURST_TXOP,7831(wlc->7832_rifs ? (EDCF_AC_VO_TXOP_AP << 5) : MAXFRAMEBURST_TXOP));78337834/* initialize maximum allowed duty cycle */7835brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_ofdm, true, true);7836brcms_c_duty_cycle_set(wlc, wlc->tx_duty_cycle_cck, false, true);78377838/*7839* Update some shared memory locations related to7840* max AMPDU size allowed to received7841*/7842brcms_c_ampdu_shm_upd(wlc->ampdu);78437844/* band-specific inits */7845brcms_c_bsinit(wlc);78467847/* Enable EDCF mode (while the MAC is suspended) */7848bcma_set16(core, D11REGOFFS(ifs_ctl), IFS_USEEDCF);7849brcms_c_edcf_setparams(wlc, false);78507851/* read the ucode version if we have not yet done so */7852if (wlc->ucode_rev == 0) {7853u16 rev;7854u16 patch;78557856rev = brcms_b_read_shm(wlc->hw, M_BOM_REV_MAJOR);7857patch = brcms_b_read_shm(wlc->hw, M_BOM_REV_MINOR);7858wlc->ucode_rev = (rev << NBITS(u16)) | patch;7859snprintf(wlc->wiphy->fw_version,7860sizeof(wlc->wiphy->fw_version), "%u.%u", rev, patch);7861}78627863/* ..now really unleash hell (allow the MAC out of suspend) */7864brcms_c_enable_mac(wlc);78657866/* suspend the tx fifos and mute the phy for preism cac time */7867if (mute_tx)7868brcms_b_mute(wlc->hw, true);78697870/* enable the RF Disable Delay timer */7871bcma_write32(core, D11REGOFFS(rfdisabledly), RFDISABLE_DEFAULT);78727873/*7874* Initialize WME parameters; if they haven't been set by some other7875* mechanism (IOVar, etc) then read them from the hardware.7876*/7877if (GFIELD(wlc->wme_retries[0], EDCF_SHORT) == 0) {7878/* Uninitialized; read from HW */7879int ac;78807881for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)7882wlc->wme_retries[ac] =7883brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));7884}7885}78867887/*7888* The common driver entry routine. Error codes should be unique7889*/7890struct brcms_c_info *7891brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,7892bool piomode, uint *perr)7893{7894struct brcms_c_info *wlc;7895uint err = 0;7896uint i, j;7897struct brcms_pub *pub;78987899/* allocate struct brcms_c_info state and its substructures */7900wlc = brcms_c_attach_malloc(unit, &err, 0);7901if (wlc == NULL)7902goto fail;7903wlc->wiphy = wl->wiphy;7904pub = wlc->pub;79057906#if defined(DEBUG)7907wlc_info_dbg = wlc;7908#endif79097910wlc->band = wlc->bandstate[0];7911wlc->core = wlc->corestate;7912wlc->wl = wl;7913pub->unit = unit;7914pub->_piomode = piomode;7915wlc->bandinit_pending = false;7916wlc->beacon_template_virgin = true;79177918/* populate struct brcms_c_info with default values */7919brcms_c_info_init(wlc, unit);79207921/* update sta/ap related parameters */7922brcms_c_ap_upd(wlc);79237924/*7925* low level attach steps(all hw accesses go7926* inside, no more in rest of the attach)7927*/7928err = brcms_b_attach(wlc, core, unit, piomode);7929if (err)7930goto fail;79317932brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, OFF);79337934pub->phy_11ncapable = BRCMS_PHY_11N_CAP(wlc->band);79357936/* disable allowed duty cycle */7937wlc->tx_duty_cycle_ofdm = 0;7938wlc->tx_duty_cycle_cck = 0;79397940brcms_c_stf_phy_chain_calc(wlc);79417942/* txchain 1: txant 0, txchain 2: txant 1 */7943if (BRCMS_ISNPHY(wlc->band) && (wlc->stf->txstreams == 1))7944wlc->stf->txant = wlc->stf->hw_txchain - 1;79457946/* push to BMAC driver */7947wlc_phy_stf_chain_init(wlc->band->pi, wlc->stf->hw_txchain,7948wlc->stf->hw_rxchain);79497950/* pull up some info resulting from the low attach */7951for (i = 0; i < NFIFO; i++)7952wlc->core->txavail[i] = wlc->hw->txavail[i];79537954memcpy(&wlc->perm_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);7955memcpy(&pub->cur_etheraddr, &wlc->hw->etheraddr, ETH_ALEN);79567957for (j = 0; j < wlc->pub->_nbands; j++) {7958wlc->band = wlc->bandstate[j];79597960if (!brcms_c_attach_stf_ant_init(wlc)) {7961err = 24;7962goto fail;7963}79647965/* default contention windows size limits */7966wlc->band->CWmin = APHY_CWMIN;7967wlc->band->CWmax = PHY_CWMAX;79687969/* init gmode value */7970if (wlc->band->bandtype == BRCM_BAND_2G) {7971wlc->band->gmode = GMODE_AUTO;7972brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER,7973wlc->band->gmode);7974}79757976/* init _n_enab supported mode */7977if (BRCMS_PHY_11N_CAP(wlc->band)) {7978pub->_n_enab = SUPPORT_11N;7979brcms_c_protection_upd(wlc, BRCMS_PROT_N_USER,7980((pub->_n_enab ==7981SUPPORT_11N) ? WL_11N_2x2 :7982WL_11N_3x3));7983}79847985/* init per-band default rateset, depend on band->gmode */7986brcms_default_rateset(wlc, &wlc->band->defrateset);79877988/* fill in hw_rateset */7989brcms_c_rateset_filter(&wlc->band->defrateset,7990&wlc->band->hw_rateset, false,7991BRCMS_RATES_CCK_OFDM, BRCMS_RATE_MASK,7992(bool) (wlc->pub->_n_enab & SUPPORT_11N));7993}79947995/*7996* update antenna config due to7997* wlc->stf->txant/txchain/ant_rx_ovr change7998*/7999brcms_c_stf_phy_txant_upd(wlc);80008001/* attach each modules */8002err = brcms_c_attach_module(wlc);8003if (err != 0)8004goto fail;80058006if (!brcms_c_timers_init(wlc, unit)) {8007wiphy_err(wl->wiphy, "wl%d: %s: init_timer failed\n", unit,8008__func__);8009err = 32;8010goto fail;8011}80128013/* depend on rateset, gmode */8014wlc->cmi = brcms_c_channel_mgr_attach(wlc);8015if (!wlc->cmi) {8016wiphy_err(wl->wiphy, "wl%d: %s: channel_mgr_attach failed"8017"\n", unit, __func__);8018err = 33;8019goto fail;8020}80218022/* init default when all parameters are ready, i.e. ->rateset */8023brcms_c_bss_default_init(wlc);80248025/*8026* Complete the wlc default state initializations..8027*/80288029wlc->bsscfg->wlc = wlc;80308031wlc->mimoft = FT_HT;8032wlc->mimo_40txbw = AUTO;8033wlc->ofdm_40txbw = AUTO;8034wlc->cck_40txbw = AUTO;8035brcms_c_update_mimo_band_bwcap(wlc, BRCMS_N_BW_20IN2G_40IN5G);80368037/* Set default values of SGI */8038if (BRCMS_SGI_CAP_PHY(wlc)) {8039brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |8040BRCMS_N_SGI_40));8041} else if (BRCMS_ISSSLPNPHY(wlc->band)) {8042brcms_c_ht_update_sgi_rx(wlc, (BRCMS_N_SGI_20 |8043BRCMS_N_SGI_40));8044} else {8045brcms_c_ht_update_sgi_rx(wlc, 0);8046}80478048brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);80498050if (perr)8051*perr = 0;80528053return wlc;80548055fail:8056wiphy_err(wl->wiphy, "wl%d: %s: failed with err %d\n",8057unit, __func__, err);8058if (wlc)8059brcms_c_detach(wlc);80608061if (perr)8062*perr = err;8063return NULL;8064}806580668067