📄 wlc.c
字号:
} /* Init precedence maps for empty FIFOs */ wlc_tx_prec_map_init(wlc); /* ..now really unleash hell (allow the MAC out of suspend) */ wlc_enable_mac(wlc); /* restore macintmask */ wl_intrsrestore(wlc->wl, macintmask); /* clear tx flow control */ if (wlc->pub.txqstopped) { wlc->pub.txqstopped = OFF; wl_txflowcontrol(wlc->wl, OFF); } /* clear tx data fifo suspends */ wlc->tx_suspended = FALSE; /* enable the RF Disable Delay timer */ if (wlc->pub.corerev >= 10) { W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT); } /* Reinitialize the precedence map to syncup with FIFOs */ wlc_tx_prec_map_init(wlc);}/* return initial host flags value */static uint32BCMINITFN(wlc_mhfdef)(wlc_info_t *wlc){ uint32 mhf; mhf = 0; if (ISGPHY(wlc->band->pi)) mhf |= MHF_SYMWAR; if (ISGPHY(wlc->band->pi) && GREV_IS(wlc->band->pi->phy_rev, 1)) mhf |= MHF_DCFILTWAR; if (ISGPHY(wlc->band->pi) && (wlc->pub.boardflags & BFL_PACTRL) && !wlc->dbgsel) mhf |= MHF_OFDMPWR; /* enable CCK power boost in ucode but not for 4318/20 */ if (ISGPHY(wlc->band->pi) && (wlc->band->pi->phy_rev < 3)) { if (mhf & MHF_OFDMPWR) WL_ERROR(("wl%d: Cannot support simultaneous MHF_OFDMPWR & MHF_CCKPWR\n", wlc->pub.unit)); else mhf |= MHF_CCKPWR; } /* prohibit use of slowclock on multifunction boards */ if (wlc->pub.boardflags & BFL_NOPLLDOWN) mhf |= MHF_FORCEFASTCLK; if ((wlc->band->pi->radioid == BCM2050_ID) && (wlc->band->pi->radiorev < 6)) mhf |= MHF_SYNTHPUWAR; if (WLC_WAR16165(wlc)) mhf |= MHF_PCISLOWCLKWAR; return (mhf);}/* set or clear ucode host flag bits and return new value * it has an optimization for no-change write * it only writes through shared memory when the core has clock; * pre-CLK changes should use wlc_write_mhf to get around the optimization * * it change both bands' shadow variables if allbands is TRUE * return value is valid only if wlc->band has been initialized */uint32wlc_mhf(wlc_info_t *wlc, uint32 mask, uint32 val, bool allbands){ uint32 save; ASSERT((val & ~mask) == 0); if (wlc->band) { save = wlc->band->mhf; wlc->band->mhf = (wlc->band->mhf & ~mask) | val; /* optimization: only write through if changed */ if (wlc->core->clk && (wlc->band->mhf != save)) { wlc_write_shm(wlc, M_HOST_FLAGS, (uint16)wlc->band->mhf); wlc_write_shm(wlc, M_HOST_FLAGS2, (uint16)(wlc->band->mhf >> M_HOST_FLAGS_SZ)); } } if (allbands) { wlc->bandstate[0].mhf = (wlc->bandstate[0].mhf & ~mask) | val; wlc->bandstate[1].mhf = (wlc->bandstate[1].mhf & ~mask) | val; } return (wlc->band ? wlc->band->mhf : 0);}static voidwlc_write_mhf(wlc_info_t *wlc, uint32 val){ wlc_write_shm(wlc, M_HOST_FLAGS, (uint16)val); wlc_write_shm(wlc, M_HOST_FLAGS2, (uint16)(val >> M_HOST_FLAGS_SZ));}/* set or clear maccontrol bits and return new value */void wlc_mctrl(wlc_info_t *wlc, uint32 mask, uint32 val){ ASSERT((val & ~mask) == 0); wlc->maccontrol = (R_REG(&wlc->regs->maccontrol) & ~mask) | val; W_REG(&wlc->regs->maccontrol, wlc->maccontrol);}voidwlc_mac_bcn_promisc(wlc_info_t *wlc){ /* default behavior: on for Gmode in BSS/IBSS) || (A/B mode in IBSS) * off for other cases */ if (wlc->band->gmode || wlc->bcnmisc_ibss || wlc->bcnmisc_scan || wlc->bcnmisc_monitor) wlc_mctrl(wlc, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC); else wlc_mctrl(wlc, MCTL_BCNS_PROMISC, 0);}/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */voidwlc_mac_promisc(wlc_info_t *wlc){ uint32 promisc_bits = 0; /* promiscuous mode just sets MCTL_PROMISC * Note: APs get all BSS traffic without the need to set the MCTL_PROMISC bit * since all BSS data traffic is directed at the AP */ if (wlc->pub.promisc) promisc_bits |= MCTL_PROMISC; /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is * handled in wlc_mac_bcn_promisc() */ if (wlc->monitor) promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL; wlc_mctrl(wlc, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);}/* push sw hps and wake state through hardware */voidwlc_set_ps_ctrl(wlc_info_t *wlc){ uint32 v1, v2; bool hps, wake; bool awake_before; hps = PS_ALLOWED(wlc); wake = STAY_AWAKE(wlc); if (!hps) wake = TRUE; WL_TRACE(("wl%d: wlc_set_ps_ctrl: hps %d wake %d\n", wlc->pub.unit, hps, wake)); v1 = v2 = R_REG(&wlc->regs->maccontrol); if (hps) v2 |= MCTL_HPS; else v2 &= ~MCTL_HPS; if (wake) v2 |= MCTL_WAKE; else v2 &= ~MCTL_WAKE; /* just return if no change */ if ((v1 & (MCTL_WAKE | MCTL_HPS)) == (v2 & ((MCTL_WAKE | MCTL_HPS)))) return; if ((v1 & MCTL_HPS) && !hps) WL_PS(("wl%d: PS mode disable \n", wlc->pub.unit)); if (!(v1 & MCTL_HPS) && hps) WL_PS(("wl%d: PS mode enable \n", wlc->pub.unit)); if (hps) { if ((v1 & MCTL_WAKE) && !wake) WL_PS(("wl%d: PS-MODE: sleep\n", wlc->pub.unit)); if (!(v1 & MCTL_WAKE) && wake) WL_PS(("wl%d: PS-MODE: wake\n", wlc->pub.unit)); } wlc_mctrl(wlc, ~0, v2); awake_before = ((v1 & MCTL_WAKE) || ((v1 & MCTL_HPS) == 0)); /* readback */ if (wake && !awake_before) { if (D11REV_LT(wlc->pub.corerev, 5)) /* no slowclock */ OSL_DELAY(5); else { if ((ISGPHY(wlc->band->pi)) && (D11REV_IS(wlc->pub.corerev, 5))) OSL_DELAY(2000); /* delay before first read */ else OSL_DELAY(40); /* delay before first read */ SPINWAIT((wlc_read_shm(wlc, M_UCODE_DBGST) == DBGST_ASLEEP), (8 * MIN_SLOW_CLK)); } ASSERT(wlc_read_shm(wlc, M_UCODE_DBGST) != DBGST_ASLEEP); }}/* * Write STA MAC address to core. * Updates RXE match engine and tx template addr fields. */static voidwlc_set_mac(wlc_info_t *wlc, struct ether_addr *addr){ d11regs_t *regs; char template_buf[(T_RAM_ACCESS_SZ*2)]; WL_TRACE(("wl%d: wlc_set_mac\n", wlc->pub.unit)); regs = wlc->regs; /* enter the MAC addr into the RXE match registers */ wlc_set_addrmatch(wlc, RCM_MAC_OFFSET, addr); /* fill out a buffer with a multiple of 4 length, starting at * a 4 byte boundary offset for wlc_write_template_ram, 6 bytes * of MAC addr and the first 2 bytes of our beaconing BSSID. */ bcopy((char*)wlc->pub.cur_etheraddr.octet, template_buf, ETHER_ADDR_LEN); bcopy((char*)wlc->announce_BSSID.octet, template_buf + ETHER_ADDR_LEN, 2); /* The A2 (SA) MAC addr appears at bytes [16, 21] in the 802.11 frames * in the templates. * 6 bytes PLCP * 2 bytes FC * 2 bytes DUR/ID * 6 bytes A1 * 6 bytes A2 (SA) * 6 bytes A3 (BSSID) */ /* update the BEACON templates */ wlc_write_template_ram(wlc, (T_BCN0_TPL_BASE + 16), (T_RAM_ACCESS_SZ*2), template_buf); wlc_write_template_ram(wlc, (T_BCN1_TPL_BASE + 16), (T_RAM_ACCESS_SZ*2), template_buf);}static voidwlc_clear_bssid(wlc_info_t *wlc){ W_REG(&wlc->regs->rcm_ctl, RCM_BSSID_OFFSET | RCM_INC_DATA); W_REG(&wlc->regs->rcm_mat_data, 0); W_REG(&wlc->regs->rcm_mat_data, 0); W_REG(&wlc->regs->rcm_mat_data, 0);}/* Write BSSID address to core (set_bssid in d11procs.tcl). * Updates RXE match engine and tx template addr fields. */static voidwlc_set_bssid(wlc_info_t *wlc){ d11regs_t *regs; char template_buf[(T_RAM_ACCESS_SZ*2)]; WL_TRACE(("wl%d: wlc_set_bssid\n", wlc->pub.unit)); regs = wlc->regs; /* enter the BSSID addr into the RXE match registers */ wlc_set_addrmatch(wlc, RCM_BSSID_OFFSET, &wlc->BSSID); /* The A3 (BSSID) MAC addr appears at bytes [22, 27] in the 802.11 frames * in the templates. * 6 bytes PLCP * 2 bytes FC * 2 bytes DUR/ID * 6 bytes A1 * 6 bytes A2 (SA) * 6 bytes A3 (BSSID) */ /* fill out a buffer with a multiple of 4 length, starting at * a 4 byte boundary offset for wlc_write_template_ram, last 2 * bytes of MAC addr and the all 6 bytes our beaconing BSSID */ bcopy((char*)wlc->pub.cur_etheraddr.octet + 4, template_buf, 2); bcopy((char*)wlc->announce_BSSID.octet, template_buf + 2, ETHER_ADDR_LEN); /* update the BEACON templates */ wlc_write_template_ram(wlc, (T_BCN0_TPL_BASE + 20), (T_RAM_ACCESS_SZ*2), template_buf); wlc_write_template_ram(wlc, (T_BCN1_TPL_BASE + 20), (T_RAM_ACCESS_SZ*2), template_buf);}/* * Write a MAC address to the rcmta structure */voidwlc_set_rcmta(wlc_info_t *wlc, int idx, const struct ether_addr *addr){ d11regs_t *regs = wlc->regs; volatile uint16* objdata16 = (uint16*)®s->objdata; uint32 mac_hm; uint16 mac_l; WL_TRACE(("wl%d: %s\n", wlc->pub.unit, __FUNCTION__)); ASSERT(wlc->pub.corerev > 4); ASSERT((idx >= 0) && (idx < (WSEC_MAX_RCMTA_KEYS - WSEC_MAX_DEFAULT_KEYS))); mac_hm = (addr->octet[3] << 24) | (addr->octet[2] << 16) | (addr->octet[1] << 8) | addr->octet[0]; mac_l = (addr->octet[5] << 8) | addr->octet[4]; W_REG(®s->objaddr, (OBJADDR_RCMTA_SEL | (idx * 2))); W_REG(®s->objdata, mac_hm); W_REG(®s->objaddr, (OBJADDR_RCMTA_SEL | ((idx * 2) + 1))); W_REG(objdata16, mac_l);}/* * Write a MAC address to the given match reg offset in the RXE match engine. */voidwlc_set_addrmatch(wlc_info_t *wlc, int match_reg_offset, const struct ether_addr *addr){ d11regs_t *regs; uint16 mac_l; uint16 mac_m; uint16 mac_h; WL_TRACE(("wl%d: wlc_set_addrmatch\n", wlc->pub.unit)); ASSERT((match_reg_offset < RCM_WEP_TA0_OFFSET) || (wlc->pub.corerev < 5)); regs = wlc->regs; mac_l = addr->octet[0] | (addr->octet[1] << 8); mac_m = addr->octet[2] | (addr->octet[3] << 8); mac_h = addr->octet[4] | (addr->octet[5] << 8); /* enter the MAC addr into the RXE match registers */ W_REG(®s->rcm_ctl, RCM_INC_DATA | match_reg_offset); W_REG(®s->rcm_mat_data, mac_l); W_REG(®s->rcm_mat_data, mac_m); W_REG(®s->rcm_mat_data, mac_h);}voidwlc_write_template_ram(wlc_info_t *wlc, int offset, int len, void *buf){ d11regs_t *regs; uint32 word; bool be_bit; WL_TRACE(("wl%d: wlc_write_template_ram\n", wlc->pub.unit)); regs = wlc->regs; ASSERT(ISALIGNED(offset, sizeof(uint32))); ASSERT(ISALIGNED(len, sizeof(uint32))); ASSERT((offset & ~0xffff) == 0); W_REG(®s->tplatewrptr, offset); /* if MCTL_BIGEND bit set in mac control register, * the chip swaps data in fifo, as well as data in * template ram */ be_bit = (R_REG(®s->maccontrol) & MCTL_BIGEND) != 0; while (len > 0) { bcopy((uint8*)buf, &word, sizeof(uint32)); if (be_bit) word = hton32(word); else word = htol32(word); W_REG(®s->tplatewrdata, word); buf = (uint8*)buf + sizeof(uint32); len -= sizeof(uint32); }}/* * Suspend the the MAC and update the slot timing * for standard 11b/g (20us slots) or shortslot 11g (9us slots). */static voidwlc_switch_shortslot(wlc_info_t *wlc, bool shortslot){ ASSERT(wlc->band->gmode);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -