Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/bwn/if_bwn.c
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
#include <net/if_arp.h> | #include <net/if_arp.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/if_llc.h> | #include <net/if_llc.h> | ||||
#include <net/if_media.h> | #include <net/if_media.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#include <dev/pci/pcivar.h> | #include <dev/pci/pcivar.h> | ||||
#include <dev/pci/pcireg.h> | #include <dev/pci/pcireg.h> | ||||
#include <dev/siba/siba_ids.h> | |||||
#include <dev/siba/sibareg.h> | |||||
#include <dev/siba/sibavar.h> | |||||
#include <net80211/ieee80211_var.h> | #include <net80211/ieee80211_var.h> | ||||
#include <net80211/ieee80211_radiotap.h> | #include <net80211/ieee80211_radiotap.h> | ||||
#include <net80211/ieee80211_regdomain.h> | #include <net80211/ieee80211_regdomain.h> | ||||
#include <net80211/ieee80211_phy.h> | #include <net80211/ieee80211_phy.h> | ||||
#include <net80211/ieee80211_ratectl.h> | #include <net80211/ieee80211_ratectl.h> | ||||
#include <dev/bwn/if_bwn_siba.h> | |||||
#include <dev/bwn/if_bwnreg.h> | #include <dev/bwn/if_bwnreg.h> | ||||
#include <dev/bwn/if_bwnvar.h> | #include <dev/bwn/if_bwnvar.h> | ||||
#include <dev/bwn/if_bwn_debug.h> | #include <dev/bwn/if_bwn_debug.h> | ||||
#include <dev/bwn/if_bwn_misc.h> | #include <dev/bwn/if_bwn_misc.h> | ||||
#include <dev/bwn/if_bwn_util.h> | #include <dev/bwn/if_bwn_util.h> | ||||
#include <dev/bwn/if_bwn_phy_common.h> | #include <dev/bwn/if_bwn_phy_common.h> | ||||
#include <dev/bwn/if_bwn_phy_g.h> | #include <dev/bwn/if_bwn_phy_g.h> | ||||
▲ Show 20 Lines • Show All 405 Lines • ▼ Show 20 Lines | static const struct siba_devid bwn_devs[] = { | ||||
SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"), | SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"), | ||||
SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"), | SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"), | ||||
SIBA_DEV(BROADCOM, 80211, 12, "Revision 12"), | SIBA_DEV(BROADCOM, 80211, 12, "Revision 12"), | ||||
SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"), | SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"), | ||||
SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"), | SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"), | ||||
SIBA_DEV(BROADCOM, 80211, 16, "Revision 16") | SIBA_DEV(BROADCOM, 80211, 16, "Revision 16") | ||||
}; | }; | ||||
static const struct bwn_bus_ops * | |||||
bwn_get_bus_ops(device_t dev) | |||||
{ | |||||
#if BWN_USE_SIBA | |||||
return (NULL); | |||||
#else | |||||
devclass_t bus_cls; | |||||
bus_cls = device_get_devclass(device_get_parent(dev)); | |||||
if (bus_cls == devclass_find("bhnd")) | |||||
return (&bwn_bhnd_bus_ops); | |||||
else | |||||
return (&bwn_siba_bus_ops); | |||||
#endif | |||||
} | |||||
static int | static int | ||||
bwn_probe(device_t dev) | bwn_probe(device_t dev) | ||||
{ | { | ||||
struct bwn_softc *sc; | |||||
int i; | int i; | ||||
sc = device_get_softc(dev); | |||||
sc->sc_bus_ops = bwn_get_bus_ops(dev); | |||||
for (i = 0; i < nitems(bwn_devs); i++) { | for (i = 0; i < nitems(bwn_devs); i++) { | ||||
if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor && | if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor && | ||||
siba_get_device(dev) == bwn_devs[i].sd_device && | siba_get_device(dev) == bwn_devs[i].sd_device && | ||||
siba_get_revid(dev) == bwn_devs[i].sd_rev) | siba_get_revid(dev) == bwn_devs[i].sd_rev) | ||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
return (ENXIO); | return (ENXIO); | ||||
} | } | ||||
static int | int | ||||
bwn_attach(device_t dev) | bwn_attach(device_t dev) | ||||
{ | { | ||||
struct bwn_mac *mac; | struct bwn_mac *mac; | ||||
struct bwn_softc *sc = device_get_softc(dev); | struct bwn_softc *sc = device_get_softc(dev); | ||||
int error, i, msic, reg; | int error, i, msic, reg; | ||||
sc->sc_dev = dev; | sc->sc_dev = dev; | ||||
#ifdef BWN_DEBUG | #ifdef BWN_DEBUG | ||||
sc->sc_debug = bwn_debug; | sc->sc_debug = bwn_debug; | ||||
#endif | #endif | ||||
sc->sc_bus_ops = bwn_get_bus_ops(dev); | |||||
if ((error = BWN_BUS_OPS_ATTACH(dev))) { | |||||
device_printf(sc->sc_dev, | |||||
"bus-specific initialization failed (%d)\n", error); | |||||
return (error); | |||||
} | |||||
if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) { | if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) { | ||||
bwn_attach_pre(sc); | bwn_attach_pre(sc); | ||||
bwn_sprom_bugfixes(dev); | bwn_sprom_bugfixes(dev); | ||||
sc->sc_flags |= BWN_FLAG_ATTACHED; | sc->sc_flags |= BWN_FLAG_ATTACHED; | ||||
} | } | ||||
if (!TAILQ_EMPTY(&sc->sc_maclist)) { | if (!TAILQ_EMPTY(&sc->sc_maclist)) { | ||||
if (siba_get_pci_device(dev) != 0x4313 && | if (siba_get_pci_device(dev) != 0x4313 && | ||||
▲ Show 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | #endif | ||||
if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0) | if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0) | ||||
bwn_attach_post(sc); | bwn_attach_post(sc); | ||||
return (0); | return (0); | ||||
fail1: | fail1: | ||||
if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) | if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
fail0: | fail0: | ||||
BWN_BUS_OPS_DETACH(dev); | |||||
free(mac, M_DEVBUF); | free(mac, M_DEVBUF); | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
bwn_is_valid_ether_addr(uint8_t *addr) | bwn_is_valid_ether_addr(uint8_t *addr) | ||||
{ | { | ||||
char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; | char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
bwn_phy_detach(struct bwn_mac *mac) | bwn_phy_detach(struct bwn_mac *mac) | ||||
{ | { | ||||
if (mac->mac_phy.detach != NULL) | if (mac->mac_phy.detach != NULL) | ||||
mac->mac_phy.detach(mac); | mac->mac_phy.detach(mac); | ||||
} | } | ||||
static int | int | ||||
bwn_detach(device_t dev) | bwn_detach(device_t dev) | ||||
{ | { | ||||
struct bwn_softc *sc = device_get_softc(dev); | struct bwn_softc *sc = device_get_softc(dev); | ||||
struct bwn_mac *mac = sc->sc_curmac; | struct bwn_mac *mac = sc->sc_curmac; | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic = &sc->sc_ic; | ||||
int i; | int i; | ||||
sc->sc_flags |= BWN_FLAG_INVALID; | sc->sc_flags |= BWN_FLAG_INVALID; | ||||
Show All 23 Lines | for (i = 0; i < BWN_MSI_MESSAGES; i++) { | ||||
} | } | ||||
} | } | ||||
bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq); | bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq); | ||||
if (mac->mac_msi != 0) | if (mac->mac_msi != 0) | ||||
pci_release_msi(dev); | pci_release_msi(dev); | ||||
mbufq_drain(&sc->sc_snd); | mbufq_drain(&sc->sc_snd); | ||||
bwn_release_firmware(mac); | bwn_release_firmware(mac); | ||||
BWN_LOCK_DESTROY(sc); | BWN_LOCK_DESTROY(sc); | ||||
BWN_BUS_OPS_DETACH(dev); | |||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
bwn_attach_pre(struct bwn_softc *sc) | bwn_attach_pre(struct bwn_softc *sc) | ||||
{ | { | ||||
BWN_LOCK_INIT(sc); | BWN_LOCK_INIT(sc); | ||||
▲ Show 20 Lines • Show All 381 Lines • ▼ Show 20 Lines | bwn_watchdog(void *arg) | ||||
callout_schedule(&sc->sc_watchdog_ch, hz); | callout_schedule(&sc->sc_watchdog_ch, hz); | ||||
} | } | ||||
static int | static int | ||||
bwn_attach_core(struct bwn_mac *mac) | bwn_attach_core(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
int error, have_bg = 0, have_a = 0; | int error, have_bg = 0, have_a = 0; | ||||
uint32_t high; | |||||
KASSERT(siba_get_revid(sc->sc_dev) >= 5, | KASSERT(siba_get_revid(sc->sc_dev) >= 5, | ||||
("unsupported revision %d", siba_get_revid(sc->sc_dev))); | ("unsupported revision %d", siba_get_revid(sc->sc_dev))); | ||||
if (bwn_is_bus_siba(mac)) { | |||||
uint32_t high; | |||||
siba_powerup(sc->sc_dev, 0); | siba_powerup(sc->sc_dev, 0); | ||||
high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH); | high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH); | ||||
have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0; | have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0; | ||||
have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0; | have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0; | ||||
if (high & BWN_TGSHIGH_DUALPHY) { | if (high & BWN_TGSHIGH_DUALPHY) { | ||||
have_bg = 1; | have_bg = 1; | ||||
have_a = 1; | have_a = 1; | ||||
} | } | ||||
#if 0 | #if 0 | ||||
device_printf(sc->sc_dev, "%s: high=0x%08x, have_a=%d, have_bg=%d," | device_printf(sc->sc_dev, "%s: high=0x%08x, have_a=%d, have_bg=%d," | ||||
" deviceid=0x%04x, siba_deviceid=0x%04x\n", | " deviceid=0x%04x, siba_deviceid=0x%04x\n", | ||||
__func__, | __func__, | ||||
high, | high, | ||||
have_a, | have_a, | ||||
have_bg, | have_bg, | ||||
siba_get_pci_device(sc->sc_dev), | siba_get_pci_device(sc->sc_dev), | ||||
siba_get_chipid(sc->sc_dev)); | siba_get_chipid(sc->sc_dev)); | ||||
#endif | #endif | ||||
} else { | |||||
device_printf(sc->sc_dev, "%s: not siba; bailing\n", __func__); | |||||
error = ENXIO; | |||||
goto fail; | |||||
} | |||||
/* | /* | ||||
* Guess at whether it has A-PHY or G-PHY. | * Guess at whether it has A-PHY or G-PHY. | ||||
* This is just used for resetting the core to probe things; | * This is just used for resetting the core to probe things; | ||||
* we will re-guess once it's all up and working. | * we will re-guess once it's all up and working. | ||||
*/ | */ | ||||
bwn_reset_core(mac, have_bg); | bwn_reset_core(mac, have_bg); | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
fail: | fail: | ||||
siba_powerdown(sc->sc_dev); | siba_powerdown(sc->sc_dev); | ||||
bwn_release_firmware(mac); | bwn_release_firmware(mac); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Reset - SIBA. | * Reset - SIBA. | ||||
* | |||||
* XXX TODO: implement BCMA version! | |||||
*/ | */ | ||||
void | void | ||||
bwn_reset_core(struct bwn_mac *mac, int g_mode) | bwn_reset_core(struct bwn_mac *mac, int g_mode) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint32_t low, ctl; | uint32_t low, ctl; | ||||
uint32_t flags = 0; | uint32_t flags = 0; | ||||
▲ Show 20 Lines • Show All 910 Lines • ▼ Show 20 Lines | bwn_chip_init(struct bwn_mac *mac) | ||||
BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00); | BWN_WRITE_4(mac, BWN_DMA2_INTR_MASK, 0x0000dc00); | ||||
BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00); | BWN_WRITE_4(mac, BWN_DMA3_INTR_MASK, 0x0001dc00); | ||||
BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00); | BWN_WRITE_4(mac, BWN_DMA4_INTR_MASK, 0x0000dc00); | ||||
BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00); | BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00); | ||||
bwn_mac_phy_clock_set(mac, true); | bwn_mac_phy_clock_set(mac, true); | ||||
/* SIBA powerup */ | /* SIBA powerup */ | ||||
/* XXX TODO: BCMA powerup */ | |||||
BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev)); | BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev)); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* read hostflags */ | /* read hostflags */ | ||||
uint64_t | uint64_t | ||||
bwn_hf_read(struct bwn_mac *mac) | bwn_hf_read(struct bwn_mac *mac) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 2,433 Lines • ▼ Show 20 Lines | bwn_rf_turnoff(struct bwn_mac *mac) | ||||
bwn_mac_suspend(mac); | bwn_mac_suspend(mac); | ||||
mac->mac_phy.rf_onoff(mac, 0); | mac->mac_phy.rf_onoff(mac, 0); | ||||
mac->mac_phy.rf_on = 0; | mac->mac_phy.rf_on = 0; | ||||
bwn_mac_enable(mac); | bwn_mac_enable(mac); | ||||
} | } | ||||
/* | /* | ||||
* SSB PHY reset. | * PHY reset. | ||||
*/ | */ | ||||
static void | static void | ||||
bwn_phy_reset_siba(struct bwn_mac *mac) | bwn_phy_reset(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
siba_write_4(sc->sc_dev, SIBA_TGSLOW, | siba_write_4(sc->sc_dev, SIBA_TGSLOW, | ||||
((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) | | ((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) | | ||||
BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC); | BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC); | ||||
DELAY(1000); | DELAY(1000); | ||||
siba_write_4(sc->sc_dev, SIBA_TGSLOW, | siba_write_4(sc->sc_dev, SIBA_TGSLOW, | ||||
(siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC)); | (siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC)); | ||||
DELAY(1000); | DELAY(1000); | ||||
} | } | ||||
static void | |||||
bwn_phy_reset(struct bwn_mac *mac) | |||||
{ | |||||
if (bwn_is_bus_siba(mac)) { | |||||
bwn_phy_reset_siba(mac); | |||||
} else { | |||||
BWN_ERRPRINTF(mac->mac_sc, "%s: unknown bus!\n", __func__); | |||||
} | |||||
} | |||||
static int | static int | ||||
bwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | bwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) | ||||
{ | { | ||||
struct bwn_vap *bvp = BWN_VAP(vap); | struct bwn_vap *bvp = BWN_VAP(vap); | ||||
struct ieee80211com *ic= vap->iv_ic; | struct ieee80211com *ic= vap->iv_ic; | ||||
enum ieee80211_state ostate = vap->iv_state; | enum ieee80211_state ostate = vap->iv_state; | ||||
struct bwn_softc *sc = ic->ic_softc; | struct bwn_softc *sc = ic->ic_softc; | ||||
struct bwn_mac *mac = sc->sc_curmac; | struct bwn_mac *mac = sc->sc_curmac; | ||||
▲ Show 20 Lines • Show All 2,711 Lines • ▼ Show 20 Lines | static device_method_t bwn_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, bwn_probe), | DEVMETHOD(device_probe, bwn_probe), | ||||
DEVMETHOD(device_attach, bwn_attach), | DEVMETHOD(device_attach, bwn_attach), | ||||
DEVMETHOD(device_detach, bwn_detach), | DEVMETHOD(device_detach, bwn_detach), | ||||
DEVMETHOD(device_suspend, bwn_suspend), | DEVMETHOD(device_suspend, bwn_suspend), | ||||
DEVMETHOD(device_resume, bwn_resume), | DEVMETHOD(device_resume, bwn_resume), | ||||
DEVMETHOD_END | DEVMETHOD_END | ||||
}; | }; | ||||
static driver_t bwn_driver = { | driver_t bwn_driver = { | ||||
"bwn", | "bwn", | ||||
bwn_methods, | bwn_methods, | ||||
sizeof(struct bwn_softc) | sizeof(struct bwn_softc) | ||||
}; | }; | ||||
static devclass_t bwn_devclass; | static devclass_t bwn_devclass; | ||||
DRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0); | DRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0); | ||||
MODULE_DEPEND(bwn, siba_bwn, 1, 1, 1); | MODULE_DEPEND(bwn, siba_bwn, 1, 1, 1); | ||||
MODULE_DEPEND(bwn, gpiobus, 1, 1, 1); | |||||
MODULE_DEPEND(bwn, wlan, 1, 1, 1); /* 802.11 media layer */ | MODULE_DEPEND(bwn, wlan, 1, 1, 1); /* 802.11 media layer */ | ||||
MODULE_DEPEND(bwn, firmware, 1, 1, 1); /* firmware support */ | MODULE_DEPEND(bwn, firmware, 1, 1, 1); /* firmware support */ | ||||
MODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1); | MODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1); | ||||
MODULE_VERSION(bwn, 1); | MODULE_VERSION(bwn, 1); |