Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/bwn/if_bwn.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | * | ||||
* Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org> | * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org> | ||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org> | |||||
* Copyright (c) 2017 The FreeBSD Foundation | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Portions of this software were developed by Landon Fuller | |||||
* under sponsorship from the FreeBSD Foundation. | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer, | * notice, this list of conditions and the following disclaimer, | ||||
* without modification. | * without modification. | ||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||||
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any | * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any | ||||
Show All 22 Lines | |||||
*/ | */ | ||||
#include "opt_bwn.h" | #include "opt_bwn.h" | ||||
#include "opt_wlan.h" | #include "opt_wlan.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/gpio.h> | |||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/firmware.h> | #include <sys/firmware.h> | ||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | #include <machine/resource.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/sockio.h> | #include <sys/sockio.h> | ||||
#include <net/ethernet.h> | #include <net/ethernet.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#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/pcireg.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/bhnd/bhnd.h> | ||||
#include <dev/bhnd/bhnd_ids.h> | |||||
#include <dev/bhnd/cores/chipc/chipc.h> | |||||
#include <dev/bhnd/cores/pmu/bhnd_pmu.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> | ||||
#include <dev/bwn/if_bwn_phy_lp.h> | #include <dev/bwn/if_bwn_phy_lp.h> | ||||
#include <dev/bwn/if_bwn_phy_n.h> | #include <dev/bwn/if_bwn_phy_n.h> | ||||
#include "bhnd_nvram_map.h" | |||||
#include "gpio_if.h" | |||||
static SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0, | static SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0, | ||||
"Broadcom driver parameters"); | "Broadcom driver parameters"); | ||||
/* | /* | ||||
* Tunable & sysctl variables. | * Tunable & sysctl variables. | ||||
*/ | */ | ||||
#ifdef BWN_DEBUG | #ifdef BWN_DEBUG | ||||
static int bwn_debug = 0; | static int bwn_debug = 0; | ||||
SYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0, | SYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RWTUN, &bwn_debug, 0, | ||||
"Broadcom debugging printfs"); | "Broadcom debugging printfs"); | ||||
#endif | #endif | ||||
static int bwn_bfp = 0; /* use "Bad Frames Preemption" */ | static int bwn_bfp = 0; /* use "Bad Frames Preemption" */ | ||||
SYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0, | SYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0, | ||||
"uses Bad Frames Preemption"); | "uses Bad Frames Preemption"); | ||||
static int bwn_bluetooth = 1; | static int bwn_bluetooth = 1; | ||||
SYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0, | SYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0, | ||||
"turns on Bluetooth Coexistence"); | "turns on Bluetooth Coexistence"); | ||||
static int bwn_hwpctl = 0; | static int bwn_hwpctl = 0; | ||||
SYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0, | SYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0, | ||||
"uses H/W power control"); | "uses H/W power control"); | ||||
static int bwn_msi_disable = 0; /* MSI disabled */ | |||||
TUNABLE_INT("hw.bwn.msi_disable", &bwn_msi_disable); | |||||
static int bwn_usedma = 1; | static int bwn_usedma = 1; | ||||
SYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0, | SYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0, | ||||
"uses DMA"); | "uses DMA"); | ||||
TUNABLE_INT("hw.bwn.usedma", &bwn_usedma); | TUNABLE_INT("hw.bwn.usedma", &bwn_usedma); | ||||
static int bwn_wme = 1; | static int bwn_wme = 1; | ||||
SYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0, | SYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0, | ||||
"uses WME support"); | "uses WME support"); | ||||
static void bwn_attach_pre(struct bwn_softc *); | static void bwn_attach_pre(struct bwn_softc *); | ||||
static int bwn_attach_post(struct bwn_softc *); | static int bwn_attach_post(struct bwn_softc *); | ||||
static int bwn_retain_bus_providers(struct bwn_softc *sc); | |||||
static void bwn_release_bus_providers(struct bwn_softc *sc); | |||||
static void bwn_sprom_bugfixes(device_t); | static void bwn_sprom_bugfixes(device_t); | ||||
static int bwn_init(struct bwn_softc *); | static int bwn_init(struct bwn_softc *); | ||||
static void bwn_parent(struct ieee80211com *); | static void bwn_parent(struct ieee80211com *); | ||||
static void bwn_start(struct bwn_softc *); | static void bwn_start(struct bwn_softc *); | ||||
static int bwn_transmit(struct ieee80211com *, struct mbuf *); | static int bwn_transmit(struct ieee80211com *, struct mbuf *); | ||||
static int bwn_attach_core(struct bwn_mac *); | static int bwn_attach_core(struct bwn_mac *); | ||||
static int bwn_phy_getinfo(struct bwn_mac *, int); | static int bwn_phy_getinfo(struct bwn_mac *, int); | ||||
static int bwn_chiptest(struct bwn_mac *); | static int bwn_chiptest(struct bwn_mac *); | ||||
Show All 16 Lines | |||||
static void bwn_scan_end(struct ieee80211com *); | static void bwn_scan_end(struct ieee80211com *); | ||||
static void bwn_set_channel(struct ieee80211com *); | static void bwn_set_channel(struct ieee80211com *); | ||||
static struct ieee80211vap *bwn_vap_create(struct ieee80211com *, | static struct ieee80211vap *bwn_vap_create(struct ieee80211com *, | ||||
const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | const char [IFNAMSIZ], int, enum ieee80211_opmode, int, | ||||
const uint8_t [IEEE80211_ADDR_LEN], | const uint8_t [IEEE80211_ADDR_LEN], | ||||
const uint8_t [IEEE80211_ADDR_LEN]); | const uint8_t [IEEE80211_ADDR_LEN]); | ||||
static void bwn_vap_delete(struct ieee80211vap *); | static void bwn_vap_delete(struct ieee80211vap *); | ||||
static void bwn_stop(struct bwn_softc *); | static void bwn_stop(struct bwn_softc *); | ||||
static int bwn_core_forceclk(struct bwn_mac *, bool); | |||||
static int bwn_core_init(struct bwn_mac *); | static int bwn_core_init(struct bwn_mac *); | ||||
static void bwn_core_start(struct bwn_mac *); | static void bwn_core_start(struct bwn_mac *); | ||||
static void bwn_core_exit(struct bwn_mac *); | static void bwn_core_exit(struct bwn_mac *); | ||||
static void bwn_bt_disable(struct bwn_mac *); | static void bwn_bt_disable(struct bwn_mac *); | ||||
static int bwn_chip_init(struct bwn_mac *); | static int bwn_chip_init(struct bwn_mac *); | ||||
static void bwn_set_txretry(struct bwn_mac *, int, int); | static void bwn_set_txretry(struct bwn_mac *, int, int); | ||||
static void bwn_rate_init(struct bwn_mac *); | static void bwn_rate_init(struct bwn_mac *); | ||||
static void bwn_set_phytxctl(struct bwn_mac *); | static void bwn_set_phytxctl(struct bwn_mac *); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
static uint16_t bwn_pio_write_multi_2(struct bwn_mac *, | static uint16_t bwn_pio_write_multi_2(struct bwn_mac *, | ||||
struct bwn_pio_txqueue *, uint16_t, const void *, int); | struct bwn_pio_txqueue *, uint16_t, const void *, int); | ||||
static uint16_t bwn_pio_write_mbuf_2(struct bwn_mac *, | static uint16_t bwn_pio_write_mbuf_2(struct bwn_mac *, | ||||
struct bwn_pio_txqueue *, uint16_t, struct mbuf *); | struct bwn_pio_txqueue *, uint16_t, struct mbuf *); | ||||
static struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *, | static struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *, | ||||
uint16_t, struct bwn_pio_txpkt **); | uint16_t, struct bwn_pio_txpkt **); | ||||
static void bwn_dma_init(struct bwn_mac *); | static void bwn_dma_init(struct bwn_mac *); | ||||
static void bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t); | static void bwn_dma_rxdirectfifo(struct bwn_mac *, int, uint8_t); | ||||
static int bwn_dma_mask2type(uint64_t); | |||||
static uint64_t bwn_dma_mask(struct bwn_mac *); | |||||
static uint16_t bwn_dma_base(int, int); | static uint16_t bwn_dma_base(int, int); | ||||
static void bwn_dma_ringfree(struct bwn_dma_ring **); | static void bwn_dma_ringfree(struct bwn_dma_ring **); | ||||
static void bwn_dma_32_getdesc(struct bwn_dma_ring *, | static void bwn_dma_32_getdesc(struct bwn_dma_ring *, | ||||
int, struct bwn_dmadesc_generic **, | int, struct bwn_dmadesc_generic **, | ||||
struct bwn_dmadesc_meta **); | struct bwn_dmadesc_meta **); | ||||
static void bwn_dma_32_setdesc(struct bwn_dma_ring *, | static void bwn_dma_32_setdesc(struct bwn_dma_ring *, | ||||
struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int, | struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int, | ||||
int, int); | int, int); | ||||
Show All 19 Lines | |||||
static void bwn_dma_cleanup(struct bwn_dma_ring *); | static void bwn_dma_cleanup(struct bwn_dma_ring *); | ||||
static void bwn_dma_free_descbufs(struct bwn_dma_ring *); | static void bwn_dma_free_descbufs(struct bwn_dma_ring *); | ||||
static int bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int); | static int bwn_dma_tx_reset(struct bwn_mac *, uint16_t, int); | ||||
static void bwn_dma_rx(struct bwn_dma_ring *); | static void bwn_dma_rx(struct bwn_dma_ring *); | ||||
static int bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int); | static int bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int); | ||||
static void bwn_dma_free_descbuf(struct bwn_dma_ring *, | static void bwn_dma_free_descbuf(struct bwn_dma_ring *, | ||||
struct bwn_dmadesc_meta *); | struct bwn_dmadesc_meta *); | ||||
static void bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *); | static void bwn_dma_set_redzone(struct bwn_dma_ring *, struct mbuf *); | ||||
static int bwn_dma_gettype(struct bwn_mac *); | |||||
static void bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int); | static void bwn_dma_ring_addr(void *, bus_dma_segment_t *, int, int); | ||||
static int bwn_dma_freeslot(struct bwn_dma_ring *); | static int bwn_dma_freeslot(struct bwn_dma_ring *); | ||||
static int bwn_dma_nextslot(struct bwn_dma_ring *, int); | static int bwn_dma_nextslot(struct bwn_dma_ring *, int); | ||||
static void bwn_dma_rxeof(struct bwn_dma_ring *, int *); | static void bwn_dma_rxeof(struct bwn_dma_ring *, int *); | ||||
static int bwn_dma_newbuf(struct bwn_dma_ring *, | static int bwn_dma_newbuf(struct bwn_dma_ring *, | ||||
struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *, | struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *, | ||||
int); | int); | ||||
static void bwn_dma_buf_addr(void *, bus_dma_segment_t *, int, | static void bwn_dma_buf_addr(void *, bus_dma_segment_t *, int, | ||||
bus_size_t, int); | bus_size_t, int); | ||||
static uint8_t bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *); | static uint8_t bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *); | ||||
static void bwn_ratectl_tx_complete(const struct ieee80211_node *, | static void bwn_ratectl_tx_complete(const struct ieee80211_node *, | ||||
const struct bwn_txstatus *); | const struct bwn_txstatus *); | ||||
static void bwn_dma_handle_txeof(struct bwn_mac *, | static void bwn_dma_handle_txeof(struct bwn_mac *, | ||||
const struct bwn_txstatus *); | const struct bwn_txstatus *); | ||||
static int bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *, | static int bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *, | ||||
struct mbuf *); | struct mbuf *); | ||||
static int bwn_dma_getslot(struct bwn_dma_ring *); | static int bwn_dma_getslot(struct bwn_dma_ring *); | ||||
static struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *, | static struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *, | ||||
uint8_t); | uint8_t); | ||||
static int bwn_dma_attach(struct bwn_mac *); | static int bwn_dma_attach(struct bwn_mac *); | ||||
static struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *, | static struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *, | ||||
int, int, int); | int, int); | ||||
static struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *, | static struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *, | ||||
const struct bwn_txstatus *, uint16_t, int *); | const struct bwn_txstatus *, uint16_t, int *); | ||||
static void bwn_dma_free(struct bwn_mac *); | static void bwn_dma_free(struct bwn_mac *); | ||||
static int bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype); | static int bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype); | ||||
static int bwn_fw_get(struct bwn_mac *, enum bwn_fwtype, | static int bwn_fw_get(struct bwn_mac *, enum bwn_fwtype, | ||||
const char *, struct bwn_fwfile *); | const char *, struct bwn_fwfile *); | ||||
static void bwn_release_firmware(struct bwn_mac *); | static void bwn_release_firmware(struct bwn_mac *); | ||||
static void bwn_do_release_fw(struct bwn_fwfile *); | static void bwn_do_release_fw(struct bwn_fwfile *); | ||||
Show All 9 Lines | |||||
static void bwn_key_macwrite(struct bwn_mac *, uint8_t, | static void bwn_key_macwrite(struct bwn_mac *, uint8_t, | ||||
const uint8_t *); | const uint8_t *); | ||||
static void bwn_key_write(struct bwn_mac *, uint8_t, uint8_t, | static void bwn_key_write(struct bwn_mac *, uint8_t, uint8_t, | ||||
const uint8_t *); | const uint8_t *); | ||||
static void bwn_phy_exit(struct bwn_mac *); | static void bwn_phy_exit(struct bwn_mac *); | ||||
static void bwn_core_stop(struct bwn_mac *); | static void bwn_core_stop(struct bwn_mac *); | ||||
static int bwn_switch_band(struct bwn_softc *, | static int bwn_switch_band(struct bwn_softc *, | ||||
struct ieee80211_channel *); | struct ieee80211_channel *); | ||||
static void bwn_phy_reset(struct bwn_mac *); | static int bwn_phy_reset(struct bwn_mac *); | ||||
static int bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int); | static int bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int); | ||||
static void bwn_set_pretbtt(struct bwn_mac *); | static void bwn_set_pretbtt(struct bwn_mac *); | ||||
static int bwn_intr(void *); | static int bwn_intr(void *); | ||||
static void bwn_intrtask(void *, int); | static void bwn_intrtask(void *, int); | ||||
static void bwn_restart(struct bwn_mac *, const char *); | static void bwn_restart(struct bwn_mac *, const char *); | ||||
static void bwn_intr_ucode_debug(struct bwn_mac *); | static void bwn_intr_ucode_debug(struct bwn_mac *); | ||||
static void bwn_intr_tbtt_indication(struct bwn_mac *); | static void bwn_intr_tbtt_indication(struct bwn_mac *); | ||||
static void bwn_intr_atim_end(struct bwn_mac *); | static void bwn_intr_atim_end(struct bwn_mac *); | ||||
Show All 33 Lines | static void bwn_rx_radiotap(struct bwn_mac *, struct mbuf *, | ||||
const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int, | const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int, | ||||
int, int); | int, int); | ||||
static void bwn_tsf_read(struct bwn_mac *, uint64_t *); | static void bwn_tsf_read(struct bwn_mac *, uint64_t *); | ||||
static void bwn_set_slot_time(struct bwn_mac *, uint16_t); | static void bwn_set_slot_time(struct bwn_mac *, uint16_t); | ||||
static void bwn_watchdog(void *); | static void bwn_watchdog(void *); | ||||
static void bwn_dma_stop(struct bwn_mac *); | static void bwn_dma_stop(struct bwn_mac *); | ||||
static void bwn_pio_stop(struct bwn_mac *); | static void bwn_pio_stop(struct bwn_mac *); | ||||
static void bwn_dma_ringstop(struct bwn_dma_ring **); | static void bwn_dma_ringstop(struct bwn_dma_ring **); | ||||
static void bwn_led_attach(struct bwn_mac *); | static int bwn_led_attach(struct bwn_mac *); | ||||
static void bwn_led_newstate(struct bwn_mac *, enum ieee80211_state); | static void bwn_led_newstate(struct bwn_mac *, enum ieee80211_state); | ||||
static void bwn_led_event(struct bwn_mac *, int); | static void bwn_led_event(struct bwn_mac *, int); | ||||
static void bwn_led_blink_start(struct bwn_mac *, int, int); | static void bwn_led_blink_start(struct bwn_mac *, int, int); | ||||
static void bwn_led_blink_next(void *); | static void bwn_led_blink_next(void *); | ||||
static void bwn_led_blink_end(void *); | static void bwn_led_blink_end(void *); | ||||
static void bwn_rfswitch(void *); | static void bwn_rfswitch(void *); | ||||
static void bwn_rf_turnon(struct bwn_mac *); | static void bwn_rf_turnon(struct bwn_mac *); | ||||
static void bwn_rf_turnoff(struct bwn_mac *); | static void bwn_rf_turnoff(struct bwn_mac *); | ||||
static void bwn_sysctl_node(struct bwn_softc *); | static void bwn_sysctl_node(struct bwn_softc *); | ||||
static struct resource_spec bwn_res_spec_legacy[] = { | |||||
{ SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, | |||||
{ -1, 0, 0 } | |||||
}; | |||||
static struct resource_spec bwn_res_spec_msi[] = { | |||||
{ SYS_RES_IRQ, 1, RF_ACTIVE }, | |||||
{ -1, 0, 0 } | |||||
}; | |||||
static const struct bwn_channelinfo bwn_chantable_bg = { | static const struct bwn_channelinfo bwn_chantable_bg = { | ||||
.channels = { | .channels = { | ||||
{ 2412, 1, 30 }, { 2417, 2, 30 }, { 2422, 3, 30 }, | { 2412, 1, 30 }, { 2417, 2, 30 }, { 2422, 3, 30 }, | ||||
{ 2427, 4, 30 }, { 2432, 5, 30 }, { 2437, 6, 30 }, | { 2427, 4, 30 }, { 2432, 5, 30 }, { 2437, 6, 30 }, | ||||
{ 2442, 7, 30 }, { 2447, 8, 30 }, { 2452, 9, 30 }, | { 2442, 7, 30 }, { 2447, 8, 30 }, { 2452, 9, 30 }, | ||||
{ 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 }, | { 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 }, | ||||
{ 2472, 13, 30 }, { 2484, 14, 30 } }, | { 2472, 13, 30 }, { 2484, 14, 30 } }, | ||||
.nchannels = 14 | .nchannels = 14 | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | #define VENDOR_LED_ACT(vendor) \ | ||||
.vid = PCI_VENDOR_##vendor, \ | .vid = PCI_VENDOR_##vendor, \ | ||||
.led_act = { BWN_VENDOR_LED_ACT_##vendor } \ | .led_act = { BWN_VENDOR_LED_ACT_##vendor } \ | ||||
} | } | ||||
static const struct { | static const struct { | ||||
uint16_t vid; | uint16_t vid; | ||||
uint8_t led_act[BWN_LED_MAX]; | uint8_t led_act[BWN_LED_MAX]; | ||||
} bwn_vendor_led_act[] = { | } bwn_vendor_led_act[] = { | ||||
VENDOR_LED_ACT(COMPAQ), | VENDOR_LED_ACT(HP_COMPAQ), | ||||
VENDOR_LED_ACT(ASUSTEK) | VENDOR_LED_ACT(ASUSTEK) | ||||
}; | }; | ||||
static const uint8_t bwn_default_led_act[BWN_LED_MAX] = | static const uint8_t bwn_default_led_act[BWN_LED_MAX] = | ||||
{ BWN_VENDOR_LED_ACT_DEFAULT }; | { BWN_VENDOR_LED_ACT_DEFAULT }; | ||||
#undef VENDOR_LED_ACT | #undef VENDOR_LED_ACT | ||||
static const char *bwn_led_vars[] = { | |||||
BHND_NVAR_LEDBH0, | |||||
BHND_NVAR_LEDBH1, | |||||
BHND_NVAR_LEDBH2, | |||||
BHND_NVAR_LEDBH3 | |||||
}; | |||||
static const struct { | static const struct { | ||||
int on_dur; | int on_dur; | ||||
int off_dur; | int off_dur; | ||||
} bwn_led_duration[109] = { | } bwn_led_duration[109] = { | ||||
[0] = { 400, 100 }, | [0] = { 400, 100 }, | ||||
[2] = { 150, 75 }, | [2] = { 150, 75 }, | ||||
[4] = { 90, 45 }, | [4] = { 90, 45 }, | ||||
[11] = { 66, 34 }, | [11] = { 66, 34 }, | ||||
Show All 10 Lines | |||||
static const uint16_t bwn_wme_shm_offsets[] = { | static const uint16_t bwn_wme_shm_offsets[] = { | ||||
[0] = BWN_WME_BESTEFFORT, | [0] = BWN_WME_BESTEFFORT, | ||||
[1] = BWN_WME_BACKGROUND, | [1] = BWN_WME_BACKGROUND, | ||||
[2] = BWN_WME_VOICE, | [2] = BWN_WME_VOICE, | ||||
[3] = BWN_WME_VIDEO, | [3] = BWN_WME_VIDEO, | ||||
}; | }; | ||||
static const struct siba_devid bwn_devs[] = { | /* Supported D11 core revisions */ | ||||
SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"), | #define BWN_DEV(_hwrev) {{ \ | ||||
SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"), | BHND_MATCH_CORE(BHND_MFGID_BCM, BHND_COREID_D11), \ | ||||
SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"), | BHND_MATCH_CORE_REV(_hwrev), \ | ||||
SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"), | }} | ||||
SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"), | static const struct bhnd_device bwn_devices[] = { | ||||
SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"), | BWN_DEV(HWREV_RANGE(5, 16)), | ||||
SIBA_DEV(BROADCOM, 80211, 12, "Revision 12"), | BWN_DEV(HWREV_EQ(23)), | ||||
SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"), | BHND_DEVICE_END | ||||
SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"), | |||||
SIBA_DEV(BROADCOM, 80211, 16, "Revision 16") | |||||
}; | }; | ||||
static const struct bwn_bus_ops * | /* D11 quirks when bridged via a PCI host bridge core */ | ||||
bwn_get_bus_ops(device_t dev) | static const struct bhnd_device_quirk pci_bridge_quirks[] = { | ||||
{ | BHND_CORE_QUIRK (HWREV_LTE(10), BWN_QUIRK_UCODE_SLOWCLOCK_WAR), | ||||
#if BWN_USE_SIBA | BHND_DEVICE_QUIRK_END | ||||
return (NULL); | }; | ||||
#else | |||||
devclass_t bus_cls; | |||||
bus_cls = device_get_devclass(device_get_parent(dev)); | /* D11 quirks when bridged via a PCMCIA host bridge core */ | ||||
if (bus_cls == devclass_find("bhnd")) | static const struct bhnd_device_quirk pcmcia_bridge_quirks[] = { | ||||
return (&bwn_bhnd_bus_ops); | BHND_CORE_QUIRK (HWREV_ANY, BWN_QUIRK_NODMA), | ||||
else | BHND_DEVICE_QUIRK_END | ||||
return (&bwn_siba_bus_ops); | }; | ||||
#endif | |||||
} | |||||
/* Host bridge cores for which D11 quirk flags should be applied */ | |||||
static const struct bhnd_device bridge_devices[] = { | |||||
BHND_DEVICE(BCM, PCI, NULL, pci_bridge_quirks), | |||||
BHND_DEVICE(BCM, PCMCIA, NULL, pcmcia_bridge_quirks), | |||||
BHND_DEVICE_END | |||||
}; | |||||
static int | static int | ||||
bwn_probe(device_t dev) | bwn_probe(device_t dev) | ||||
{ | { | ||||
struct bwn_softc *sc; | const struct bhnd_device *id; | ||||
int i; | |||||
sc = device_get_softc(dev); | id = bhnd_device_lookup(dev, bwn_devices, sizeof(bwn_devices[0])); | ||||
sc->sc_bus_ops = bwn_get_bus_ops(dev); | if (id == NULL) | ||||
return (ENXIO); | |||||
for (i = 0; i < nitems(bwn_devs); i++) { | bhnd_set_default_core_desc(dev); | ||||
if (siba_get_vendor(dev) == bwn_devs[i].sd_vendor && | |||||
siba_get_device(dev) == bwn_devs[i].sd_device && | |||||
siba_get_revid(dev) == bwn_devs[i].sd_rev) | |||||
return (BUS_PROBE_DEFAULT); | return (BUS_PROBE_DEFAULT); | ||||
} | } | ||||
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; | ||||
int error, i, msic, reg; | device_t parent, hostb; | ||||
char chip_name[BHND_CHIPID_MAX_NAMELEN]; | |||||
int error; | |||||
sc = device_get_softc(dev); | |||||
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); | mac = NULL; | ||||
if ((error = BWN_BUS_OPS_ATTACH(dev))) { | |||||
device_printf(sc->sc_dev, | /* Determine the driver quirks applicable to this device, including any | ||||
"bus-specific initialization failed (%d)\n", error); | * quirks specific to the bus host bridge core (if any) */ | ||||
sc->sc_quirks = bhnd_device_quirks(dev, bwn_devices, | |||||
sizeof(bwn_devices[0])); | |||||
parent = device_get_parent(dev); | |||||
if ((hostb = bhnd_bus_find_hostb_device(parent)) != NULL) { | |||||
sc->sc_quirks |= bhnd_device_quirks(hostb, bridge_devices, | |||||
sizeof(bridge_devices[0])); | |||||
} | |||||
/* DMA explicitly disabled? */ | |||||
if (!bwn_usedma) | |||||
sc->sc_quirks |= BWN_QUIRK_NODMA; | |||||
/* Fetch our chip identification and board info */ | |||||
sc->sc_cid = *bhnd_get_chipid(dev); | |||||
if ((error = bhnd_read_board_info(dev, &sc->sc_board_info))) { | |||||
device_printf(sc->sc_dev, "couldn't read board info\n"); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* Allocate our D11 register block and PMU state */ | |||||
sc->sc_mem_rid = 0; | |||||
sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, | |||||
&sc->sc_mem_rid, RF_ACTIVE); | |||||
if (sc->sc_mem_res == NULL) { | |||||
device_printf(sc->sc_dev, "couldn't allocate registers\n"); | |||||
return (error); | |||||
} | |||||
if ((error = bhnd_alloc_pmu(sc->sc_dev))) { | |||||
bus_release_resource(sc->sc_dev, SYS_RES_MEMORY, | |||||
sc->sc_mem_rid, sc->sc_mem_res); | |||||
return (error); | |||||
} | |||||
/* Retain references to all required bus service providers */ | |||||
if ((error = bwn_retain_bus_providers(sc))) | |||||
goto fail; | |||||
/* Fetch mask of available antennas */ | |||||
error = bhnd_nvram_getvar_uint8(sc->sc_dev, BHND_NVAR_AA2G, | |||||
&sc->sc_ant2g); | |||||
if (error) { | |||||
device_printf(sc->sc_dev, "error determining 2GHz antenna " | |||||
"availability from NVRAM: %d\n", error); | |||||
goto fail; | |||||
} | |||||
error = bhnd_nvram_getvar_uint8(sc->sc_dev, BHND_NVAR_AA5G, | |||||
&sc->sc_ant5g); | |||||
if (error) { | |||||
device_printf(sc->sc_dev, "error determining 5GHz antenna " | |||||
"availability from NVRAM: %d\n", error); | |||||
goto fail; | |||||
} | |||||
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 (siba_get_pci_device(dev) != 0x4313 && | |||||
siba_get_pci_device(dev) != 0x431a && | |||||
siba_get_pci_device(dev) != 0x4321) { | |||||
device_printf(sc->sc_dev, | |||||
"skip 802.11 cores\n"); | |||||
return (ENODEV); | |||||
} | |||||
} | |||||
mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO); | mac = malloc(sizeof(*mac), M_DEVBUF, M_WAITOK | M_ZERO); | ||||
mac->mac_sc = sc; | mac->mac_sc = sc; | ||||
mac->mac_status = BWN_MAC_STATUS_UNINIT; | mac->mac_status = BWN_MAC_STATUS_UNINIT; | ||||
if (bwn_bfp != 0) | if (bwn_bfp != 0) | ||||
mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP; | mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP; | ||||
TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac); | TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac); | ||||
TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac); | TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac); | ||||
TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac); | TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac); | ||||
error = bwn_attach_core(mac); | error = bwn_attach_core(mac); | ||||
if (error) | if (error) | ||||
goto fail0; | goto fail; | ||||
bwn_led_attach(mac); | error = bwn_led_attach(mac); | ||||
if (error) | |||||
goto fail; | |||||
device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) " | bhnd_format_chip_id(chip_name, sizeof(chip_name), sc->sc_cid.chip_id); | ||||
device_printf(sc->sc_dev, "WLAN (%s rev %u) " | |||||
"PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n", | "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n", | ||||
siba_get_chipid(sc->sc_dev), siba_get_revid(sc->sc_dev), | chip_name, bhnd_get_hwrev(sc->sc_dev), mac->mac_phy.analog, | ||||
mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev, | mac->mac_phy.type, mac->mac_phy.rev, mac->mac_phy.rf_manuf, | ||||
mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver, | mac->mac_phy.rf_ver, mac->mac_phy.rf_rev); | ||||
mac->mac_phy.rf_rev); | |||||
if (mac->mac_flags & BWN_MAC_FLAG_DMA) | if (mac->mac_flags & BWN_MAC_FLAG_DMA) | ||||
device_printf(sc->sc_dev, "DMA (%d bits)\n", | device_printf(sc->sc_dev, "DMA (%d bits)\n", mac->mac_dmatype); | ||||
mac->mac_method.dma.dmatype); | |||||
else | else | ||||
device_printf(sc->sc_dev, "PIO\n"); | device_printf(sc->sc_dev, "PIO\n"); | ||||
#ifdef BWN_GPL_PHY | #ifdef BWN_GPL_PHY | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"Note: compiled with BWN_GPL_PHY; includes GPLv2 code\n"); | "Note: compiled with BWN_GPL_PHY; includes GPLv2 code\n"); | ||||
#endif | #endif | ||||
/* | mac->mac_rid_irq = 0; | ||||
* setup PCI resources and interrupt. | mac->mac_res_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, | ||||
*/ | &mac->mac_rid_irq, RF_ACTIVE | RF_SHAREABLE); | ||||
if (pci_find_cap(dev, PCIY_EXPRESS, ®) == 0) { | |||||
msic = pci_msi_count(dev); | |||||
if (bootverbose) | |||||
device_printf(sc->sc_dev, "MSI count : %d\n", msic); | |||||
} else | |||||
msic = 0; | |||||
mac->mac_intr_spec = bwn_res_spec_legacy; | if (mac->mac_res_irq == NULL) { | ||||
if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) { | device_printf(sc->sc_dev, "couldn't allocate IRQ resource\n"); | ||||
if (pci_alloc_msi(dev, &msic) == 0) { | error = ENXIO; | ||||
device_printf(sc->sc_dev, | goto fail; | ||||
"Using %d MSI messages\n", msic); | |||||
mac->mac_intr_spec = bwn_res_spec_msi; | |||||
mac->mac_msi = 1; | |||||
} | } | ||||
} | |||||
error = bus_alloc_resources(dev, mac->mac_intr_spec, | error = bus_setup_intr(dev, mac->mac_res_irq, | ||||
mac->mac_res_irq); | |||||
if (error) { | |||||
device_printf(sc->sc_dev, | |||||
"couldn't allocate IRQ resources (%d)\n", error); | |||||
goto fail1; | |||||
} | |||||
if (mac->mac_msi == 0) | |||||
error = bus_setup_intr(dev, mac->mac_res_irq[0], | |||||
INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac, | INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac, | ||||
&mac->mac_intrhand[0]); | &mac->mac_intrhand); | ||||
else { | |||||
for (i = 0; i < BWN_MSI_MESSAGES; i++) { | |||||
error = bus_setup_intr(dev, mac->mac_res_irq[i], | |||||
INTR_TYPE_NET | INTR_MPSAFE, bwn_intr, NULL, mac, | |||||
&mac->mac_intrhand[i]); | |||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, "couldn't setup interrupt (%d)\n", | ||||
"couldn't setup interrupt (%d)\n", error); | error); | ||||
break; | goto fail; | ||||
} | } | ||||
} | |||||
} | |||||
TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list); | TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list); | ||||
/* | /* | ||||
* calls attach-post routine | * calls attach-post routine | ||||
*/ | */ | ||||
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: | fail: | ||||
if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) | if (mac != NULL && mac->mac_res_irq != NULL) { | ||||
pci_release_msi(dev); | bus_release_resource(dev, SYS_RES_IRQ, mac->mac_rid_irq, | ||||
fail0: | mac->mac_res_irq); | ||||
BWN_BUS_OPS_DETACH(dev); | } | ||||
free(mac, M_DEVBUF); | free(mac, M_DEVBUF); | ||||
bhnd_release_pmu(dev); | |||||
bwn_release_bus_providers(sc); | |||||
if (sc->sc_mem_res != NULL) { | |||||
bus_release_resource(sc->sc_dev, SYS_RES_MEMORY, | |||||
sc->sc_mem_rid, sc->sc_mem_res); | |||||
} | |||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
bwn_is_valid_ether_addr(uint8_t *addr) | bwn_retain_bus_providers(struct bwn_softc *sc) | ||||
{ | { | ||||
char zero_addr[6] = { 0, 0, 0, 0, 0, 0 }; | struct chipc_caps *ccaps; | ||||
if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN))) | sc->sc_chipc = bhnd_retain_provider(sc->sc_dev, BHND_SERVICE_CHIPC); | ||||
return (FALSE); | if (sc->sc_chipc == NULL) { | ||||
device_printf(sc->sc_dev, "ChipCommon device not found\n"); | |||||
goto failed; | |||||
} | |||||
return (TRUE); | ccaps = BHND_CHIPC_GET_CAPS(sc->sc_chipc); | ||||
sc->sc_gpio = bhnd_retain_provider(sc->sc_dev, BHND_SERVICE_GPIO); | |||||
if (sc->sc_gpio == NULL) { | |||||
device_printf(sc->sc_dev, "GPIO device not found\n"); | |||||
goto failed; | |||||
} | } | ||||
if (ccaps->pmu) { | |||||
sc->sc_pmu = bhnd_retain_provider(sc->sc_dev, BHND_SERVICE_PMU); | |||||
if (sc->sc_pmu == NULL) { | |||||
device_printf(sc->sc_dev, "PMU device not found\n"); | |||||
goto failed; | |||||
} | |||||
} | |||||
return (0); | |||||
failed: | |||||
bwn_release_bus_providers(sc); | |||||
return (ENXIO); | |||||
} | |||||
static void | |||||
bwn_release_bus_providers(struct bwn_softc *sc) | |||||
{ | |||||
#define BWN_RELEASE_PROV(_sc, _prov, _service) do { \ | |||||
if ((_sc)-> _prov != NULL) { \ | |||||
bhnd_release_provider((_sc)->sc_dev, (_sc)-> _prov, \ | |||||
(_service)); \ | |||||
(_sc)-> _prov = NULL; \ | |||||
} \ | |||||
} while (0) | |||||
BWN_RELEASE_PROV(sc, sc_chipc, BHND_SERVICE_CHIPC); | |||||
BWN_RELEASE_PROV(sc, sc_gpio, BHND_SERVICE_GPIO); | |||||
BWN_RELEASE_PROV(sc, sc_pmu, BHND_SERVICE_PMU); | |||||
#undef BWN_RELEASE_PROV | |||||
} | |||||
static int | static int | ||||
bwn_attach_post(struct bwn_softc *sc) | bwn_attach_post(struct bwn_softc *sc) | ||||
{ | { | ||||
struct ieee80211com *ic = &sc->sc_ic; | struct ieee80211com *ic; | ||||
const char *mac_varname; | |||||
u_int core_unit; | |||||
int error; | |||||
ic = &sc->sc_ic; | |||||
ic->ic_softc = sc; | ic->ic_softc = sc; | ||||
ic->ic_name = device_get_nameunit(sc->sc_dev); | ic->ic_name = device_get_nameunit(sc->sc_dev); | ||||
/* XXX not right but it's not used anywhere important */ | /* XXX not right but it's not used anywhere important */ | ||||
ic->ic_phytype = IEEE80211_T_OFDM; | ic->ic_phytype = IEEE80211_T_OFDM; | ||||
ic->ic_opmode = IEEE80211_M_STA; | ic->ic_opmode = IEEE80211_M_STA; | ||||
ic->ic_caps = | ic->ic_caps = | ||||
IEEE80211_C_STA /* station mode supported */ | IEEE80211_C_STA /* station mode supported */ | ||||
| IEEE80211_C_MONITOR /* monitor mode */ | | IEEE80211_C_MONITOR /* monitor mode */ | ||||
| IEEE80211_C_AHDEMO /* adhoc demo mode */ | | IEEE80211_C_AHDEMO /* adhoc demo mode */ | ||||
| IEEE80211_C_SHPREAMBLE /* short preamble supported */ | | IEEE80211_C_SHPREAMBLE /* short preamble supported */ | ||||
| IEEE80211_C_SHSLOT /* short slot time supported */ | | IEEE80211_C_SHSLOT /* short slot time supported */ | ||||
| IEEE80211_C_WME /* WME/WMM supported */ | | IEEE80211_C_WME /* WME/WMM supported */ | ||||
| IEEE80211_C_WPA /* capable of WPA1+WPA2 */ | | IEEE80211_C_WPA /* capable of WPA1+WPA2 */ | ||||
#if 0 | #if 0 | ||||
| IEEE80211_C_BGSCAN /* capable of bg scanning */ | | IEEE80211_C_BGSCAN /* capable of bg scanning */ | ||||
#endif | #endif | ||||
| IEEE80211_C_TXPMGT /* capable of txpow mgt */ | | IEEE80211_C_TXPMGT /* capable of txpow mgt */ | ||||
; | ; | ||||
ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; /* s/w bmiss */ | ic->ic_flags_ext |= IEEE80211_FEXT_SWBMISS; /* s/w bmiss */ | ||||
IEEE80211_ADDR_COPY(ic->ic_macaddr, | /* Determine the NVRAM variable containing our MAC address */ | ||||
bwn_is_valid_ether_addr(siba_sprom_get_mac_80211a(sc->sc_dev)) ? | core_unit = bhnd_get_core_unit(sc->sc_dev); | ||||
siba_sprom_get_mac_80211a(sc->sc_dev) : | mac_varname = NULL; | ||||
siba_sprom_get_mac_80211bg(sc->sc_dev)); | if (sc->sc_board_info.board_srom_rev <= 2) { | ||||
if (core_unit == 0) { | |||||
mac_varname = BHND_NVAR_IL0MACADDR; | |||||
} else if (core_unit == 1) { | |||||
mac_varname = BHND_NVAR_ET1MACADDR; | |||||
} | |||||
} else { | |||||
if (core_unit == 0) { | |||||
mac_varname = BHND_NVAR_MACADDR; | |||||
} | |||||
} | |||||
if (mac_varname == NULL) { | |||||
device_printf(sc->sc_dev, "missing MAC address variable for " | |||||
"D11 core %u", core_unit); | |||||
return (ENXIO); | |||||
} | |||||
/* Read the MAC address from NVRAM */ | |||||
error = bhnd_nvram_getvar_array(sc->sc_dev, mac_varname, ic->ic_macaddr, | |||||
sizeof(ic->ic_macaddr), BHND_NVRAM_TYPE_UINT8_ARRAY); | |||||
if (error) { | |||||
device_printf(sc->sc_dev, "error reading %s: %d\n", mac_varname, | |||||
error); | |||||
return (error); | |||||
} | |||||
/* call MI attach routine. */ | /* call MI attach routine. */ | ||||
ieee80211_ifattach(ic); | ieee80211_ifattach(ic); | ||||
ic->ic_headroom = sizeof(struct bwn_txhdr); | ic->ic_headroom = sizeof(struct bwn_txhdr); | ||||
/* override default methods */ | /* override default methods */ | ||||
ic->ic_raw_xmit = bwn_raw_xmit; | ic->ic_raw_xmit = bwn_raw_xmit; | ||||
ic->ic_updateslot = bwn_updateslot; | ic->ic_updateslot = bwn_updateslot; | ||||
Show All 23 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); | ||||
} | } | ||||
int | static 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; | |||||
sc->sc_flags |= BWN_FLAG_INVALID; | sc->sc_flags |= BWN_FLAG_INVALID; | ||||
if (device_is_attached(sc->sc_dev)) { | if (device_is_attached(sc->sc_dev)) { | ||||
BWN_LOCK(sc); | BWN_LOCK(sc); | ||||
bwn_stop(sc); | bwn_stop(sc); | ||||
BWN_UNLOCK(sc); | BWN_UNLOCK(sc); | ||||
bwn_dma_free(mac); | bwn_dma_free(mac); | ||||
callout_drain(&sc->sc_led_blink_ch); | callout_drain(&sc->sc_led_blink_ch); | ||||
callout_drain(&sc->sc_rfswitch_ch); | callout_drain(&sc->sc_rfswitch_ch); | ||||
callout_drain(&sc->sc_task_ch); | callout_drain(&sc->sc_task_ch); | ||||
callout_drain(&sc->sc_watchdog_ch); | callout_drain(&sc->sc_watchdog_ch); | ||||
bwn_phy_detach(mac); | bwn_phy_detach(mac); | ||||
ieee80211_draintask(ic, &mac->mac_hwreset); | ieee80211_draintask(ic, &mac->mac_hwreset); | ||||
ieee80211_draintask(ic, &mac->mac_txpower); | ieee80211_draintask(ic, &mac->mac_txpower); | ||||
ieee80211_ifdetach(ic); | ieee80211_ifdetach(ic); | ||||
} | } | ||||
taskqueue_drain(sc->sc_tq, &mac->mac_intrtask); | taskqueue_drain(sc->sc_tq, &mac->mac_intrtask); | ||||
taskqueue_free(sc->sc_tq); | taskqueue_free(sc->sc_tq); | ||||
for (i = 0; i < BWN_MSI_MESSAGES; i++) { | if (mac->mac_intrhand != NULL) { | ||||
if (mac->mac_intrhand[i] != NULL) { | bus_teardown_intr(dev, mac->mac_res_irq, mac->mac_intrhand); | ||||
bus_teardown_intr(dev, mac->mac_res_irq[i], | mac->mac_intrhand = NULL; | ||||
mac->mac_intrhand[i]); | |||||
mac->mac_intrhand[i] = NULL; | |||||
} | } | ||||
} | |||||
bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq); | bhnd_release_pmu(dev); | ||||
if (mac->mac_msi != 0) | bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, | ||||
pci_release_msi(dev); | sc->sc_mem_res); | ||||
bus_release_resource(dev, SYS_RES_IRQ, mac->mac_rid_irq, | |||||
mac->mac_res_irq); | |||||
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); | |||||
bwn_release_bus_providers(sc); | |||||
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); | ||||
TAILQ_INIT(&sc->sc_maclist); | TAILQ_INIT(&sc->sc_maclist); | ||||
callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_rfswitch_ch, &sc->sc_mtx, 0); | ||||
callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_task_ch, &sc->sc_mtx, 0); | ||||
callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_watchdog_ch, &sc->sc_mtx, 0); | ||||
mbufq_init(&sc->sc_snd, ifqmaxlen); | mbufq_init(&sc->sc_snd, ifqmaxlen); | ||||
sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT, | sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT, | ||||
taskqueue_thread_enqueue, &sc->sc_tq); | taskqueue_thread_enqueue, &sc->sc_tq); | ||||
taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, | taskqueue_start_threads(&sc->sc_tq, 1, PI_NET, | ||||
"%s taskq", device_get_nameunit(sc->sc_dev)); | "%s taskq", device_get_nameunit(sc->sc_dev)); | ||||
} | } | ||||
static void | static void | ||||
bwn_sprom_bugfixes(device_t dev) | bwn_sprom_bugfixes(device_t dev) | ||||
{ | { | ||||
#define BWN_ISDEV(_vendor, _device, _subvendor, _subdevice) \ | struct bwn_softc *sc = device_get_softc(dev); | ||||
((siba_get_pci_vendor(dev) == PCI_VENDOR_##_vendor) && \ | |||||
(siba_get_pci_device(dev) == _device) && \ | |||||
(siba_get_pci_subvendor(dev) == PCI_VENDOR_##_subvendor) && \ | |||||
(siba_get_pci_subdevice(dev) == _subdevice)) | |||||
if (siba_get_pci_subvendor(dev) == PCI_VENDOR_APPLE && | #define BWN_ISDEV(_device, _subvendor, _subdevice) \ | ||||
siba_get_pci_subdevice(dev) == 0x4e && | ((sc->sc_board_info.board_devid == PCI_DEVID_##_device) && \ | ||||
siba_get_pci_revid(dev) > 0x40) | (sc->sc_board_info.board_vendor == PCI_VENDOR_##_subvendor) && \ | ||||
siba_sprom_set_bf_lo(dev, | (sc->sc_board_info.board_type == _subdevice)) | ||||
siba_sprom_get_bf_lo(dev) | BWN_BFL_PACTRL); | |||||
if (siba_get_pci_subvendor(dev) == SIBA_BOARDVENDOR_DELL && | /* A subset of Apple Airport Extreme (BCM4306 rev 2) devices | ||||
siba_get_chipid(dev) == 0x4301 && siba_get_pci_revid(dev) == 0x74) | * were programmed with a missing PACTRL boardflag */ | ||||
siba_sprom_set_bf_lo(dev, | if (sc->sc_board_info.board_vendor == PCI_VENDOR_APPLE && | ||||
siba_sprom_get_bf_lo(dev) | BWN_BFL_BTCOEXIST); | sc->sc_board_info.board_type == 0x4e && | ||||
if (siba_get_type(dev) == SIBA_TYPE_PCI) { | sc->sc_board_info.board_rev > 0x40) | ||||
if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) || | sc->sc_board_info.board_flags |= BHND_BFL_PACTRL; | ||||
BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) || | |||||
BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) || | if (BWN_ISDEV(BCM4318_D11G, ASUSTEK, 0x100f) || | ||||
BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) || | BWN_ISDEV(BCM4306_D11G, DELL, 0x0003) || | ||||
BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) || | BWN_ISDEV(BCM4306_D11G, HP, 0x12f8) || | ||||
BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) || | BWN_ISDEV(BCM4306_D11G, LINKSYS, 0x0013) || | ||||
BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010)) | BWN_ISDEV(BCM4306_D11G, LINKSYS, 0x0014) || | ||||
siba_sprom_set_bf_lo(dev, | BWN_ISDEV(BCM4306_D11G, LINKSYS, 0x0015) || | ||||
siba_sprom_get_bf_lo(dev) & ~BWN_BFL_BTCOEXIST); | BWN_ISDEV(BCM4306_D11G, MOTOROLA, 0x7010)) | ||||
} | sc->sc_board_info.board_flags &= ~BHND_BFL_BTCOEX; | ||||
#undef BWN_ISDEV | #undef BWN_ISDEV | ||||
} | } | ||||
static void | static void | ||||
bwn_parent(struct ieee80211com *ic) | bwn_parent(struct ieee80211com *ic) | ||||
{ | { | ||||
struct bwn_softc *sc = ic->ic_softc; | struct bwn_softc *sc = ic->ic_softc; | ||||
int startall = 0; | int startall = 0; | ||||
▲ Show 20 Lines • Show All 160 Lines • ▼ Show 20 Lines | if (error) { | ||||
device_printf(sc->sc_dev, "tx fail\n"); | device_printf(sc->sc_dev, "tx fail\n"); | ||||
return (error); | return (error); | ||||
} | } | ||||
TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list); | TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list); | ||||
tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4); | tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4); | ||||
tq->tq_free--; | tq->tq_free--; | ||||
if (siba_get_revid(sc->sc_dev) >= 8) { | if (bhnd_get_hwrev(sc->sc_dev) >= 8) { | ||||
/* | /* | ||||
* XXX please removes m_defrag(9) | * XXX please removes m_defrag(9) | ||||
*/ | */ | ||||
m_new = m_defrag(m, M_NOWAIT); | m_new = m_defrag(m, M_NOWAIT); | ||||
if (m_new == NULL) { | if (m_new == NULL) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"%s: can't defrag TX buffer\n", | "%s: can't defrag TX buffer\n", | ||||
__func__); | __func__); | ||||
▲ Show 20 Lines • Show All 156 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; | uint16_t iost; | ||||
KASSERT(siba_get_revid(sc->sc_dev) >= 5, | KASSERT(bhnd_get_hwrev(sc->sc_dev) >= 5, | ||||
("unsupported revision %d", siba_get_revid(sc->sc_dev))); | ("unsupported revision %d", bhnd_get_hwrev(sc->sc_dev))); | ||||
siba_powerup(sc->sc_dev, 0); | if ((error = bwn_core_forceclk(mac, true))) | ||||
high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH); | return (error); | ||||
have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0; | |||||
have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0; | if ((error = bhnd_read_iost(sc->sc_dev, &iost))) { | ||||
if (high & BWN_TGSHIGH_DUALPHY) { | device_printf(sc->sc_dev, "error reading I/O status flags: " | ||||
"%d\n", error); | |||||
return (error); | |||||
} | |||||
if (iost & BHND_IOST_DMA64) { | |||||
mac->mac_dmatype = BHND_DMA_ADDR_64BIT; | |||||
} else { | |||||
uint32_t tmp; | |||||
uint16_t base; | |||||
base = bwn_dma_base(0, 0); | |||||
BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, | |||||
BWN_DMA32_TXADDREXT_MASK); | |||||
tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL); | |||||
if (tmp & BWN_DMA32_TXADDREXT_MASK) { | |||||
mac->mac_dmatype = BHND_DMA_ADDR_32BIT; | |||||
} else { | |||||
mac->mac_dmatype = BHND_DMA_ADDR_30BIT; | |||||
} | |||||
} | |||||
have_a = (iost & BWN_IOST_HAVE_5GHZ) ? 1 : 0; | |||||
have_bg = (iost & BWN_IOST_HAVE_2GHZ) ? 1 : 0; | |||||
if (iost & BWN_IOST_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: iost=0x%04hx, 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, | iost, | ||||
have_a, | have_a, | ||||
have_bg, | have_bg, | ||||
siba_get_pci_device(sc->sc_dev), | sc->sc_board_info.board_devid, | ||||
siba_get_chipid(sc->sc_dev)); | sc->sc_cid.chip_id); | ||||
#endif | #endif | ||||
/* | /* | ||||
* 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); | error = bwn_reset_core(mac, have_bg); | ||||
if (error) | |||||
goto fail; | |||||
/* | /* | ||||
* Get the PHY version. | * Get the PHY version. | ||||
*/ | */ | ||||
error = bwn_phy_getinfo(mac, have_bg); | error = bwn_phy_getinfo(mac, have_bg); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
/* | /* | ||||
* This is the whitelist of devices which we "believe" | * This is the whitelist of devices which we "believe" | ||||
* the SPROM PHY config from. The rest are "guessed". | * the SPROM PHY config from. The rest are "guessed". | ||||
*/ | */ | ||||
if (siba_get_pci_device(sc->sc_dev) != 0x4312 && | if (sc->sc_board_info.board_devid != PCI_DEVID_BCM4311_D11DUAL && | ||||
siba_get_pci_device(sc->sc_dev) != 0x4315 && | sc->sc_board_info.board_devid != PCI_DEVID_BCM4328_D11G && | ||||
siba_get_pci_device(sc->sc_dev) != 0x4319 && | sc->sc_board_info.board_devid != PCI_DEVID_BCM4318_D11DUAL && | ||||
siba_get_pci_device(sc->sc_dev) != 0x4324 && | sc->sc_board_info.board_devid != PCI_DEVID_BCM4306_D11DUAL && | ||||
siba_get_pci_device(sc->sc_dev) != 0x4328 && | sc->sc_board_info.board_devid != PCI_DEVID_BCM4321_D11N && | ||||
siba_get_pci_device(sc->sc_dev) != 0x432b) { | sc->sc_board_info.board_devid != PCI_DEVID_BCM4322_D11N) { | ||||
have_a = have_bg = 0; | have_a = have_bg = 0; | ||||
if (mac->mac_phy.type == BWN_PHYTYPE_A) | if (mac->mac_phy.type == BWN_PHYTYPE_A) | ||||
have_a = 1; | have_a = 1; | ||||
else if (mac->mac_phy.type == BWN_PHYTYPE_G || | else if (mac->mac_phy.type == BWN_PHYTYPE_G || | ||||
mac->mac_phy.type == BWN_PHYTYPE_N || | mac->mac_phy.type == BWN_PHYTYPE_N || | ||||
mac->mac_phy.type == BWN_PHYTYPE_LP) | mac->mac_phy.type == BWN_PHYTYPE_LP) | ||||
have_bg = 1; | have_bg = 1; | ||||
else | else | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | #endif | ||||
if (mac->mac_phy.attach != NULL) { | if (mac->mac_phy.attach != NULL) { | ||||
error = mac->mac_phy.attach(mac); | error = mac->mac_phy.attach(mac); | ||||
if (error) { | if (error) { | ||||
device_printf(sc->sc_dev, "failed\n"); | device_printf(sc->sc_dev, "failed\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
} | } | ||||
bwn_reset_core(mac, have_bg); | error = bwn_reset_core(mac, have_bg); | ||||
if (error) | |||||
goto fail; | |||||
error = bwn_chiptest(mac); | error = bwn_chiptest(mac); | ||||
if (error) | if (error) | ||||
goto fail; | goto fail; | ||||
error = bwn_setup_channels(mac, have_bg, have_a); | error = bwn_setup_channels(mac, have_bg, have_a); | ||||
if (error) { | if (error) { | ||||
device_printf(sc->sc_dev, "failed to setup channels\n"); | device_printf(sc->sc_dev, "failed to setup channels\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
if (sc->sc_curmac == NULL) | if (sc->sc_curmac == NULL) | ||||
sc->sc_curmac = mac; | sc->sc_curmac = mac; | ||||
error = bwn_dma_attach(mac); | error = bwn_dma_attach(mac); | ||||
if (error != 0) { | if (error != 0) { | ||||
device_printf(sc->sc_dev, "failed to initialize DMA\n"); | device_printf(sc->sc_dev, "failed to initialize DMA\n"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
mac->mac_phy.switch_analog(mac, 0); | mac->mac_phy.switch_analog(mac, 0); | ||||
siba_dev_down(sc->sc_dev, 0); | |||||
fail: | fail: | ||||
siba_powerdown(sc->sc_dev); | bhnd_suspend_hw(sc->sc_dev, 0); | ||||
bwn_release_firmware(mac); | bwn_release_firmware(mac); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Reset - SIBA. | * Reset | ||||
*/ | */ | ||||
void | int | ||||
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; | ||||
uint32_t low, ctl; | uint32_t ctl; | ||||
uint32_t flags = 0; | uint16_t ioctl, ioctl_mask; | ||||
int error; | |||||
sc = mac->mac_sc; | |||||
DPRINTF(sc, BWN_DEBUG_RESET, "%s: g_mode=%d\n", __func__, g_mode); | DPRINTF(sc, BWN_DEBUG_RESET, "%s: g_mode=%d\n", __func__, g_mode); | ||||
flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET); | /* Reset core */ | ||||
ioctl = (BWN_IOCTL_PHYCLOCK_ENABLE | BWN_IOCTL_PHYRESET); | |||||
if (g_mode) | if (g_mode) | ||||
flags |= BWN_TGSLOW_SUPPORT_G; | ioctl |= BWN_IOCTL_SUPPORT_G; | ||||
/* XXX N-PHY only; and hard-code to 20MHz for now */ | /* XXX N-PHY only; and hard-code to 20MHz for now */ | ||||
if (mac->mac_phy.type == BWN_PHYTYPE_N) | if (mac->mac_phy.type == BWN_PHYTYPE_N) | ||||
flags |= BWN_TGSLOW_PHY_BANDWIDTH_20MHZ; | ioctl |= BWN_IOCTL_PHY_BANDWIDTH_20MHZ; | ||||
siba_dev_up(sc->sc_dev, flags); | if ((error = bhnd_reset_hw(sc->sc_dev, ioctl, ioctl))) { | ||||
device_printf(sc->sc_dev, "core reset failed: %d", error); | |||||
return (error); | |||||
} | |||||
DELAY(2000); | DELAY(2000); | ||||
/* Take PHY out of reset */ | /* Take PHY out of reset */ | ||||
low = (siba_read_4(sc->sc_dev, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) & | ioctl = BHND_IOCTL_CLK_FORCE; | ||||
~(BWN_TGSLOW_PHYRESET | BWN_TGSLOW_PHYCLOCK_ENABLE); | ioctl_mask = BHND_IOCTL_CLK_FORCE | | ||||
siba_write_4(sc->sc_dev, SIBA_TGSLOW, low); | BWN_IOCTL_PHYRESET | | ||||
siba_read_4(sc->sc_dev, SIBA_TGSLOW); | BWN_IOCTL_PHYCLOCK_ENABLE; | ||||
if ((error = bhnd_write_ioctl(sc->sc_dev, ioctl, ioctl_mask))) { | |||||
device_printf(sc->sc_dev, "failed to set core ioctl flags: " | |||||
"%d\n", error); | |||||
return (error); | |||||
} | |||||
DELAY(2000); | DELAY(2000); | ||||
low &= ~SIBA_TGSLOW_FGC; | |||||
low |= BWN_TGSLOW_PHYCLOCK_ENABLE; | ioctl = BWN_IOCTL_PHYCLOCK_ENABLE; | ||||
siba_write_4(sc->sc_dev, SIBA_TGSLOW, low); | if ((error = bhnd_write_ioctl(sc->sc_dev, ioctl, ioctl_mask))) { | ||||
siba_read_4(sc->sc_dev, SIBA_TGSLOW); | device_printf(sc->sc_dev, "failed to set core ioctl flags: " | ||||
"%d\n", error); | |||||
return (error); | |||||
} | |||||
DELAY(2000); | DELAY(2000); | ||||
if (mac->mac_phy.switch_analog != NULL) | if (mac->mac_phy.switch_analog != NULL) | ||||
mac->mac_phy.switch_analog(mac, 1); | mac->mac_phy.switch_analog(mac, 1); | ||||
ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE; | ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE; | ||||
if (g_mode) | if (g_mode) | ||||
ctl |= BWN_MACCTL_GMODE; | ctl |= BWN_MACCTL_GMODE; | ||||
BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON); | BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON); | ||||
return (0); | |||||
} | } | ||||
static int | static int | ||||
bwn_phy_getinfo(struct bwn_mac *mac, int gmode) | bwn_phy_getinfo(struct bwn_mac *mac, int gmode) | ||||
{ | { | ||||
struct bwn_phy *phy = &mac->mac_phy; | struct bwn_phy *phy = &mac->mac_phy; | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint32_t tmp; | uint32_t tmp; | ||||
Show All 9 Lines | if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) || | ||||
(phy->type == BWN_PHYTYPE_B && phy->rev != 2 && | (phy->type == BWN_PHYTYPE_B && phy->rev != 2 && | ||||
phy->rev != 4 && phy->rev != 6 && phy->rev != 7) || | phy->rev != 4 && phy->rev != 6 && phy->rev != 7) || | ||||
(phy->type == BWN_PHYTYPE_G && phy->rev > 9) || | (phy->type == BWN_PHYTYPE_G && phy->rev > 9) || | ||||
(phy->type == BWN_PHYTYPE_N && phy->rev > 6) || | (phy->type == BWN_PHYTYPE_N && phy->rev > 6) || | ||||
(phy->type == BWN_PHYTYPE_LP && phy->rev > 2)) | (phy->type == BWN_PHYTYPE_LP && phy->rev > 2)) | ||||
goto unsupphy; | goto unsupphy; | ||||
/* RADIO */ | /* RADIO */ | ||||
if (siba_get_chipid(sc->sc_dev) == 0x4317) { | |||||
if (siba_get_chiprev(sc->sc_dev) == 0) | |||||
tmp = 0x3205017f; | |||||
else if (siba_get_chiprev(sc->sc_dev) == 1) | |||||
tmp = 0x4205017f; | |||||
else | |||||
tmp = 0x5205017f; | |||||
} else { | |||||
BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID); | BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID); | ||||
tmp = BWN_READ_2(mac, BWN_RFDATALO); | tmp = BWN_READ_2(mac, BWN_RFDATALO); | ||||
BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID); | BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID); | ||||
tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16; | tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16; | ||||
} | |||||
phy->rf_rev = (tmp & 0xf0000000) >> 28; | phy->rf_rev = (tmp & 0xf0000000) >> 28; | ||||
phy->rf_ver = (tmp & 0x0ffff000) >> 12; | phy->rf_ver = (tmp & 0x0ffff000) >> 12; | ||||
phy->rf_manuf = (tmp & 0x00000fff); | phy->rf_manuf = (tmp & 0x00000fff); | ||||
/* | /* | ||||
* For now, just always do full init (ie, what bwn has traditionally | * For now, just always do full init (ie, what bwn has traditionally | ||||
* done) | * done) | ||||
*/ | */ | ||||
Show All 40 Lines | #define TESTVAL1 0xaa5555aa | ||||
if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0) | if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0) | ||||
goto error; | goto error; | ||||
bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1); | bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1); | ||||
if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1) | if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1) | ||||
goto error; | goto error; | ||||
bwn_shm_write_4(mac, BWN_SHARED, 0, backup); | bwn_shm_write_4(mac, BWN_SHARED, 0, backup); | ||||
if ((siba_get_revid(sc->sc_dev) >= 3) && | if ((bhnd_get_hwrev(sc->sc_dev) >= 3) && | ||||
(siba_get_revid(sc->sc_dev) <= 10)) { | (bhnd_get_hwrev(sc->sc_dev) <= 10)) { | ||||
BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa); | BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa); | ||||
BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb); | BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb); | ||||
if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb) | if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb) | ||||
goto error; | goto error; | ||||
if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc) | if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc) | ||||
goto error; | goto error; | ||||
} | } | ||||
BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0); | BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0); | ||||
▲ Show 20 Lines • Show All 511 Lines • ▼ Show 20 Lines | case BWN_WME_BACKGROUND: | ||||
break; | break; | ||||
default: | default: | ||||
KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__)); | KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__)); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
bwn_core_forceclk(struct bwn_mac *mac, bool force) | |||||
{ | |||||
struct bwn_softc *sc; | |||||
bhnd_clock clock; | |||||
int error; | |||||
sc = mac->mac_sc; | |||||
/* On PMU equipped devices, we do not need to force the HT clock */ | |||||
if (sc->sc_pmu != NULL) | |||||
return (0); | |||||
/* Issue a PMU clock request */ | |||||
if (force) | |||||
clock = BHND_CLOCK_HT; | |||||
else | |||||
clock = BHND_CLOCK_DYN; | |||||
if ((error = bhnd_request_clock(sc->sc_dev, clock))) { | |||||
device_printf(sc->sc_dev, "%d clock request failed: %d\n", | |||||
clock, error); | |||||
return (error); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | |||||
bwn_core_init(struct bwn_mac *mac) | bwn_core_init(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint64_t hf; | uint64_t hf; | ||||
int error; | int error; | ||||
KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT, | KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT, | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__); | DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: called\n", __func__); | ||||
siba_powerup(sc->sc_dev, 0); | if ((error = bwn_core_forceclk(mac, true))) | ||||
if (!siba_dev_isup(sc->sc_dev)) | return (error); | ||||
bwn_reset_core(mac, mac->mac_phy.gmode); | |||||
if (bhnd_is_hw_suspended(sc->sc_dev)) { | |||||
if ((error = bwn_reset_core(mac, mac->mac_phy.gmode))) | |||||
goto fail0; | |||||
} | |||||
mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID; | mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID; | ||||
mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON; | mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON; | ||||
mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0; | mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0; | ||||
BWN_GETTIME(mac->mac_phy.nexttime); | BWN_GETTIME(mac->mac_phy.nexttime); | ||||
mac->mac_phy.txerrors = BWN_TXERROR_MAX; | mac->mac_phy.txerrors = BWN_TXERROR_MAX; | ||||
bzero(&mac->mac_stats, sizeof(mac->mac_stats)); | bzero(&mac->mac_stats, sizeof(mac->mac_stats)); | ||||
mac->mac_stats.link_noise = -95; | mac->mac_stats.link_noise = -95; | ||||
mac->mac_reason_intr = 0; | mac->mac_reason_intr = 0; | ||||
bzero(mac->mac_reason, sizeof(mac->mac_reason)); | bzero(mac->mac_reason, sizeof(mac->mac_reason)); | ||||
mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE; | mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE; | ||||
#ifdef BWN_DEBUG | #ifdef BWN_DEBUG | ||||
if (sc->sc_debug & BWN_DEBUG_XMIT) | if (sc->sc_debug & BWN_DEBUG_XMIT) | ||||
mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR; | mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR; | ||||
#endif | #endif | ||||
mac->mac_suspended = 1; | mac->mac_suspended = 1; | ||||
mac->mac_task_state = 0; | mac->mac_task_state = 0; | ||||
memset(&mac->mac_noise, 0, sizeof(mac->mac_noise)); | memset(&mac->mac_noise, 0, sizeof(mac->mac_noise)); | ||||
mac->mac_phy.init_pre(mac); | mac->mac_phy.init_pre(mac); | ||||
siba_pcicore_intr(sc->sc_dev); | |||||
siba_fix_imcfglobug(sc->sc_dev); | |||||
bwn_bt_disable(mac); | bwn_bt_disable(mac); | ||||
if (mac->mac_phy.prepare_hw) { | if (mac->mac_phy.prepare_hw) { | ||||
error = mac->mac_phy.prepare_hw(mac); | error = mac->mac_phy.prepare_hw(mac); | ||||
if (error) | if (error) | ||||
goto fail0; | goto fail0; | ||||
} | } | ||||
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: chip_init\n", __func__); | DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: chip_init\n", __func__); | ||||
error = bwn_chip_init(mac); | error = bwn_chip_init(mac); | ||||
if (error) | if (error) | ||||
goto fail0; | goto fail0; | ||||
bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV, | bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV, | ||||
siba_get_revid(sc->sc_dev)); | bhnd_get_hwrev(sc->sc_dev)); | ||||
hf = bwn_hf_read(mac); | hf = bwn_hf_read(mac); | ||||
if (mac->mac_phy.type == BWN_PHYTYPE_G) { | if (mac->mac_phy.type == BWN_PHYTYPE_G) { | ||||
hf |= BWN_HF_GPHY_SYM_WORKAROUND; | hf |= BWN_HF_GPHY_SYM_WORKAROUND; | ||||
if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) | if (sc->sc_board_info.board_flags & BHND_BFL_PACTRL) | ||||
hf |= BWN_HF_PAGAINBOOST_OFDM_ON; | hf |= BWN_HF_PAGAINBOOST_OFDM_ON; | ||||
if (mac->mac_phy.rev == 1) | if (mac->mac_phy.rev == 1) | ||||
hf |= BWN_HF_GPHY_DC_CANCELFILTER; | hf |= BWN_HF_GPHY_DC_CANCELFILTER; | ||||
} | } | ||||
if (mac->mac_phy.rf_ver == 0x2050) { | if (mac->mac_phy.rf_ver == 0x2050) { | ||||
if (mac->mac_phy.rf_rev < 6) | if (mac->mac_phy.rf_rev < 6) | ||||
hf |= BWN_HF_FORCE_VCO_RECALC; | hf |= BWN_HF_FORCE_VCO_RECALC; | ||||
if (mac->mac_phy.rf_rev == 6) | if (mac->mac_phy.rf_rev == 6) | ||||
hf |= BWN_HF_4318_TSSI; | hf |= BWN_HF_4318_TSSI; | ||||
} | } | ||||
if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW) | if (sc->sc_board_info.board_flags & BHND_BFL_NOPLLDOWN) | ||||
hf |= BWN_HF_SLOWCLOCK_REQ_OFF; | hf |= BWN_HF_SLOWCLOCK_REQ_OFF; | ||||
if ((siba_get_type(sc->sc_dev) == SIBA_TYPE_PCI) && | if (sc->sc_quirks & BWN_QUIRK_UCODE_SLOWCLOCK_WAR) | ||||
(siba_get_pcicore_revid(sc->sc_dev) <= 10)) | |||||
hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND; | hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND; | ||||
hf &= ~BWN_HF_SKIP_CFP_UPDATE; | hf &= ~BWN_HF_SKIP_CFP_UPDATE; | ||||
bwn_hf_write(mac, hf); | bwn_hf_write(mac, hf); | ||||
/* Tell the firmware about the MAC capabilities */ | /* Tell the firmware about the MAC capabilities */ | ||||
if (siba_get_revid(sc->sc_dev) >= 13) { | if (bhnd_get_hwrev(sc->sc_dev) >= 13) { | ||||
uint32_t cap; | uint32_t cap; | ||||
cap = BWN_READ_4(mac, BWN_MAC_HW_CAP); | cap = BWN_READ_4(mac, BWN_MAC_HW_CAP); | ||||
DPRINTF(sc, BWN_DEBUG_RESET, | DPRINTF(sc, BWN_DEBUG_RESET, | ||||
"%s: hw capabilities: 0x%08x\n", | "%s: hw capabilities: 0x%08x\n", | ||||
__func__, cap); | __func__, cap); | ||||
bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_L, | bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_L, | ||||
cap & 0xffff); | cap & 0xffff); | ||||
bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_H, | bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_MACHW_H, | ||||
(cap >> 16) & 0xffff); | (cap >> 16) & 0xffff); | ||||
} | } | ||||
bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG); | bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG); | ||||
bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3); | bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SHORT_RETRY_FALLBACK, 3); | ||||
bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2); | bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_LONG_RETRY_FALLBACK, 2); | ||||
bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1); | bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1); | ||||
bwn_rate_init(mac); | bwn_rate_init(mac); | ||||
bwn_set_phytxctl(mac); | bwn_set_phytxctl(mac); | ||||
bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN, | bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN, | ||||
(mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf); | (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf); | ||||
bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff); | bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff); | ||||
if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0) | if (sc->sc_quirks & BWN_QUIRK_NODMA) | ||||
bwn_pio_init(mac); | bwn_pio_init(mac); | ||||
else | else | ||||
bwn_dma_init(mac); | bwn_dma_init(mac); | ||||
bwn_wme_init(mac); | bwn_wme_init(mac); | ||||
bwn_spu_setdelay(mac, 1); | bwn_spu_setdelay(mac, 1); | ||||
bwn_bt_enable(mac); | bwn_bt_enable(mac); | ||||
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: powerup\n", __func__); | DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: powerup\n", __func__); | ||||
siba_powerup(sc->sc_dev, | if (sc->sc_board_info.board_flags & BHND_BFL_NOPLLDOWN) | ||||
!(siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_CRYSTAL_NOSLOW)); | bwn_core_forceclk(mac, true); | ||||
else | |||||
bwn_core_forceclk(mac, false); | |||||
bwn_set_macaddr(mac); | bwn_set_macaddr(mac); | ||||
bwn_crypt_init(mac); | bwn_crypt_init(mac); | ||||
/* XXX LED initializatin */ | /* XXX LED initializatin */ | ||||
mac->mac_status = BWN_MAC_STATUS_INITED; | mac->mac_status = BWN_MAC_STATUS_INITED; | ||||
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: done\n", __func__); | DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: done\n", __func__); | ||||
return (error); | return (error); | ||||
fail0: | fail0: | ||||
siba_powerdown(sc->sc_dev); | bhnd_suspend_hw(sc->sc_dev, 0); | ||||
KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT, | KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT, | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: fail\n", __func__); | DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: fail\n", __func__); | ||||
return (error); | return (error); | ||||
} | } | ||||
static void | static void | ||||
bwn_core_start(struct bwn_mac *mac) | bwn_core_start(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint32_t tmp; | uint32_t tmp; | ||||
KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED, | KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED, | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
if (siba_get_revid(sc->sc_dev) < 5) | if (bhnd_get_hwrev(sc->sc_dev) < 5) | ||||
return; | return; | ||||
while (1) { | while (1) { | ||||
tmp = BWN_READ_4(mac, BWN_XMITSTAT_0); | tmp = BWN_READ_4(mac, BWN_XMITSTAT_0); | ||||
if (!(tmp & 0x00000001)) | if (!(tmp & 0x00000001)) | ||||
break; | break; | ||||
tmp = BWN_READ_4(mac, BWN_XMITSTAT_1); | tmp = BWN_READ_4(mac, BWN_XMITSTAT_1); | ||||
} | } | ||||
Show All 24 Lines | bwn_core_exit(struct bwn_mac *mac) | ||||
macctl &= ~BWN_MACCTL_MCODE_RUN; | macctl &= ~BWN_MACCTL_MCODE_RUN; | ||||
macctl |= BWN_MACCTL_MCODE_JMP0; | macctl |= BWN_MACCTL_MCODE_JMP0; | ||||
BWN_WRITE_4(mac, BWN_MACCTL, macctl); | BWN_WRITE_4(mac, BWN_MACCTL, macctl); | ||||
bwn_dma_stop(mac); | bwn_dma_stop(mac); | ||||
bwn_pio_stop(mac); | bwn_pio_stop(mac); | ||||
bwn_chip_exit(mac); | bwn_chip_exit(mac); | ||||
mac->mac_phy.switch_analog(mac, 0); | mac->mac_phy.switch_analog(mac, 0); | ||||
siba_dev_down(sc->sc_dev, 0); | bhnd_suspend_hw(sc->sc_dev, 0); | ||||
siba_powerdown(sc->sc_dev); | |||||
} | } | ||||
static void | static void | ||||
bwn_bt_disable(struct bwn_mac *mac) | bwn_bt_disable(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
(void)sc; | (void)sc; | ||||
/* XXX do nothing yet */ | /* XXX do nothing yet */ | ||||
} | } | ||||
static int | static int | ||||
bwn_chip_init(struct bwn_mac *mac) | bwn_chip_init(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
struct bwn_phy *phy = &mac->mac_phy; | struct bwn_phy *phy = &mac->mac_phy; | ||||
uint32_t macctl; | uint32_t macctl; | ||||
u_int delay; | |||||
int error; | int error; | ||||
macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA; | macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA; | ||||
if (phy->gmode) | if (phy->gmode) | ||||
macctl |= BWN_MACCTL_GMODE; | macctl |= BWN_MACCTL_GMODE; | ||||
BWN_WRITE_4(mac, BWN_MACCTL, macctl); | BWN_WRITE_4(mac, BWN_MACCTL, macctl); | ||||
error = bwn_fw_fillinfo(mac); | error = bwn_fw_fillinfo(mac); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = bwn_fw_loaducode(mac); | error = bwn_fw_loaducode(mac); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = bwn_gpio_init(mac); | error = bwn_gpio_init(mac); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
error = bwn_fw_loadinitvals(mac); | error = bwn_fw_loadinitvals(mac); | ||||
if (error) { | if (error) | ||||
siba_gpio_set(sc->sc_dev, 0); | |||||
return (error); | return (error); | ||||
} | |||||
phy->switch_analog(mac, 1); | phy->switch_analog(mac, 1); | ||||
error = bwn_phy_init(mac); | error = bwn_phy_init(mac); | ||||
if (error) { | if (error) | ||||
siba_gpio_set(sc->sc_dev, 0); | |||||
return (error); | return (error); | ||||
} | |||||
if (phy->set_im) | if (phy->set_im) | ||||
phy->set_im(mac, BWN_IMMODE_NONE); | phy->set_im(mac, BWN_IMMODE_NONE); | ||||
if (phy->set_antenna) | if (phy->set_antenna) | ||||
phy->set_antenna(mac, BWN_ANT_DEFAULT); | phy->set_antenna(mac, BWN_ANT_DEFAULT); | ||||
bwn_set_txantenna(mac, BWN_ANT_DEFAULT); | bwn_set_txantenna(mac, BWN_ANT_DEFAULT); | ||||
if (phy->type == BWN_PHYTYPE_B) | if (phy->type == BWN_PHYTYPE_B) | ||||
BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004); | BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004); | ||||
BWN_WRITE_4(mac, 0x0100, 0x01000000); | BWN_WRITE_4(mac, 0x0100, 0x01000000); | ||||
if (siba_get_revid(sc->sc_dev) < 5) | if (bhnd_get_hwrev(sc->sc_dev) < 5) | ||||
BWN_WRITE_4(mac, 0x010c, 0x01000000); | BWN_WRITE_4(mac, 0x010c, 0x01000000); | ||||
BWN_WRITE_4(mac, BWN_MACCTL, | BWN_WRITE_4(mac, BWN_MACCTL, | ||||
BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA); | BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA); | ||||
BWN_WRITE_4(mac, BWN_MACCTL, | BWN_WRITE_4(mac, BWN_MACCTL, | ||||
BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA); | BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA); | ||||
bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000); | bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000); | ||||
bwn_set_opmode(mac); | bwn_set_opmode(mac); | ||||
if (siba_get_revid(sc->sc_dev) < 3) { | if (bhnd_get_hwrev(sc->sc_dev) < 3) { | ||||
BWN_WRITE_2(mac, 0x060e, 0x0000); | BWN_WRITE_2(mac, 0x060e, 0x0000); | ||||
BWN_WRITE_2(mac, 0x0610, 0x8000); | BWN_WRITE_2(mac, 0x0610, 0x8000); | ||||
BWN_WRITE_2(mac, 0x0604, 0x0000); | BWN_WRITE_2(mac, 0x0604, 0x0000); | ||||
BWN_WRITE_2(mac, 0x0606, 0x0200); | BWN_WRITE_2(mac, 0x0606, 0x0200); | ||||
} else { | } else { | ||||
BWN_WRITE_4(mac, 0x0188, 0x80000000); | BWN_WRITE_4(mac, 0x0188, 0x80000000); | ||||
BWN_WRITE_4(mac, 0x018c, 0x02000000); | BWN_WRITE_4(mac, 0x018c, 0x02000000); | ||||
} | } | ||||
BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000); | BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000); | ||||
BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00); | BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00); | ||||
BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00); | BWN_WRITE_4(mac, BWN_DMA1_INTR_MASK, 0x0000dc00); | ||||
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 */ | /* Provide the HT clock transition latency to the MAC core */ | ||||
BWN_WRITE_2(mac, BWN_POWERUP_DELAY, siba_get_cc_powerdelay(sc->sc_dev)); | error = bhnd_get_clock_latency(sc->sc_dev, BHND_CLOCK_HT, &delay); | ||||
if (error) { | |||||
device_printf(sc->sc_dev, "failed to fetch HT clock latency: " | |||||
"%d\n", error); | |||||
return (error); | return (error); | ||||
} | } | ||||
if (delay > UINT16_MAX) { | |||||
device_printf(sc->sc_dev, "invalid HT clock latency: %u\n", | |||||
delay); | |||||
return (ENXIO); | |||||
} | |||||
BWN_WRITE_2(mac, BWN_POWERUP_DELAY, delay); | |||||
return (0); | |||||
} | |||||
/* read hostflags */ | /* read hostflags */ | ||||
uint64_t | uint64_t | ||||
bwn_hf_read(struct bwn_mac *mac) | bwn_hf_read(struct bwn_mac *mac) | ||||
{ | { | ||||
uint64_t ret; | uint64_t ret; | ||||
ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI); | ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI); | ||||
ret <<= 16; | ret <<= 16; | ||||
▲ Show 20 Lines • Show All 149 Lines • ▼ Show 20 Lines | bwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq, | ||||
struct bwn_pio_txpkt *tp; | struct bwn_pio_txpkt *tp; | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
unsigned int i; | unsigned int i; | ||||
tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac); | tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac); | ||||
tq->tq_index = index; | tq->tq_index = index; | ||||
tq->tq_free = BWN_PIO_MAX_TXPACKETS; | tq->tq_free = BWN_PIO_MAX_TXPACKETS; | ||||
if (siba_get_revid(sc->sc_dev) >= 8) | if (bhnd_get_hwrev(sc->sc_dev) >= 8) | ||||
tq->tq_size = 1920; | tq->tq_size = 1920; | ||||
else { | else { | ||||
tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE); | tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE); | ||||
tq->tq_size -= 80; | tq->tq_size -= 80; | ||||
} | } | ||||
TAILQ_INIT(&tq->tq_pktlist); | TAILQ_INIT(&tq->tq_pktlist); | ||||
for (i = 0; i < N(tq->tq_pkts); i++) { | for (i = 0; i < N(tq->tq_pkts); i++) { | ||||
Show All 22 Lines | static const uint16_t bases_rev11[] = { | ||||
BWN_PIO11_BASE0, | BWN_PIO11_BASE0, | ||||
BWN_PIO11_BASE1, | BWN_PIO11_BASE1, | ||||
BWN_PIO11_BASE2, | BWN_PIO11_BASE2, | ||||
BWN_PIO11_BASE3, | BWN_PIO11_BASE3, | ||||
BWN_PIO11_BASE4, | BWN_PIO11_BASE4, | ||||
BWN_PIO11_BASE5, | BWN_PIO11_BASE5, | ||||
}; | }; | ||||
if (siba_get_revid(sc->sc_dev) >= 11) { | if (bhnd_get_hwrev(sc->sc_dev) >= 11) { | ||||
if (index >= N(bases_rev11)) | if (index >= N(bases_rev11)) | ||||
device_printf(sc->sc_dev, "%s: warning\n", __func__); | device_printf(sc->sc_dev, "%s: warning\n", __func__); | ||||
return (bases_rev11[index]); | return (bases_rev11[index]); | ||||
} | } | ||||
if (index >= N(bases)) | if (index >= N(bases)) | ||||
device_printf(sc->sc_dev, "%s: warning\n", __func__); | device_printf(sc->sc_dev, "%s: warning\n", __func__); | ||||
return (bases[index]); | return (bases[index]); | ||||
} | } | ||||
static void | static void | ||||
bwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq, | bwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq, | ||||
int index) | int index) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
prq->prq_mac = mac; | prq->prq_mac = mac; | ||||
prq->prq_rev = siba_get_revid(sc->sc_dev); | prq->prq_rev = bhnd_get_hwrev(sc->sc_dev); | ||||
prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac); | prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac); | ||||
bwn_dma_rxdirectfifo(mac, index, 1); | bwn_dma_rxdirectfifo(mac, index, 1); | ||||
} | } | ||||
static void | static void | ||||
bwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq) | bwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq) | ||||
{ | { | ||||
if (tq == NULL) | if (tq == NULL) | ||||
Show All 15 Lines | bwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq, | ||||
return (BWN_READ_2(mac, tq->tq_base + offset)); | return (BWN_READ_2(mac, tq->tq_base + offset)); | ||||
} | } | ||||
static void | static void | ||||
bwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable) | bwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable) | ||||
{ | { | ||||
uint32_t ctl; | uint32_t ctl; | ||||
int type; | |||||
uint16_t base; | uint16_t base; | ||||
type = bwn_dma_mask2type(bwn_dma_mask(mac)); | base = bwn_dma_base(mac->mac_dmatype, idx); | ||||
base = bwn_dma_base(type, idx); | if (mac->mac_dmatype == BHND_DMA_ADDR_64BIT) { | ||||
if (type == BWN_DMA_64BIT) { | |||||
ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL); | ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL); | ||||
ctl &= ~BWN_DMA64_RXDIRECTFIFO; | ctl &= ~BWN_DMA64_RXDIRECTFIFO; | ||||
if (enable) | if (enable) | ||||
ctl |= BWN_DMA64_RXDIRECTFIFO; | ctl |= BWN_DMA64_RXDIRECTFIFO; | ||||
BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl); | BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl); | ||||
} else { | } else { | ||||
ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL); | ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL); | ||||
ctl &= ~BWN_DMA32_RXDIRECTFIFO; | ctl &= ~BWN_DMA32_RXDIRECTFIFO; | ||||
if (enable) | if (enable) | ||||
ctl |= BWN_DMA32_RXDIRECTFIFO; | ctl |= BWN_DMA32_RXDIRECTFIFO; | ||||
BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl); | BWN_WRITE_4(mac, base + BWN_DMA32_RXCTL, ctl); | ||||
} | } | ||||
} | } | ||||
static uint64_t | |||||
bwn_dma_mask(struct bwn_mac *mac) | |||||
{ | |||||
uint32_t tmp; | |||||
uint16_t base; | |||||
tmp = BWN_READ_4(mac, SIBA_TGSHIGH); | |||||
if (tmp & SIBA_TGSHIGH_DMA64) | |||||
return (BWN_DMA_BIT_MASK(64)); | |||||
base = bwn_dma_base(0, 0); | |||||
BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK); | |||||
tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL); | |||||
if (tmp & BWN_DMA32_TXADDREXT_MASK) | |||||
return (BWN_DMA_BIT_MASK(32)); | |||||
return (BWN_DMA_BIT_MASK(30)); | |||||
} | |||||
static int | |||||
bwn_dma_mask2type(uint64_t dmamask) | |||||
{ | |||||
if (dmamask == BWN_DMA_BIT_MASK(30)) | |||||
return (BWN_DMA_30BIT); | |||||
if (dmamask == BWN_DMA_BIT_MASK(32)) | |||||
return (BWN_DMA_32BIT); | |||||
if (dmamask == BWN_DMA_BIT_MASK(64)) | |||||
return (BWN_DMA_64BIT); | |||||
KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__)); | |||||
return (BWN_DMA_30BIT); | |||||
} | |||||
static void | static void | ||||
bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq) | bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq) | ||||
{ | { | ||||
struct bwn_pio_txpkt *tp; | struct bwn_pio_txpkt *tp; | ||||
unsigned int i; | unsigned int i; | ||||
for (i = 0; i < N(tq->tq_pkts); i++) { | for (i = 0; i < N(tq->tq_pkts); i++) { | ||||
tp = &(tq->tq_pkts[i]); | tp = &(tq->tq_pkts[i]); | ||||
Show All 19 Lines | static const uint16_t map32[] = { | ||||
BWN_DMA32_BASE0, | BWN_DMA32_BASE0, | ||||
BWN_DMA32_BASE1, | BWN_DMA32_BASE1, | ||||
BWN_DMA32_BASE2, | BWN_DMA32_BASE2, | ||||
BWN_DMA32_BASE3, | BWN_DMA32_BASE3, | ||||
BWN_DMA32_BASE4, | BWN_DMA32_BASE4, | ||||
BWN_DMA32_BASE5, | BWN_DMA32_BASE5, | ||||
}; | }; | ||||
if (type == BWN_DMA_64BIT) { | if (type == BHND_DMA_ADDR_64BIT) { | ||||
KASSERT(controller_idx >= 0 && controller_idx < N(map64), | KASSERT(controller_idx >= 0 && controller_idx < N(map64), | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
return (map64[controller_idx]); | return (map64[controller_idx]); | ||||
} | } | ||||
KASSERT(controller_idx >= 0 && controller_idx < N(map32), | KASSERT(controller_idx >= 0 && controller_idx < N(map32), | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
return (map32[controller_idx]); | return (map32[controller_idx]); | ||||
} | } | ||||
Show All 10 Lines | bwn_dma_init(struct bwn_mac *mac) | ||||
bwn_dma_setup(dma->wme[WME_AC_VO]); | bwn_dma_setup(dma->wme[WME_AC_VO]); | ||||
bwn_dma_setup(dma->mcast); | bwn_dma_setup(dma->mcast); | ||||
/* setup RX DMA channel. */ | /* setup RX DMA channel. */ | ||||
bwn_dma_setup(dma->rx); | bwn_dma_setup(dma->rx); | ||||
} | } | ||||
static struct bwn_dma_ring * | static struct bwn_dma_ring * | ||||
bwn_dma_ringsetup(struct bwn_mac *mac, int controller_index, | bwn_dma_ringsetup(struct bwn_mac *mac, int controller_index, | ||||
int for_tx, int type) | int for_tx) | ||||
{ | { | ||||
struct bwn_dma *dma = &mac->mac_method.dma; | struct bwn_dma *dma = &mac->mac_method.dma; | ||||
struct bwn_dma_ring *dr; | struct bwn_dma_ring *dr; | ||||
struct bwn_dmadesc_generic *desc; | struct bwn_dmadesc_generic *desc; | ||||
struct bwn_dmadesc_meta *mt; | struct bwn_dmadesc_meta *mt; | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
int error, i; | int error, i; | ||||
dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO); | dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO); | ||||
if (dr == NULL) | if (dr == NULL) | ||||
goto out; | goto out; | ||||
dr->dr_numslots = BWN_RXRING_SLOTS; | dr->dr_numslots = BWN_RXRING_SLOTS; | ||||
if (for_tx) | if (for_tx) | ||||
dr->dr_numslots = BWN_TXRING_SLOTS; | dr->dr_numslots = BWN_TXRING_SLOTS; | ||||
dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta), | dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta), | ||||
M_DEVBUF, M_NOWAIT | M_ZERO); | M_DEVBUF, M_NOWAIT | M_ZERO); | ||||
if (dr->dr_meta == NULL) | if (dr->dr_meta == NULL) | ||||
goto fail0; | goto fail0; | ||||
dr->dr_type = type; | dr->dr_type = mac->mac_dmatype; | ||||
dr->dr_mac = mac; | dr->dr_mac = mac; | ||||
dr->dr_base = bwn_dma_base(type, controller_index); | dr->dr_base = bwn_dma_base(dr->dr_type, controller_index); | ||||
dr->dr_index = controller_index; | dr->dr_index = controller_index; | ||||
if (type == BWN_DMA_64BIT) { | if (dr->dr_type == BHND_DMA_ADDR_64BIT) { | ||||
dr->getdesc = bwn_dma_64_getdesc; | dr->getdesc = bwn_dma_64_getdesc; | ||||
dr->setdesc = bwn_dma_64_setdesc; | dr->setdesc = bwn_dma_64_setdesc; | ||||
dr->start_transfer = bwn_dma_64_start_transfer; | dr->start_transfer = bwn_dma_64_start_transfer; | ||||
dr->suspend = bwn_dma_64_suspend; | dr->suspend = bwn_dma_64_suspend; | ||||
dr->resume = bwn_dma_64_resume; | dr->resume = bwn_dma_64_resume; | ||||
dr->get_curslot = bwn_dma_64_get_curslot; | dr->get_curslot = bwn_dma_64_get_curslot; | ||||
dr->set_curslot = bwn_dma_64_set_curslot; | dr->set_curslot = bwn_dma_64_set_curslot; | ||||
} else { | } else { | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | bwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot, | ||||
*gdesc = (struct bwn_dmadesc_generic *)desc; | *gdesc = (struct bwn_dmadesc_generic *)desc; | ||||
} | } | ||||
static void | static void | ||||
bwn_dma_32_setdesc(struct bwn_dma_ring *dr, | bwn_dma_32_setdesc(struct bwn_dma_ring *dr, | ||||
struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize, | struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize, | ||||
int start, int end, int irq) | int start, int end, int irq) | ||||
{ | { | ||||
struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase; | struct bwn_dmadesc32 *descbase; | ||||
struct bwn_softc *sc = dr->dr_mac->mac_sc; | struct bwn_dma *dma; | ||||
struct bhnd_dma_translation *dt; | |||||
uint32_t addr, addrext, ctl; | uint32_t addr, addrext, ctl; | ||||
int slot; | int slot; | ||||
descbase = dr->dr_ring_descbase; | |||||
dma = &dr->dr_mac->mac_method.dma; | |||||
dt = &dma->translation; | |||||
slot = (int)(&(desc->dma.dma32) - descbase); | slot = (int)(&(desc->dma.dma32) - descbase); | ||||
KASSERT(slot >= 0 && slot < dr->dr_numslots, | KASSERT(slot >= 0 && slot < dr->dr_numslots, | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK); | addr = (dmaaddr & dt->addr_mask) | dt->base_addr; | ||||
addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30; | addrext = ((dmaaddr & dt->addrext_mask) >> dma->addrext_shift); | ||||
addr |= siba_dma_translation(sc->sc_dev); | |||||
ctl = bufsize & BWN_DMA32_DCTL_BYTECNT; | ctl = bufsize & BWN_DMA32_DCTL_BYTECNT; | ||||
if (slot == dr->dr_numslots - 1) | if (slot == dr->dr_numslots - 1) | ||||
ctl |= BWN_DMA32_DCTL_DTABLEEND; | ctl |= BWN_DMA32_DCTL_DTABLEEND; | ||||
if (start) | if (start) | ||||
ctl |= BWN_DMA32_DCTL_FRAMESTART; | ctl |= BWN_DMA32_DCTL_FRAMESTART; | ||||
if (end) | if (end) | ||||
ctl |= BWN_DMA32_DCTL_FRAMEEND; | ctl |= BWN_DMA32_DCTL_FRAMEEND; | ||||
if (irq) | if (irq) | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | bwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot, | ||||
*gdesc = (struct bwn_dmadesc_generic *)desc; | *gdesc = (struct bwn_dmadesc_generic *)desc; | ||||
} | } | ||||
static void | static void | ||||
bwn_dma_64_setdesc(struct bwn_dma_ring *dr, | bwn_dma_64_setdesc(struct bwn_dma_ring *dr, | ||||
struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize, | struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize, | ||||
int start, int end, int irq) | int start, int end, int irq) | ||||
{ | { | ||||
struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase; | struct bwn_dmadesc64 *descbase; | ||||
struct bwn_softc *sc = dr->dr_mac->mac_sc; | struct bwn_dma *dma; | ||||
int slot; | struct bhnd_dma_translation *dt; | ||||
uint32_t ctl0 = 0, ctl1 = 0; | bhnd_addr_t addr; | ||||
uint32_t addrlo, addrhi; | uint32_t addrhi, addrlo; | ||||
uint32_t addrext; | uint32_t addrext; | ||||
uint32_t ctl0, ctl1; | |||||
int slot; | |||||
descbase = dr->dr_ring_descbase; | |||||
dma = &dr->dr_mac->mac_method.dma; | |||||
dt = &dma->translation; | |||||
slot = (int)(&(desc->dma.dma64) - descbase); | slot = (int)(&(desc->dma.dma64) - descbase); | ||||
KASSERT(slot >= 0 && slot < dr->dr_numslots, | KASSERT(slot >= 0 && slot < dr->dr_numslots, | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
addrlo = (uint32_t) (dmaaddr & 0xffffffff); | addr = (dmaaddr & dt->addr_mask) | dt->base_addr; | ||||
addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK); | addrhi = (addr >> 32); | ||||
addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >> | addrlo = (addr & UINT32_MAX); | ||||
30; | addrext = ((dmaaddr & dt->addrext_mask) >> dma->addrext_shift); | ||||
addrhi |= (siba_dma_translation(sc->sc_dev) << 1); | |||||
ctl0 = 0; | |||||
if (slot == dr->dr_numslots - 1) | if (slot == dr->dr_numslots - 1) | ||||
ctl0 |= BWN_DMA64_DCTL0_DTABLEEND; | ctl0 |= BWN_DMA64_DCTL0_DTABLEEND; | ||||
if (start) | if (start) | ||||
ctl0 |= BWN_DMA64_DCTL0_FRAMESTART; | ctl0 |= BWN_DMA64_DCTL0_FRAMESTART; | ||||
if (end) | if (end) | ||||
ctl0 |= BWN_DMA64_DCTL0_FRAMEEND; | ctl0 |= BWN_DMA64_DCTL0_FRAMEEND; | ||||
if (irq) | if (irq) | ||||
ctl0 |= BWN_DMA64_DCTL0_IRQ; | ctl0 |= BWN_DMA64_DCTL0_IRQ; | ||||
ctl1 = 0; | |||||
ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT; | ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT; | ||||
ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT) | ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT) | ||||
& BWN_DMA64_DCTL1_ADDREXT_MASK; | & BWN_DMA64_DCTL1_ADDREXT_MASK; | ||||
desc->dma.dma64.control0 = htole32(ctl0); | desc->dma.dma64.control0 = htole32(ctl0); | ||||
desc->dma.dma64.control1 = htole32(ctl1); | desc->dma.dma64.control1 = htole32(ctl1); | ||||
desc->dma.dma64.address_low = htole32(addrlo); | desc->dma.dma64.address_low = htole32(addrlo); | ||||
desc->dma.dma64.address_high = htole32(addrhi); | desc->dma.dma64.address_high = htole32(addrhi); | ||||
▲ Show 20 Lines • Show All 85 Lines • ▼ Show 20 Lines | bwn_dma_allocringmemory(struct bwn_dma_ring *dr) | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
bwn_dma_setup(struct bwn_dma_ring *dr) | bwn_dma_setup(struct bwn_dma_ring *dr) | ||||
{ | { | ||||
struct bwn_softc *sc = dr->dr_mac->mac_sc; | struct bwn_mac *mac; | ||||
uint64_t ring64; | struct bwn_dma *dma; | ||||
uint32_t addrext, ring32, value; | struct bhnd_dma_translation *dt; | ||||
uint32_t trans = siba_dma_translation(sc->sc_dev); | bhnd_addr_t addr, paddr; | ||||
uint32_t addrhi, addrlo, addrext, value; | |||||
mac = dr->dr_mac; | |||||
dma = &mac->mac_method.dma; | |||||
dt = &dma->translation; | |||||
paddr = dr->dr_ring_dmabase; | |||||
addr = (paddr & dt->addr_mask) | dt->base_addr; | |||||
addrhi = (addr >> 32); | |||||
addrlo = (addr & UINT32_MAX); | |||||
addrext = ((paddr & dt->addrext_mask) >> dma->addrext_shift); | |||||
if (dr->dr_tx) { | if (dr->dr_tx) { | ||||
dr->dr_curslot = -1; | dr->dr_curslot = -1; | ||||
if (dr->dr_type == BWN_DMA_64BIT) { | if (dr->dr_type == BHND_DMA_ADDR_64BIT) { | ||||
ring64 = (uint64_t)(dr->dr_ring_dmabase); | |||||
addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) | |||||
>> 30; | |||||
value = BWN_DMA64_TXENABLE; | value = BWN_DMA64_TXENABLE; | ||||
value |= BWN_DMA64_TXPARITY_DISABLE; | value |= BWN_DMA64_TXPARITY_DISABLE; | ||||
value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT) | value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT) | ||||
& BWN_DMA64_TXADDREXT_MASK; | & BWN_DMA64_TXADDREXT_MASK; | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value); | BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value); | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, | BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, addrlo); | ||||
(ring64 & 0xffffffff)); | BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, addrhi); | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, | |||||
((ring64 >> 32) & | |||||
~SIBA_DMA_TRANSLATION_MASK) | (trans << 1)); | |||||
} else { | } else { | ||||
ring32 = (uint32_t)(dr->dr_ring_dmabase); | |||||
addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30; | |||||
value = BWN_DMA32_TXENABLE; | value = BWN_DMA32_TXENABLE; | ||||
value |= BWN_DMA32_TXPARITY_DISABLE; | value |= BWN_DMA32_TXPARITY_DISABLE; | ||||
value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT) | value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT) | ||||
& BWN_DMA32_TXADDREXT_MASK; | & BWN_DMA32_TXADDREXT_MASK; | ||||
BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value); | BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value); | ||||
BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, | BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, addrlo); | ||||
(ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
/* | /* | ||||
* set for RX | * set for RX | ||||
*/ | */ | ||||
dr->dr_usedslot = dr->dr_numslots; | dr->dr_usedslot = dr->dr_numslots; | ||||
if (dr->dr_type == BWN_DMA_64BIT) { | if (dr->dr_type == BHND_DMA_ADDR_64BIT) { | ||||
ring64 = (uint64_t)(dr->dr_ring_dmabase); | |||||
addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK) >> 30; | |||||
value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT); | value = (dr->dr_frameoffset << BWN_DMA64_RXFROFF_SHIFT); | ||||
value |= BWN_DMA64_RXENABLE; | value |= BWN_DMA64_RXENABLE; | ||||
value |= BWN_DMA64_RXPARITY_DISABLE; | value |= BWN_DMA64_RXPARITY_DISABLE; | ||||
value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT) | value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT) | ||||
& BWN_DMA64_RXADDREXT_MASK; | & BWN_DMA64_RXADDREXT_MASK; | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value); | BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value); | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff)); | BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, addrlo); | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, | BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, addrhi); | ||||
((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK) | |||||
| (trans << 1)); | |||||
BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots * | BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots * | ||||
sizeof(struct bwn_dmadesc64)); | sizeof(struct bwn_dmadesc64)); | ||||
} else { | } else { | ||||
ring32 = (uint32_t)(dr->dr_ring_dmabase); | |||||
addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30; | |||||
value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT); | value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT); | ||||
value |= BWN_DMA32_RXENABLE; | value |= BWN_DMA32_RXENABLE; | ||||
value |= BWN_DMA32_RXPARITY_DISABLE; | value |= BWN_DMA32_RXPARITY_DISABLE; | ||||
value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT) | value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT) | ||||
& BWN_DMA32_RXADDREXT_MASK; | & BWN_DMA32_RXADDREXT_MASK; | ||||
BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value); | BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value); | ||||
BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, | BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, addrlo); | ||||
(ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans); | |||||
BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots * | BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots * | ||||
sizeof(struct bwn_dmadesc32)); | sizeof(struct bwn_dmadesc32)); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
bwn_dma_free_ringmemory(struct bwn_dma_ring *dr) | bwn_dma_free_ringmemory(struct bwn_dma_ring *dr) | ||||
{ | { | ||||
bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap); | bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap); | ||||
bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase, | bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase, | ||||
dr->dr_ring_dmap); | dr->dr_ring_dmap); | ||||
} | } | ||||
static void | static void | ||||
bwn_dma_cleanup(struct bwn_dma_ring *dr) | bwn_dma_cleanup(struct bwn_dma_ring *dr) | ||||
{ | { | ||||
if (dr->dr_tx) { | if (dr->dr_tx) { | ||||
bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type); | bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type); | ||||
if (dr->dr_type == BWN_DMA_64BIT) { | if (dr->dr_type == BHND_DMA_ADDR_64BIT) { | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0); | BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0); | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0); | BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0); | ||||
} else | } else | ||||
BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0); | BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0); | ||||
} else { | } else { | ||||
bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type); | bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type); | ||||
if (dr->dr_type == BWN_DMA_64BIT) { | if (dr->dr_type == BHND_DMA_ADDR_64BIT) { | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0); | BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0); | ||||
BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0); | BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0); | ||||
} else | } else | ||||
BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0); | BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
Show All 35 Lines | bwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base, | ||||
int type) | int type) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint32_t value; | uint32_t value; | ||||
int i; | int i; | ||||
uint16_t offset; | uint16_t offset; | ||||
for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) { | ||||
offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS : | offset = (type == BHND_DMA_ADDR_64BIT) ? BWN_DMA64_TXSTATUS : | ||||
BWN_DMA32_TXSTATUS; | BWN_DMA32_TXSTATUS; | ||||
value = BWN_READ_4(mac, base + offset); | value = BWN_READ_4(mac, base + offset); | ||||
if (type == BWN_DMA_64BIT) { | if (type == BHND_DMA_ADDR_64BIT) { | ||||
value &= BWN_DMA64_TXSTAT; | value &= BWN_DMA64_TXSTAT; | ||||
if (value == BWN_DMA64_TXSTAT_DISABLED || | if (value == BWN_DMA64_TXSTAT_DISABLED || | ||||
value == BWN_DMA64_TXSTAT_IDLEWAIT || | value == BWN_DMA64_TXSTAT_IDLEWAIT || | ||||
value == BWN_DMA64_TXSTAT_STOPPED) | value == BWN_DMA64_TXSTAT_STOPPED) | ||||
break; | break; | ||||
} else { | } else { | ||||
value &= BWN_DMA32_TXSTATE; | value &= BWN_DMA32_TXSTATE; | ||||
if (value == BWN_DMA32_TXSTAT_DISABLED || | if (value == BWN_DMA32_TXSTAT_DISABLED || | ||||
value == BWN_DMA32_TXSTAT_IDLEWAIT || | value == BWN_DMA32_TXSTAT_IDLEWAIT || | ||||
value == BWN_DMA32_TXSTAT_STOPPED) | value == BWN_DMA32_TXSTAT_STOPPED) | ||||
break; | break; | ||||
} | } | ||||
DELAY(1000); | DELAY(1000); | ||||
} | } | ||||
offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL; | offset = (type == BHND_DMA_ADDR_64BIT) ? BWN_DMA64_TXCTL : | ||||
BWN_DMA32_TXCTL; | |||||
BWN_WRITE_4(mac, base + offset, 0); | BWN_WRITE_4(mac, base + offset, 0); | ||||
for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) { | ||||
offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS : | offset = (type == BHND_DMA_ADDR_64BIT) ? BWN_DMA64_TXSTATUS : | ||||
BWN_DMA32_TXSTATUS; | BWN_DMA32_TXSTATUS; | ||||
value = BWN_READ_4(mac, base + offset); | value = BWN_READ_4(mac, base + offset); | ||||
if (type == BWN_DMA_64BIT) { | if (type == BHND_DMA_ADDR_64BIT) { | ||||
value &= BWN_DMA64_TXSTAT; | value &= BWN_DMA64_TXSTAT; | ||||
if (value == BWN_DMA64_TXSTAT_DISABLED) { | if (value == BWN_DMA64_TXSTAT_DISABLED) { | ||||
i = -1; | i = -1; | ||||
break; | break; | ||||
} | } | ||||
} else { | } else { | ||||
value &= BWN_DMA32_TXSTATE; | value &= BWN_DMA32_TXSTATE; | ||||
if (value == BWN_DMA32_TXSTAT_DISABLED) { | if (value == BWN_DMA32_TXSTAT_DISABLED) { | ||||
Show All 16 Lines | |||||
bwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base, | bwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base, | ||||
int type) | int type) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint32_t value; | uint32_t value; | ||||
int i; | int i; | ||||
uint16_t offset; | uint16_t offset; | ||||
offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL; | offset = (type == BHND_DMA_ADDR_64BIT) ? BWN_DMA64_RXCTL : | ||||
BWN_DMA32_RXCTL; | |||||
BWN_WRITE_4(mac, base + offset, 0); | BWN_WRITE_4(mac, base + offset, 0); | ||||
for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) { | ||||
offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS : | offset = (type == BHND_DMA_ADDR_64BIT) ? BWN_DMA64_RXSTATUS : | ||||
BWN_DMA32_RXSTATUS; | BWN_DMA32_RXSTATUS; | ||||
value = BWN_READ_4(mac, base + offset); | value = BWN_READ_4(mac, base + offset); | ||||
if (type == BWN_DMA_64BIT) { | if (type == BHND_DMA_ADDR_64BIT) { | ||||
value &= BWN_DMA64_RXSTAT; | value &= BWN_DMA64_RXSTAT; | ||||
if (value == BWN_DMA64_RXSTAT_DISABLED) { | if (value == BWN_DMA64_RXSTAT_DISABLED) { | ||||
i = -1; | i = -1; | ||||
break; | break; | ||||
} | } | ||||
} else { | } else { | ||||
value &= BWN_DMA32_RXSTATE; | value &= BWN_DMA32_RXSTATE; | ||||
if (value == BWN_DMA32_RXSTAT_DISABLED) { | if (value == BWN_DMA32_RXSTAT_DISABLED) { | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
bwn_bt_enable(struct bwn_mac *mac) | bwn_bt_enable(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint64_t hf; | uint64_t hf; | ||||
if (bwn_bluetooth == 0) | if (bwn_bluetooth == 0) | ||||
return; | return; | ||||
if ((siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCOEXIST) == 0) | if ((sc->sc_board_info.board_flags & BHND_BFL_BTCOEX) == 0) | ||||
return; | return; | ||||
if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode) | if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode) | ||||
return; | return; | ||||
hf = bwn_hf_read(mac); | hf = bwn_hf_read(mac); | ||||
if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_BTCMOD) | if (sc->sc_board_info.board_flags & BHND_BFL_BTC2WIRE_ALTGPIO) | ||||
hf |= BWN_HF_BT_COEXISTALT; | hf |= BWN_HF_BT_COEXISTALT; | ||||
else | else | ||||
hf |= BWN_HF_BT_COEXIST; | hf |= BWN_HF_BT_COEXIST; | ||||
bwn_hf_write(mac, hf); | bwn_hf_write(mac, hf); | ||||
} | } | ||||
static void | static void | ||||
bwn_set_macaddr(struct bwn_mac *mac) | bwn_set_macaddr(struct bwn_mac *mac) | ||||
Show All 23 Lines | bwn_clear_keys(struct bwn_mac *mac) | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
bwn_crypt_init(struct bwn_mac *mac) | bwn_crypt_init(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
mac->mac_max_nr_keys = (siba_get_revid(sc->sc_dev) >= 5) ? 58 : 20; | mac->mac_max_nr_keys = (bhnd_get_hwrev(sc->sc_dev) >= 5) ? 58 : 20; | ||||
KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key), | KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key), | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP); | mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP); | ||||
mac->mac_ktp *= 2; | mac->mac_ktp *= 2; | ||||
if (siba_get_revid(sc->sc_dev) >= 5) | if (bhnd_get_hwrev(sc->sc_dev) >= 5) | ||||
BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8); | BWN_WRITE_2(mac, BWN_RCMTA_COUNT, mac->mac_max_nr_keys - 8); | ||||
bwn_clear_keys(mac); | bwn_clear_keys(mac); | ||||
} | } | ||||
static void | static void | ||||
bwn_chip_exit(struct bwn_mac *mac) | bwn_chip_exit(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | |||||
bwn_phy_exit(mac); | bwn_phy_exit(mac); | ||||
siba_gpio_set(sc->sc_dev, 0); | |||||
} | } | ||||
static int | static int | ||||
bwn_fw_fillinfo(struct bwn_mac *mac) | bwn_fw_fillinfo(struct bwn_mac *mac) | ||||
{ | { | ||||
int error; | int error; | ||||
error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT); | error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT); | ||||
if (error == 0) | if (error == 0) | ||||
return (0); | return (0); | ||||
error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE); | error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE); | ||||
if (error == 0) | if (error == 0) | ||||
return (0); | return (0); | ||||
return (error); | return (error); | ||||
} | } | ||||
/** | |||||
* Request that the GPIO controller tristate all pins set in @p mask, granting | |||||
* the MAC core control over the pins. | |||||
* | |||||
* @param mac bwn MAC state. | |||||
* @param pins If the bit position for a pin number is set to one, tristate the | |||||
* pin. | |||||
*/ | |||||
int | |||||
bwn_gpio_control(struct bwn_mac *mac, uint32_t pins) | |||||
{ | |||||
struct bwn_softc *sc; | |||||
uint32_t flags[32]; | |||||
int error; | |||||
sc = mac->mac_sc; | |||||
/* Determine desired pin flags */ | |||||
for (size_t pin = 0; pin < nitems(flags); pin++) { | |||||
uint32_t pinbit = (1 << pin); | |||||
if (pins & pinbit) { | |||||
/* Tristate output */ | |||||
flags[pin] = GPIO_PIN_OUTPUT|GPIO_PIN_TRISTATE; | |||||
} else { | |||||
/* Leave unmodified */ | |||||
flags[pin] = 0; | |||||
} | |||||
} | |||||
/* Configure all pins */ | |||||
error = GPIO_PIN_CONFIG_32(sc->sc_gpio, 0, nitems(flags), flags); | |||||
if (error) { | |||||
device_printf(sc->sc_dev, "error configuring %s pin flags: " | |||||
"%d\n", device_get_nameunit(sc->sc_gpio), error); | |||||
return (error); | |||||
} | |||||
return (0); | |||||
} | |||||
static int | static int | ||||
bwn_gpio_init(struct bwn_mac *mac) | bwn_gpio_init(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc; | ||||
uint32_t mask = 0x1f, set = 0xf, value; | uint32_t pins; | ||||
sc = mac->mac_sc; | |||||
pins = 0xF; | |||||
BWN_WRITE_4(mac, BWN_MACCTL, | BWN_WRITE_4(mac, BWN_MACCTL, | ||||
BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK); | BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK); | ||||
BWN_WRITE_2(mac, BWN_GPIO_MASK, | BWN_WRITE_2(mac, BWN_GPIO_MASK, | ||||
BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f); | BWN_READ_2(mac, BWN_GPIO_MASK) | pins); | ||||
if (siba_get_chipid(sc->sc_dev) == 0x4301) { | if (sc->sc_board_info.board_flags & BHND_BFL_PACTRL) { | ||||
mask |= 0x0060; | /* MAC core is responsible for toggling PAREF via gpio9 */ | ||||
set |= 0x0060; | |||||
} | |||||
if (siba_sprom_get_bf_lo(sc->sc_dev) & BWN_BFL_PACTRL) { | |||||
BWN_WRITE_2(mac, BWN_GPIO_MASK, | BWN_WRITE_2(mac, BWN_GPIO_MASK, | ||||
BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200); | BWN_READ_2(mac, BWN_GPIO_MASK) | BHND_GPIO_BOARD_PACTRL); | ||||
mask |= 0x0200; | |||||
set |= 0x0200; | pins |= BHND_GPIO_BOARD_PACTRL; | ||||
} | } | ||||
if (siba_get_revid(sc->sc_dev) >= 2) | |||||
mask |= 0x0010; | |||||
value = siba_gpio_get(sc->sc_dev); | return (bwn_gpio_control(mac, pins)); | ||||
if (value == -1) | |||||
return (0); | |||||
siba_gpio_set(sc->sc_dev, (value & mask) | set); | |||||
return (0); | |||||
} | } | ||||
static int | static int | ||||
bwn_fw_loadinitvals(struct bwn_mac *mac) | bwn_fw_loadinitvals(struct bwn_mac *mac) | ||||
{ | { | ||||
#define GETFWOFFSET(fwp, offset) \ | #define GETFWOFFSET(fwp, offset) \ | ||||
((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset)) | ((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset)) | ||||
const size_t hdr_len = sizeof(struct bwn_fwhdr); | const size_t hdr_len = sizeof(struct bwn_fwhdr); | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | bwn_set_opmode(struct bwn_mac *mac) | ||||
if (ic->ic_opmode == IEEE80211_M_HOSTAP || | if (ic->ic_opmode == IEEE80211_M_HOSTAP || | ||||
ic->ic_opmode == IEEE80211_M_MBSS) | ic->ic_opmode == IEEE80211_M_MBSS) | ||||
ctl |= BWN_MACCTL_HOSTAP; | ctl |= BWN_MACCTL_HOSTAP; | ||||
else if (ic->ic_opmode == IEEE80211_M_IBSS) | else if (ic->ic_opmode == IEEE80211_M_IBSS) | ||||
ctl &= ~BWN_MACCTL_STA; | ctl &= ~BWN_MACCTL_STA; | ||||
ctl |= sc->sc_filters; | ctl |= sc->sc_filters; | ||||
if (siba_get_revid(sc->sc_dev) <= 4) | if (bhnd_get_hwrev(sc->sc_dev) <= 4) | ||||
ctl |= BWN_MACCTL_PROMISC; | ctl |= BWN_MACCTL_PROMISC; | ||||
BWN_WRITE_4(mac, BWN_MACCTL, ctl); | BWN_WRITE_4(mac, BWN_MACCTL, ctl); | ||||
cfp_pretbtt = 2; | cfp_pretbtt = 2; | ||||
if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) { | if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) { | ||||
if (siba_get_chipid(sc->sc_dev) == 0x4306 && | if (sc->sc_cid.chip_id == BHND_CHIPID_BCM4306 && | ||||
siba_get_chiprev(sc->sc_dev) == 3) | sc->sc_cid.chip_rev == 3) | ||||
cfp_pretbtt = 100; | cfp_pretbtt = 100; | ||||
else | else | ||||
cfp_pretbtt = 50; | cfp_pretbtt = 50; | ||||
} | } | ||||
BWN_WRITE_2(mac, 0x612, cfp_pretbtt); | BWN_WRITE_2(mac, 0x612, cfp_pretbtt); | ||||
} | } | ||||
static int | |||||
bwn_dma_gettype(struct bwn_mac *mac) | |||||
{ | |||||
uint32_t tmp; | |||||
uint16_t base; | |||||
tmp = BWN_READ_4(mac, SIBA_TGSHIGH); | |||||
if (tmp & SIBA_TGSHIGH_DMA64) | |||||
return (BWN_DMA_64BIT); | |||||
base = bwn_dma_base(0, 0); | |||||
BWN_WRITE_4(mac, base + BWN_DMA32_TXCTL, BWN_DMA32_TXADDREXT_MASK); | |||||
tmp = BWN_READ_4(mac, base + BWN_DMA32_TXCTL); | |||||
if (tmp & BWN_DMA32_TXADDREXT_MASK) | |||||
return (BWN_DMA_32BIT); | |||||
return (BWN_DMA_30BIT); | |||||
} | |||||
static void | static void | ||||
bwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error) | bwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error) | ||||
{ | { | ||||
if (!error) { | if (!error) { | ||||
KASSERT(nseg == 1, ("too many segments(%d)\n", nseg)); | KASSERT(nseg == 1, ("too many segments(%d)\n", nseg)); | ||||
*((bus_addr_t *)arg) = seg->ds_addr; | *((bus_addr_t *)arg) = seg->ds_addr; | ||||
} | } | ||||
} | } | ||||
Show All 19 Lines | bwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon) | ||||
BWN_ASSERT_LOCKED(mac->mac_sc); | BWN_ASSERT_LOCKED(mac->mac_sc); | ||||
for (i = 0; i < 5; i++) | for (i = 0; i < 5; i++) | ||||
bwn_ram_write(mac, i * 4, buffer[i]); | bwn_ram_write(mac, i * 4, buffer[i]); | ||||
BWN_WRITE_2(mac, 0x0568, 0x0000); | BWN_WRITE_2(mac, 0x0568, 0x0000); | ||||
BWN_WRITE_2(mac, 0x07c0, | BWN_WRITE_2(mac, 0x07c0, | ||||
(siba_get_revid(sc->sc_dev) < 11) ? 0x0000 : 0x0100); | (bhnd_get_hwrev(sc->sc_dev) < 11) ? 0x0000 : 0x0100); | ||||
value = (ofdm ? 0x41 : 0x40); | value = (ofdm ? 0x41 : 0x40); | ||||
BWN_WRITE_2(mac, 0x050c, value); | BWN_WRITE_2(mac, 0x050c, value); | ||||
if (phy->type == BWN_PHYTYPE_N || phy->type == BWN_PHYTYPE_LP || | if (phy->type == BWN_PHYTYPE_N || phy->type == BWN_PHYTYPE_LP || | ||||
phy->type == BWN_PHYTYPE_LCN) | phy->type == BWN_PHYTYPE_LCN) | ||||
BWN_WRITE_2(mac, 0x0514, 0x1a02); | BWN_WRITE_2(mac, 0x0514, 0x1a02); | ||||
BWN_WRITE_2(mac, 0x0508, 0x0000); | BWN_WRITE_2(mac, 0x0508, 0x0000); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | bwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val) | ||||
KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__)); | KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__)); | ||||
macctl = BWN_READ_4(mac, BWN_MACCTL); | macctl = BWN_READ_4(mac, BWN_MACCTL); | ||||
if (macctl & BWN_MACCTL_BIGENDIAN) | if (macctl & BWN_MACCTL_BIGENDIAN) | ||||
printf("TODO: need swap\n"); | printf("TODO: need swap\n"); | ||||
BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset); | BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset); | ||||
BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE); | BWN_BARRIER(mac, BWN_RAM_CONTROL, 4, BUS_SPACE_BARRIER_WRITE); | ||||
BWN_WRITE_4(mac, BWN_RAM_DATA, val); | BWN_WRITE_4(mac, BWN_RAM_DATA, val); | ||||
} | } | ||||
void | void | ||||
bwn_mac_suspend(struct bwn_mac *mac) | bwn_mac_suspend(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
int i; | int i; | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)), | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
/* XXX forcibly awake and hwps-off */ | /* XXX forcibly awake and hwps-off */ | ||||
BWN_WRITE_4(mac, BWN_MACCTL, | BWN_WRITE_4(mac, BWN_MACCTL, | ||||
(BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) & | (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) & | ||||
~BWN_MACCTL_HWPS); | ~BWN_MACCTL_HWPS); | ||||
BWN_READ_4(mac, BWN_MACCTL); | BWN_READ_4(mac, BWN_MACCTL); | ||||
if (siba_get_revid(sc->sc_dev) >= 5) { | if (bhnd_get_hwrev(sc->sc_dev) >= 5) { | ||||
for (i = 0; i < 100; i++) { | for (i = 0; i < 100; i++) { | ||||
ucstat = bwn_shm_read_2(mac, BWN_SHARED, | ucstat = bwn_shm_read_2(mac, BWN_SHARED, | ||||
BWN_SHARED_UCODESTAT); | BWN_SHARED_UCODESTAT); | ||||
if (ucstat != BWN_SHARED_UCODESTAT_SLEEP) | if (ucstat != BWN_SHARED_UCODESTAT_SLEEP) | ||||
break; | break; | ||||
DELAY(10); | DELAY(10); | ||||
} | } | ||||
} | } | ||||
DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: ucstat=%d\n", __func__, | DPRINTF(mac->mac_sc, BWN_DEBUG_RESET, "%s: ucstat=%d\n", __func__, | ||||
ucstat); | ucstat); | ||||
} | } | ||||
static int | static int | ||||
bwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type) | bwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
struct bwn_fw *fw = &mac->mac_fw; | struct bwn_fw *fw = &mac->mac_fw; | ||||
const uint8_t rev = siba_get_revid(sc->sc_dev); | const uint8_t rev = bhnd_get_hwrev(sc->sc_dev); | ||||
const char *filename; | const char *filename; | ||||
uint32_t high; | uint16_t iost; | ||||
int error; | int error; | ||||
/* microcode */ | /* microcode */ | ||||
filename = NULL; | filename = NULL; | ||||
switch (rev) { | switch (rev) { | ||||
case 42: | case 42: | ||||
if (mac->mac_phy.type == BWN_PHYTYPE_AC) | if (mac->mac_phy.type == BWN_PHYTYPE_AC) | ||||
filename = "ucode42"; | filename = "ucode42"; | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | if (rev >= 5 && rev <= 10) { | ||||
} | } | ||||
} else if (rev < 11) { | } else if (rev < 11) { | ||||
device_printf(sc->sc_dev, "no PCM for rev %d\n", rev); | device_printf(sc->sc_dev, "no PCM for rev %d\n", rev); | ||||
bwn_release_firmware(mac); | bwn_release_firmware(mac); | ||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | ||||
} | } | ||||
/* initvals */ | /* initvals */ | ||||
high = siba_read_4(sc->sc_dev, SIBA_TGSHIGH); | error = bhnd_read_iost(sc->sc_dev, &iost); | ||||
if (error) | |||||
goto fail1; | |||||
switch (mac->mac_phy.type) { | switch (mac->mac_phy.type) { | ||||
case BWN_PHYTYPE_A: | case BWN_PHYTYPE_A: | ||||
if (rev < 5 || rev > 10) | if (rev < 5 || rev > 10) | ||||
goto fail1; | goto fail1; | ||||
if (high & BWN_TGSHIGH_HAVE_2GHZ) | if (iost & BWN_IOST_HAVE_2GHZ) | ||||
filename = "a0g1initvals5"; | filename = "a0g1initvals5"; | ||||
else | else | ||||
filename = "a0g0initvals5"; | filename = "a0g0initvals5"; | ||||
break; | break; | ||||
case BWN_PHYTYPE_G: | case BWN_PHYTYPE_G: | ||||
if (rev >= 5 && rev <= 10) | if (rev >= 5 && rev <= 10) | ||||
filename = "b0g0initvals5"; | filename = "b0g0initvals5"; | ||||
else if (rev >= 13) | else if (rev >= 13) | ||||
Show All 35 Lines | if (error) { | ||||
bwn_release_firmware(mac); | bwn_release_firmware(mac); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* bandswitch initvals */ | /* bandswitch initvals */ | ||||
switch (mac->mac_phy.type) { | switch (mac->mac_phy.type) { | ||||
case BWN_PHYTYPE_A: | case BWN_PHYTYPE_A: | ||||
if (rev >= 5 && rev <= 10) { | if (rev >= 5 && rev <= 10) { | ||||
if (high & BWN_TGSHIGH_HAVE_2GHZ) | if (iost & BWN_IOST_HAVE_2GHZ) | ||||
filename = "a0g1bsinitvals5"; | filename = "a0g1bsinitvals5"; | ||||
else | else | ||||
filename = "a0g0bsinitvals5"; | filename = "a0g0bsinitvals5"; | ||||
} else if (rev >= 11) | } else if (rev >= 11) | ||||
filename = NULL; | filename = NULL; | ||||
else | else | ||||
goto fail1; | goto fail1; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 528 Lines • ▼ Show 20 Lines | if (addr) { | ||||
addrtmp[0] = addr[0]; | addrtmp[0] = addr[0]; | ||||
addrtmp[0] |= ((uint32_t) (addr[1]) << 8); | addrtmp[0] |= ((uint32_t) (addr[1]) << 8); | ||||
addrtmp[0] |= ((uint32_t) (addr[2]) << 16); | addrtmp[0] |= ((uint32_t) (addr[2]) << 16); | ||||
addrtmp[0] |= ((uint32_t) (addr[3]) << 24); | addrtmp[0] |= ((uint32_t) (addr[3]) << 24); | ||||
addrtmp[1] = addr[4]; | addrtmp[1] = addr[4]; | ||||
addrtmp[1] |= ((uint32_t) (addr[5]) << 8); | addrtmp[1] |= ((uint32_t) (addr[5]) << 8); | ||||
} | } | ||||
if (siba_get_revid(sc->sc_dev) >= 5) { | if (bhnd_get_hwrev(sc->sc_dev) >= 5) { | ||||
bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]); | bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]); | ||||
bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]); | bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]); | ||||
} else { | } else { | ||||
if (index >= 8) { | if (index >= 8) { | ||||
bwn_shm_write_4(mac, BWN_SHARED, | bwn_shm_write_4(mac, BWN_SHARED, | ||||
BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]); | BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]); | ||||
bwn_shm_write_2(mac, BWN_SHARED, | bwn_shm_write_2(mac, BWN_SHARED, | ||||
BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]); | BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]); | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | bwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan) | ||||
down_dev = sc->sc_curmac; | down_dev = sc->sc_curmac; | ||||
status = down_dev->mac_status; | status = down_dev->mac_status; | ||||
if (status >= BWN_MAC_STATUS_STARTED) | if (status >= BWN_MAC_STATUS_STARTED) | ||||
bwn_core_stop(down_dev); | bwn_core_stop(down_dev); | ||||
if (status >= BWN_MAC_STATUS_INITED) | if (status >= BWN_MAC_STATUS_INITED) | ||||
bwn_core_exit(down_dev); | bwn_core_exit(down_dev); | ||||
if (down_dev != up_dev) | if (down_dev != up_dev) { | ||||
bwn_phy_reset(down_dev); | err = bwn_phy_reset(down_dev); | ||||
if (err) | |||||
goto fail; | |||||
} | |||||
up_dev->mac_phy.gmode = gmode; | up_dev->mac_phy.gmode = gmode; | ||||
if (status >= BWN_MAC_STATUS_INITED) { | if (status >= BWN_MAC_STATUS_INITED) { | ||||
err = bwn_core_init(up_dev); | err = bwn_core_init(up_dev); | ||||
if (err) { | if (err) { | ||||
device_printf(sc->sc_dev, | device_printf(sc->sc_dev, | ||||
"fatal: failed to initialize for %s-GHz\n", | "fatal: failed to initialize for %s-GHz\n", | ||||
IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5"); | IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5"); | ||||
Show All 33 Lines | bwn_rf_turnoff(struct bwn_mac *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); | ||||
} | } | ||||
/* | /* | ||||
* PHY reset. | * PHY reset. | ||||
*/ | */ | ||||
static void | static int | ||||
bwn_phy_reset(struct bwn_mac *mac) | bwn_phy_reset(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc; | ||||
uint16_t iost, mask; | |||||
int error; | |||||
siba_write_4(sc->sc_dev, SIBA_TGSLOW, | sc = mac->mac_sc; | ||||
((siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) | | |||||
BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC); | iost = BWN_IOCTL_PHYRESET | BHND_IOCTL_CLK_FORCE; | ||||
mask = iost | BWN_IOCTL_SUPPORT_G; | |||||
if ((error = bhnd_write_ioctl(sc->sc_dev, iost, mask))) | |||||
return (error); | |||||
DELAY(1000); | DELAY(1000); | ||||
siba_write_4(sc->sc_dev, SIBA_TGSLOW, | |||||
(siba_read_4(sc->sc_dev, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC)); | iost &= ~BHND_IOCTL_CLK_FORCE; | ||||
if ((error = bhnd_write_ioctl(sc->sc_dev, iost, mask))) | |||||
return (error); | |||||
DELAY(1000); | DELAY(1000); | ||||
return (0); | |||||
} | } | ||||
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; | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | bwn_intr(void *arg) | ||||
BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]); | BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]); | ||||
BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]); | BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]); | ||||
/* Disable interrupts. */ | /* Disable interrupts. */ | ||||
BWN_WRITE_4(mac, BWN_INTR_MASK, 0); | BWN_WRITE_4(mac, BWN_INTR_MASK, 0); | ||||
mac->mac_reason_intr = reason; | mac->mac_reason_intr = reason; | ||||
BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ); | BWN_BARRIER(mac, 0, 0, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); | ||||
BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE); | |||||
taskqueue_enqueue(sc->sc_tq, &mac->mac_intrtask); | taskqueue_enqueue(sc->sc_tq, &mac->mac_intrtask); | ||||
return (FILTER_HANDLED); | return (FILTER_HANDLED); | ||||
} | } | ||||
static void | static void | ||||
bwn_intrtask(void *arg, int npending) | bwn_intrtask(void *arg, int npending) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | if (sc->sc_blink_led != NULL && sc->sc_led_blink) { | ||||
if (evt != BWN_LED_EVENT_NONE) | if (evt != BWN_LED_EVENT_NONE) | ||||
bwn_led_event(mac, evt); | bwn_led_event(mac, evt); | ||||
} | } | ||||
if (mbufq_first(&sc->sc_snd) != NULL) | if (mbufq_first(&sc->sc_snd) != NULL) | ||||
bwn_start(sc); | bwn_start(sc); | ||||
BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ); | BWN_BARRIER(mac, 0, 0, BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); | ||||
BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE); | |||||
BWN_UNLOCK(sc); | BWN_UNLOCK(sc); | ||||
} | } | ||||
static void | static void | ||||
bwn_restart(struct bwn_mac *mac, const char *msg) | bwn_restart(struct bwn_mac *mac, const char *msg) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
▲ Show 20 Lines • Show All 512 Lines • ▼ Show 20 Lines | for (i = 0; i < 10; i++) { | ||||
if (ctl16 & BWN_PIO_RXCTL_DATAREADY) | if (ctl16 & BWN_PIO_RXCTL_DATAREADY) | ||||
goto ready; | goto ready; | ||||
DELAY(10); | DELAY(10); | ||||
} | } | ||||
} | } | ||||
device_printf(sc->sc_dev, "%s: timed out\n", __func__); | device_printf(sc->sc_dev, "%s: timed out\n", __func__); | ||||
return (1); | return (1); | ||||
ready: | ready: | ||||
if (prq->prq_rev >= 8) | if (prq->prq_rev >= 8) { | ||||
siba_read_multi_4(sc->sc_dev, &rxhdr, sizeof(rxhdr), | bus_read_multi_4(sc->sc_mem_res, | ||||
prq->prq_base + BWN_PIO8_RXDATA); | prq->prq_base + BWN_PIO8_RXDATA, (void *)&rxhdr, | ||||
else | sizeof(rxhdr)); | ||||
siba_read_multi_2(sc->sc_dev, &rxhdr, sizeof(rxhdr), | } else { | ||||
prq->prq_base + BWN_PIO_RXDATA); | bus_read_multi_2(sc->sc_mem_res, | ||||
prq->prq_base + BWN_PIO_RXDATA, (void *)&rxhdr, | |||||
sizeof(rxhdr)); | |||||
} | |||||
len = le16toh(rxhdr.frame_len); | len = le16toh(rxhdr.frame_len); | ||||
if (len > 0x700) { | if (len > 0x700) { | ||||
device_printf(sc->sc_dev, "%s: len is too big\n", __func__); | device_printf(sc->sc_dev, "%s: len is too big\n", __func__); | ||||
goto error; | goto error; | ||||
} | } | ||||
if (len == 0) { | if (len == 0) { | ||||
device_printf(sc->sc_dev, "%s: len is 0\n", __func__); | device_printf(sc->sc_dev, "%s: len is 0\n", __func__); | ||||
goto error; | goto error; | ||||
Show All 21 Lines | ready: | ||||
KASSERT(totlen <= MCLBYTES, ("too big..\n")); | KASSERT(totlen <= MCLBYTES, ("too big..\n")); | ||||
m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); | ||||
if (m == NULL) { | if (m == NULL) { | ||||
device_printf(sc->sc_dev, "%s: out of memory", __func__); | device_printf(sc->sc_dev, "%s: out of memory", __func__); | ||||
goto error; | goto error; | ||||
} | } | ||||
mp = mtod(m, unsigned char *); | mp = mtod(m, unsigned char *); | ||||
if (prq->prq_rev >= 8) { | if (prq->prq_rev >= 8) { | ||||
siba_read_multi_4(sc->sc_dev, mp, (totlen & ~3), | bus_read_multi_4(sc->sc_mem_res, | ||||
prq->prq_base + BWN_PIO8_RXDATA); | prq->prq_base + BWN_PIO8_RXDATA, (void *)mp, (totlen & ~3)); | ||||
if (totlen & 3) { | if (totlen & 3) { | ||||
v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA); | v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA); | ||||
data = &(mp[totlen - 1]); | data = &(mp[totlen - 1]); | ||||
switch (totlen & 3) { | switch (totlen & 3) { | ||||
case 3: | case 3: | ||||
*data = (v32 >> 16); | *data = (v32 >> 16); | ||||
data--; | data--; | ||||
case 2: | case 2: | ||||
*data = (v32 >> 8); | *data = (v32 >> 8); | ||||
data--; | data--; | ||||
case 1: | case 1: | ||||
*data = v32; | *data = v32; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
siba_read_multi_2(sc->sc_dev, mp, (totlen & ~1), | bus_read_multi_2(sc->sc_mem_res, | ||||
prq->prq_base + BWN_PIO_RXDATA); | prq->prq_base + BWN_PIO_RXDATA, (void *)mp, (totlen & ~1)); | ||||
if (totlen & 1) { | if (totlen & 1) { | ||||
v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA); | v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA); | ||||
mp[totlen - 1] = v16; | mp[totlen - 1] = v16; | ||||
} | } | ||||
} | } | ||||
m->m_len = m->m_pkthdr.len = totlen; | m->m_len = m->m_pkthdr.len = totlen; | ||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | if (ofdm) { | ||||
if (tmp > 127) | if (tmp > 127) | ||||
tmp -= 256; | tmp -= 256; | ||||
tmp = tmp * 73 / 64; | tmp = tmp * 73 / 64; | ||||
if (adjust_2050) | if (adjust_2050) | ||||
tmp += 25; | tmp += 25; | ||||
else | else | ||||
tmp -= 3; | tmp -= 3; | ||||
} else { | } else { | ||||
if (siba_sprom_get_bf_lo(mac->mac_sc->sc_dev) | if (mac->mac_sc->sc_board_info.board_flags | ||||
& BWN_BFL_RSSI) { | & BHND_BFL_ADCDIV) { | ||||
if (in_rssi > 63) | if (in_rssi > 63) | ||||
in_rssi = 63; | in_rssi = 63; | ||||
tmp = gphy->pg_nrssi_lt[in_rssi]; | tmp = gphy->pg_nrssi_lt[in_rssi]; | ||||
tmp = (31 - tmp) * -131 / 128 - 57; | tmp = (31 - tmp) * -131 / 128 - 57; | ||||
} else { | } else { | ||||
tmp = in_rssi; | tmp = in_rssi; | ||||
tmp = (31 - tmp) * -149 / 128 - 68; | tmp = (31 - tmp) * -149 / 128 - 68; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 284 Lines • ▼ Show 20 Lines | bwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags) | ||||
bwn_txpwr_result_t result; | bwn_txpwr_result_t result; | ||||
BWN_GETTIME(now); | BWN_GETTIME(now); | ||||
if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime)) | if (!(flags & BWN_TXPWR_IGNORE_TIME) && ieee80211_time_before(now, phy->nexttime)) | ||||
return; | return; | ||||
phy->nexttime = now + 2 * 1000; | phy->nexttime = now + 2 * 1000; | ||||
if (siba_get_pci_subvendor(sc->sc_dev) == SIBA_BOARDVENDOR_BCM && | if (sc->sc_board_info.board_vendor == PCI_VENDOR_BROADCOM && | ||||
siba_get_pci_subdevice(sc->sc_dev) == SIBA_BOARD_BU4306) | sc->sc_board_info.board_type == BHND_BOARD_BU4306) | ||||
return; | return; | ||||
if (phy->recalc_txpwr != NULL) { | if (phy->recalc_txpwr != NULL) { | ||||
result = phy->recalc_txpwr(mac, | result = phy->recalc_txpwr(mac, | ||||
(flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0); | (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0); | ||||
if (result == BWN_TXPWR_RES_DONE) | if (result == BWN_TXPWR_RES_DONE) | ||||
return; | return; | ||||
KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST, | KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST, | ||||
▲ Show 20 Lines • Show All 466 Lines • ▼ Show 20 Lines | |||||
bwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n) | bwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint8_t mask; | uint8_t mask; | ||||
if (n == 0) | if (n == 0) | ||||
return (0); | return (0); | ||||
if (mac->mac_phy.gmode) | if (mac->mac_phy.gmode) | ||||
mask = siba_sprom_get_ant_bg(sc->sc_dev); | mask = sc->sc_ant2g; | ||||
else | else | ||||
mask = siba_sprom_get_ant_a(sc->sc_dev); | mask = sc->sc_ant5g; | ||||
if (!(mask & (1 << (n - 1)))) | if (!(mask & (1 << (n - 1)))) | ||||
return (0); | return (0); | ||||
return (n); | return (n); | ||||
} | } | ||||
/* | /* | ||||
* Return a fallback rate for the given rate. | * Return a fallback rate for the given rate. | ||||
* | * | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | bwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq, | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
uint32_t value = 0; | uint32_t value = 0; | ||||
const uint8_t *data = _data; | const uint8_t *data = _data; | ||||
ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 | | ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 | | ||||
BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31; | BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31; | ||||
bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl); | bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl); | ||||
siba_write_multi_4(sc->sc_dev, data, (len & ~3), | bus_write_multi_4(sc->sc_mem_res, tq->tq_base + BWN_PIO8_TXDATA, | ||||
tq->tq_base + BWN_PIO8_TXDATA); | __DECONST(void *, data), (len & ~3)); | ||||
if (len & 3) { | if (len & 3) { | ||||
ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 | | ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 | | ||||
BWN_PIO8_TXCTL_24_31); | BWN_PIO8_TXCTL_24_31); | ||||
data = &(data[len - 1]); | data = &(data[len - 1]); | ||||
switch (len & 3) { | switch (len & 3) { | ||||
case 3: | case 3: | ||||
ctl |= BWN_PIO8_TXCTL_16_23; | ctl |= BWN_PIO8_TXCTL_16_23; | ||||
value |= (uint32_t)(*data) << 16; | value |= (uint32_t)(*data) << 16; | ||||
Show All 25 Lines | bwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq, | ||||
uint16_t ctl, const void *_data, int len) | uint16_t ctl, const void *_data, int len) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
const uint8_t *data = _data; | const uint8_t *data = _data; | ||||
ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI; | ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI; | ||||
BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl); | BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl); | ||||
siba_write_multi_2(sc->sc_dev, data, (len & ~1), | bus_write_multi_2(sc->sc_mem_res, tq->tq_base + BWN_PIO_TXDATA, | ||||
tq->tq_base + BWN_PIO_TXDATA); | __DECONST(void *, data), (len & ~1)); | ||||
if (len & 1) { | if (len & 1) { | ||||
ctl &= ~BWN_PIO_TXCTL_WRITEHI; | ctl &= ~BWN_PIO_TXCTL_WRITEHI; | ||||
BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl); | BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl); | ||||
BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]); | BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]); | ||||
} | } | ||||
return (ctl); | return (ctl); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | bwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m, | ||||
sc->sc_rx_th.wr_antnoise = noise; | sc->sc_rx_th.wr_antnoise = noise; | ||||
} | } | ||||
static void | static void | ||||
bwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf) | bwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf) | ||||
{ | { | ||||
uint32_t low, high; | uint32_t low, high; | ||||
KASSERT(siba_get_revid(mac->mac_sc->sc_dev) >= 3, | KASSERT(bhnd_get_hwrev(mac->mac_sc->sc_dev) >= 3, | ||||
("%s:%d: fail", __func__, __LINE__)); | ("%s:%d: fail", __func__, __LINE__)); | ||||
low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW); | low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW); | ||||
high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH); | high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH); | ||||
*tsf = high; | *tsf = high; | ||||
*tsf <<= 32; | *tsf <<= 32; | ||||
*tsf |= low; | *tsf |= low; | ||||
} | } | ||||
static int | static int | ||||
bwn_dma_attach(struct bwn_mac *mac) | bwn_dma_attach(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_dma *dma = &mac->mac_method.dma; | struct bwn_dma *dma; | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc; | ||||
bus_addr_t lowaddr = 0; | struct bhnd_dma_translation *dt, dma_translation; | ||||
bhnd_addr_t addrext_req; | |||||
bus_dma_tag_t dmat; | |||||
bus_addr_t lowaddr; | |||||
u_int addrext_shift; | |||||
int error; | int error; | ||||
if (siba_get_type(sc->sc_dev) == SIBA_TYPE_PCMCIA || bwn_usedma == 0) | dma = &mac->mac_method.dma; | ||||
sc = mac->mac_sc; | |||||
dt = NULL; | |||||
if (sc->sc_quirks & BWN_QUIRK_NODMA) | |||||
return (0); | return (0); | ||||
KASSERT(siba_get_revid(sc->sc_dev) >= 5, ("%s: fail", __func__)); | KASSERT(bhnd_get_hwrev(sc->sc_dev) >= 5, ("%s: fail", __func__)); | ||||
/* Fetch our device->host DMA translation and tag */ | |||||
error = bhnd_get_dma_translation(sc->sc_dev, mac->mac_dmatype, 0, &dmat, | |||||
&dma_translation); | |||||
if (error) { | |||||
device_printf(sc->sc_dev, "error fetching DMA translation: " | |||||
"%d\n", error); | |||||
return (error); | |||||
} | |||||
/* Determine any DMA engine constraints to be applied to the | |||||
* translation's addrext mask */ | |||||
switch (mac->mac_dmatype) { | |||||
case BHND_DMA_ADDR_30BIT: | |||||
/* 32-bit engine has no addrext support */ | |||||
addrext_req = 0x0; | |||||
addrext_shift = 0; | |||||
break; | |||||
case BHND_DMA_ADDR_32BIT: | |||||
/* 32-bit engine with addrext support */ | |||||
addrext_req = BWN_DMA32_ADDREXT_MASK; | |||||
addrext_shift = BWN_DMA32_ADDREXT_SHIFT; | |||||
break; | |||||
case BHND_DMA_ADDR_64BIT: | |||||
/* 64-bit engine with addrext support */ | |||||
addrext_req = BWN_DMA64_ADDREXT_MASK; | |||||
addrext_shift = BWN_DMA64_ADDREXT_SHIFT; | |||||
break; | |||||
default: | |||||
device_printf(sc->sc_dev, "unsupported DMA address width: %d\n", | |||||
mac->mac_dmatype); | |||||
return (ENXIO); | |||||
} | |||||
/* Verify that our DMA engine's addrext constraints are compatible with | |||||
* our DMA translation */ | |||||
if (addrext_req != 0x0 && | |||||
(dma_translation.addrext_mask & addrext_req) != addrext_req) | |||||
{ | |||||
device_printf(sc->sc_dev, "bus addrext mask %#jx incompatible " | |||||
"with device addrext mask %#jx, disabling extended address " | |||||
"support\n", (uintmax_t)dma_translation.addrext_mask, | |||||
(uintmax_t)addrext_req); | |||||
addrext_req = 0x0; | |||||
addrext_shift = 0; | |||||
} | |||||
/* Apply our addrext translation constraint */ | |||||
dma_translation.addrext_mask = addrext_req; | |||||
/* Initialize our DMA engine configuration */ | |||||
mac->mac_flags |= BWN_MAC_FLAG_DMA; | mac->mac_flags |= BWN_MAC_FLAG_DMA; | ||||
dma->dmatype = bwn_dma_gettype(mac); | dma->addrext_shift = addrext_shift; | ||||
if (dma->dmatype == BWN_DMA_30BIT) | dma->translation = dma_translation; | ||||
lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT; | |||||
else if (dma->dmatype == BWN_DMA_32BIT) | |||||
lowaddr = BUS_SPACE_MAXADDR_32BIT; | |||||
else | |||||
lowaddr = BUS_SPACE_MAXADDR; | |||||
dt = &dma->translation; | |||||
/* Dermine our translation's maximum supported address */ | |||||
lowaddr = MIN((dt->addr_mask | dt->addrext_mask), BUS_SPACE_MAXADDR); | |||||
/* | /* | ||||
* Create top level DMA tag | * Create top level DMA tag | ||||
*/ | */ | ||||
error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */ | error = bus_dma_tag_create(dmat, /* parent */ | ||||
BWN_ALIGN, 0, /* alignment, bounds */ | BWN_ALIGN, 0, /* alignment, bounds */ | ||||
lowaddr, /* lowaddr */ | lowaddr, /* lowaddr */ | ||||
BUS_SPACE_MAXADDR, /* highaddr */ | BUS_SPACE_MAXADDR, /* highaddr */ | ||||
NULL, NULL, /* filter, filterarg */ | NULL, NULL, /* filter, filterarg */ | ||||
BUS_SPACE_MAXSIZE, /* maxsize */ | BUS_SPACE_MAXSIZE, /* maxsize */ | ||||
BUS_SPACE_UNRESTRICTED, /* nsegments */ | BUS_SPACE_UNRESTRICTED, /* nsegments */ | ||||
BUS_SPACE_MAXSIZE, /* maxsegsize */ | BUS_SPACE_MAXSIZE, /* maxsegsize */ | ||||
0, /* flags */ | 0, /* flags */ | ||||
Show All 35 Lines | error = bus_dma_tag_create(dma->parent_dtag, | ||||
0, | 0, | ||||
NULL, NULL, | NULL, NULL, | ||||
&dma->txbuf_dtag); | &dma->txbuf_dtag); | ||||
if (error) { | if (error) { | ||||
device_printf(sc->sc_dev, "can't create mbuf DMA tag\n"); | device_printf(sc->sc_dev, "can't create mbuf DMA tag\n"); | ||||
goto fail1; | goto fail1; | ||||
} | } | ||||
dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype); | dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1); | ||||
if (!dma->wme[WME_AC_BK]) | if (!dma->wme[WME_AC_BK]) | ||||
goto fail2; | goto fail2; | ||||
dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype); | dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1); | ||||
if (!dma->wme[WME_AC_BE]) | if (!dma->wme[WME_AC_BE]) | ||||
goto fail3; | goto fail3; | ||||
dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype); | dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1); | ||||
if (!dma->wme[WME_AC_VI]) | if (!dma->wme[WME_AC_VI]) | ||||
goto fail4; | goto fail4; | ||||
dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype); | dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1); | ||||
if (!dma->wme[WME_AC_VO]) | if (!dma->wme[WME_AC_VO]) | ||||
goto fail5; | goto fail5; | ||||
dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype); | dma->mcast = bwn_dma_ringsetup(mac, 4, 1); | ||||
if (!dma->mcast) | if (!dma->mcast) | ||||
goto fail6; | goto fail6; | ||||
dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype); | dma->rx = bwn_dma_ringsetup(mac, 0, 0); | ||||
if (!dma->rx) | if (!dma->rx) | ||||
goto fail7; | goto fail7; | ||||
return (error); | return (error); | ||||
fail7: bwn_dma_ringfree(&dma->mcast); | fail7: bwn_dma_ringfree(&dma->mcast); | ||||
fail6: bwn_dma_ringfree(&dma->wme[WME_AC_VO]); | fail6: bwn_dma_ringfree(&dma->wme[WME_AC_VO]); | ||||
fail5: bwn_dma_ringfree(&dma->wme[WME_AC_VI]); | fail5: bwn_dma_ringfree(&dma->wme[WME_AC_VI]); | ||||
▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | bwn_pio_stop(struct bwn_mac *mac) | ||||
bwn_destroy_queue_tx(&pio->mcast); | bwn_destroy_queue_tx(&pio->mcast); | ||||
bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]); | bwn_destroy_queue_tx(&pio->wme[WME_AC_VO]); | ||||
bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]); | bwn_destroy_queue_tx(&pio->wme[WME_AC_VI]); | ||||
bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]); | bwn_destroy_queue_tx(&pio->wme[WME_AC_BE]); | ||||
bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]); | bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]); | ||||
} | } | ||||
static void | static int | ||||
bwn_led_attach(struct bwn_mac *mac) | bwn_led_attach(struct bwn_mac *mac) | ||||
{ | { | ||||
struct bwn_softc *sc = mac->mac_sc; | struct bwn_softc *sc = mac->mac_sc; | ||||
const uint8_t *led_act = NULL; | const uint8_t *led_act = NULL; | ||||
uint16_t val[BWN_LED_MAX]; | int error; | ||||
int i; | int i; | ||||
sc->sc_led_idle = (2350 * hz) / 1000; | sc->sc_led_idle = (2350 * hz) / 1000; | ||||
sc->sc_led_blink = 1; | sc->sc_led_blink = 1; | ||||
for (i = 0; i < N(bwn_vendor_led_act); ++i) { | for (i = 0; i < N(bwn_vendor_led_act); ++i) { | ||||
if (siba_get_pci_subvendor(sc->sc_dev) == | if (sc->sc_board_info.board_vendor == | ||||
bwn_vendor_led_act[i].vid) { | bwn_vendor_led_act[i].vid) { | ||||
led_act = bwn_vendor_led_act[i].led_act; | led_act = bwn_vendor_led_act[i].led_act; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (led_act == NULL) | if (led_act == NULL) | ||||
led_act = bwn_default_led_act; | led_act = bwn_default_led_act; | ||||
val[0] = siba_sprom_get_gpio0(sc->sc_dev); | _Static_assert(nitems(bwn_led_vars) == BWN_LED_MAX, | ||||
val[1] = siba_sprom_get_gpio1(sc->sc_dev); | "invalid NVRAM variable name array"); | ||||
val[2] = siba_sprom_get_gpio2(sc->sc_dev); | |||||
val[3] = siba_sprom_get_gpio3(sc->sc_dev); | |||||
for (i = 0; i < BWN_LED_MAX; ++i) { | for (i = 0; i < BWN_LED_MAX; ++i) { | ||||
struct bwn_led *led = &sc->sc_leds[i]; | struct bwn_led *led; | ||||
uint8_t val; | |||||
if (val[i] == 0xff) { | led = &sc->sc_leds[i]; | ||||
KASSERT(i < nitems(bwn_led_vars), ("unknown LED index")); | |||||
error = bhnd_nvram_getvar_uint8(sc->sc_dev, bwn_led_vars[i], | |||||
&val); | |||||
if (error) { | |||||
if (error != ENOENT) { | |||||
device_printf(sc->sc_dev, "NVRAM variable %s " | |||||
"unreadable: %d", bwn_led_vars[i], error); | |||||
return (error); | |||||
} | |||||
/* Not found; use default */ | |||||
led->led_act = led_act[i]; | led->led_act = led_act[i]; | ||||
} else { | } else { | ||||
if (val[i] & BWN_LED_ACT_LOW) | if (val & BWN_LED_ACT_LOW) | ||||
led->led_flags |= BWN_LED_F_ACTLOW; | led->led_flags |= BWN_LED_F_ACTLOW; | ||||
led->led_act = val[i] & BWN_LED_ACT_MASK; | led->led_act = val & BWN_LED_ACT_MASK; | ||||
} | } | ||||
led->led_mask = (1 << i); | led->led_mask = (1 << i); | ||||
if (led->led_act == BWN_LED_ACT_BLINK_SLOW || | if (led->led_act == BWN_LED_ACT_BLINK_SLOW || | ||||
led->led_act == BWN_LED_ACT_BLINK_POLL || | led->led_act == BWN_LED_ACT_BLINK_POLL || | ||||
led->led_act == BWN_LED_ACT_BLINK) { | led->led_act == BWN_LED_ACT_BLINK) { | ||||
led->led_flags |= BWN_LED_F_BLINK; | led->led_flags |= BWN_LED_F_BLINK; | ||||
if (led->led_act == BWN_LED_ACT_BLINK_POLL) | if (led->led_act == BWN_LED_ACT_BLINK_POLL) | ||||
led->led_flags |= BWN_LED_F_POLLABLE; | led->led_flags |= BWN_LED_F_POLLABLE; | ||||
else if (led->led_act == BWN_LED_ACT_BLINK_SLOW) | else if (led->led_act == BWN_LED_ACT_BLINK_SLOW) | ||||
led->led_flags |= BWN_LED_F_SLOW; | led->led_flags |= BWN_LED_F_SLOW; | ||||
if (sc->sc_blink_led == NULL) { | if (sc->sc_blink_led == NULL) { | ||||
sc->sc_blink_led = led; | sc->sc_blink_led = led; | ||||
if (led->led_flags & BWN_LED_F_SLOW) | if (led->led_flags & BWN_LED_F_SLOW) | ||||
BWN_LED_SLOWDOWN(sc->sc_led_idle); | BWN_LED_SLOWDOWN(sc->sc_led_idle); | ||||
} | } | ||||
} | } | ||||
DPRINTF(sc, BWN_DEBUG_LED, | DPRINTF(sc, BWN_DEBUG_LED, | ||||
"%dth led, act %d, lowact %d\n", i, | "%dth led, act %d, lowact %d\n", i, | ||||
led->led_act, led->led_flags & BWN_LED_F_ACTLOW); | led->led_act, led->led_flags & BWN_LED_F_ACTLOW); | ||||
} | } | ||||
callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0); | callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0); | ||||
return (0); | |||||
} | } | ||||
static __inline uint16_t | static __inline uint16_t | ||||
bwn_led_onoff(const struct bwn_led *led, uint16_t val, int on) | bwn_led_onoff(const struct bwn_led *led, uint16_t val, int on) | ||||
{ | { | ||||
if (led->led_flags & BWN_LED_F_ACTLOW) | if (led->led_flags & BWN_LED_F_ACTLOW) | ||||
on = !on; | on = !on; | ||||
▲ Show 20 Lines • Show All 254 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 | ||||
}; | }; | ||||
driver_t bwn_driver = { | static 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, bhnd, bwn_driver, bwn_devclass, 0, 0); | ||||
MODULE_DEPEND(bwn, siba_bwn, 1, 1, 1); | MODULE_DEPEND(bwn, bhnd, 1, 1, 1); | ||||
MODULE_DEPEND(bwn, gpiobus, 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); |