Commit 839f9f62 authored by Roland Vossen's avatar Roland Vossen Committed by Greg Kroah-Hartman

staging: brcm80211: shuffled sections in main.c

Moved bmac functions above 'common' functions invoking them. This facilitates
merging these functions in a later commit. Also declared locally used
functions static.
Signed-off-by: default avatarRoland Vossen <rvossen@broadcom.com>
Reviewed-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarArend van Spriel <arend@broadcom.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 8702fee6
...@@ -271,7 +271,6 @@ struct brcms_b_state { ...@@ -271,7 +271,6 @@ struct brcms_b_state {
/* local prototypes */ /* local prototypes */
static void brcms_b_clkctl_clk(struct brcms_hardware *wlc, uint mode); static void brcms_b_clkctl_clk(struct brcms_hardware *wlc, uint mode);
static void brcms_b_coreinit(struct brcms_c_info *wlc);
/* used by wlc_wakeucode_init() */ /* used by wlc_wakeucode_init() */
static void brcms_c_write_inits(struct brcms_hardware *wlc_hw, static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
...@@ -281,13 +280,6 @@ static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[], ...@@ -281,13 +280,6 @@ static void brcms_ucode_write(struct brcms_hardware *wlc_hw, const u32 ucode[],
static void brcms_ucode_download(struct brcms_hardware *wlc); static void brcms_ucode_download(struct brcms_hardware *wlc);
static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw); static void brcms_c_ucode_txant_set(struct brcms_hardware *wlc_hw);
/* used by brcms_c_dpc() */
static bool brcms_b_dotxstatus(struct brcms_hardware *wlc,
struct tx_status *txs, u32 s2);
static bool brcms_b_txstatus(struct brcms_hardware *wlc, bool bound,
bool *fatal);
static bool brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound);
/* used by brcms_c_down() */ /* used by brcms_c_down() */
static void brcms_c_flushqueues(struct brcms_c_info *wlc); static void brcms_c_flushqueues(struct brcms_c_info *wlc);
...@@ -296,8 +288,6 @@ static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw); ...@@ -296,8 +288,6 @@ static void brcms_c_mctrl_reset(struct brcms_hardware *wlc_hw);
static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw); static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw);
static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw, static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
uint tx_fifo); uint tx_fifo);
static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
uint tx_fifo);
static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
uint tx_fifo); uint tx_fifo);
...@@ -305,66 +295,38 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, ...@@ -305,66 +295,38 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
struct brcms_b_state; struct brcms_b_state;
extern int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, static int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device,
uint unit, bool piomode, void *regsva, uint bustype, uint unit, bool piomode, void *regsva, uint bustype,
void *btparam); void *btparam);
extern int brcms_b_detach(struct brcms_c_info *wlc);
extern void brcms_b_watchdog(void *arg);
/* up/down, reset, clk */ /* up/down, reset, clk */
extern void brcms_b_reset(struct brcms_hardware *wlc_hw); static void brcms_b_reset(struct brcms_hardware *wlc_hw);
extern void brcms_b_init(struct brcms_hardware *wlc_hw, chanspec_t chanspec, static int brcms_b_state_get(struct brcms_hardware *wlc_hw,
bool mute);
extern int brcms_b_up_prep(struct brcms_hardware *wlc_hw);
extern int brcms_b_up_finish(struct brcms_hardware *wlc_hw);
extern int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw);
extern int brcms_b_down_finish(struct brcms_hardware *wlc_hw);
extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
uint *blocks);
extern u16 brcms_b_mhf_get(struct brcms_hardware *wlc_hw, u8 idx, int bands);
extern int brcms_b_state_get(struct brcms_hardware *wlc_hw,
struct brcms_b_state *state); struct brcms_b_state *state);
extern void brcms_b_copyfrom_vars(struct brcms_hardware *wlc_hw, char **buf, static void brcms_b_copyfrom_vars(struct brcms_hardware *wlc_hw, char **buf,
uint *len); uint *len);
extern void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw, static void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw,
u8 *ea); u8 *ea);
extern bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw); static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw);
extern void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw);
bool shortslot);
extern void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw);
extern void brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, static void brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw,
int match_reg_offset, int match_reg_offset,
const u8 *addr); const u8 *addr);
extern void brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw, static void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin);
void *bcn, int len, bool both); static void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax);
extern void brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
u32 *tsf_h_ptr);
extern void brcms_b_set_cwmin(struct brcms_hardware *wlc_hw, u16 newmin);
extern void brcms_b_set_cwmax(struct brcms_hardware *wlc_hw, u16 newmax);
extern void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, u16 SRL, static void brcms_b_retrylimit_upd(struct brcms_hardware *wlc_hw, u16 SRL,
u16 LRL); u16 LRL);
extern void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw); static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw);
/* API for BMAC driver (e.g. wlc_phy.c etc) */
extern void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, static void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set,
mbool req_bit); mbool req_bit);
extern void brcms_b_hw_up(struct brcms_hardware *wlc_hw); static void brcms_b_antsel_set(struct brcms_hardware *wlc_hw,
extern void brcms_b_antsel_set(struct brcms_hardware *wlc_hw,
u32 antsel_avail); u32 antsel_avail);
static int brcms_b_bandtype(struct brcms_hardware *wlc_hw); static int brcms_b_bandtype(struct brcms_hardware *wlc_hw);
static void brcms_b_info_init(struct brcms_hardware *wlc_hw); static void brcms_b_info_init(struct brcms_hardware *wlc_hw);
static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want); static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want);
...@@ -546,19 +508,6 @@ static const char fifo_names[6][0]; ...@@ -546,19 +508,6 @@ static const char fifo_names[6][0];
static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL); static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
#endif #endif
/* === Low Level functions === */
void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
{
wlc_hw->shortslot = shortslot;
if (BAND_2G(brcms_b_bandtype(wlc_hw)) && wlc_hw->up) {
brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
brcms_b_update_slot_timing(wlc_hw, shortslot);
brcms_c_enable_mac(wlc_hw->wlc);
}
}
/* /*
* Update the slot timing for standard 11b/g (20us slots) * Update the slot timing for standard 11b/g (20us slots)
* or shortslot 11g (9us slots) * or shortslot 11g (9us slots)
...@@ -687,6 +636,81 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound) ...@@ -687,6 +636,81 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
return n >= bound_limit; return n >= bound_limit;
} }
static bool
brcms_b_dotxstatus(struct brcms_hardware *wlc_hw, struct tx_status *txs,
u32 s2)
{
/* discard intermediate indications for ucode with one legitimate case:
* e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
* tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
* transmission count)
*/
if (!(txs->status & TX_STATUS_AMPDU)
&& (txs->status & TX_STATUS_INTERMEDIATE)) {
return false;
}
return brcms_c_dotxstatus(wlc_hw->wlc, txs, s2);
}
/* process tx completion events in BMAC
* Return true if more tx status need to be processed. false otherwise.
*/
static bool
brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
{
bool morepending = false;
struct brcms_c_info *wlc = wlc_hw->wlc;
d11regs_t *regs;
struct tx_status txstatus, *txs;
u32 s1, s2;
uint n = 0;
/*
* Param 'max_tx_num' indicates max. # tx status to process before
* break out.
*/
uint max_tx_num = bound ? wlc->pub->tunables->txsbnd : -1;
BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
txs = &txstatus;
regs = wlc_hw->regs;
while (!(*fatal)
&& (s1 = R_REG(&regs->frmtxstatus)) & TXS_V) {
if (s1 == 0xffffffff) {
wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
wlc_hw->unit, __func__);
return morepending;
}
s2 = R_REG(&regs->frmtxstatus2);
txs->status = s1 & TXS_STATUS_MASK;
txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
txs->sequence = s2 & TXS_SEQ_MASK;
txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
txs->lasttxtime = 0;
*fatal = brcms_b_dotxstatus(wlc_hw, txs, s2);
/* !give others some time to run! */
if (++n >= max_tx_num)
break;
}
if (*fatal)
return 0;
if (n >= max_tx_num)
morepending = true;
if (!pktq_empty(&wlc->pkt_queue->q))
brcms_c_send_q(wlc);
return morepending;
}
/* second-level interrupt processing /* second-level interrupt processing
* Return true if another dpc needs to be re-scheduled. false otherwise. * Return true if another dpc needs to be re-scheduled. false otherwise.
* Param 'bounded' indicates if applicable loops should be bounded. * Param 'bounded' indicates if applicable loops should be bounded.
...@@ -790,73 +814,6 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) ...@@ -790,73 +814,6 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
return wlc->macintstatus != 0; return wlc->macintstatus != 0;
} }
/* common low-level watchdog code */
void brcms_b_watchdog(void *arg)
{
struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
struct brcms_hardware *wlc_hw = wlc->hw;
BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
if (!wlc_hw->up)
return;
/* increment second count */
wlc_hw->now++;
/* Check for FIFO error interrupts */
brcms_b_fifoerrors(wlc_hw);
/* make sure RX dma has buffers */
dma_rxfill(wlc->hw->di[RX_FIFO]);
wlc_phy_watchdog(wlc_hw->band->pi);
}
void
brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
bool mute, struct txpwr_limits *txpwr)
{
uint bandunit;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
wlc_hw->chanspec = chanspec;
/* Switch bands if necessary */
if (NBANDS_HW(wlc_hw) > 1) {
bandunit = CHSPEC_BANDUNIT(chanspec);
if (wlc_hw->band->bandunit != bandunit) {
/* brcms_b_setband disables other bandunit,
* use light band switch if not up yet
*/
if (wlc_hw->up) {
wlc_phy_chanspec_radio_set(wlc_hw->
bandstate[bandunit]->
pi, chanspec);
brcms_b_setband(wlc_hw, bandunit, chanspec);
} else {
brcms_c_setxband(wlc_hw, bandunit);
}
}
}
wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
if (!wlc_hw->up) {
if (wlc_hw->clk)
wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
chanspec);
wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
} else {
wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
/* Update muting of the channel */
brcms_b_mute(wlc_hw, mute, 0);
}
}
int brcms_b_state_get(struct brcms_hardware *wlc_hw, int brcms_b_state_get(struct brcms_hardware *wlc_hw,
struct brcms_b_state *state) struct brcms_b_state *state)
{ {
...@@ -974,636 +931,39 @@ static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw) ...@@ -974,636 +931,39 @@ static void brcms_b_detach_dmapio(struct brcms_hardware *wlc_hw)
} }
} }
/* low level attach /*
* run backplane attach, init nvram * Initialize brcms_c_info default values ...
* run phy attach * may get overrides later in this function
* initialize software state for each core and band * BMAC_NOTES, move low out and resolve the dangling ones
* put the whole chip in reset(driver down state), no clock
*/ */
int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, uint unit, static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
bool piomode, void *regsva, uint bustype, void *btparam)
{ {
struct brcms_hardware *wlc_hw; struct brcms_c_info *wlc = wlc_hw->wlc;
d11regs_t *regs;
char *macaddr = NULL;
char *vars;
uint err = 0;
uint j;
bool wme = false;
struct shared_phy_params sha_params;
struct wiphy *wiphy = wlc->wiphy;
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor, /* set default sw macintmask value */
device); wlc->defmacintmask = DEF_MACINTMASK;
wme = true; /* various 802.11g modes */
wlc_hw->shortslot = false;
wlc_hw = wlc->hw; wlc_hw->SFBL = RETRY_SHORT_FB;
wlc_hw->wlc = wlc; wlc_hw->LFBL = RETRY_LONG_FB;
wlc_hw->unit = unit;
wlc_hw->band = wlc_hw->bandstate[0];
wlc_hw->_piomode = piomode;
/* populate struct brcms_hardware with default values */ /* default mac retry limits */
brcms_b_info_init(wlc_hw); wlc_hw->SRL = RETRY_SHORT_DEF;
wlc_hw->LRL = RETRY_LONG_DEF;
wlc_hw->chanspec = CH20MHZ_CHSPEC(1);
}
/* void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
* Do the hardware portion of the attach. {
* Also initialize software state that depends on the particular hardware /* delay before first read of ucode state */
* we are running. udelay(40);
*/
wlc_hw->sih = ai_attach(regsva, bustype, btparam,
&wlc_hw->vars, &wlc_hw->vars_size);
if (wlc_hw->sih == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
unit);
err = 11;
goto fail;
}
vars = wlc_hw->vars;
/* /* wait until ucode is no longer asleep */
* Get vendid/devid nvram overwrites, which could be different SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
* than those the BIOS recognizes for devices on PCMCIA_BUS, DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
* SDIO_BUS, and SROMless devices on PCI_BUS. }
*/
#ifdef BCMBUSTYPE
bustype = BCMBUSTYPE;
#endif
if (bustype != SI_BUS) {
char *var;
var = getvar(vars, "vendid");
if (var) {
vendor = (u16) simple_strtoul(var, NULL, 0);
wiphy_err(wiphy, "Overriding vendor id = 0x%x\n",
vendor);
}
var = getvar(vars, "devid");
if (var) {
u16 devid = (u16) simple_strtoul(var, NULL, 0);
if (devid != 0xffff) {
device = devid;
wiphy_err(wiphy, "Overriding device id = 0x%x"
"\n", device);
}
}
/* verify again the device is supported */
if (!brcms_c_chipmatch(vendor, device)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
"vendor/device (0x%x/0x%x)\n",
unit, vendor, device);
err = 12;
goto fail;
}
}
wlc_hw->vendorid = vendor;
wlc_hw->deviceid = device;
/* set bar0 window to point at D11 core */
wlc_hw->regs = (d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
wlc_hw->corerev = ai_corerev(wlc_hw->sih);
regs = wlc_hw->regs;
wlc->regs = wlc_hw->regs;
/* validate chip, chiprev and corerev */
if (!brcms_c_isgoodchip(wlc_hw)) {
err = 13;
goto fail;
}
/* initialize power control registers */
ai_clkctl_init(wlc_hw->sih);
/* request fastclock and force fastclock for the rest of attach
* bring the d11 core out of reset.
* For PMU chips, the first wlc_clkctl_clk is no-op since core-clk is still false;
* But it will be called again inside wlc_corereset, after d11 is out of reset.
*/
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
if (!brcms_b_validate_chip_access(wlc_hw)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
"failed\n", unit);
err = 14;
goto fail;
}
/* get the board rev, used just below */
j = getintvar(vars, "boardrev");
/* promote srom boardrev of 0xFF to 1 */
if (j == BOARDREV_PROMOTABLE)
j = BOARDREV_PROMOTED;
wlc_hw->boardrev = (u16) j;
if (!brcms_c_validboardtype(wlc_hw)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
"board type (0x%x)" " or revision level (0x%x)\n",
unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
err = 15;
goto fail;
}
wlc_hw->sromrev = (u8) getintvar(vars, "sromrev");
wlc_hw->boardflags = (u32) getintvar(vars, "boardflags");
wlc_hw->boardflags2 = (u32) getintvar(vars, "boardflags2");
if (wlc_hw->boardflags & BFL_NOPLLDOWN)
brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
if ((wlc_hw->sih->bustype == PCI_BUS)
&& (ai_pci_war16165(wlc_hw->sih)))
wlc->war16165 = true;
/* check device id(srom, nvram etc.) to set bands */
if (wlc_hw->deviceid == BCM43224_D11N_ID ||
wlc_hw->deviceid == BCM43224_D11N_ID_VEN1) {
/* Dualband boards */
wlc_hw->_nbands = 2;
} else
wlc_hw->_nbands = 1;
if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
wlc_hw->_nbands = 1;
/* BMAC_NOTE: remove init of pub values when brcms_c_attach()
* unconditionally does the init of these values
*/
wlc->vendorid = wlc_hw->vendorid;
wlc->deviceid = wlc_hw->deviceid;
wlc->pub->sih = wlc_hw->sih;
wlc->pub->corerev = wlc_hw->corerev;
wlc->pub->sromrev = wlc_hw->sromrev;
wlc->pub->boardrev = wlc_hw->boardrev;
wlc->pub->boardflags = wlc_hw->boardflags;
wlc->pub->boardflags2 = wlc_hw->boardflags2;
wlc->pub->_nbands = wlc_hw->_nbands;
wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
if (wlc_hw->physhim == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
"failed\n", unit);
err = 25;
goto fail;
}
/* pass all the parameters to wlc_phy_shared_attach in one struct */
sha_params.sih = wlc_hw->sih;
sha_params.physhim = wlc_hw->physhim;
sha_params.unit = unit;
sha_params.corerev = wlc_hw->corerev;
sha_params.vars = vars;
sha_params.vid = wlc_hw->vendorid;
sha_params.did = wlc_hw->deviceid;
sha_params.chip = wlc_hw->sih->chip;
sha_params.chiprev = wlc_hw->sih->chiprev;
sha_params.chippkg = wlc_hw->sih->chippkg;
sha_params.sromrev = wlc_hw->sromrev;
sha_params.boardtype = wlc_hw->sih->boardtype;
sha_params.boardrev = wlc_hw->boardrev;
sha_params.boardvendor = wlc_hw->sih->boardvendor;
sha_params.boardflags = wlc_hw->boardflags;
sha_params.boardflags2 = wlc_hw->boardflags2;
sha_params.bustype = wlc_hw->sih->bustype;
sha_params.buscorerev = wlc_hw->sih->buscorerev;
/* alloc and save pointer to shared phy state area */
wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
if (!wlc_hw->phy_sh) {
err = 16;
goto fail;
}
/* initialize software state for each core and band */
for (j = 0; j < NBANDS_HW(wlc_hw); j++) {
/*
* band0 is always 2.4Ghz
* band1, if present, is 5Ghz
*/
/* So if this is a single band 11a card, use band 1 */
if (IS_SINGLEBAND_5G(wlc_hw->deviceid))
j = BAND_5G_INDEX;
brcms_c_setxband(wlc_hw, j);
wlc_hw->band->bandunit = j;
wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
wlc->band->bandunit = j;
wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
wlc->core->coreidx = ai_coreidx(wlc_hw->sih);
wlc_hw->machwcap = R_REG(&regs->machwcap);
wlc_hw->machwcap_backup = wlc_hw->machwcap;
/* init tx fifo size */
wlc_hw->xmtfifo_sz =
xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
/* Get a phy for this band */
wlc_hw->band->pi = wlc_phy_attach(wlc_hw->phy_sh,
(void *)regs, brcms_b_bandtype(wlc_hw), vars,
wlc->wiphy);
if (wlc_hw->band->pi == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
"attach failed\n", unit);
err = 17;
goto fail;
}
wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
&wlc_hw->band->phyrev,
&wlc_hw->band->radioid,
&wlc_hw->band->radiorev);
wlc_hw->band->abgphy_encore =
wlc_phy_get_encore(wlc_hw->band->pi);
wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
wlc_hw->band->core_flags =
wlc_phy_get_coreflags(wlc_hw->band->pi);
/* verify good phy_type & supported phy revision */
if (BRCMS_ISNPHY(wlc_hw->band)) {
if (NCONF_HAS(wlc_hw->band->phyrev))
goto good_phy;
else
goto bad_phy;
} else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
if (LCNCONF_HAS(wlc_hw->band->phyrev))
goto good_phy;
else
goto bad_phy;
} else {
bad_phy:
wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
"phy type/rev (%d/%d)\n", unit,
wlc_hw->band->phytype, wlc_hw->band->phyrev);
err = 18;
goto fail;
}
good_phy:
/* BMAC_NOTE: wlc->band->pi should not be set below and should be done in the
* high level attach. However we can not make that change until all low level access
* is changed to wlc_hw->band->pi. Instead do the wlc->band->pi init below, keeping
* wlc_hw->band->pi as well for incremental update of low level fns, and cut over
* low only init when all fns updated.
*/
wlc->band->pi = wlc_hw->band->pi;
wlc->band->phytype = wlc_hw->band->phytype;
wlc->band->phyrev = wlc_hw->band->phyrev;
wlc->band->radioid = wlc_hw->band->radioid;
wlc->band->radiorev = wlc_hw->band->radiorev;
/* default contention windows size limits */
wlc_hw->band->CWmin = APHY_CWMIN;
wlc_hw->band->CWmax = PHY_CWMAX;
if (!brcms_b_attach_dmapio(wlc, j, wme)) {
err = 19;
goto fail;
}
}
/* disable core to match driver "down" state */
brcms_c_coredisable(wlc_hw);
/* Match driver "down" state */
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_down(wlc_hw->sih);
/* register sb interrupt callback functions */
ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff,
(void *)brcms_c_wlintrsrestore, NULL, wlc);
/* turn off pll and xtal to match driver "down" state */
brcms_b_xtal(wlc_hw, OFF);
/* *********************************************************************
* The hardware is in the DOWN state at this point. D11 core
* or cores are in reset with clocks off, and the board PLLs
* are off if possible.
*
* Beyond this point, wlc->sbclk == false and chip registers
* should not be touched.
*********************************************************************
*/
/* init etheraddr state variables */
macaddr = brcms_c_get_macaddr(wlc_hw);
if (macaddr == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
unit);
err = 21;
goto fail;
}
brcmu_ether_atoe(macaddr, wlc_hw->etheraddr);
if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
is_zero_ether_addr(wlc_hw->etheraddr)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
unit, macaddr);
err = 22;
goto fail;
}
BCMMSG(wlc->wiphy,
"deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
wlc_hw->deviceid, wlc_hw->_nbands,
wlc_hw->sih->boardtype, macaddr);
return err;
fail:
wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
err);
return err;
}
/*
* Initialize brcms_c_info default values ...
* may get overrides later in this function
* BMAC_NOTES, move low out and resolve the dangling ones
*/
static void brcms_b_info_init(struct brcms_hardware *wlc_hw)
{
struct brcms_c_info *wlc = wlc_hw->wlc;
/* set default sw macintmask value */
wlc->defmacintmask = DEF_MACINTMASK;
/* various 802.11g modes */
wlc_hw->shortslot = false;
wlc_hw->SFBL = RETRY_SHORT_FB;
wlc_hw->LFBL = RETRY_LONG_FB;
/* default mac retry limits */
wlc_hw->SRL = RETRY_SHORT_DEF;
wlc_hw->LRL = RETRY_LONG_DEF;
wlc_hw->chanspec = CH20MHZ_CHSPEC(1);
}
/*
* low level detach
*/
int brcms_b_detach(struct brcms_c_info *wlc)
{
uint i;
struct brcms_hw_band *band;
struct brcms_hardware *wlc_hw = wlc->hw;
int callbacks;
callbacks = 0;
if (wlc_hw->sih) {
/* detach interrupt sync mechanism since interrupt is disabled and per-port
* interrupt object may has been freed. this must be done before sb core switch
*/
ai_deregister_intr_callback(wlc_hw->sih);
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_sleep(wlc_hw->sih);
}
brcms_b_detach_dmapio(wlc_hw);
band = wlc_hw->band;
for (i = 0; i < NBANDS_HW(wlc_hw); i++) {
if (band->pi) {
/* Detach this band's phy */
wlc_phy_detach(band->pi);
band->pi = NULL;
}
band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
}
/* Free shared phy state */
kfree(wlc_hw->phy_sh);
wlc_phy_shim_detach(wlc_hw->physhim);
/* free vars */
kfree(wlc_hw->vars);
wlc_hw->vars = NULL;
if (wlc_hw->sih) {
ai_detach(wlc_hw->sih);
wlc_hw->sih = NULL;
}
return callbacks;
}
void brcms_b_reset(struct brcms_hardware *wlc_hw)
{
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/* reset the core */
if (!DEVICEREMOVED(wlc_hw->wlc))
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
/* purge the dma rings */
brcms_c_flushqueues(wlc_hw->wlc);
brcms_c_reset_bmac_done(wlc_hw->wlc);
}
void
brcms_b_init(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
bool mute) {
u32 macintmask;
bool fastclk;
struct brcms_c_info *wlc = wlc_hw->wlc;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
/* disable interrupts */
macintmask = brcms_intrsoff(wlc->wl);
/* set up the specified band and chanspec */
brcms_c_setxband(wlc_hw, CHSPEC_BANDUNIT(chanspec));
wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
/* do one-time phy inits and calibration */
wlc_phy_cal_init(wlc_hw->band->pi);
/* core-specific initialization */
brcms_b_coreinit(wlc);
/* suspend the tx fifos and mute the phy for preism cac time */
if (mute)
brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
/* band-specific inits */
brcms_b_bsinit(wlc, chanspec);
/* restore macintmask */
brcms_intrsrestore(wlc->wl, macintmask);
/* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
* is suspended and brcms_c_enable_mac() will clear this override bit.
*/
mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
/*
* initialize mac_suspend_depth to 1 to match ucode initial suspended state
*/
wlc_hw->mac_suspend_depth = 1;
/* restore the clk */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
}
int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
{
uint coremask;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
* Enable pll and xtal, initialize the power control registers,
* and force fastclock for the remainder of brcms_c_up().
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
/*
* Configure pci/pcmcia here instead of in brcms_c_attach()
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
*/
coremask = (1 << wlc_hw->wlc->core->coreidx);
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_setup(wlc_hw->sih, coremask);
/*
* Need to read the hwradio status here to cover the case where the system
* is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
*/
if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
/* put SB PCI in down state again */
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_down(wlc_hw->sih);
brcms_b_xtal(wlc_hw, OFF);
return -ENOMEDIUM;
}
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_up(wlc_hw->sih);
/* reset the d11 core */
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
return 0;
}
int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
{
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
wlc_hw->up = true;
wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
/* FULLY enable dynamic power control and d11 core interrupt */
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_intrson(wlc_hw->wlc->wl);
return 0;
}
int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
{
bool dev_gone;
uint callbacks = 0;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
if (!wlc_hw->up)
return callbacks;
dev_gone = DEVICEREMOVED(wlc_hw->wlc);
/* disable interrupts */
if (dev_gone)
wlc_hw->wlc->macintmask = 0;
else {
/* now disable interrupts */
brcms_intrsoff(wlc_hw->wlc->wl);
/* ensure we're running on the pll clock again */
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
}
/* down phy at the last of this stage */
callbacks += wlc_phy_down(wlc_hw->band->pi);
return callbacks;
}
int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
{
uint callbacks = 0;
bool dev_gone;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
if (!wlc_hw->up)
return callbacks;
wlc_hw->up = false;
wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
dev_gone = DEVICEREMOVED(wlc_hw->wlc);
if (dev_gone) {
wlc_hw->sbclk = false;
wlc_hw->clk = false;
wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
/* reclaim any posted packets */
brcms_c_flushqueues(wlc_hw->wlc);
} else {
/* Reset and disable the core */
if (ai_iscoreup(wlc_hw->sih)) {
if (R_REG(&wlc_hw->regs->maccontrol) &
MCTL_EN_MAC)
brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
callbacks += brcms_reset(wlc_hw->wlc->wl);
brcms_c_coredisable(wlc_hw);
}
/* turn off primary xtal and pll */
if (!wlc_hw->noreset) {
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_down(wlc_hw->sih);
brcms_b_xtal(wlc_hw, OFF);
}
}
return callbacks;
}
void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
{
/* delay before first read of ucode state */
udelay(40);
/* wait until ucode is no longer asleep */
SPINWAIT((brcms_b_read_shm(wlc_hw, M_UCODE_DBGST) ==
DBGST_ASLEEP), wlc_hw->wlc->fastpwrup_dly);
}
void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw, u8 *ea) void brcms_b_hw_etheraddr(struct brcms_hardware *wlc_hw, u8 *ea)
{ {
...@@ -1769,32 +1129,6 @@ brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val, ...@@ -1769,32 +1129,6 @@ brcms_b_mhf(struct brcms_hardware *wlc_hw, u8 idx, u16 mask, u16 val,
} }
} }
u16 brcms_b_mhf_get(struct brcms_hardware *wlc_hw, u8 idx, int bands)
{
struct brcms_hw_band *band;
if (idx >= MHFMAX)
return 0; /* error condition */
switch (bands) {
case BRCM_BAND_AUTO:
band = wlc_hw->band;
break;
case BRCM_BAND_5G:
band = wlc_hw->bandstate[BAND_5G_INDEX];
break;
case BRCM_BAND_2G:
band = wlc_hw->bandstate[BAND_2G_INDEX];
break;
default:
band = NULL; /* error condition */
}
if (!band)
return 0;
return band->mhfs[idx];
}
static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs) static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
{ {
u8 idx; u8 idx;
...@@ -2043,37 +1377,16 @@ brcms_c_write_hw_bcntemplate0(struct brcms_hardware *wlc_hw, void *bcn, ...@@ -2043,37 +1377,16 @@ brcms_c_write_hw_bcntemplate0(struct brcms_hardware *wlc_hw, void *bcn,
static void static void
brcms_c_write_hw_bcntemplate1(struct brcms_hardware *wlc_hw, void *bcn, brcms_c_write_hw_bcntemplate1(struct brcms_hardware *wlc_hw, void *bcn,
int len) int len)
{
d11regs_t *regs = wlc_hw->regs;
brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE, (len + 3) & ~3,
bcn);
/* write beacon length to SCR */
brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
/* mark beacon1 valid */
OR_REG(&regs->maccommand, MCMD_BCN1VLD);
}
/* mac is assumed to be suspended at this point */
void
brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw, void *bcn,
int len, bool both)
{ {
d11regs_t *regs = wlc_hw->regs; d11regs_t *regs = wlc_hw->regs;
if (both) { brcms_b_write_template_ram(wlc_hw, T_BCN1_TPL_BASE, (len + 3) & ~3,
brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len); bcn);
brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len); /* write beacon length to SCR */
} else { brcms_b_write_shm(wlc_hw, M_BCN1_FRM_BYTESZ, (u16) len);
/* bcn 0 */ /* mark beacon1 valid */
if (!(R_REG(&regs->maccommand) & MCMD_BCN0VLD)) OR_REG(&regs->maccommand, MCMD_BCN1VLD);
brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len);
/* bcn 1 */
else if (!
(R_REG(&regs->maccommand) & MCMD_BCN1VLD))
brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len);
}
} }
static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw) static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
...@@ -2403,48 +1716,6 @@ bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) ...@@ -2403,48 +1716,6 @@ bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw)
return v; return v;
} }
/* Initialize just the hardware when coming out of POR or S3/S5 system states */
void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
{
if (wlc_hw->wlc->pub->hw_up)
return;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
* Enable pll and xtal, initialize the power control registers,
* and force fastclock for the remainder of brcms_c_up().
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
if (wlc_hw->sih->bustype == PCI_BUS) {
ai_pci_fixcfg(wlc_hw->sih);
/* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
(wlc_hw->sih->chip == BCM43225_CHIP_ID))
wlc_hw->regs =
(d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID,
0);
}
/* Inform phy that a POR reset has occurred so it does a complete phy init */
wlc_phy_por_inform(wlc_hw->band->pi);
wlc_hw->ucode_loaded = false;
wlc_hw->wlc->pub->hw_up = true;
if ((wlc_hw->boardflags & BFL_FEM)
&& (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
if (!
(wlc_hw->boardrev >= 0x1250
&& (wlc_hw->boardflags & BFL_FEM_BT)))
ai_epa_4313war(wlc_hw->sih);
}
}
static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo) static bool wlc_dma_rxreset(struct brcms_hardware *wlc_hw, uint fifo)
{ {
struct dma_pub *di = wlc_hw->di[fifo]; struct dma_pub *di = wlc_hw->di[fifo];
...@@ -2550,228 +1821,43 @@ static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw) ...@@ -2550,228 +1821,43 @@ static void brcms_b_corerev_fifofixup(struct brcms_hardware *wlc_hw)
u16 txfifo_def, txfifo_def1; u16 txfifo_def, txfifo_def1;
u16 txfifo_cmd; u16 txfifo_cmd;
/* tx fifos start at TXFIFO_START_BLK from the Base address */ /* tx fifos start at TXFIFO_START_BLK from the Base address */
txfifo_startblk = TXFIFO_START_BLK; txfifo_startblk = TXFIFO_START_BLK;
/* sequence of operations: reset fifo, set fifo size, reset fifo */
for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
txfifo_def = (txfifo_startblk & 0xff) |
(((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
((((txfifo_endblk -
1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
txfifo_cmd =
TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
W_REG(&regs->xmtfifocmd, txfifo_cmd);
W_REG(&regs->xmtfifodef, txfifo_def);
W_REG(&regs->xmtfifodef1, txfifo_def1);
W_REG(&regs->xmtfifocmd, txfifo_cmd);
txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
}
/*
* need to propagate to shm location to be in sync since ucode/hw won't
* do this
*/
brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
xmtfifo_sz[TX_AC_BK_FIFO]));
brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
xmtfifo_sz[TX_BCMC_FIFO]));
}
/* d11 core init
* reset PSM
* download ucode/PCM
* let ucode run to suspended
* download ucode inits
* config other core registers
* init dma
*/
static void brcms_b_coreinit(struct brcms_c_info *wlc)
{
struct brcms_hardware *wlc_hw = wlc->hw;
d11regs_t *regs;
u32 sflags;
uint bcnint_us;
uint i = 0;
bool fifosz_fixup = false;
int err = 0;
u16 buf[NFIFO];
struct wiphy *wiphy = wlc->wiphy;
regs = wlc_hw->regs;
BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
/* reset PSM */
brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
brcms_ucode_download(wlc_hw);
/*
* FIFOSZ fixup. driver wants to controls the fifo allocation.
*/
fifosz_fixup = true;
/* let the PSM run to the suspended state, set mode to BSS STA */
W_REG(&regs->macintstatus, -1);
brcms_b_mctrl(wlc_hw, ~0,
(MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
/* wait for ucode to self-suspend after auto-init */
SPINWAIT(((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0),
1000 * 1000);
if ((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0)
wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
"suspend!\n", wlc_hw->unit);
brcms_c_gpio_init(wlc);
sflags = ai_core_sflags(wlc_hw->sih, 0, 0);
if (D11REV_IS(wlc_hw->corerev, 23)) {
if (BRCMS_ISNPHY(wlc_hw->band))
brcms_c_write_inits(wlc_hw, d11n0initvals16);
else
wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
" %d\n", __func__, wlc_hw->unit,
wlc_hw->corerev);
} else if (D11REV_IS(wlc_hw->corerev, 24)) {
if (BRCMS_ISLCNPHY(wlc_hw->band)) {
brcms_c_write_inits(wlc_hw, d11lcn0initvals24);
} else {
wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
" %d\n", __func__, wlc_hw->unit,
wlc_hw->corerev);
}
} else {
wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
__func__, wlc_hw->unit, wlc_hw->corerev);
}
/* For old ucode, txfifo sizes needs to be modified(increased) */
if (fifosz_fixup == true) {
brcms_b_corerev_fifofixup(wlc_hw);
}
/* check txfifo allocations match between ucode and driver */
buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
i = TX_AC_BE_FIFO;
err = -1;
}
buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
i = TX_AC_VI_FIFO;
err = -1;
}
buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
buf[TX_AC_BK_FIFO] &= 0xff;
if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
i = TX_AC_BK_FIFO;
err = -1;
}
if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
i = TX_AC_VO_FIFO;
err = -1;
}
buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
buf[TX_BCMC_FIFO] &= 0xff;
if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
i = TX_BCMC_FIFO;
err = -1;
}
if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
i = TX_ATIM_FIFO;
err = -1;
}
if (err != 0) {
wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
" driver size %d index %d\n", buf[i],
wlc_hw->xmtfifo_sz[i], i);
}
/* make sure we can still talk to the mac */
WARN_ON(R_REG(&regs->maccontrol) == 0xffffffff);
/* band-specific inits done by wlc_bsinit() */
/* Set up frame burst size and antenna swap threshold init values */
brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
/* enable one rx interrupt per received frame */
W_REG(&regs->intrcvlazy[0], (1 << IRL_FC_SHIFT));
/* set the station mode (BSS STA) */
brcms_b_mctrl(wlc_hw,
(MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
(MCTL_INFRA | MCTL_DISCARD_PMQ));
/* set up Beacon interval */
bcnint_us = 0x8000 << 10;
W_REG(&regs->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT));
W_REG(&regs->tsf_cfpstart, bcnint_us);
W_REG(&regs->macintstatus, MI_GP1);
/* write interrupt mask */
W_REG(&regs->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK);
/* allow the MAC to control the PHY clock (dynamic on/off) */
brcms_b_macphyclk_set(wlc_hw, ON);
/* program dynamic clock control fast powerup delay register */
wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
W_REG(&regs->scc_fastpwrup_dly, wlc->fastpwrup_dly);
/* tell the ucode the corerev */
brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
/* tell the ucode MAC capabilities */
brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
(u16) (wlc_hw->machwcap & 0xffff));
brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
(u16) ((wlc_hw->
machwcap >> 16) & 0xffff));
/* write retry limits to SCR, this done after PSM init */
W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
(void)R_REG(&regs->objaddr);
W_REG(&regs->objdata, wlc_hw->SRL);
W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
(void)R_REG(&regs->objaddr);
W_REG(&regs->objdata, wlc_hw->LRL);
/* write rate fallback retry limits */ /* sequence of operations: reset fifo, set fifo size, reset fifo */
brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL); for (fifo_nu = 0; fifo_nu < NFIFO; fifo_nu++) {
brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
AND_REG(&regs->ifs_ctl, 0x0FFF); txfifo_endblk = txfifo_startblk + wlc_hw->xmtfifo_sz[fifo_nu];
W_REG(&regs->ifs_aifsn, EDCF_AIFSN_MIN); txfifo_def = (txfifo_startblk & 0xff) |
(((txfifo_endblk - 1) & 0xff) << TXFIFO_FIFOTOP_SHIFT);
txfifo_def1 = ((txfifo_startblk >> 8) & 0x1) |
((((txfifo_endblk -
1) >> 8) & 0x1) << TXFIFO_FIFOTOP_SHIFT);
txfifo_cmd =
TXFIFOCMD_RESET_MASK | (fifo_nu << TXFIFOCMD_FIFOSEL_SHIFT);
/* dma initializations */ W_REG(&regs->xmtfifocmd, txfifo_cmd);
wlc->txpend16165war = 0; W_REG(&regs->xmtfifodef, txfifo_def);
W_REG(&regs->xmtfifodef1, txfifo_def1);
/* init the tx dma engines */ W_REG(&regs->xmtfifocmd, txfifo_cmd);
for (i = 0; i < NFIFO; i++) {
if (wlc_hw->di[i])
dma_txinit(wlc_hw->di[i]);
}
/* init the rx dma engine(s) and post receive buffers */ txfifo_startblk += wlc_hw->xmtfifo_sz[fifo_nu];
dma_rxinit(wlc_hw->di[RX_FIFO]); }
dma_rxfill(wlc_hw->di[RX_FIFO]); /*
* need to propagate to shm location to be in sync since ucode/hw won't
* do this
*/
brcms_b_write_shm(wlc_hw, M_FIFOSIZE0,
wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]);
brcms_b_write_shm(wlc_hw, M_FIFOSIZE1,
wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]);
brcms_b_write_shm(wlc_hw, M_FIFOSIZE2,
((wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO] << 8) | wlc_hw->
xmtfifo_sz[TX_AC_BK_FIFO]));
brcms_b_write_shm(wlc_hw, M_FIFOSIZE3,
((wlc_hw->xmtfifo_sz[TX_ATIM_FIFO] << 8) | wlc_hw->
xmtfifo_sz[TX_BCMC_FIFO]));
} }
/* This function is used for changing the tsf frac register /* This function is used for changing the tsf frac register
...@@ -3107,6 +2193,39 @@ void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask) ...@@ -3107,6 +2193,39 @@ void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
W_REG(&wlc_hw->regs->macintmask, wlc->macintmask); W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
} }
static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
uint tx_fifo)
{
u8 fifo = 1 << tx_fifo;
/* Two clients of this code, 11h Quiet period and scanning. */
/* only suspend if not already suspended */
if ((wlc_hw->suspended_fifos & fifo) == fifo)
return;
/* force the core awake only if not already */
if (wlc_hw->suspended_fifos == 0)
brcms_c_ucode_wake_override_set(wlc_hw,
BRCMS_WAKE_OVERRIDE_TXFIFO);
wlc_hw->suspended_fifos |= fifo;
if (wlc_hw->di[tx_fifo]) {
/* Suspending AMPDU transmissions in the middle can cause underflow
* which may result in mismatch between ucode and driver
* so suspend the mac before suspending the FIFO
*/
if (BRCMS_PHY_11N_CAP(wlc_hw->band))
brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
dma_txsuspend(wlc_hw->di[tx_fifo]);
if (BRCMS_PHY_11N_CAP(wlc_hw->band))
brcms_c_enable_mac(wlc_hw->wlc);
}
}
static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, mbool flags) static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, mbool flags)
{ {
u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
...@@ -3143,17 +2262,6 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, mbool flags) ...@@ -3143,17 +2262,6 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, mbool flags)
brcms_c_ucode_mute_override_clear(wlc_hw); brcms_c_ucode_mute_override_clear(wlc_hw);
} }
int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
uint *blocks)
{
if (fifo >= NFIFO)
return -EINVAL;
*blocks = wlc_hw->xmtfifo_sz[fifo];
return 0;
}
/* brcms_b_tx_fifo_suspended: /* brcms_b_tx_fifo_suspended:
* Check the MAC's tx suspend status for a tx fifo. * Check the MAC's tx suspend status for a tx fifo.
* *
...@@ -3183,39 +2291,6 @@ static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw, ...@@ -3183,39 +2291,6 @@ static bool brcms_b_tx_fifo_suspended(struct brcms_hardware *wlc_hw,
return false; return false;
} }
static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
uint tx_fifo)
{
u8 fifo = 1 << tx_fifo;
/* Two clients of this code, 11h Quiet period and scanning. */
/* only suspend if not already suspended */
if ((wlc_hw->suspended_fifos & fifo) == fifo)
return;
/* force the core awake only if not already */
if (wlc_hw->suspended_fifos == 0)
brcms_c_ucode_wake_override_set(wlc_hw,
BRCMS_WAKE_OVERRIDE_TXFIFO);
wlc_hw->suspended_fifos |= fifo;
if (wlc_hw->di[tx_fifo]) {
/* Suspending AMPDU transmissions in the middle can cause underflow
* which may result in mismatch between ucode and driver
* so suspend the mac before suspending the FIFO
*/
if (BRCMS_PHY_11N_CAP(wlc_hw->band))
brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
dma_txsuspend(wlc_hw->di[tx_fifo]);
if (BRCMS_PHY_11N_CAP(wlc_hw->band))
brcms_c_enable_mac(wlc_hw->wlc);
}
}
static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw, static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
uint tx_fifo) uint tx_fifo)
{ {
...@@ -3356,81 +2431,6 @@ bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc) ...@@ -3356,81 +2431,6 @@ bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc)
} }
static bool
brcms_b_dotxstatus(struct brcms_hardware *wlc_hw, struct tx_status *txs,
u32 s2)
{
/* discard intermediate indications for ucode with one legitimate case:
* e.g. if "useRTS" is set. ucode did a successful rts/cts exchange, but the subsequent
* tx of DATA failed. so it will start rts/cts from the beginning (resetting the rts
* transmission count)
*/
if (!(txs->status & TX_STATUS_AMPDU)
&& (txs->status & TX_STATUS_INTERMEDIATE)) {
return false;
}
return brcms_c_dotxstatus(wlc_hw->wlc, txs, s2);
}
/* process tx completion events in BMAC
* Return true if more tx status need to be processed. false otherwise.
*/
static bool
brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
{
bool morepending = false;
struct brcms_c_info *wlc = wlc_hw->wlc;
d11regs_t *regs;
struct tx_status txstatus, *txs;
u32 s1, s2;
uint n = 0;
/*
* Param 'max_tx_num' indicates max. # tx status to process before
* break out.
*/
uint max_tx_num = bound ? wlc->pub->tunables->txsbnd : -1;
BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
txs = &txstatus;
regs = wlc_hw->regs;
while (!(*fatal)
&& (s1 = R_REG(&regs->frmtxstatus)) & TXS_V) {
if (s1 == 0xffffffff) {
wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
wlc_hw->unit, __func__);
return morepending;
}
s2 = R_REG(&regs->frmtxstatus2);
txs->status = s1 & TXS_STATUS_MASK;
txs->frameid = (s1 & TXS_FID_MASK) >> TXS_FID_SHIFT;
txs->sequence = s2 & TXS_SEQ_MASK;
txs->phyerr = (s2 & TXS_PTX_MASK) >> TXS_PTX_SHIFT;
txs->lasttxtime = 0;
*fatal = brcms_b_dotxstatus(wlc_hw, txs, s2);
/* !give others some time to run! */
if (++n >= max_tx_num)
break;
}
if (*fatal)
return 0;
if (n >= max_tx_num)
morepending = true;
if (!pktq_empty(&wlc->pkt_queue->q))
brcms_c_send_q(wlc);
return morepending;
}
void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc) void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
{ {
struct brcms_hardware *wlc_hw = wlc->hw; struct brcms_hardware *wlc_hw = wlc->hw;
...@@ -3612,19 +2612,6 @@ void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode) ...@@ -3612,19 +2612,6 @@ void brcms_b_band_stf_ss_set(struct brcms_hardware *wlc_hw, u8 stf_mode)
brcms_upd_ofdm_pctl1_table(wlc_hw); brcms_upd_ofdm_pctl1_table(wlc_hw);
} }
void
brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
u32 *tsf_h_ptr)
{
d11regs_t *regs = wlc_hw->regs;
/* read the tsf timer low, then high to get an atomic read */
*tsf_l_ptr = R_REG(&regs->tsf_timerlow);
*tsf_h_ptr = R_REG(&regs->tsf_timerhigh);
return;
}
static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw) static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
{ {
d11regs_t *regs; d11regs_t *regs;
...@@ -3966,29 +2953,6 @@ void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, mbool req_bit) ...@@ -3966,29 +2953,6 @@ void brcms_b_pllreq(struct brcms_hardware *wlc_hw, bool set, mbool req_bit)
return; return;
} }
u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
{
u16 table_ptr;
u8 phy_rate, index;
/* get the phy specific rate encoding for the PLCP SIGNAL field */
if (IS_OFDM(rate))
table_ptr = M_RT_DIRMAP_A;
else
table_ptr = M_RT_DIRMAP_B;
/* for a given rate, the LS-nibble of the PLCP SIGNAL field is
* the index into the rate table.
*/
phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
index = phy_rate & 0xf;
/* Find the SHM pointer to the rate table entry by looking in the
* Direct-map Table
*/
return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
}
void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail) void brcms_b_antsel_set(struct brcms_hardware *wlc_hw, u32 antsel_avail)
{ {
wlc_hw->antsel_avail = antsel_avail; wlc_hw->antsel_avail = antsel_avail;
...@@ -4019,12 +2983,26 @@ bool brcms_c_ps_allowed(struct brcms_c_info *wlc) ...@@ -4019,12 +2983,26 @@ bool brcms_c_ps_allowed(struct brcms_c_info *wlc)
if (!cfg->BSS || !BRCMS_PORTOPEN(cfg)) if (!cfg->BSS || !BRCMS_PORTOPEN(cfg))
return false; return false;
if (!cfg->dtim_programmed) if (!cfg->dtim_programmed)
return false; return false;
} }
} }
return true;
}
void brcms_b_reset(struct brcms_hardware *wlc_hw)
{
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/* reset the core */
if (!DEVICEREMOVED(wlc_hw->wlc))
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
/* purge the dma rings */
brcms_c_flushqueues(wlc_hw->wlc);
return true; brcms_c_reset_bmac_done(wlc_hw->wlc);
} }
void brcms_c_reset(struct brcms_c_info *wlc) void brcms_c_reset(struct brcms_c_info *wlc)
...@@ -4072,6 +3050,243 @@ static void brcms_c_init_scb(struct brcms_c_info *wlc, struct scb *scb) ...@@ -4072,6 +3050,243 @@ static void brcms_c_init_scb(struct brcms_c_info *wlc, struct scb *scb)
scb->seqnum[i] = 0; scb->seqnum[i] = 0;
} }
/* d11 core init
* reset PSM
* download ucode/PCM
* let ucode run to suspended
* download ucode inits
* config other core registers
* init dma
*/
static void brcms_b_coreinit(struct brcms_c_info *wlc)
{
struct brcms_hardware *wlc_hw = wlc->hw;
d11regs_t *regs;
u32 sflags;
uint bcnint_us;
uint i = 0;
bool fifosz_fixup = false;
int err = 0;
u16 buf[NFIFO];
struct wiphy *wiphy = wlc->wiphy;
regs = wlc_hw->regs;
BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
/* reset PSM */
brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
brcms_ucode_download(wlc_hw);
/*
* FIFOSZ fixup. driver wants to controls the fifo allocation.
*/
fifosz_fixup = true;
/* let the PSM run to the suspended state, set mode to BSS STA */
W_REG(&regs->macintstatus, -1);
brcms_b_mctrl(wlc_hw, ~0,
(MCTL_IHR_EN | MCTL_INFRA | MCTL_PSM_RUN | MCTL_WAKE));
/* wait for ucode to self-suspend after auto-init */
SPINWAIT(((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0),
1000 * 1000);
if ((R_REG(&regs->macintstatus) & MI_MACSSPNDD) == 0)
wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
"suspend!\n", wlc_hw->unit);
brcms_c_gpio_init(wlc);
sflags = ai_core_sflags(wlc_hw->sih, 0, 0);
if (D11REV_IS(wlc_hw->corerev, 23)) {
if (BRCMS_ISNPHY(wlc_hw->band))
brcms_c_write_inits(wlc_hw, d11n0initvals16);
else
wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
" %d\n", __func__, wlc_hw->unit,
wlc_hw->corerev);
} else if (D11REV_IS(wlc_hw->corerev, 24)) {
if (BRCMS_ISLCNPHY(wlc_hw->band)) {
brcms_c_write_inits(wlc_hw, d11lcn0initvals24);
} else {
wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
" %d\n", __func__, wlc_hw->unit,
wlc_hw->corerev);
}
} else {
wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
__func__, wlc_hw->unit, wlc_hw->corerev);
}
/* For old ucode, txfifo sizes needs to be modified(increased) */
if (fifosz_fixup == true) {
brcms_b_corerev_fifofixup(wlc_hw);
}
/* check txfifo allocations match between ucode and driver */
buf[TX_AC_BE_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE0);
if (buf[TX_AC_BE_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BE_FIFO]) {
i = TX_AC_BE_FIFO;
err = -1;
}
buf[TX_AC_VI_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE1);
if (buf[TX_AC_VI_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VI_FIFO]) {
i = TX_AC_VI_FIFO;
err = -1;
}
buf[TX_AC_BK_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE2);
buf[TX_AC_VO_FIFO] = (buf[TX_AC_BK_FIFO] >> 8) & 0xff;
buf[TX_AC_BK_FIFO] &= 0xff;
if (buf[TX_AC_BK_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_BK_FIFO]) {
i = TX_AC_BK_FIFO;
err = -1;
}
if (buf[TX_AC_VO_FIFO] != wlc_hw->xmtfifo_sz[TX_AC_VO_FIFO]) {
i = TX_AC_VO_FIFO;
err = -1;
}
buf[TX_BCMC_FIFO] = brcms_b_read_shm(wlc_hw, M_FIFOSIZE3);
buf[TX_ATIM_FIFO] = (buf[TX_BCMC_FIFO] >> 8) & 0xff;
buf[TX_BCMC_FIFO] &= 0xff;
if (buf[TX_BCMC_FIFO] != wlc_hw->xmtfifo_sz[TX_BCMC_FIFO]) {
i = TX_BCMC_FIFO;
err = -1;
}
if (buf[TX_ATIM_FIFO] != wlc_hw->xmtfifo_sz[TX_ATIM_FIFO]) {
i = TX_ATIM_FIFO;
err = -1;
}
if (err != 0) {
wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
" driver size %d index %d\n", buf[i],
wlc_hw->xmtfifo_sz[i], i);
}
/* make sure we can still talk to the mac */
WARN_ON(R_REG(&regs->maccontrol) == 0xffffffff);
/* band-specific inits done by wlc_bsinit() */
/* Set up frame burst size and antenna swap threshold init values */
brcms_b_write_shm(wlc_hw, M_MBURST_SIZE, MAXTXFRAMEBURST);
brcms_b_write_shm(wlc_hw, M_MAX_ANTCNT, ANTCNT);
/* enable one rx interrupt per received frame */
W_REG(&regs->intrcvlazy[0], (1 << IRL_FC_SHIFT));
/* set the station mode (BSS STA) */
brcms_b_mctrl(wlc_hw,
(MCTL_INFRA | MCTL_DISCARD_PMQ | MCTL_AP),
(MCTL_INFRA | MCTL_DISCARD_PMQ));
/* set up Beacon interval */
bcnint_us = 0x8000 << 10;
W_REG(&regs->tsf_cfprep, (bcnint_us << CFPREP_CBI_SHIFT));
W_REG(&regs->tsf_cfpstart, bcnint_us);
W_REG(&regs->macintstatus, MI_GP1);
/* write interrupt mask */
W_REG(&regs->intctrlregs[RX_FIFO].intmask, DEF_RXINTMASK);
/* allow the MAC to control the PHY clock (dynamic on/off) */
brcms_b_macphyclk_set(wlc_hw, ON);
/* program dynamic clock control fast powerup delay register */
wlc->fastpwrup_dly = ai_clkctl_fast_pwrup_delay(wlc_hw->sih);
W_REG(&regs->scc_fastpwrup_dly, wlc->fastpwrup_dly);
/* tell the ucode the corerev */
brcms_b_write_shm(wlc_hw, M_MACHW_VER, (u16) wlc_hw->corerev);
/* tell the ucode MAC capabilities */
brcms_b_write_shm(wlc_hw, M_MACHW_CAP_L,
(u16) (wlc_hw->machwcap & 0xffff));
brcms_b_write_shm(wlc_hw, M_MACHW_CAP_H,
(u16) ((wlc_hw->
machwcap >> 16) & 0xffff));
/* write retry limits to SCR, this done after PSM init */
W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_SRC_LMT);
(void)R_REG(&regs->objaddr);
W_REG(&regs->objdata, wlc_hw->SRL);
W_REG(&regs->objaddr, OBJADDR_SCR_SEL | S_DOT11_LRC_LMT);
(void)R_REG(&regs->objaddr);
W_REG(&regs->objdata, wlc_hw->LRL);
/* write rate fallback retry limits */
brcms_b_write_shm(wlc_hw, M_SFRMTXCNTFBRTHSD, wlc_hw->SFBL);
brcms_b_write_shm(wlc_hw, M_LFRMTXCNTFBRTHSD, wlc_hw->LFBL);
AND_REG(&regs->ifs_ctl, 0x0FFF);
W_REG(&regs->ifs_aifsn, EDCF_AIFSN_MIN);
/* dma initializations */
wlc->txpend16165war = 0;
/* init the tx dma engines */
for (i = 0; i < NFIFO; i++) {
if (wlc_hw->di[i])
dma_txinit(wlc_hw->di[i]);
}
/* init the rx dma engine(s) and post receive buffers */
dma_rxinit(wlc_hw->di[RX_FIFO]);
dma_rxfill(wlc_hw->di[RX_FIFO]);
}
void
brcms_b_init(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
bool mute) {
u32 macintmask;
bool fastclk;
struct brcms_c_info *wlc = wlc_hw->wlc;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
/* disable interrupts */
macintmask = brcms_intrsoff(wlc->wl);
/* set up the specified band and chanspec */
brcms_c_setxband(wlc_hw, CHSPEC_BANDUNIT(chanspec));
wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
/* do one-time phy inits and calibration */
wlc_phy_cal_init(wlc_hw->band->pi);
/* core-specific initialization */
brcms_b_coreinit(wlc);
/* suspend the tx fifos and mute the phy for preism cac time */
if (mute)
brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
/* band-specific inits */
brcms_b_bsinit(wlc, chanspec);
/* restore macintmask */
brcms_intrsrestore(wlc->wl, macintmask);
/* seed wake_override with BRCMS_WAKE_OVERRIDE_MACSUSPEND since the mac
* is suspended and brcms_c_enable_mac() will clear this override bit.
*/
mboolset(wlc_hw->wake_override, BRCMS_WAKE_OVERRIDE_MACSUSPEND);
/*
* initialize mac_suspend_depth to 1 to match ucode initial suspended state
*/
wlc_hw->mac_suspend_depth = 1;
/* restore the clk */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
}
void brcms_c_init(struct brcms_c_info *wlc) void brcms_c_init(struct brcms_c_info *wlc)
{ {
d11regs_t *regs; d11regs_t *regs;
...@@ -4293,7 +3508,18 @@ void brcms_c_set_bssid(struct brcms_bss_cfg *cfg) ...@@ -4293,7 +3508,18 @@ void brcms_c_set_bssid(struct brcms_bss_cfg *cfg)
else if (BSSCFG_STA(cfg) && cfg->BSS) { else if (BSSCFG_STA(cfg) && cfg->BSS) {
brcms_c_rcmta_add_bssid(wlc, cfg); brcms_c_rcmta_add_bssid(wlc, cfg);
} }
#endif #endif
}
void brcms_b_set_shortslot(struct brcms_hardware *wlc_hw, bool shortslot)
{
wlc_hw->shortslot = shortslot;
if (BAND_2G(brcms_b_bandtype(wlc_hw)) && wlc_hw->up) {
brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
brcms_b_update_slot_timing(wlc_hw, shortslot);
brcms_c_enable_mac(wlc_hw->wlc);
}
} }
/* /*
...@@ -4394,6 +3620,50 @@ static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, ...@@ -4394,6 +3620,50 @@ static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
} }
void
brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, chanspec_t chanspec,
bool mute, struct txpwr_limits *txpwr)
{
uint bandunit;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
wlc_hw->chanspec = chanspec;
/* Switch bands if necessary */
if (NBANDS_HW(wlc_hw) > 1) {
bandunit = CHSPEC_BANDUNIT(chanspec);
if (wlc_hw->band->bandunit != bandunit) {
/* brcms_b_setband disables other bandunit,
* use light band switch if not up yet
*/
if (wlc_hw->up) {
wlc_phy_chanspec_radio_set(wlc_hw->
bandstate[bandunit]->
pi, chanspec);
brcms_b_setband(wlc_hw, bandunit, chanspec);
} else {
brcms_c_setxband(wlc_hw, bandunit);
}
}
}
wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
if (!wlc_hw->up) {
if (wlc_hw->clk)
wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr,
chanspec);
wlc_phy_chanspec_radio_set(wlc_hw->band->pi, chanspec);
} else {
wlc_phy_chanspec_set(wlc_hw->band->pi, chanspec);
wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
/* Update muting of the channel */
brcms_b_mute(wlc_hw, mute, 0);
}
}
void brcms_c_set_chanspec(struct brcms_c_info *wlc, chanspec_t chanspec) void brcms_c_set_chanspec(struct brcms_c_info *wlc, chanspec_t chanspec)
{ {
uint bandunit; uint bandunit;
...@@ -4772,215 +4042,565 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci, ...@@ -4772,215 +4042,565 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
wme_shmemacindex(aci) * M_EDCF_QLEN + i, wme_shmemacindex(aci) * M_EDCF_QLEN + i,
*shm_entry++); *shm_entry++);
} while (0); } while (0);
if (suspend)
brcms_c_suspend_mac_and_wait(wlc);
if (suspend)
brcms_c_enable_mac(wlc);
}
void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
{
u16 aci;
int i_ac;
struct edcf_acparam *edcf_acp;
struct ieee80211_tx_queue_params txq_pars;
struct ieee80211_tx_queue_params *params = &txq_pars;
/*
* AP uses AC params from wme_param_ie_ap.
* AP advertises AC params from wme_param_ie.
* STA uses AC params from wme_param_ie.
*/
edcf_acp = (struct edcf_acparam *) &wlc->wme_param_ie.acparam[0];
for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
/* find out which ac this set of params applies to */
aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
/* fill in shm ac params struct */
params->txop = edcf_acp->TXOP;
params->aifs = edcf_acp->ACI;
/* CWmin = 2^(ECWmin) - 1 */
params->cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK);
/* CWmax = 2^(ECWmax) - 1 */
params->cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
>> EDCF_ECWMAX_SHIFT);
brcms_c_wme_setparams(wlc, aci, params, suspend);
}
if (suspend)
brcms_c_suspend_mac_and_wait(wlc);
if (AP_ENAB(wlc->pub) && WME_ENAB(wlc->pub)) {
brcms_c_update_beacon(wlc);
brcms_c_update_probe_resp(wlc, false);
}
if (suspend)
brcms_c_enable_mac(wlc);
}
bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit)
{
wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
wlc, "watchdog");
if (!wlc->wdtimer) {
wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer "
"failed\n", unit);
goto fail;
}
wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer,
wlc, "radio");
if (!wlc->radio_timer) {
wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer "
"failed\n", unit);
goto fail;
}
return true;
fail:
return false;
}
/*
* Initialize brcms_c_info default values ...
* may get overrides later in this function
*/
void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
{
int i;
/* Assume the device is there until proven otherwise */
wlc->device_present = true;
/* Save our copy of the chanspec */
wlc->chanspec = CH20MHZ_CHSPEC(1);
/* various 802.11g modes */
wlc->shortslot = false;
wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO;
brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO);
brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false);
brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR,
BRCMS_PROTECTION_AUTO);
brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF);
brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR,
BRCMS_PROTECTION_AUTO);
brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false);
brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP,
BRCMS_PROTECTION_CTL_OVERLAP);
/* 802.11g draft 4.0 NonERP elt advertisement */
wlc->include_legacy_erp = true;
wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF;
wlc->stf->txant = ANT_TX_DEF;
wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT;
wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN;
for (i = 0; i < NFIFO; i++)
wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN;
wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;
/* default rate fallback retry limits */
wlc->SFBL = RETRY_SHORT_FB;
wlc->LFBL = RETRY_LONG_FB;
/* default mac retry limits */
wlc->SRL = RETRY_SHORT_DEF;
wlc->LRL = RETRY_LONG_DEF;
/* Set flag to indicate that hw keys should be used when available. */
wlc->wsec_swkeys = false;
/* init the 4 static WEP default keys */
for (i = 0; i < WSEC_MAX_DEFAULT_KEYS; i++) {
wlc->wsec_keys[i] = wlc->wsec_def_keys[i];
wlc->wsec_keys[i]->idx = (u8) i;
}
/* WME QoS mode is Auto by default */
wlc->pub->_wme = AUTO;
#ifdef BCMSDIODEV_ENABLED
wlc->pub->_priofc = true; /* enable priority flow control for sdio dongle */
#endif
wlc->pub->_ampdu = AMPDU_AGG_HOST;
wlc->pub->bcmerror = 0;
wlc->pub->_coex = ON;
/* initialize mpc delay */
wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
}
static bool brcms_c_state_bmac_sync(struct brcms_c_info *wlc)
{
struct brcms_b_state state_bmac = {0};
if (brcms_b_state_get(wlc->hw, &state_bmac) != 0)
return false;
wlc->machwcap = state_bmac.machwcap;
brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR,
(s8) state_bmac.preamble_ovr);
return true;
}
static uint brcms_c_attach_module(struct brcms_c_info *wlc)
{
uint err = 0;
uint unit;
unit = wlc->pub->unit;
wlc->asi = brcms_c_antsel_attach(wlc);
if (wlc->asi == NULL) {
wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach "
"failed\n", unit);
err = 44;
goto fail;
}
wlc->ampdu = brcms_c_ampdu_attach(wlc);
if (wlc->ampdu == NULL) {
wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach "
"failed\n", unit);
err = 50;
goto fail;
}
if ((brcms_c_stf_attach(wlc) != 0)) {
wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach "
"failed\n", unit);
err = 68;
goto fail;
}
fail:
return err;
}
struct brcms_pub *brcms_c_pub(void *wlc)
{
return ((struct brcms_c_info *) wlc)->pub;
}
#define CHIP_SUPPORTS_11N(wlc) 1
/* low level attach
* run backplane attach, init nvram
* run phy attach
* initialize software state for each core and band
* put the whole chip in reset(driver down state), no clock
*/
int brcms_b_attach(struct brcms_c_info *wlc, u16 vendor, u16 device, uint unit,
bool piomode, void *regsva, uint bustype, void *btparam)
{
struct brcms_hardware *wlc_hw;
d11regs_t *regs;
char *macaddr = NULL;
char *vars;
uint err = 0;
uint j;
bool wme = false;
struct shared_phy_params sha_params;
struct wiphy *wiphy = wlc->wiphy;
if (suspend) BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, vendor,
brcms_c_suspend_mac_and_wait(wlc); device);
if (suspend) wme = true;
brcms_c_enable_mac(wlc);
} wlc_hw = wlc->hw;
wlc_hw->wlc = wlc;
wlc_hw->unit = unit;
wlc_hw->band = wlc_hw->bandstate[0];
wlc_hw->_piomode = piomode;
void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend) /* populate struct brcms_hardware with default values */
{ brcms_b_info_init(wlc_hw);
u16 aci;
int i_ac;
struct edcf_acparam *edcf_acp;
struct ieee80211_tx_queue_params txq_pars; /*
struct ieee80211_tx_queue_params *params = &txq_pars; * Do the hardware portion of the attach.
* Also initialize software state that depends on the particular hardware
* we are running.
*/
wlc_hw->sih = ai_attach(regsva, bustype, btparam,
&wlc_hw->vars, &wlc_hw->vars_size);
if (wlc_hw->sih == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: si_attach failed\n",
unit);
err = 11;
goto fail;
}
vars = wlc_hw->vars;
/* /*
* AP uses AC params from wme_param_ie_ap. * Get vendid/devid nvram overwrites, which could be different
* AP advertises AC params from wme_param_ie. * than those the BIOS recognizes for devices on PCMCIA_BUS,
* STA uses AC params from wme_param_ie. * SDIO_BUS, and SROMless devices on PCI_BUS.
*/ */
#ifdef BCMBUSTYPE
bustype = BCMBUSTYPE;
#endif
if (bustype != SI_BUS) {
char *var;
edcf_acp = (struct edcf_acparam *) &wlc->wme_param_ie.acparam[0]; var = getvar(vars, "vendid");
if (var) {
vendor = (u16) simple_strtoul(var, NULL, 0);
wiphy_err(wiphy, "Overriding vendor id = 0x%x\n",
vendor);
}
var = getvar(vars, "devid");
if (var) {
u16 devid = (u16) simple_strtoul(var, NULL, 0);
if (devid != 0xffff) {
device = devid;
wiphy_err(wiphy, "Overriding device id = 0x%x"
"\n", device);
}
}
for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) { /* verify again the device is supported */
/* find out which ac this set of params applies to */ if (!brcms_c_chipmatch(vendor, device)) {
aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT; wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
"vendor/device (0x%x/0x%x)\n",
unit, vendor, device);
err = 12;
goto fail;
}
}
/* fill in shm ac params struct */ wlc_hw->vendorid = vendor;
params->txop = edcf_acp->TXOP; wlc_hw->deviceid = device;
params->aifs = edcf_acp->ACI;
/* CWmin = 2^(ECWmin) - 1 */ /* set bar0 window to point at D11 core */
params->cw_min = EDCF_ECW2CW(edcf_acp->ECW & EDCF_ECWMIN_MASK); wlc_hw->regs = (d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID, 0);
/* CWmax = 2^(ECWmax) - 1 */ wlc_hw->corerev = ai_corerev(wlc_hw->sih);
params->cw_max = EDCF_ECW2CW((edcf_acp->ECW & EDCF_ECWMAX_MASK)
>> EDCF_ECWMAX_SHIFT);
brcms_c_wme_setparams(wlc, aci, params, suspend);
}
if (suspend) regs = wlc_hw->regs;
brcms_c_suspend_mac_and_wait(wlc);
if (AP_ENAB(wlc->pub) && WME_ENAB(wlc->pub)) { wlc->regs = wlc_hw->regs;
brcms_c_update_beacon(wlc);
brcms_c_update_probe_resp(wlc, false); /* validate chip, chiprev and corerev */
if (!brcms_c_isgoodchip(wlc_hw)) {
err = 13;
goto fail;
} }
if (suspend) /* initialize power control registers */
brcms_c_enable_mac(wlc); ai_clkctl_init(wlc_hw->sih);
} /* request fastclock and force fastclock for the rest of attach
* bring the d11 core out of reset.
* For PMU chips, the first wlc_clkctl_clk is no-op since core-clk is still false;
* But it will be called again inside wlc_corereset, after d11 is out of reset.
*/
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) if (!brcms_b_validate_chip_access(wlc_hw)) {
{ wiphy_err(wiphy, "wl%d: brcms_b_attach: validate_chip_access "
wlc->wdtimer = brcms_init_timer(wlc->wl, brcms_c_watchdog_by_timer,
wlc, "watchdog");
if (!wlc->wdtimer) {
wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for wdtimer "
"failed\n", unit); "failed\n", unit);
err = 14;
goto fail; goto fail;
} }
wlc->radio_timer = brcms_init_timer(wlc->wl, brcms_c_radio_timer, /* get the board rev, used just below */
wlc, "radio"); j = getintvar(vars, "boardrev");
if (!wlc->radio_timer) { /* promote srom boardrev of 0xFF to 1 */
wiphy_err(wlc->wiphy, "wl%d: wl_init_timer for radio_timer " if (j == BOARDREV_PROMOTABLE)
"failed\n", unit); j = BOARDREV_PROMOTED;
wlc_hw->boardrev = (u16) j;
if (!brcms_c_validboardtype(wlc_hw)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported Broadcom "
"board type (0x%x)" " or revision level (0x%x)\n",
unit, wlc_hw->sih->boardtype, wlc_hw->boardrev);
err = 15;
goto fail; goto fail;
} }
wlc_hw->sromrev = (u8) getintvar(vars, "sromrev");
wlc_hw->boardflags = (u32) getintvar(vars, "boardflags");
wlc_hw->boardflags2 = (u32) getintvar(vars, "boardflags2");
return true; if (wlc_hw->boardflags & BFL_NOPLLDOWN)
brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
fail: if ((wlc_hw->sih->bustype == PCI_BUS)
return false; && (ai_pci_war16165(wlc_hw->sih)))
} wlc->war16165 = true;
/* /* check device id(srom, nvram etc.) to set bands */
* Initialize brcms_c_info default values ... if (wlc_hw->deviceid == BCM43224_D11N_ID ||
* may get overrides later in this function wlc_hw->deviceid == BCM43224_D11N_ID_VEN1) {
/* Dualband boards */
wlc_hw->_nbands = 2;
} else
wlc_hw->_nbands = 1;
if ((wlc_hw->sih->chip == BCM43225_CHIP_ID))
wlc_hw->_nbands = 1;
/* BMAC_NOTE: remove init of pub values when brcms_c_attach()
* unconditionally does the init of these values
*/ */
void brcms_c_info_init(struct brcms_c_info *wlc, int unit) wlc->vendorid = wlc_hw->vendorid;
{ wlc->deviceid = wlc_hw->deviceid;
int i; wlc->pub->sih = wlc_hw->sih;
/* Assume the device is there until proven otherwise */ wlc->pub->corerev = wlc_hw->corerev;
wlc->device_present = true; wlc->pub->sromrev = wlc_hw->sromrev;
wlc->pub->boardrev = wlc_hw->boardrev;
wlc->pub->boardflags = wlc_hw->boardflags;
wlc->pub->boardflags2 = wlc_hw->boardflags2;
wlc->pub->_nbands = wlc_hw->_nbands;
/* Save our copy of the chanspec */ wlc_hw->physhim = wlc_phy_shim_attach(wlc_hw, wlc->wl, wlc);
wlc->chanspec = CH20MHZ_CHSPEC(1);
/* various 802.11g modes */ if (wlc_hw->physhim == NULL) {
wlc->shortslot = false; wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_shim_attach "
wlc->shortslot_override = BRCMS_SHORTSLOT_AUTO; "failed\n", unit);
err = 25;
goto fail;
}
brcms_c_protection_upd(wlc, BRCMS_PROT_G_OVR, BRCMS_PROTECTION_AUTO); /* pass all the parameters to wlc_phy_shared_attach in one struct */
brcms_c_protection_upd(wlc, BRCMS_PROT_G_SPEC, false); sha_params.sih = wlc_hw->sih;
sha_params.physhim = wlc_hw->physhim;
sha_params.unit = unit;
sha_params.corerev = wlc_hw->corerev;
sha_params.vars = vars;
sha_params.vid = wlc_hw->vendorid;
sha_params.did = wlc_hw->deviceid;
sha_params.chip = wlc_hw->sih->chip;
sha_params.chiprev = wlc_hw->sih->chiprev;
sha_params.chippkg = wlc_hw->sih->chippkg;
sha_params.sromrev = wlc_hw->sromrev;
sha_params.boardtype = wlc_hw->sih->boardtype;
sha_params.boardrev = wlc_hw->boardrev;
sha_params.boardvendor = wlc_hw->sih->boardvendor;
sha_params.boardflags = wlc_hw->boardflags;
sha_params.boardflags2 = wlc_hw->boardflags2;
sha_params.bustype = wlc_hw->sih->bustype;
sha_params.buscorerev = wlc_hw->sih->buscorerev;
brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG_OVR, /* alloc and save pointer to shared phy state area */
BRCMS_PROTECTION_AUTO); wlc_hw->phy_sh = wlc_phy_shared_attach(&sha_params);
brcms_c_protection_upd(wlc, BRCMS_PROT_N_CFG, BRCMS_N_PROTECTION_OFF); if (!wlc_hw->phy_sh) {
brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF_OVR, err = 16;
BRCMS_PROTECTION_AUTO); goto fail;
brcms_c_protection_upd(wlc, BRCMS_PROT_N_NONGF, false); }
brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, AUTO);
brcms_c_protection_upd(wlc, BRCMS_PROT_OVERLAP, /* initialize software state for each core and band */
BRCMS_PROTECTION_CTL_OVERLAP); for (j = 0; j < NBANDS_HW(wlc_hw); j++) {
/*
* band0 is always 2.4Ghz
* band1, if present, is 5Ghz
*/
/* So if this is a single band 11a card, use band 1 */
if (IS_SINGLEBAND_5G(wlc_hw->deviceid))
j = BAND_5G_INDEX;
/* 802.11g draft 4.0 NonERP elt advertisement */ brcms_c_setxband(wlc_hw, j);
wlc->include_legacy_erp = true;
wlc->stf->ant_rx_ovr = ANT_RX_DIV_DEF; wlc_hw->band->bandunit = j;
wlc->stf->txant = ANT_TX_DEF; wlc_hw->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
wlc->band->bandunit = j;
wlc->band->bandtype = j ? BRCM_BAND_5G : BRCM_BAND_2G;
wlc->core->coreidx = ai_coreidx(wlc_hw->sih);
wlc->prb_resp_timeout = BRCMS_PRB_RESP_TIMEOUT; wlc_hw->machwcap = R_REG(&regs->machwcap);
wlc_hw->machwcap_backup = wlc_hw->machwcap;
wlc->usr_fragthresh = DOT11_DEFAULT_FRAG_LEN; /* init tx fifo size */
for (i = 0; i < NFIFO; i++) wlc_hw->xmtfifo_sz =
wlc->fragthresh[i] = DOT11_DEFAULT_FRAG_LEN; xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)];
wlc->RTSThresh = DOT11_DEFAULT_RTS_LEN;
/* default rate fallback retry limits */ /* Get a phy for this band */
wlc->SFBL = RETRY_SHORT_FB; wlc_hw->band->pi = wlc_phy_attach(wlc_hw->phy_sh,
wlc->LFBL = RETRY_LONG_FB; (void *)regs, brcms_b_bandtype(wlc_hw), vars,
wlc->wiphy);
if (wlc_hw->band->pi == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: wlc_phy_"
"attach failed\n", unit);
err = 17;
goto fail;
}
/* default mac retry limits */ wlc_phy_machwcap_set(wlc_hw->band->pi, wlc_hw->machwcap);
wlc->SRL = RETRY_SHORT_DEF;
wlc->LRL = RETRY_LONG_DEF;
/* Set flag to indicate that hw keys should be used when available. */ wlc_phy_get_phyversion(wlc_hw->band->pi, &wlc_hw->band->phytype,
wlc->wsec_swkeys = false; &wlc_hw->band->phyrev,
&wlc_hw->band->radioid,
&wlc_hw->band->radiorev);
wlc_hw->band->abgphy_encore =
wlc_phy_get_encore(wlc_hw->band->pi);
wlc->band->abgphy_encore = wlc_phy_get_encore(wlc_hw->band->pi);
wlc_hw->band->core_flags =
wlc_phy_get_coreflags(wlc_hw->band->pi);
/* init the 4 static WEP default keys */ /* verify good phy_type & supported phy revision */
for (i = 0; i < WSEC_MAX_DEFAULT_KEYS; i++) { if (BRCMS_ISNPHY(wlc_hw->band)) {
wlc->wsec_keys[i] = wlc->wsec_def_keys[i]; if (NCONF_HAS(wlc_hw->band->phyrev))
wlc->wsec_keys[i]->idx = (u8) i; goto good_phy;
else
goto bad_phy;
} else if (BRCMS_ISLCNPHY(wlc_hw->band)) {
if (LCNCONF_HAS(wlc_hw->band->phyrev))
goto good_phy;
else
goto bad_phy;
} else {
bad_phy:
wiphy_err(wiphy, "wl%d: brcms_b_attach: unsupported "
"phy type/rev (%d/%d)\n", unit,
wlc_hw->band->phytype, wlc_hw->band->phyrev);
err = 18;
goto fail;
} }
/* WME QoS mode is Auto by default */ good_phy:
wlc->pub->_wme = AUTO; /* BMAC_NOTE: wlc->band->pi should not be set below and should be done in the
* high level attach. However we can not make that change until all low level access
#ifdef BCMSDIODEV_ENABLED * is changed to wlc_hw->band->pi. Instead do the wlc->band->pi init below, keeping
wlc->pub->_priofc = true; /* enable priority flow control for sdio dongle */ * wlc_hw->band->pi as well for incremental update of low level fns, and cut over
#endif * low only init when all fns updated.
*/
wlc->band->pi = wlc_hw->band->pi;
wlc->band->phytype = wlc_hw->band->phytype;
wlc->band->phyrev = wlc_hw->band->phyrev;
wlc->band->radioid = wlc_hw->band->radioid;
wlc->band->radiorev = wlc_hw->band->radiorev;
wlc->pub->_ampdu = AMPDU_AGG_HOST; /* default contention windows size limits */
wlc->pub->bcmerror = 0; wlc_hw->band->CWmin = APHY_CWMIN;
wlc->pub->_coex = ON; wlc_hw->band->CWmax = PHY_CWMAX;
/* initialize mpc delay */ if (!brcms_b_attach_dmapio(wlc, j, wme)) {
wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT; err = 19;
} goto fail;
}
}
static bool brcms_c_state_bmac_sync(struct brcms_c_info *wlc) /* disable core to match driver "down" state */
{ brcms_c_coredisable(wlc_hw);
struct brcms_b_state state_bmac = {0};
if (brcms_b_state_get(wlc->hw, &state_bmac) != 0) /* Match driver "down" state */
return false; if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_down(wlc_hw->sih);
wlc->machwcap = state_bmac.machwcap; /* register sb interrupt callback functions */
brcms_c_protection_upd(wlc, BRCMS_PROT_N_PAM_OVR, ai_register_intr_callback(wlc_hw->sih, (void *)brcms_c_wlintrsoff,
(s8) state_bmac.preamble_ovr); (void *)brcms_c_wlintrsrestore, NULL, wlc);
return true; /* turn off pll and xtal to match driver "down" state */
} brcms_b_xtal(wlc_hw, OFF);
static uint brcms_c_attach_module(struct brcms_c_info *wlc) /* *********************************************************************
{ * The hardware is in the DOWN state at this point. D11 core
uint err = 0; * or cores are in reset with clocks off, and the board PLLs
uint unit; * are off if possible.
unit = wlc->pub->unit; *
* Beyond this point, wlc->sbclk == false and chip registers
* should not be touched.
*********************************************************************
*/
wlc->asi = brcms_c_antsel_attach(wlc); /* init etheraddr state variables */
if (wlc->asi == NULL) { macaddr = brcms_c_get_macaddr(wlc_hw);
wiphy_err(wlc->wiphy, "wl%d: attach: antsel_attach " if (macaddr == NULL) {
"failed\n", unit); wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
err = 44; unit);
err = 21;
goto fail; goto fail;
} }
brcmu_ether_atoe(macaddr, wlc_hw->etheraddr);
wlc->ampdu = brcms_c_ampdu_attach(wlc); if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
if (wlc->ampdu == NULL) { is_zero_ether_addr(wlc_hw->etheraddr)) {
wiphy_err(wlc->wiphy, "wl%d: attach: ampdu_attach " wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
"failed\n", unit); unit, macaddr);
err = 50; err = 22;
goto fail; goto fail;
} }
if ((brcms_c_stf_attach(wlc) != 0)) { BCMMSG(wlc->wiphy,
wiphy_err(wlc->wiphy, "wl%d: attach: stf_attach " "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
"failed\n", unit); wlc_hw->deviceid, wlc_hw->_nbands,
err = 68; wlc_hw->sih->boardtype, macaddr);
goto fail;
}
fail:
return err; return err;
}
struct brcms_pub *brcms_c_pub(void *wlc) fail:
{ wiphy_err(wiphy, "wl%d: brcms_b_attach: failed with err %d\n", unit,
return ((struct brcms_c_info *) wlc)->pub; err);
return err;
} }
#define CHIP_SUPPORTS_11N(wlc) 1
/* /*
* The common driver entry routine. Error codes should be unique * The common driver entry routine. Error codes should be unique
*/ */
...@@ -5333,6 +4953,58 @@ static void brcms_c_detach_module(struct brcms_c_info *wlc) ...@@ -5333,6 +4953,58 @@ static void brcms_c_detach_module(struct brcms_c_info *wlc)
brcms_c_stf_detach(wlc); brcms_c_stf_detach(wlc);
} }
/*
* low level detach
*/
int brcms_b_detach(struct brcms_c_info *wlc)
{
uint i;
struct brcms_hw_band *band;
struct brcms_hardware *wlc_hw = wlc->hw;
int callbacks;
callbacks = 0;
if (wlc_hw->sih) {
/* detach interrupt sync mechanism since interrupt is disabled and per-port
* interrupt object may has been freed. this must be done before sb core switch
*/
ai_deregister_intr_callback(wlc_hw->sih);
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_sleep(wlc_hw->sih);
}
brcms_b_detach_dmapio(wlc_hw);
band = wlc_hw->band;
for (i = 0; i < NBANDS_HW(wlc_hw); i++) {
if (band->pi) {
/* Detach this band's phy */
wlc_phy_detach(band->pi);
band->pi = NULL;
}
band = wlc_hw->bandstate[OTHERBANDUNIT(wlc)];
}
/* Free shared phy state */
kfree(wlc_hw->phy_sh);
wlc_phy_shim_detach(wlc_hw->physhim);
/* free vars */
kfree(wlc_hw->vars);
wlc_hw->vars = NULL;
if (wlc_hw->sih) {
ai_detach(wlc_hw->sih);
wlc_hw->sih = NULL;
}
return callbacks;
}
/* /*
* Return a count of the number of driver callbacks still pending. * Return a count of the number of driver callbacks still pending.
* *
...@@ -5550,14 +5222,37 @@ static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc) ...@@ -5550,14 +5222,37 @@ static bool brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
return true; return true;
} }
bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc) bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
{ {
if (!wlc->radio_monitor) if (!wlc->radio_monitor)
return true; return true;
wlc->radio_monitor = false;
brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_RADIO_MON);
return brcms_del_timer(wlc->wl, wlc->radio_timer);
}
/* common low-level watchdog code */
void brcms_b_watchdog(void *arg)
{
struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
struct brcms_hardware *wlc_hw = wlc->hw;
BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
if (!wlc_hw->up)
return;
/* increment second count */
wlc_hw->now++;
wlc->radio_monitor = false; /* Check for FIFO error interrupts */
brcms_c_pllreq(wlc, false, BRCMS_PLLREQ_RADIO_MON); brcms_b_fifoerrors(wlc_hw);
return brcms_del_timer(wlc->wl, wlc->radio_timer);
/* make sure RX dma has buffers */
dma_rxfill(wlc->hw->di[RX_FIFO]);
wlc_phy_watchdog(wlc_hw->band->pi);
} }
static void brcms_c_watchdog_by_timer(void *arg) static void brcms_c_watchdog_by_timer(void *arg)
...@@ -5637,6 +5332,105 @@ static void brcms_c_watchdog(void *arg) ...@@ -5637,6 +5332,105 @@ static void brcms_c_watchdog(void *arg)
} }
} }
/* Initialize just the hardware when coming out of POR or S3/S5 system states */
void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
{
if (wlc_hw->wlc->pub->hw_up)
return;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
* Enable pll and xtal, initialize the power control registers,
* and force fastclock for the remainder of brcms_c_up().
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
if (wlc_hw->sih->bustype == PCI_BUS) {
ai_pci_fixcfg(wlc_hw->sih);
/* AI chip doesn't restore bar0win2 on hibernation/resume, need sw fixup */
if ((wlc_hw->sih->chip == BCM43224_CHIP_ID) ||
(wlc_hw->sih->chip == BCM43225_CHIP_ID))
wlc_hw->regs =
(d11regs_t *) ai_setcore(wlc_hw->sih, D11_CORE_ID,
0);
}
/* Inform phy that a POR reset has occurred so it does a complete phy init */
wlc_phy_por_inform(wlc_hw->band->pi);
wlc_hw->ucode_loaded = false;
wlc_hw->wlc->pub->hw_up = true;
if ((wlc_hw->boardflags & BFL_FEM)
&& (wlc_hw->sih->chip == BCM4313_CHIP_ID)) {
if (!
(wlc_hw->boardrev >= 0x1250
&& (wlc_hw->boardflags & BFL_FEM_BT)))
ai_epa_4313war(wlc_hw->sih);
}
}
int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
{
uint coremask;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
* Enable pll and xtal, initialize the power control registers,
* and force fastclock for the remainder of brcms_c_up().
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
/*
* Configure pci/pcmcia here instead of in brcms_c_attach()
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
*/
coremask = (1 << wlc_hw->wlc->core->coreidx);
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_setup(wlc_hw->sih, coremask);
/*
* Need to read the hwradio status here to cover the case where the system
* is loaded with the hw radio disabled. We do not want to bring the driver up in this case.
*/
if (brcms_b_radio_read_hwdisabled(wlc_hw)) {
/* put SB PCI in down state again */
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_down(wlc_hw->sih);
brcms_b_xtal(wlc_hw, OFF);
return -ENOMEDIUM;
}
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_up(wlc_hw->sih);
/* reset the d11 core */
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
return 0;
}
int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
{
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
wlc_hw->up = true;
wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
/* FULLY enable dynamic power control and d11 core interrupt */
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_intrson(wlc_hw->wlc->wl);
return 0;
}
/* make interface operational */ /* make interface operational */
int brcms_c_up(struct brcms_c_info *wlc) int brcms_c_up(struct brcms_c_info *wlc)
{ {
...@@ -5773,6 +5567,78 @@ static uint brcms_c_down_del_timer(struct brcms_c_info *wlc) ...@@ -5773,6 +5567,78 @@ static uint brcms_c_down_del_timer(struct brcms_c_info *wlc)
return callbacks; return callbacks;
} }
int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
{
bool dev_gone;
uint callbacks = 0;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
if (!wlc_hw->up)
return callbacks;
dev_gone = DEVICEREMOVED(wlc_hw->wlc);
/* disable interrupts */
if (dev_gone)
wlc_hw->wlc->macintmask = 0;
else {
/* now disable interrupts */
brcms_intrsoff(wlc_hw->wlc->wl);
/* ensure we're running on the pll clock again */
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
}
/* down phy at the last of this stage */
callbacks += wlc_phy_down(wlc_hw->band->pi);
return callbacks;
}
int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
{
uint callbacks = 0;
bool dev_gone;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
if (!wlc_hw->up)
return callbacks;
wlc_hw->up = false;
wlc_phy_hw_state_upd(wlc_hw->band->pi, false);
dev_gone = DEVICEREMOVED(wlc_hw->wlc);
if (dev_gone) {
wlc_hw->sbclk = false;
wlc_hw->clk = false;
wlc_phy_hw_clk_state_upd(wlc_hw->band->pi, false);
/* reclaim any posted packets */
brcms_c_flushqueues(wlc_hw->wlc);
} else {
/* Reset and disable the core */
if (ai_iscoreup(wlc_hw->sih)) {
if (R_REG(&wlc_hw->regs->maccontrol) &
MCTL_EN_MAC)
brcms_c_suspend_mac_and_wait(wlc_hw->wlc);
callbacks += brcms_reset(wlc_hw->wlc->wl);
brcms_c_coredisable(wlc_hw);
}
/* turn off primary xtal and pll */
if (!wlc_hw->noreset) {
if (wlc_hw->sih->bustype == PCI_BUS)
ai_pci_down(wlc_hw->sih);
brcms_b_xtal(wlc_hw, OFF);
}
}
return callbacks;
}
/* /*
* Mark the interface nonoperational, stop the software mechanisms, * Mark the interface nonoperational, stop the software mechanisms,
* disable the hardware, free any transient buffer state. * disable the hardware, free any transient buffer state.
...@@ -6709,6 +6575,29 @@ void brcms_c_print_rxh(struct d11rxhdr *rxh) ...@@ -6709,6 +6575,29 @@ void brcms_c_print_rxh(struct d11rxhdr *rxh)
} }
#endif /* defined(BCMDBG) */ #endif /* defined(BCMDBG) */
u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
{
u16 table_ptr;
u8 phy_rate, index;
/* get the phy specific rate encoding for the PLCP SIGNAL field */
if (IS_OFDM(rate))
table_ptr = M_RT_DIRMAP_A;
else
table_ptr = M_RT_DIRMAP_B;
/* for a given rate, the LS-nibble of the PLCP SIGNAL field is
* the index into the rate table.
*/
phy_rate = rate_info[rate] & BRCMS_RATE_MASK;
index = phy_rate & 0xf;
/* Find the SHM pointer to the rate table entry by looking in the
* Direct-map Table
*/
return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
}
static u16 brcms_c_rate_shm_offset(struct brcms_c_info *wlc, u8 rate) static u16 brcms_c_rate_shm_offset(struct brcms_c_info *wlc, u8 rate)
{ {
return brcms_b_rate_shm_offset(wlc->hw, rate); return brcms_b_rate_shm_offset(wlc->hw, rate);
...@@ -8114,6 +8003,19 @@ void brcms_c_bcn_li_upd(struct brcms_c_info *wlc) ...@@ -8114,6 +8003,19 @@ void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
(wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn); (wlc->bcn_li_dtim << 8) | wlc->bcn_li_bcn);
} }
void
brcms_b_read_tsf(struct brcms_hardware *wlc_hw, u32 *tsf_l_ptr,
u32 *tsf_h_ptr)
{
d11regs_t *regs = wlc_hw->regs;
/* read the tsf timer low, then high to get an atomic read */
*tsf_l_ptr = R_REG(&regs->tsf_timerlow);
*tsf_h_ptr = R_REG(&regs->tsf_timerhigh);
return;
}
/* /*
* recover 64bit TSF value from the 16bit TSF value in the rx header * recover 64bit TSF value from the 16bit TSF value in the rx header
* given the assumption that the TSF passed in header is within 65ms * given the assumption that the TSF passed in header is within 65ms
...@@ -8933,6 +8835,27 @@ int brcms_c_get_header_len() ...@@ -8933,6 +8835,27 @@ int brcms_c_get_header_len()
return TXOFF; return TXOFF;
} }
/* mac is assumed to be suspended at this point */
void
brcms_b_write_hw_bcntemplates(struct brcms_hardware *wlc_hw, void *bcn,
int len, bool both)
{
d11regs_t *regs = wlc_hw->regs;
if (both) {
brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len);
brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len);
} else {
/* bcn 0 */
if (!(R_REG(&regs->maccommand) & MCMD_BCN0VLD))
brcms_c_write_hw_bcntemplate0(wlc_hw, bcn, len);
/* bcn 1 */
else if (!
(R_REG(&regs->maccommand) & MCMD_BCN1VLD))
brcms_c_write_hw_bcntemplate1(wlc_hw, bcn, len);
}
}
/* Update a beacon for a particular BSS /* Update a beacon for a particular BSS
* For MBSS, this updates the software template and sets "latest" to the index of the * For MBSS, this updates the software template and sets "latest" to the index of the
* template updated. * template updated.
...@@ -9341,6 +9264,17 @@ void brcms_c_mhf(struct brcms_c_info *wlc, u8 idx, u16 mask, u16 val, int bands) ...@@ -9341,6 +9264,17 @@ void brcms_c_mhf(struct brcms_c_info *wlc, u8 idx, u16 mask, u16 val, int bands)
brcms_b_mhf(wlc->hw, idx, mask, val, bands); brcms_b_mhf(wlc->hw, idx, mask, val, bands);
} }
int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
uint *blocks)
{
if (fifo >= NFIFO)
return -EINVAL;
*blocks = wlc_hw->xmtfifo_sz[fifo];
return 0;
}
int brcms_c_xmtfifo_sz_get(struct brcms_c_info *wlc, uint fifo, uint *blocks) int brcms_c_xmtfifo_sz_get(struct brcms_c_info *wlc, uint fifo, uint *blocks)
{ {
return brcms_b_xmtfifo_sz_get(wlc->hw, fifo, blocks); return brcms_b_xmtfifo_sz_get(wlc->hw, fifo, blocks);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment