Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/bwi/bwimac.c
Show First 20 Lines • Show All 826 Lines • ▼ Show 20 Lines | bwi_mac_detach(struct bwi_mac *mac) | ||||
bwi_mac_fw_free(mac); | bwi_mac_fw_free(mac); | ||||
} | } | ||||
static __inline int | static __inline int | ||||
bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw, | bwi_fwimage_is_valid(struct bwi_softc *sc, const struct firmware *fw, | ||||
uint8_t fw_type) | uint8_t fw_type) | ||||
{ | { | ||||
const struct bwi_fwhdr *hdr; | const struct bwi_fwhdr *hdr; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
if (fw->datasize < sizeof(*hdr)) { | if (fw->datasize < sizeof(*hdr)) { | ||||
if_printf(ifp, "invalid firmware (%s): invalid size %zu\n", | device_printf(sc->sc_dev, | ||||
"invalid firmware (%s): invalid size %zu\n", | |||||
fw->name, fw->datasize); | fw->name, fw->datasize); | ||||
return 0; | return 0; | ||||
} | } | ||||
hdr = (const struct bwi_fwhdr *)fw->data; | hdr = (const struct bwi_fwhdr *)fw->data; | ||||
if (fw_type != BWI_FW_T_IV) { | if (fw_type != BWI_FW_T_IV) { | ||||
/* | /* | ||||
* Don't verify IV's size, it has different meaning | * Don't verify IV's size, it has different meaning | ||||
*/ | */ | ||||
if (be32toh(hdr->fw_size) != fw->datasize - sizeof(*hdr)) { | if (be32toh(hdr->fw_size) != fw->datasize - sizeof(*hdr)) { | ||||
if_printf(ifp, "invalid firmware (%s): size mismatch, " | device_printf(sc->sc_dev, | ||||
"invalid firmware (%s): size mismatch, " | |||||
"fw %u, real %zu\n", fw->name, | "fw %u, real %zu\n", fw->name, | ||||
be32toh(hdr->fw_size), | be32toh(hdr->fw_size), fw->datasize - sizeof(*hdr)); | ||||
fw->datasize - sizeof(*hdr)); | |||||
return 0; | return 0; | ||||
} | } | ||||
} | } | ||||
if (hdr->fw_type != fw_type) { | if (hdr->fw_type != fw_type) { | ||||
if_printf(ifp, "invalid firmware (%s): type mismatch, " | device_printf(sc->sc_dev, | ||||
"invalid firmware (%s): type mismatch, " | |||||
"fw \'%c\', target \'%c\'\n", fw->name, | "fw \'%c\', target \'%c\'\n", fw->name, | ||||
hdr->fw_type, fw_type); | hdr->fw_type, fw_type); | ||||
return 0; | return 0; | ||||
} | } | ||||
if (hdr->fw_gen != BWI_FW_GEN_1) { | if (hdr->fw_gen != BWI_FW_GEN_1) { | ||||
if_printf(ifp, "invalid firmware (%s): wrong generation, " | device_printf(sc->sc_dev, | ||||
"fw %d, target %d\n", fw->name, | "invalid firmware (%s): wrong generation, " | ||||
hdr->fw_gen, BWI_FW_GEN_1); | "fw %d, target %d\n", fw->name, hdr->fw_gen, BWI_FW_GEN_1); | ||||
return 0; | return 0; | ||||
} | } | ||||
return 1; | return 1; | ||||
} | } | ||||
/* | /* | ||||
* XXX Error cleanup | * XXX Error cleanup | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | if (mac->mac_stub != NULL) { | ||||
mac->mac_stub = NULL; | mac->mac_stub = NULL; | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
bwi_mac_fw_load(struct bwi_mac *mac) | bwi_mac_fw_load(struct bwi_mac *mac) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
const uint32_t *fw; | const uint32_t *fw; | ||||
uint16_t fw_rev; | uint16_t fw_rev; | ||||
int fw_len, i; | int fw_len, i; | ||||
/* | /* | ||||
* Load ucode image | * Load ucode image | ||||
*/ | */ | ||||
fw = (const uint32_t *) | fw = (const uint32_t *) | ||||
Show All 38 Lines | for (i = 0; i < NRETRY; ++i) { | ||||
uint32_t intr_status; | uint32_t intr_status; | ||||
intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); | intr_status = CSR_READ_4(sc, BWI_MAC_INTR_STATUS); | ||||
if (intr_status == BWI_INTR_READY) | if (intr_status == BWI_INTR_READY) | ||||
break; | break; | ||||
DELAY(10); | DELAY(10); | ||||
} | } | ||||
if (i == NRETRY) { | if (i == NRETRY) { | ||||
if_printf(ifp, "firmware (ucode&pcm) loading timed out\n"); | device_printf(sc->sc_dev, | ||||
"firmware (ucode&pcm) loading timed out\n"); | |||||
return ETIMEDOUT; | return ETIMEDOUT; | ||||
} | } | ||||
#undef NRETRY | #undef NRETRY | ||||
CSR_READ_4(sc, BWI_MAC_INTR_STATUS); /* dummy read */ | CSR_READ_4(sc, BWI_MAC_INTR_STATUS); /* dummy read */ | ||||
fw_rev = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWREV); | fw_rev = MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWREV); | ||||
if (fw_rev > BWI_FW_VERSION3_REVMAX) { | if (fw_rev > BWI_FW_VERSION3_REVMAX) { | ||||
if_printf(ifp, "firmware version 4 is not supported yet\n"); | device_printf(sc->sc_dev, | ||||
"firmware version 4 is not supported yet\n"); | |||||
return ENODEV; | return ENODEV; | ||||
} | } | ||||
if_printf(ifp, "firmware rev 0x%04x, patch level 0x%04x\n", fw_rev, | device_printf(sc->sc_dev, | ||||
"firmware rev 0x%04x, patch level 0x%04x\n", fw_rev, | |||||
MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV)); | MOBJ_READ_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_FWPATCHLV)); | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
bwi_mac_gpio_init(struct bwi_mac *mac) | bwi_mac_gpio_init(struct bwi_mac *mac) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct bwi_regwin *old, *gpio_rw; | struct bwi_regwin *old, *gpio_rw; | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | bwi_mac_gpio_fini(struct bwi_mac *mac) | ||||
return bwi_regwin_switch(sc, old, NULL); | return bwi_regwin_switch(sc, old, NULL); | ||||
} | } | ||||
static int | static int | ||||
bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) | bwi_mac_fw_load_iv(struct bwi_mac *mac, const struct firmware *fw) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | |||||
const struct bwi_fwhdr *hdr; | const struct bwi_fwhdr *hdr; | ||||
const struct bwi_fw_iv *iv; | const struct bwi_fw_iv *iv; | ||||
int n, i, iv_img_size; | int n, i, iv_img_size; | ||||
/* Get the number of IVs in the IV image */ | /* Get the number of IVs in the IV image */ | ||||
hdr = (const struct bwi_fwhdr *)fw->data; | hdr = (const struct bwi_fwhdr *)fw->data; | ||||
n = be32toh(hdr->fw_iv_cnt); | n = be32toh(hdr->fw_iv_cnt); | ||||
DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_FIRMWARE, | DPRINTF(sc, BWI_DBG_MAC | BWI_DBG_INIT | BWI_DBG_FIRMWARE, | ||||
"IV count %d\n", n); | "IV count %d\n", n); | ||||
/* Calculate the IV image size, for later sanity check */ | /* Calculate the IV image size, for later sanity check */ | ||||
iv_img_size = fw->datasize - sizeof(*hdr); | iv_img_size = fw->datasize - sizeof(*hdr); | ||||
/* Locate the first IV */ | /* Locate the first IV */ | ||||
iv = (const struct bwi_fw_iv *) | iv = (const struct bwi_fw_iv *) | ||||
((const uint8_t *)fw->data + sizeof(*hdr)); | ((const uint8_t *)fw->data + sizeof(*hdr)); | ||||
for (i = 0; i < n; ++i) { | for (i = 0; i < n; ++i) { | ||||
uint16_t iv_ofs, ofs; | uint16_t iv_ofs, ofs; | ||||
int sz = 0; | int sz = 0; | ||||
if (iv_img_size < sizeof(iv->iv_ofs)) { | if (iv_img_size < sizeof(iv->iv_ofs)) { | ||||
if_printf(ifp, "invalid IV image, ofs\n"); | device_printf(sc->sc_dev, "invalid IV image, ofs\n"); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
iv_img_size -= sizeof(iv->iv_ofs); | iv_img_size -= sizeof(iv->iv_ofs); | ||||
sz += sizeof(iv->iv_ofs); | sz += sizeof(iv->iv_ofs); | ||||
iv_ofs = be16toh(iv->iv_ofs); | iv_ofs = be16toh(iv->iv_ofs); | ||||
ofs = __SHIFTOUT(iv_ofs, BWI_FW_IV_OFS_MASK); | ofs = __SHIFTOUT(iv_ofs, BWI_FW_IV_OFS_MASK); | ||||
if (ofs >= 0x1000) { | if (ofs >= 0x1000) { | ||||
if_printf(ifp, "invalid ofs (0x%04x) " | device_printf(sc->sc_dev, "invalid ofs (0x%04x) " | ||||
"for %dth iv\n", ofs, i); | "for %dth iv\n", ofs, i); | ||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
if (iv_ofs & BWI_FW_IV_IS_32BIT) { | if (iv_ofs & BWI_FW_IV_IS_32BIT) { | ||||
uint32_t val32; | uint32_t val32; | ||||
if (iv_img_size < sizeof(iv->iv_val.val32)) { | if (iv_img_size < sizeof(iv->iv_val.val32)) { | ||||
if_printf(ifp, "invalid IV image, val32\n"); | device_printf(sc->sc_dev, | ||||
"invalid IV image, val32\n"); | |||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
iv_img_size -= sizeof(iv->iv_val.val32); | iv_img_size -= sizeof(iv->iv_val.val32); | ||||
sz += sizeof(iv->iv_val.val32); | sz += sizeof(iv->iv_val.val32); | ||||
val32 = be32toh(iv->iv_val.val32); | val32 = be32toh(iv->iv_val.val32); | ||||
CSR_WRITE_4(sc, ofs, val32); | CSR_WRITE_4(sc, ofs, val32); | ||||
} else { | } else { | ||||
uint16_t val16; | uint16_t val16; | ||||
if (iv_img_size < sizeof(iv->iv_val.val16)) { | if (iv_img_size < sizeof(iv->iv_val.val16)) { | ||||
if_printf(ifp, "invalid IV image, val16\n"); | device_printf(sc->sc_dev, | ||||
"invalid IV image, val16\n"); | |||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
iv_img_size -= sizeof(iv->iv_val.val16); | iv_img_size -= sizeof(iv->iv_val.val16); | ||||
sz += sizeof(iv->iv_val.val16); | sz += sizeof(iv->iv_val.val16); | ||||
val16 = be16toh(iv->iv_val.val16); | val16 = be16toh(iv->iv_val.val16); | ||||
CSR_WRITE_2(sc, ofs, val16); | CSR_WRITE_2(sc, ofs, val16); | ||||
} | } | ||||
iv = (const struct bwi_fw_iv *)((const uint8_t *)iv + sz); | iv = (const struct bwi_fw_iv *)((const uint8_t *)iv + sz); | ||||
} | } | ||||
if (iv_img_size != 0) { | if (iv_img_size != 0) { | ||||
if_printf(ifp, "invalid IV image, size left %d\n", iv_img_size); | device_printf(sc->sc_dev, "invalid IV image, size left %d\n", | ||||
iv_img_size); | |||||
return EINVAL; | return EINVAL; | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
static int | static int | ||||
bwi_mac_fw_init(struct bwi_mac *mac) | bwi_mac_fw_init(struct bwi_mac *mac) | ||||
{ | { | ||||
struct ifnet *ifp = mac->mac_sc->sc_ifp; | device_t dev = mac->mac_sc->sc_dev; | ||||
int error; | int error; | ||||
error = bwi_mac_fw_load_iv(mac, mac->mac_iv); | error = bwi_mac_fw_load_iv(mac, mac->mac_iv); | ||||
if (error) { | if (error) { | ||||
if_printf(ifp, "load IV failed\n"); | device_printf(dev, "load IV failed\n"); | ||||
return error; | return error; | ||||
} | } | ||||
if (mac->mac_iv_ext != NULL) { | if (mac->mac_iv_ext != NULL) { | ||||
error = bwi_mac_fw_load_iv(mac, mac->mac_iv_ext); | error = bwi_mac_fw_load_iv(mac, mac->mac_iv_ext); | ||||
if (error) | if (error) | ||||
if_printf(ifp, "load ExtIV failed\n"); | device_printf(dev, "load ExtIV failed\n"); | ||||
} | } | ||||
return error; | return error; | ||||
} | } | ||||
static void | static void | ||||
bwi_mac_opmode_init(struct bwi_mac *mac) | bwi_mac_opmode_init(struct bwi_mac *mac) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
uint32_t mac_status; | uint32_t mac_status; | ||||
uint16_t pre_tbtt; | uint16_t pre_tbtt; | ||||
CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA); | CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA); | ||||
CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA); | CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_INFRA); | ||||
/* Set probe resp timeout to infinite */ | /* Set probe resp timeout to infinite */ | ||||
MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_PROBE_RESP_TO, 0); | MOBJ_WRITE_2(mac, BWI_COMM_MOBJ, BWI_COMM_MOBJ_PROBE_RESP_TO, 0); | ||||
Show All 32 Lines | #else | ||||
mac_status |= BWI_MAC_STATUS_PASS_CTL; | mac_status |= BWI_MAC_STATUS_PASS_CTL; | ||||
#endif | #endif | ||||
/* Promisc? */ | /* Promisc? */ | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
if (ic->ic_ifp->if_flags & IFF_PROMISC) | if (ic->ic_promisc > 0) | ||||
mac_status |= BWI_MAC_STATUS_PROMISC; | mac_status |= BWI_MAC_STATUS_PROMISC; | ||||
CSR_WRITE_4(sc, BWI_MAC_STATUS, mac_status); | CSR_WRITE_4(sc, BWI_MAC_STATUS, mac_status); | ||||
if (ic->ic_opmode != IEEE80211_M_IBSS && | if (ic->ic_opmode != IEEE80211_M_IBSS && | ||||
ic->ic_opmode != IEEE80211_M_HOSTAP) { | ic->ic_opmode != IEEE80211_M_HOSTAP) { | ||||
if (sc->sc_bbp_id == BWI_BBPID_BCM4306 && sc->sc_bbp_rev == 3) | if (sc->sc_bbp_id == BWI_BBPID_BCM4306 && sc->sc_bbp_rev == 3) | ||||
pre_tbtt = 100; | pre_tbtt = 100; | ||||
Show All 34 Lines | bwi_mac_hostflags_init(struct bwi_mac *mac) | ||||
HFLAGS_WRITE(mac, host_flags); | HFLAGS_WRITE(mac, host_flags); | ||||
} | } | ||||
static void | static void | ||||
bwi_mac_bss_param_init(struct bwi_mac *mac) | bwi_mac_bss_param_init(struct bwi_mac *mac) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct bwi_phy *phy = &mac->mac_phy; | struct bwi_phy *phy = &mac->mac_phy; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
const struct ieee80211_rate_table *rt; | const struct ieee80211_rate_table *rt; | ||||
struct bwi_retry_lim lim; | struct bwi_retry_lim lim; | ||||
uint16_t cw_min; | uint16_t cw_min; | ||||
/* | /* | ||||
* Set short/long retry limits | * Set short/long retry limits | ||||
*/ | */ | ||||
bzero(&lim, sizeof(lim)); | bzero(&lim, sizeof(lim)); | ||||
▲ Show 20 Lines • Show All 566 Lines • ▼ Show 20 Lines | calib: | ||||
bwi_mac_adjust_tpctl(mac, rf_atten_adj, bbp_atten_adj); | bwi_mac_adjust_tpctl(mac, rf_atten_adj, bbp_atten_adj); | ||||
/* TODO: LO */ | /* TODO: LO */ | ||||
} | } | ||||
static void | static void | ||||
bwi_mac_lock(struct bwi_mac *mac) | bwi_mac_lock(struct bwi_mac *mac) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
KASSERT((mac->mac_flags & BWI_MAC_F_LOCKED) == 0, | KASSERT((mac->mac_flags & BWI_MAC_F_LOCKED) == 0, | ||||
("mac_flags 0x%x", mac->mac_flags)); | ("mac_flags 0x%x", mac->mac_flags)); | ||||
if (mac->mac_rev < 3) | if (mac->mac_rev < 3) | ||||
bwi_mac_stop(mac); | bwi_mac_stop(mac); | ||||
else if (ic->ic_opmode != IEEE80211_M_HOSTAP) | else if (ic->ic_opmode != IEEE80211_M_HOSTAP) | ||||
bwi_mac_config_ps(mac); | bwi_mac_config_ps(mac); | ||||
CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK); | CSR_SETBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK); | ||||
/* Flush pending bus write */ | /* Flush pending bus write */ | ||||
CSR_READ_4(sc, BWI_MAC_STATUS); | CSR_READ_4(sc, BWI_MAC_STATUS); | ||||
DELAY(10); | DELAY(10); | ||||
mac->mac_flags |= BWI_MAC_F_LOCKED; | mac->mac_flags |= BWI_MAC_F_LOCKED; | ||||
} | } | ||||
static void | static void | ||||
bwi_mac_unlock(struct bwi_mac *mac) | bwi_mac_unlock(struct bwi_mac *mac) | ||||
{ | { | ||||
struct bwi_softc *sc = mac->mac_sc; | struct bwi_softc *sc = mac->mac_sc; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ieee80211com *ic = &sc->sc_ic; | ||||
struct ieee80211com *ic = ifp->if_l2com; | |||||
KASSERT(mac->mac_flags & BWI_MAC_F_LOCKED, | KASSERT(mac->mac_flags & BWI_MAC_F_LOCKED, | ||||
("mac_flags 0x%x", mac->mac_flags)); | ("mac_flags 0x%x", mac->mac_flags)); | ||||
CSR_READ_2(sc, BWI_PHYINFO); /* dummy read */ | CSR_READ_2(sc, BWI_PHYINFO); /* dummy read */ | ||||
CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK); | CSR_CLRBITS_4(sc, BWI_MAC_STATUS, BWI_MAC_STATUS_RFLOCK); | ||||
Show All 21 Lines |