summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorweongyo <weongyo@FreeBSD.org>2010-04-20 21:40:09 +0000
committerweongyo <weongyo@FreeBSD.org>2010-04-20 21:40:09 +0000
commitc8cdd2e9e85ca658e8c4ef843e5bc983f3dbb393 (patch)
tree5c148b509ce62110d1ae8741deeb43bc82856f30
parentfd4bc17e03aee0abfdaaa6e0418d29ee8870e4f1 (diff)
downloadFreeBSD-src-c8cdd2e9e85ca658e8c4ef843e5bc983f3dbb393.zip
FreeBSD-src-c8cdd2e9e85ca658e8c4ef843e5bc983f3dbb393.tar.gz
MFC r203945:
adds bwn(4) driver for supporting Broadcom BCM43xx chipsets. o uses v4 firmware instead of v3. A port will be committed to create the bwn firmware module. o supports B/G and LP(low power) PHYs. o supports 32 / 64 bits DMA operations. o tested on big / little endian machines so should work on all architectures. It'd not connected to the build until the firmware port is committed.
-rw-r--r--sys/dev/bwn/if_bwn.c14317
-rw-r--r--sys/dev/bwn/if_bwnreg.h998
-rw-r--r--sys/dev/bwn/if_bwnvar.h957
-rw-r--r--sys/modules/bwn/Makefile9
4 files changed, 16281 insertions, 0 deletions
diff --git a/sys/dev/bwn/if_bwn.c b/sys/dev/bwn/if_bwn.c
new file mode 100644
index 0000000..6120474
--- /dev/null
+++ b/sys/dev/bwn/if_bwn.c
@@ -0,0 +1,14317 @@
+/*-
+ * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * The Broadcom Wireless LAN controller driver.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/module.h>
+#include <sys/kernel.h>
+#include <sys/endian.h>
+#include <sys/errno.h>
+#include <sys/firmware.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <net/if_dl.h>
+#include <net/if_llc.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/siba/siba_ids.h>
+#include <dev/siba/sibareg.h>
+#include <dev/siba/sibavar.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+#include <net80211/ieee80211_regdomain.h>
+#include <net80211/ieee80211_amrr.h>
+#include <net80211/ieee80211_phy.h>
+
+#include <dev/bwn/if_bwnreg.h>
+#include <dev/bwn/if_bwnvar.h>
+
+SYSCTL_NODE(_hw, OID_AUTO, bwn, CTLFLAG_RD, 0, "Broadcom driver parameters");
+
+/*
+ * Tunable & sysctl variables.
+ */
+
+#ifdef BWN_DEBUG
+static int bwn_debug = 0;
+SYSCTL_INT(_hw_bwn, OID_AUTO, debug, CTLFLAG_RW, &bwn_debug, 0,
+ "Broadcom debugging printfs");
+TUNABLE_INT("hw.bwn.debug", &bwn_debug);
+enum {
+ BWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
+ BWN_DEBUG_RECV = 0x00000002, /* basic recv operation */
+ BWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */
+ BWN_DEBUG_TXPOW = 0x00000008, /* tx power processing */
+ BWN_DEBUG_RESET = 0x00000010, /* reset processing */
+ BWN_DEBUG_OPS = 0x00000020, /* bwn_ops processing */
+ BWN_DEBUG_BEACON = 0x00000040, /* beacon handling */
+ BWN_DEBUG_WATCHDOG = 0x00000080, /* watchdog timeout */
+ BWN_DEBUG_INTR = 0x00000100, /* ISR */
+ BWN_DEBUG_CALIBRATE = 0x00000200, /* periodic calibration */
+ BWN_DEBUG_NODE = 0x00000400, /* node management */
+ BWN_DEBUG_LED = 0x00000800, /* led management */
+ BWN_DEBUG_CMD = 0x00001000, /* cmd submission */
+ BWN_DEBUG_LO = 0x00002000, /* LO */
+ BWN_DEBUG_FW = 0x00004000, /* firmware */
+ BWN_DEBUG_WME = 0x00008000, /* WME */
+ BWN_DEBUG_RF = 0x00010000, /* RF */
+ BWN_DEBUG_FATAL = 0x80000000, /* fatal errors */
+ BWN_DEBUG_ANY = 0xffffffff
+};
+#define DPRINTF(sc, m, fmt, ...) do { \
+ if (sc->sc_debug & (m)) \
+ printf(fmt, __VA_ARGS__); \
+} while (0)
+#else
+#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
+#endif
+
+static int bwn_bfp = 0; /* use "Bad Frames Preemption" */
+SYSCTL_INT(_hw_bwn, OID_AUTO, bfp, CTLFLAG_RW, &bwn_bfp, 0,
+ "uses Bad Frames Preemption");
+static int bwn_bluetooth = 1;
+SYSCTL_INT(_hw_bwn, OID_AUTO, bluetooth, CTLFLAG_RW, &bwn_bluetooth, 0,
+ "turns on Bluetooth Coexistence");
+static int bwn_hwpctl = 0;
+SYSCTL_INT(_hw_bwn, OID_AUTO, hwpctl, CTLFLAG_RW, &bwn_hwpctl, 0,
+ "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;
+SYSCTL_INT(_hw_bwn, OID_AUTO, usedma, CTLFLAG_RD, &bwn_usedma, 0,
+ "uses DMA");
+TUNABLE_INT("hw.bwn.usedma", &bwn_usedma);
+static int bwn_wme = 1;
+SYSCTL_INT(_hw_bwn, OID_AUTO, wme, CTLFLAG_RW, &bwn_wme, 0,
+ "uses WME support");
+
+static int bwn_attach_pre(struct bwn_softc *);
+static int bwn_attach_post(struct bwn_softc *);
+static void bwn_sprom_bugfixes(struct siba_softc *);
+static void bwn_init(void *);
+static int bwn_init_locked(struct bwn_softc *);
+static int bwn_ioctl(struct ifnet *, u_long, caddr_t);
+static void bwn_start(struct ifnet *);
+static int bwn_attach_core(struct bwn_mac *);
+static void bwn_reset_core(struct bwn_mac *, uint32_t);
+static int bwn_phy_getinfo(struct bwn_mac *, int);
+static int bwn_chiptest(struct bwn_mac *);
+static int bwn_setup_channels(struct bwn_mac *, int, int);
+static int bwn_phy_g_attach(struct bwn_mac *);
+static void bwn_phy_g_detach(struct bwn_mac *);
+static void bwn_phy_g_init_pre(struct bwn_mac *);
+static int bwn_phy_g_prepare_hw(struct bwn_mac *);
+static int bwn_phy_g_init(struct bwn_mac *);
+static void bwn_phy_g_exit(struct bwn_mac *);
+static uint16_t bwn_phy_g_read(struct bwn_mac *, uint16_t);
+static void bwn_phy_g_write(struct bwn_mac *, uint16_t,
+ uint16_t);
+static uint16_t bwn_phy_g_rf_read(struct bwn_mac *, uint16_t);
+static void bwn_phy_g_rf_write(struct bwn_mac *, uint16_t,
+ uint16_t);
+static int bwn_phy_g_hwpctl(struct bwn_mac *);
+static void bwn_phy_g_rf_onoff(struct bwn_mac *, int);
+static int bwn_phy_g_switch_channel(struct bwn_mac *, uint32_t);
+static uint32_t bwn_phy_g_get_default_chan(struct bwn_mac *);
+static void bwn_phy_g_set_antenna(struct bwn_mac *, int);
+static int bwn_phy_g_im(struct bwn_mac *, int);
+static int bwn_phy_g_recalc_txpwr(struct bwn_mac *, int);
+static void bwn_phy_g_set_txpwr(struct bwn_mac *);
+static void bwn_phy_g_task_15s(struct bwn_mac *);
+static void bwn_phy_g_task_60s(struct bwn_mac *);
+static uint16_t bwn_phy_g_txctl(struct bwn_mac *);
+static void bwn_phy_switch_analog(struct bwn_mac *, int);
+static uint16_t bwn_shm_read_2(struct bwn_mac *, uint16_t, uint16_t);
+static void bwn_shm_write_2(struct bwn_mac *, uint16_t, uint16_t,
+ uint16_t);
+static uint32_t bwn_shm_read_4(struct bwn_mac *, uint16_t, uint16_t);
+static void bwn_shm_write_4(struct bwn_mac *, uint16_t, uint16_t,
+ uint32_t);
+static void bwn_shm_ctlword(struct bwn_mac *, uint16_t,
+ uint16_t);
+static void bwn_addchannels(struct ieee80211_channel [], int, int *,
+ const struct bwn_channelinfo *, int);
+static int bwn_raw_xmit(struct ieee80211_node *, struct mbuf *,
+ const struct ieee80211_bpf_params *);
+static void bwn_newassoc(struct ieee80211_node *, int);
+static void bwn_updateslot(struct ifnet *);
+static void bwn_update_promisc(struct ifnet *);
+static void bwn_wme_init(struct bwn_mac *);
+static int bwn_wme_update(struct ieee80211com *);
+static struct ieee80211_node *bwn_node_alloc(struct ieee80211vap *,
+ const uint8_t [IEEE80211_ADDR_LEN]);
+static void bwn_wme_clear(struct bwn_softc *);
+static void bwn_wme_load(struct bwn_mac *);
+static void bwn_wme_loadparams(struct bwn_mac *,
+ const struct wmeParams *, uint16_t);
+static void bwn_node_cleanup(struct ieee80211_node *);
+static void bwn_scan_start(struct ieee80211com *);
+static void bwn_scan_end(struct ieee80211com *);
+static void bwn_set_channel(struct ieee80211com *);
+static struct ieee80211vap *bwn_vap_create(struct ieee80211com *,
+ const char [IFNAMSIZ], int, int,
+ int, const uint8_t [IEEE80211_ADDR_LEN],
+ const uint8_t [IEEE80211_ADDR_LEN]);
+static void bwn_vap_delete(struct ieee80211vap *);
+static void bwn_stop(struct bwn_softc *, int);
+static void bwn_stop_locked(struct bwn_softc *, int);
+static int bwn_core_init(struct bwn_mac *);
+static void bwn_core_start(struct bwn_mac *);
+static void bwn_core_exit(struct bwn_mac *);
+static void bwn_fix_imcfglobug(struct bwn_mac *);
+static void bwn_bt_disable(struct bwn_mac *);
+static int bwn_chip_init(struct bwn_mac *);
+static uint64_t bwn_hf_read(struct bwn_mac *);
+static void bwn_hf_write(struct bwn_mac *, uint64_t);
+static void bwn_set_txretry(struct bwn_mac *, int, int);
+static void bwn_rate_init(struct bwn_mac *);
+static void bwn_set_phytxctl(struct bwn_mac *);
+static void bwn_spu_setdelay(struct bwn_mac *, int);
+static void bwn_bt_enable(struct bwn_mac *);
+static void bwn_set_macaddr(struct bwn_mac *);
+static void bwn_crypt_init(struct bwn_mac *);
+static void bwn_chip_exit(struct bwn_mac *);
+static int bwn_fw_fillinfo(struct bwn_mac *);
+static int bwn_fw_loaducode(struct bwn_mac *);
+static int bwn_gpio_init(struct bwn_mac *);
+static int bwn_fw_loadinitvals(struct bwn_mac *);
+static int bwn_phy_init(struct bwn_mac *);
+static void bwn_set_txantenna(struct bwn_mac *, int);
+static void bwn_set_opmode(struct bwn_mac *);
+static void bwn_gpio_cleanup(struct bwn_mac *);
+static void bwn_rate_write(struct bwn_mac *, uint16_t, int);
+static uint8_t bwn_plcp_getcck(const uint8_t);
+static uint8_t bwn_plcp_getofdm(const uint8_t);
+static void bwn_pio_init(struct bwn_mac *);
+static uint16_t bwn_pio_idx2base(struct bwn_mac *, int);
+static void bwn_pio_set_txqueue(struct bwn_mac *, struct bwn_pio_txqueue *,
+ int);
+static void bwn_pio_setupqueue_rx(struct bwn_mac *,
+ struct bwn_pio_rxqueue *, int);
+static void bwn_destroy_queue_tx(struct bwn_pio_txqueue *);
+static uint16_t bwn_pio_read_2(struct bwn_mac *, struct bwn_pio_txqueue *,
+ uint16_t);
+static void bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *);
+static int bwn_pio_rx(struct bwn_pio_rxqueue *);
+static uint8_t bwn_pio_rxeof(struct bwn_pio_rxqueue *);
+static void bwn_pio_handle_txeof(struct bwn_mac *,
+ const struct bwn_txstatus *);
+static uint16_t bwn_pio_rx_read_2(struct bwn_pio_rxqueue *, uint16_t);
+static uint32_t bwn_pio_rx_read_4(struct bwn_pio_rxqueue *, uint16_t);
+static void bwn_pio_rx_write_2(struct bwn_pio_rxqueue *, uint16_t,
+ uint16_t);
+static void bwn_pio_rx_write_4(struct bwn_pio_rxqueue *, uint16_t,
+ uint32_t);
+static int bwn_pio_tx_start(struct bwn_mac *, struct ieee80211_node *,
+ struct mbuf *);
+static struct bwn_pio_txqueue *bwn_pio_select(struct bwn_mac *, uint8_t);
+static uint32_t bwn_pio_write_multi_4(struct bwn_mac *,
+ struct bwn_pio_txqueue *, uint32_t, const void *, int);
+static void bwn_pio_write_4(struct bwn_mac *, struct bwn_pio_txqueue *,
+ uint16_t, uint32_t);
+static uint16_t bwn_pio_write_multi_2(struct bwn_mac *,
+ struct bwn_pio_txqueue *, uint16_t, const void *, int);
+static uint16_t bwn_pio_write_mbuf_2(struct bwn_mac *,
+ struct bwn_pio_txqueue *, uint16_t, struct mbuf *);
+static struct bwn_pio_txqueue *bwn_pio_parse_cookie(struct bwn_mac *,
+ uint16_t, struct bwn_pio_txpkt **);
+static void bwn_dma_init(struct bwn_mac *);
+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 void bwn_dma_ringfree(struct bwn_dma_ring **);
+static void bwn_dma_32_getdesc(struct bwn_dma_ring *,
+ int, struct bwn_dmadesc_generic **,
+ struct bwn_dmadesc_meta **);
+static void bwn_dma_32_setdesc(struct bwn_dma_ring *,
+ struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
+ int, int);
+static void bwn_dma_32_start_transfer(struct bwn_dma_ring *, int);
+static void bwn_dma_32_suspend(struct bwn_dma_ring *);
+static void bwn_dma_32_resume(struct bwn_dma_ring *);
+static int bwn_dma_32_get_curslot(struct bwn_dma_ring *);
+static void bwn_dma_32_set_curslot(struct bwn_dma_ring *, int);
+static void bwn_dma_64_getdesc(struct bwn_dma_ring *,
+ int, struct bwn_dmadesc_generic **,
+ struct bwn_dmadesc_meta **);
+static void bwn_dma_64_setdesc(struct bwn_dma_ring *,
+ struct bwn_dmadesc_generic *, bus_addr_t, uint16_t, int,
+ int, int);
+static void bwn_dma_64_start_transfer(struct bwn_dma_ring *, int);
+static void bwn_dma_64_suspend(struct bwn_dma_ring *);
+static void bwn_dma_64_resume(struct bwn_dma_ring *);
+static int bwn_dma_64_get_curslot(struct bwn_dma_ring *);
+static void bwn_dma_64_set_curslot(struct bwn_dma_ring *, int);
+static int bwn_dma_allocringmemory(struct bwn_dma_ring *);
+static void bwn_dma_setup(struct bwn_dma_ring *);
+static void bwn_dma_free_ringmemory(struct bwn_dma_ring *);
+static void bwn_dma_cleanup(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 void bwn_dma_rx(struct bwn_dma_ring *);
+static int bwn_dma_rx_reset(struct bwn_mac *, uint16_t, int);
+static void bwn_dma_free_descbuf(struct bwn_dma_ring *,
+ struct bwn_dmadesc_meta *);
+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 int bwn_dma_freeslot(struct bwn_dma_ring *);
+static int bwn_dma_nextslot(struct bwn_dma_ring *, int);
+static void bwn_dma_rxeof(struct bwn_dma_ring *, int *);
+static int bwn_dma_newbuf(struct bwn_dma_ring *,
+ struct bwn_dmadesc_generic *, struct bwn_dmadesc_meta *,
+ int);
+static void bwn_dma_buf_addr(void *, bus_dma_segment_t *, int,
+ bus_size_t, int);
+static uint8_t bwn_dma_check_redzone(struct bwn_dma_ring *, struct mbuf *);
+static void bwn_dma_handle_txeof(struct bwn_mac *,
+ const struct bwn_txstatus *);
+static int bwn_dma_tx_start(struct bwn_mac *, struct ieee80211_node *,
+ struct mbuf *);
+static int bwn_dma_getslot(struct bwn_dma_ring *);
+static struct bwn_dma_ring *bwn_dma_select(struct bwn_mac *,
+ uint8_t);
+static int bwn_dma_attach(struct bwn_mac *);
+static struct bwn_dma_ring *bwn_dma_ringsetup(struct bwn_mac *,
+ int, int, int);
+static struct bwn_dma_ring *bwn_dma_parse_cookie(struct bwn_mac *,
+ const struct bwn_txstatus *, uint16_t, int *);
+static void bwn_dma_free(struct bwn_mac *);
+static void bwn_phy_g_init_sub(struct bwn_mac *);
+static uint8_t bwn_has_hwpctl(struct bwn_mac *);
+static void bwn_phy_init_b5(struct bwn_mac *);
+static void bwn_phy_init_b6(struct bwn_mac *);
+static void bwn_phy_init_a(struct bwn_mac *);
+static void bwn_loopback_calcgain(struct bwn_mac *);
+static uint16_t bwn_rf_init_bcm2050(struct bwn_mac *);
+static void bwn_lo_g_init(struct bwn_mac *);
+static void bwn_lo_g_adjust(struct bwn_mac *);
+static void bwn_lo_get_powervector(struct bwn_mac *);
+static struct bwn_lo_calib *bwn_lo_calibset(struct bwn_mac *,
+ const struct bwn_bbatt *, const struct bwn_rfatt *);
+static void bwn_lo_write(struct bwn_mac *, struct bwn_loctl *);
+static void bwn_phy_hwpctl_init(struct bwn_mac *);
+static void bwn_phy_g_switch_chan(struct bwn_mac *, int, uint8_t);
+static void bwn_phy_g_set_txpwr_sub(struct bwn_mac *,
+ const struct bwn_bbatt *, const struct bwn_rfatt *,
+ uint8_t);
+static void bwn_phy_g_set_bbatt(struct bwn_mac *, uint16_t);
+static uint16_t bwn_rf_2050_rfoverval(struct bwn_mac *, uint16_t, uint32_t);
+static void bwn_spu_workaround(struct bwn_mac *, uint8_t);
+static void bwn_wa_init(struct bwn_mac *);
+static void bwn_ofdmtab_write_2(struct bwn_mac *, uint16_t, uint16_t,
+ uint16_t);
+static void bwn_dummy_transmission(struct bwn_mac *, int, int);
+static void bwn_ofdmtab_write_4(struct bwn_mac *, uint16_t, uint16_t,
+ uint32_t);
+static void bwn_gtab_write(struct bwn_mac *, uint16_t, uint16_t,
+ uint16_t);
+static void bwn_ram_write(struct bwn_mac *, uint16_t, uint32_t);
+static void bwn_mac_suspend(struct bwn_mac *);
+static void bwn_mac_enable(struct bwn_mac *);
+static void bwn_psctl(struct bwn_mac *, uint32_t);
+static int16_t bwn_nrssi_read(struct bwn_mac *, uint16_t);
+static void bwn_nrssi_offset(struct bwn_mac *);
+static void bwn_nrssi_threshold(struct bwn_mac *);
+static void bwn_nrssi_slope_11g(struct bwn_mac *);
+static void bwn_set_all_gains(struct bwn_mac *, int16_t, int16_t,
+ int16_t);
+static void bwn_set_original_gains(struct bwn_mac *);
+static void bwn_hwpctl_early_init(struct bwn_mac *);
+static void bwn_hwpctl_init_gphy(struct bwn_mac *);
+static uint16_t bwn_phy_g_chan2freq(uint8_t);
+static int bwn_fw_gets(struct bwn_mac *, enum bwn_fwtype);
+static int bwn_fw_get(struct bwn_mac *, enum bwn_fwtype,
+ const char *, struct bwn_fwfile *);
+static void bwn_release_firmware(struct bwn_mac *);
+static void bwn_do_release_fw(struct bwn_fwfile *);
+static uint16_t bwn_fwcaps_read(struct bwn_mac *);
+static int bwn_fwinitvals_write(struct bwn_mac *,
+ const struct bwn_fwinitvals *, size_t, size_t);
+static int bwn_switch_channel(struct bwn_mac *, int);
+static uint16_t bwn_ant2phy(int);
+static void bwn_mac_write_bssid(struct bwn_mac *);
+static void bwn_mac_setfilter(struct bwn_mac *, uint16_t,
+ const uint8_t *);
+static void bwn_key_dowrite(struct bwn_mac *, uint8_t, uint8_t,
+ const uint8_t *, size_t, const uint8_t *);
+static void bwn_key_macwrite(struct bwn_mac *, uint8_t,
+ const uint8_t *);
+static void bwn_key_write(struct bwn_mac *, uint8_t, uint8_t,
+ const uint8_t *);
+static void bwn_phy_exit(struct bwn_mac *);
+static void bwn_core_stop(struct bwn_mac *);
+static int bwn_switch_band(struct bwn_softc *,
+ struct ieee80211_channel *);
+static void bwn_phy_reset(struct bwn_mac *);
+static int bwn_newstate(struct ieee80211vap *, enum ieee80211_state, int);
+static void bwn_set_pretbtt(struct bwn_mac *);
+static int bwn_intr(void *);
+static void bwn_intrtask(void *, int);
+static void bwn_restart(struct bwn_mac *, const char *);
+static void bwn_intr_ucode_debug(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_beacon(struct bwn_mac *);
+static void bwn_intr_pmq(struct bwn_mac *);
+static void bwn_intr_noise(struct bwn_mac *);
+static void bwn_intr_txeof(struct bwn_mac *);
+static void bwn_hwreset(void *, int);
+static void bwn_handle_fwpanic(struct bwn_mac *);
+static void bwn_load_beacon0(struct bwn_mac *);
+static void bwn_load_beacon1(struct bwn_mac *);
+static uint32_t bwn_jssi_read(struct bwn_mac *);
+static void bwn_noise_gensample(struct bwn_mac *);
+static void bwn_handle_txeof(struct bwn_mac *,
+ const struct bwn_txstatus *);
+static void bwn_rxeof(struct bwn_mac *, struct mbuf *, const void *);
+static void bwn_phy_txpower_check(struct bwn_mac *, uint32_t);
+static void bwn_start_locked(struct ifnet *);
+static int bwn_tx_start(struct bwn_softc *, struct ieee80211_node *,
+ struct mbuf *);
+static int bwn_tx_isfull(struct bwn_softc *, struct mbuf *);
+static int bwn_set_txhdr(struct bwn_mac *,
+ struct ieee80211_node *, struct mbuf *, struct bwn_txhdr *,
+ uint16_t);
+static void bwn_plcp_genhdr(struct bwn_plcp4 *, const uint16_t,
+ const uint8_t);
+static uint8_t bwn_antenna_sanitize(struct bwn_mac *, uint8_t);
+static uint8_t bwn_get_fbrate(uint8_t);
+static int bwn_phy_shm_tssi_read(struct bwn_mac *, uint16_t);
+static void bwn_phy_g_setatt(struct bwn_mac *, int *, int *);
+static void bwn_phy_lock(struct bwn_mac *);
+static void bwn_phy_unlock(struct bwn_mac *);
+static void bwn_rf_lock(struct bwn_mac *);
+static void bwn_rf_unlock(struct bwn_mac *);
+static void bwn_txpwr(void *, int);
+static void bwn_tasks(void *);
+static void bwn_task_15s(struct bwn_mac *);
+static void bwn_task_30s(struct bwn_mac *);
+static void bwn_task_60s(struct bwn_mac *);
+static int bwn_plcp_get_ofdmrate(struct bwn_mac *, struct bwn_plcp6 *,
+ uint8_t);
+static int bwn_plcp_get_cckrate(struct bwn_mac *, struct bwn_plcp6 *);
+static void bwn_rx_radiotap(struct bwn_mac *, struct mbuf *,
+ const struct bwn_rxhdr4 *, struct bwn_plcp6 *, int,
+ int, int);
+static void bwn_tsf_read(struct bwn_mac *, uint64_t *);
+static void bwn_phy_g_dc_lookup_init(struct bwn_mac *, uint8_t);
+static void bwn_set_slot_time(struct bwn_mac *, uint16_t);
+static void bwn_watchdog(void *);
+static void bwn_dma_stop(struct bwn_mac *);
+static void bwn_pio_stop(struct bwn_mac *);
+static void bwn_dma_ringstop(struct bwn_dma_ring **);
+static void bwn_led_attach(struct bwn_mac *);
+static void bwn_led_newstate(struct bwn_mac *, enum ieee80211_state);
+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_next(void *);
+static void bwn_led_blink_end(void *);
+static void bwn_rfswitch(void *);
+static void bwn_rf_turnon(struct bwn_mac *);
+static void bwn_rf_turnoff(struct bwn_mac *);
+static void bwn_phy_lp_init_pre(struct bwn_mac *);
+static int bwn_phy_lp_init(struct bwn_mac *);
+static uint16_t bwn_phy_lp_read(struct bwn_mac *, uint16_t);
+static void bwn_phy_lp_write(struct bwn_mac *, uint16_t, uint16_t);
+static void bwn_phy_lp_maskset(struct bwn_mac *, uint16_t, uint16_t,
+ uint16_t);
+static uint16_t bwn_phy_lp_rf_read(struct bwn_mac *, uint16_t);
+static void bwn_phy_lp_rf_write(struct bwn_mac *, uint16_t, uint16_t);
+static void bwn_phy_lp_rf_onoff(struct bwn_mac *, int);
+static int bwn_phy_lp_switch_channel(struct bwn_mac *, uint32_t);
+static uint32_t bwn_phy_lp_get_default_chan(struct bwn_mac *);
+static void bwn_phy_lp_set_antenna(struct bwn_mac *, int);
+static void bwn_phy_lp_task_60s(struct bwn_mac *);
+static void bwn_phy_lp_readsprom(struct bwn_mac *);
+static void bwn_phy_lp_bbinit(struct bwn_mac *);
+static void bwn_phy_lp_txpctl_init(struct bwn_mac *);
+static void bwn_phy_lp_calib(struct bwn_mac *);
+static void bwn_phy_lp_switch_analog(struct bwn_mac *, int);
+static int bwn_phy_lp_b2062_switch_channel(struct bwn_mac *, uint8_t);
+static int bwn_phy_lp_b2063_switch_channel(struct bwn_mac *, uint8_t);
+static void bwn_phy_lp_set_anafilter(struct bwn_mac *, uint8_t);
+static void bwn_phy_lp_set_gaintbl(struct bwn_mac *, uint32_t);
+static void bwn_phy_lp_digflt_save(struct bwn_mac *);
+static void bwn_phy_lp_get_txpctlmode(struct bwn_mac *);
+static void bwn_phy_lp_set_txpctlmode(struct bwn_mac *, uint8_t);
+static void bwn_phy_lp_bugfix(struct bwn_mac *);
+static void bwn_phy_lp_digflt_restore(struct bwn_mac *);
+static void bwn_phy_lp_tblinit(struct bwn_mac *);
+static void bwn_phy_lp_bbinit_r2(struct bwn_mac *);
+static void bwn_phy_lp_bbinit_r01(struct bwn_mac *);
+static void bwn_phy_lp_b2062_init(struct bwn_mac *);
+static void bwn_phy_lp_b2063_init(struct bwn_mac *);
+static void bwn_phy_lp_rxcal_r2(struct bwn_mac *);
+static void bwn_phy_lp_rccal_r12(struct bwn_mac *);
+static void bwn_phy_lp_set_rccap(struct bwn_mac *);
+static uint32_t bwn_phy_lp_roundup(uint32_t, uint32_t, uint8_t);
+static void bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *);
+static void bwn_phy_lp_b2062_vco_calib(struct bwn_mac *);
+static void bwn_tab_write_multi(struct bwn_mac *, uint32_t, int,
+ const void *);
+static void bwn_tab_read_multi(struct bwn_mac *, uint32_t, int, void *);
+static struct bwn_txgain
+ bwn_phy_lp_get_txgain(struct bwn_mac *);
+static uint8_t bwn_phy_lp_get_bbmult(struct bwn_mac *);
+static void bwn_phy_lp_set_txgain(struct bwn_mac *, struct bwn_txgain *);
+static void bwn_phy_lp_set_bbmult(struct bwn_mac *, uint8_t);
+static void bwn_phy_lp_set_trsw_over(struct bwn_mac *, uint8_t, uint8_t);
+static void bwn_phy_lp_set_rxgain(struct bwn_mac *, uint32_t);
+static void bwn_phy_lp_set_deaf(struct bwn_mac *, uint8_t);
+static int bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *, uint16_t);
+static void bwn_phy_lp_clear_deaf(struct bwn_mac *, uint8_t);
+static void bwn_phy_lp_tblinit_r01(struct bwn_mac *);
+static void bwn_phy_lp_tblinit_r2(struct bwn_mac *);
+static void bwn_phy_lp_tblinit_txgain(struct bwn_mac *);
+static void bwn_tab_write(struct bwn_mac *, uint32_t, uint32_t);
+static void bwn_phy_lp_b2062_tblinit(struct bwn_mac *);
+static void bwn_phy_lp_b2063_tblinit(struct bwn_mac *);
+static int bwn_phy_lp_loopback(struct bwn_mac *);
+static void bwn_phy_lp_set_rxgain_idx(struct bwn_mac *, uint16_t);
+static void bwn_phy_lp_ddfs_turnon(struct bwn_mac *, int, int, int, int,
+ int);
+static uint8_t bwn_phy_lp_rx_iq_est(struct bwn_mac *, uint16_t, uint8_t,
+ struct bwn_phy_lp_iq_est *);
+static void bwn_phy_lp_ddfs_turnoff(struct bwn_mac *);
+static uint32_t bwn_tab_read(struct bwn_mac *, uint32_t);
+static void bwn_phy_lp_set_txgain_dac(struct bwn_mac *, uint16_t);
+static void bwn_phy_lp_set_txgain_pa(struct bwn_mac *, uint16_t);
+static void bwn_phy_lp_set_txgain_override(struct bwn_mac *);
+static uint16_t bwn_phy_lp_get_pa_gain(struct bwn_mac *);
+static uint8_t bwn_nbits(int32_t);
+static void bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *, int, int,
+ struct bwn_txgain_entry *);
+static void bwn_phy_lp_gaintbl_write(struct bwn_mac *, int,
+ struct bwn_txgain_entry);
+static void bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *, int,
+ struct bwn_txgain_entry);
+static void bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *, int,
+ struct bwn_txgain_entry);
+
+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 = {
+ .channels = {
+ { 2412, 1, 30 }, { 2417, 2, 30 }, { 2422, 3, 30 },
+ { 2427, 4, 30 }, { 2432, 5, 30 }, { 2437, 6, 30 },
+ { 2442, 7, 30 }, { 2447, 8, 30 }, { 2452, 9, 30 },
+ { 2457, 10, 30 }, { 2462, 11, 30 }, { 2467, 12, 30 },
+ { 2472, 13, 30 }, { 2484, 14, 30 } },
+ .nchannels = 14
+};
+
+static const struct bwn_channelinfo bwn_chantable_a = {
+ .channels = {
+ { 5170, 34, 30 }, { 5180, 36, 30 }, { 5190, 38, 30 },
+ { 5200, 40, 30 }, { 5210, 42, 30 }, { 5220, 44, 30 },
+ { 5230, 46, 30 }, { 5240, 48, 30 }, { 5260, 52, 30 },
+ { 5280, 56, 30 }, { 5300, 60, 30 }, { 5320, 64, 30 },
+ { 5500, 100, 30 }, { 5520, 104, 30 }, { 5540, 108, 30 },
+ { 5560, 112, 30 }, { 5580, 116, 30 }, { 5600, 120, 30 },
+ { 5620, 124, 30 }, { 5640, 128, 30 }, { 5660, 132, 30 },
+ { 5680, 136, 30 }, { 5700, 140, 30 }, { 5745, 149, 30 },
+ { 5765, 153, 30 }, { 5785, 157, 30 }, { 5805, 161, 30 },
+ { 5825, 165, 30 }, { 5920, 184, 30 }, { 5940, 188, 30 },
+ { 5960, 192, 30 }, { 5980, 196, 30 }, { 6000, 200, 30 },
+ { 6020, 204, 30 }, { 6040, 208, 30 }, { 6060, 212, 30 },
+ { 6080, 216, 30 } },
+ .nchannels = 37
+};
+
+static const struct bwn_channelinfo bwn_chantable_n = {
+ .channels = {
+ { 5160, 32, 30 }, { 5170, 34, 30 }, { 5180, 36, 30 },
+ { 5190, 38, 30 }, { 5200, 40, 30 }, { 5210, 42, 30 },
+ { 5220, 44, 30 }, { 5230, 46, 30 }, { 5240, 48, 30 },
+ { 5250, 50, 30 }, { 5260, 52, 30 }, { 5270, 54, 30 },
+ { 5280, 56, 30 }, { 5290, 58, 30 }, { 5300, 60, 30 },
+ { 5310, 62, 30 }, { 5320, 64, 30 }, { 5330, 66, 30 },
+ { 5340, 68, 30 }, { 5350, 70, 30 }, { 5360, 72, 30 },
+ { 5370, 74, 30 }, { 5380, 76, 30 }, { 5390, 78, 30 },
+ { 5400, 80, 30 }, { 5410, 82, 30 }, { 5420, 84, 30 },
+ { 5430, 86, 30 }, { 5440, 88, 30 }, { 5450, 90, 30 },
+ { 5460, 92, 30 }, { 5470, 94, 30 }, { 5480, 96, 30 },
+ { 5490, 98, 30 }, { 5500, 100, 30 }, { 5510, 102, 30 },
+ { 5520, 104, 30 }, { 5530, 106, 30 }, { 5540, 108, 30 },
+ { 5550, 110, 30 }, { 5560, 112, 30 }, { 5570, 114, 30 },
+ { 5580, 116, 30 }, { 5590, 118, 30 }, { 5600, 120, 30 },
+ { 5610, 122, 30 }, { 5620, 124, 30 }, { 5630, 126, 30 },
+ { 5640, 128, 30 }, { 5650, 130, 30 }, { 5660, 132, 30 },
+ { 5670, 134, 30 }, { 5680, 136, 30 }, { 5690, 138, 30 },
+ { 5700, 140, 30 }, { 5710, 142, 30 }, { 5720, 144, 30 },
+ { 5725, 145, 30 }, { 5730, 146, 30 }, { 5735, 147, 30 },
+ { 5740, 148, 30 }, { 5745, 149, 30 }, { 5750, 150, 30 },
+ { 5755, 151, 30 }, { 5760, 152, 30 }, { 5765, 153, 30 },
+ { 5770, 154, 30 }, { 5775, 155, 30 }, { 5780, 156, 30 },
+ { 5785, 157, 30 }, { 5790, 158, 30 }, { 5795, 159, 30 },
+ { 5800, 160, 30 }, { 5805, 161, 30 }, { 5810, 162, 30 },
+ { 5815, 163, 30 }, { 5820, 164, 30 }, { 5825, 165, 30 },
+ { 5830, 166, 30 }, { 5840, 168, 30 }, { 5850, 170, 30 },
+ { 5860, 172, 30 }, { 5870, 174, 30 }, { 5880, 176, 30 },
+ { 5890, 178, 30 }, { 5900, 180, 30 }, { 5910, 182, 30 },
+ { 5920, 184, 30 }, { 5930, 186, 30 }, { 5940, 188, 30 },
+ { 5950, 190, 30 }, { 5960, 192, 30 }, { 5970, 194, 30 },
+ { 5980, 196, 30 }, { 5990, 198, 30 }, { 6000, 200, 30 },
+ { 6010, 202, 30 }, { 6020, 204, 30 }, { 6030, 206, 30 },
+ { 6040, 208, 30 }, { 6050, 210, 30 }, { 6060, 212, 30 },
+ { 6070, 214, 30 }, { 6080, 216, 30 }, { 6090, 218, 30 },
+ { 6100, 220, 30 }, { 6110, 222, 30 }, { 6120, 224, 30 },
+ { 6130, 226, 30 }, { 6140, 228, 30 } },
+ .nchannels = 110
+};
+
+static const uint8_t bwn_b2063_chantable_data[33][12] = {
+ { 0x6f, 0x3c, 0x3c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
+ { 0x6f, 0x2c, 0x2c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
+ { 0x6f, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
+ { 0x6e, 0x1c, 0x1c, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
+ { 0x6e, 0xc, 0xc, 0x4, 0x5, 0x5, 0x5, 0x5, 0x77, 0x80, 0x80, 0x70 },
+ { 0x6a, 0xc, 0xc, 0, 0x2, 0x5, 0xd, 0xd, 0x77, 0x80, 0x20, 0 },
+ { 0x6a, 0xc, 0xc, 0, 0x1, 0x5, 0xd, 0xc, 0x77, 0x80, 0x20, 0 },
+ { 0x6a, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x80, 0x20, 0 },
+ { 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xc, 0xc, 0x77, 0x70, 0x20, 0 },
+ { 0x69, 0xc, 0xc, 0, 0x1, 0x4, 0xb, 0xc, 0x77, 0x70, 0x20, 0 },
+ { 0x69, 0xc, 0xc, 0, 0, 0x4, 0xb, 0xb, 0x77, 0x60, 0x20, 0 },
+ { 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xb, 0x77, 0x60, 0x20, 0 },
+ { 0x69, 0xc, 0xc, 0, 0, 0x3, 0xa, 0xa, 0x77, 0x60, 0x20, 0 },
+ { 0x68, 0xc, 0xc, 0, 0, 0x2, 0x9, 0x9, 0x77, 0x60, 0x20, 0 },
+ { 0x68, 0xc, 0xc, 0, 0, 0x1, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
+ { 0x67, 0xc, 0xc, 0, 0, 0, 0x8, 0x8, 0x77, 0x50, 0x10, 0 },
+ { 0x64, 0xc, 0xc, 0, 0, 0, 0x2, 0x1, 0x77, 0x20, 0, 0 },
+ { 0x64, 0xc, 0xc, 0, 0, 0, 0x1, 0x1, 0x77, 0x20, 0, 0 },
+ { 0x63, 0xc, 0xc, 0, 0, 0, 0x1, 0, 0x77, 0x10, 0, 0 },
+ { 0x63, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
+ { 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0x10, 0, 0 },
+ { 0x62, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
+ { 0x61, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
+ { 0x60, 0xc, 0xc, 0, 0, 0, 0, 0, 0x77, 0, 0, 0 },
+ { 0x6e, 0xc, 0xc, 0, 0x9, 0xe, 0xf, 0xf, 0x77, 0xc0, 0x50, 0 },
+ { 0x6e, 0xc, 0xc, 0, 0x9, 0xd, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
+ { 0x6e, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xb0, 0x50, 0 },
+ { 0x6d, 0xc, 0xc, 0, 0x8, 0xc, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
+ { 0x6d, 0xc, 0xc, 0, 0x8, 0xb, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
+ { 0x6d, 0xc, 0xc, 0, 0x8, 0xa, 0xf, 0xf, 0x77, 0xa0, 0x40, 0 },
+ { 0x6c, 0xc, 0xc, 0, 0x7, 0x9, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
+ { 0x6c, 0xc, 0xc, 0, 0x6, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 },
+ { 0x6c, 0xc, 0xc, 0, 0x5, 0x8, 0xf, 0xf, 0x77, 0x90, 0x40, 0 }
+};
+
+static const struct bwn_b206x_chan bwn_b2063_chantable[] = {
+ { 1, 2412, bwn_b2063_chantable_data[0] },
+ { 2, 2417, bwn_b2063_chantable_data[0] },
+ { 3, 2422, bwn_b2063_chantable_data[0] },
+ { 4, 2427, bwn_b2063_chantable_data[1] },
+ { 5, 2432, bwn_b2063_chantable_data[1] },
+ { 6, 2437, bwn_b2063_chantable_data[1] },
+ { 7, 2442, bwn_b2063_chantable_data[1] },
+ { 8, 2447, bwn_b2063_chantable_data[1] },
+ { 9, 2452, bwn_b2063_chantable_data[2] },
+ { 10, 2457, bwn_b2063_chantable_data[2] },
+ { 11, 2462, bwn_b2063_chantable_data[3] },
+ { 12, 2467, bwn_b2063_chantable_data[3] },
+ { 13, 2472, bwn_b2063_chantable_data[3] },
+ { 14, 2484, bwn_b2063_chantable_data[4] },
+ { 34, 5170, bwn_b2063_chantable_data[5] },
+ { 36, 5180, bwn_b2063_chantable_data[6] },
+ { 38, 5190, bwn_b2063_chantable_data[7] },
+ { 40, 5200, bwn_b2063_chantable_data[8] },
+ { 42, 5210, bwn_b2063_chantable_data[9] },
+ { 44, 5220, bwn_b2063_chantable_data[10] },
+ { 46, 5230, bwn_b2063_chantable_data[11] },
+ { 48, 5240, bwn_b2063_chantable_data[12] },
+ { 52, 5260, bwn_b2063_chantable_data[13] },
+ { 56, 5280, bwn_b2063_chantable_data[14] },
+ { 60, 5300, bwn_b2063_chantable_data[14] },
+ { 64, 5320, bwn_b2063_chantable_data[15] },
+ { 100, 5500, bwn_b2063_chantable_data[16] },
+ { 104, 5520, bwn_b2063_chantable_data[17] },
+ { 108, 5540, bwn_b2063_chantable_data[18] },
+ { 112, 5560, bwn_b2063_chantable_data[19] },
+ { 116, 5580, bwn_b2063_chantable_data[20] },
+ { 120, 5600, bwn_b2063_chantable_data[21] },
+ { 124, 5620, bwn_b2063_chantable_data[21] },
+ { 128, 5640, bwn_b2063_chantable_data[22] },
+ { 132, 5660, bwn_b2063_chantable_data[22] },
+ { 136, 5680, bwn_b2063_chantable_data[22] },
+ { 140, 5700, bwn_b2063_chantable_data[23] },
+ { 149, 5745, bwn_b2063_chantable_data[23] },
+ { 153, 5765, bwn_b2063_chantable_data[23] },
+ { 157, 5785, bwn_b2063_chantable_data[23] },
+ { 161, 5805, bwn_b2063_chantable_data[23] },
+ { 165, 5825, bwn_b2063_chantable_data[23] },
+ { 184, 4920, bwn_b2063_chantable_data[24] },
+ { 188, 4940, bwn_b2063_chantable_data[25] },
+ { 192, 4960, bwn_b2063_chantable_data[26] },
+ { 196, 4980, bwn_b2063_chantable_data[27] },
+ { 200, 5000, bwn_b2063_chantable_data[28] },
+ { 204, 5020, bwn_b2063_chantable_data[29] },
+ { 208, 5040, bwn_b2063_chantable_data[30] },
+ { 212, 5060, bwn_b2063_chantable_data[31] },
+ { 216, 5080, bwn_b2063_chantable_data[32] }
+};
+
+static const uint8_t bwn_b2062_chantable_data[22][12] = {
+ { 0xff, 0xff, 0xb5, 0x1b, 0x24, 0x32, 0x32, 0x88, 0x88, 0, 0, 0 },
+ { 0, 0x22, 0x20, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0x11, 0x10, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0x11, 0x20, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0x11, 0x10, 0x84, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0x11, 0, 0x83, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0x63, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0x62, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0x30, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0x20, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0x10, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0, 0, 0, 0x3c, 0x77, 0x37, 0xff, 0x88, 0, 0, 0 },
+ { 0x55, 0x77, 0x90, 0xf7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x44, 0x77, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x44, 0x66, 0x80, 0xe7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x33, 0x66, 0x70, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x22, 0x55, 0x60, 0xd7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x22, 0x55, 0x60, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x22, 0x44, 0x50, 0xc7, 0x3c, 0x77, 0x35, 0xff, 0xff, 0, 0, 0 },
+ { 0x11, 0x44, 0x50, 0xa5, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 },
+ { 0, 0x44, 0x40, 0xb6, 0x3c, 0x77, 0x35, 0xff, 0x88, 0, 0, 0 }
+};
+
+static const struct bwn_b206x_chan bwn_b2062_chantable[] = {
+ { 1, 2412, bwn_b2062_chantable_data[0] },
+ { 2, 2417, bwn_b2062_chantable_data[0] },
+ { 3, 2422, bwn_b2062_chantable_data[0] },
+ { 4, 2427, bwn_b2062_chantable_data[0] },
+ { 5, 2432, bwn_b2062_chantable_data[0] },
+ { 6, 2437, bwn_b2062_chantable_data[0] },
+ { 7, 2442, bwn_b2062_chantable_data[0] },
+ { 8, 2447, bwn_b2062_chantable_data[0] },
+ { 9, 2452, bwn_b2062_chantable_data[0] },
+ { 10, 2457, bwn_b2062_chantable_data[0] },
+ { 11, 2462, bwn_b2062_chantable_data[0] },
+ { 12, 2467, bwn_b2062_chantable_data[0] },
+ { 13, 2472, bwn_b2062_chantable_data[0] },
+ { 14, 2484, bwn_b2062_chantable_data[0] },
+ { 34, 5170, bwn_b2062_chantable_data[1] },
+ { 38, 5190, bwn_b2062_chantable_data[2] },
+ { 42, 5210, bwn_b2062_chantable_data[2] },
+ { 46, 5230, bwn_b2062_chantable_data[3] },
+ { 36, 5180, bwn_b2062_chantable_data[4] },
+ { 40, 5200, bwn_b2062_chantable_data[5] },
+ { 44, 5220, bwn_b2062_chantable_data[6] },
+ { 48, 5240, bwn_b2062_chantable_data[3] },
+ { 52, 5260, bwn_b2062_chantable_data[3] },
+ { 56, 5280, bwn_b2062_chantable_data[3] },
+ { 60, 5300, bwn_b2062_chantable_data[7] },
+ { 64, 5320, bwn_b2062_chantable_data[8] },
+ { 100, 5500, bwn_b2062_chantable_data[9] },
+ { 104, 5520, bwn_b2062_chantable_data[10] },
+ { 108, 5540, bwn_b2062_chantable_data[10] },
+ { 112, 5560, bwn_b2062_chantable_data[10] },
+ { 116, 5580, bwn_b2062_chantable_data[11] },
+ { 120, 5600, bwn_b2062_chantable_data[12] },
+ { 124, 5620, bwn_b2062_chantable_data[12] },
+ { 128, 5640, bwn_b2062_chantable_data[12] },
+ { 132, 5660, bwn_b2062_chantable_data[12] },
+ { 136, 5680, bwn_b2062_chantable_data[12] },
+ { 140, 5700, bwn_b2062_chantable_data[12] },
+ { 149, 5745, bwn_b2062_chantable_data[12] },
+ { 153, 5765, bwn_b2062_chantable_data[12] },
+ { 157, 5785, bwn_b2062_chantable_data[12] },
+ { 161, 5805, bwn_b2062_chantable_data[12] },
+ { 165, 5825, bwn_b2062_chantable_data[12] },
+ { 184, 4920, bwn_b2062_chantable_data[13] },
+ { 188, 4940, bwn_b2062_chantable_data[14] },
+ { 192, 4960, bwn_b2062_chantable_data[15] },
+ { 196, 4980, bwn_b2062_chantable_data[16] },
+ { 200, 5000, bwn_b2062_chantable_data[17] },
+ { 204, 5020, bwn_b2062_chantable_data[18] },
+ { 208, 5040, bwn_b2062_chantable_data[19] },
+ { 212, 5060, bwn_b2062_chantable_data[20] },
+ { 216, 5080, bwn_b2062_chantable_data[21] }
+};
+
+/* for LP PHY */
+static const struct bwn_rxcompco bwn_rxcompco_5354[] = {
+ { 1, -66, 15 }, { 2, -66, 15 }, { 3, -66, 15 }, { 4, -66, 15 },
+ { 5, -66, 15 }, { 6, -66, 15 }, { 7, -66, 14 }, { 8, -66, 14 },
+ { 9, -66, 14 }, { 10, -66, 14 }, { 11, -66, 14 }, { 12, -66, 13 },
+ { 13, -66, 13 }, { 14, -66, 13 },
+};
+
+/* for LP PHY */
+static const struct bwn_rxcompco bwn_rxcompco_r12[] = {
+ { 1, -64, 13 }, { 2, -64, 13 }, { 3, -64, 13 }, { 4, -64, 13 },
+ { 5, -64, 12 }, { 6, -64, 12 }, { 7, -64, 12 }, { 8, -64, 12 },
+ { 9, -64, 12 }, { 10, -64, 11 }, { 11, -64, 11 }, { 12, -64, 11 },
+ { 13, -64, 11 }, { 14, -64, 10 }, { 34, -62, 24 }, { 38, -62, 24 },
+ { 42, -62, 24 }, { 46, -62, 23 }, { 36, -62, 24 }, { 40, -62, 24 },
+ { 44, -62, 23 }, { 48, -62, 23 }, { 52, -62, 23 }, { 56, -62, 22 },
+ { 60, -62, 22 }, { 64, -62, 22 }, { 100, -62, 16 }, { 104, -62, 16 },
+ { 108, -62, 15 }, { 112, -62, 14 }, { 116, -62, 14 }, { 120, -62, 13 },
+ { 124, -62, 12 }, { 128, -62, 12 }, { 132, -62, 12 }, { 136, -62, 11 },
+ { 140, -62, 10 }, { 149, -61, 9 }, { 153, -61, 9 }, { 157, -61, 9 },
+ { 161, -61, 8 }, { 165, -61, 8 }, { 184, -62, 25 }, { 188, -62, 25 },
+ { 192, -62, 25 }, { 196, -62, 25 }, { 200, -62, 25 }, { 204, -62, 25 },
+ { 208, -62, 25 }, { 212, -62, 25 }, { 216, -62, 26 },
+};
+
+static const struct bwn_rxcompco bwn_rxcompco_r2 = { 0, -64, 0 };
+
+static const uint8_t bwn_tab_sigsq_tbl[] = {
+ 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd4, 0xd2, 0xcf, 0xcd,
+ 0xca, 0xc7, 0xc4, 0xc1, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+ 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x00,
+ 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe,
+ 0xbe, 0xbe, 0xbe, 0xbe, 0xc1, 0xc4, 0xc7, 0xca, 0xcd,
+ 0xcf, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde,
+};
+
+static const uint8_t bwn_tab_pllfrac_tbl[] = {
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+};
+
+static const uint16_t bwn_tabl_iqlocal_tbl[] = {
+ 0x0200, 0x0300, 0x0400, 0x0600, 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002,
+ 0x1003, 0x1004, 0x1005, 0x1006, 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0200, 0x0300, 0x0400, 0x0600,
+ 0x0800, 0x0b00, 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006,
+ 0x1007, 0x1707, 0x2007, 0x2d07, 0x4007, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x4000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const uint16_t bwn_tab_noise_g1[] = BWN_TAB_NOISE_G1;
+static const uint16_t bwn_tab_noise_g2[] = BWN_TAB_NOISE_G2;
+static const uint16_t bwn_tab_noisescale_g1[] = BWN_TAB_NOISESCALE_G1;
+static const uint16_t bwn_tab_noisescale_g2[] = BWN_TAB_NOISESCALE_G2;
+static const uint16_t bwn_tab_noisescale_g3[] = BWN_TAB_NOISESCALE_G3;
+const uint8_t bwn_bitrev_table[256] = BWN_BITREV_TABLE;
+
+#define VENDOR_LED_ACT(vendor) \
+{ \
+ .vid = PCI_VENDOR_##vendor, \
+ .led_act = { BWN_VENDOR_LED_ACT_##vendor } \
+}
+
+static const struct {
+ uint16_t vid;
+ uint8_t led_act[BWN_LED_MAX];
+} bwn_vendor_led_act[] = {
+ VENDOR_LED_ACT(COMPAQ),
+ VENDOR_LED_ACT(ASUSTEK)
+};
+
+static const uint8_t bwn_default_led_act[BWN_LED_MAX] =
+ { BWN_VENDOR_LED_ACT_DEFAULT };
+
+#undef VENDOR_LED_ACT
+
+static const struct {
+ int on_dur;
+ int off_dur;
+} bwn_led_duration[109] = {
+ [0] = { 400, 100 },
+ [2] = { 150, 75 },
+ [4] = { 90, 45 },
+ [11] = { 66, 34 },
+ [12] = { 53, 26 },
+ [18] = { 42, 21 },
+ [22] = { 35, 17 },
+ [24] = { 32, 16 },
+ [36] = { 21, 10 },
+ [48] = { 16, 8 },
+ [72] = { 11, 5 },
+ [96] = { 9, 4 },
+ [108] = { 7, 3 }
+};
+
+static const uint16_t bwn_wme_shm_offsets[] = {
+ [0] = BWN_WME_BESTEFFORT,
+ [1] = BWN_WME_BACKGROUND,
+ [2] = BWN_WME_VOICE,
+ [3] = BWN_WME_VIDEO,
+};
+
+static const struct siba_devid bwn_devs[] = {
+ SIBA_DEV(BROADCOM, 80211, 5, "Revision 5"),
+ SIBA_DEV(BROADCOM, 80211, 6, "Revision 6"),
+ SIBA_DEV(BROADCOM, 80211, 7, "Revision 7"),
+ SIBA_DEV(BROADCOM, 80211, 9, "Revision 9"),
+ SIBA_DEV(BROADCOM, 80211, 10, "Revision 10"),
+ SIBA_DEV(BROADCOM, 80211, 11, "Revision 11"),
+ SIBA_DEV(BROADCOM, 80211, 13, "Revision 13"),
+ SIBA_DEV(BROADCOM, 80211, 15, "Revision 15"),
+ SIBA_DEV(BROADCOM, 80211, 16, "Revision 16")
+};
+
+static int
+bwn_probe(device_t dev)
+{
+ struct siba_dev_softc *sd = device_get_ivars(dev);
+ int i;
+
+ for (i = 0; i < sizeof(bwn_devs) / sizeof(bwn_devs[0]); i++) {
+ if (sd->sd_id.sd_vendor == bwn_devs[i].sd_vendor &&
+ sd->sd_id.sd_device == bwn_devs[i].sd_device &&
+ sd->sd_id.sd_rev == bwn_devs[i].sd_rev)
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+bwn_attach(device_t dev)
+{
+ struct bwn_mac *mac;
+ struct bwn_softc *sc = device_get_softc(dev);
+ struct siba_dev_softc *sd = device_get_ivars(dev);
+ struct siba_softc *siba = sd->sd_bus;
+ int error, i, msic, reg;
+
+ sc->sc_dev = dev;
+ sc->sc_sd = sd;
+#ifdef BWN_DEBUG
+ sc->sc_debug = bwn_debug;
+#endif
+
+ if ((sc->sc_flags & BWN_FLAG_ATTACHED) == 0) {
+ error = bwn_attach_pre(sc);
+ if (error != 0)
+ return (error);
+ bwn_sprom_bugfixes(sd->sd_bus);
+ sc->sc_flags |= BWN_FLAG_ATTACHED;
+ }
+
+ if (!TAILQ_EMPTY(&sc->sc_maclist)) {
+ if (siba->siba_pci_did != 0x4313 &&
+ siba->siba_pci_did != 0x431a &&
+ siba->siba_pci_did != 0x4321) {
+ device_printf(sc->sc_dev,
+ "skip 802.11 cores\n");
+ return (ENODEV);
+ }
+ }
+
+ mac = (struct bwn_mac *)malloc(sizeof(*mac), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (mac == NULL)
+ return (ENOMEM);
+ mac->mac_sc = sc;
+ mac->mac_sd = sd;
+ mac->mac_status = BWN_MAC_STATUS_UNINIT;
+ if (bwn_bfp != 0)
+ mac->mac_flags |= BWN_MAC_FLAG_BADFRAME_PREEMP;
+
+ TASK_INIT(&mac->mac_hwreset, 0, bwn_hwreset, mac);
+ TASK_INIT(&mac->mac_intrtask, 0, bwn_intrtask, mac);
+ TASK_INIT(&mac->mac_txpower, 0, bwn_txpwr, mac);
+
+ error = bwn_attach_core(mac);
+ if (error)
+ goto fail0;
+ bwn_led_attach(mac);
+
+ device_printf(sc->sc_dev, "WLAN (chipid %#x rev %u) "
+ "PHY (analog %d type %d rev %d) RADIO (manuf %#x ver %#x rev %d)\n",
+ sd->sd_bus->siba_chipid, sd->sd_id.sd_rev,
+ mac->mac_phy.analog, mac->mac_phy.type, mac->mac_phy.rev,
+ mac->mac_phy.rf_manuf, mac->mac_phy.rf_ver,
+ mac->mac_phy.rf_rev);
+ if (mac->mac_flags & BWN_MAC_FLAG_DMA)
+ device_printf(sc->sc_dev, "DMA (%d bits)\n",
+ mac->mac_method.dma.dmatype);
+ else
+ device_printf(sc->sc_dev, "PIO\n");
+
+ /*
+ * setup PCI resources and interrupt.
+ */
+ if (pci_find_extcap(dev, PCIY_EXPRESS, &reg) == 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 (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0) {
+ if (pci_alloc_msi(dev, &msic) == 0) {
+ device_printf(sc->sc_dev,
+ "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,
+ 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,
+ &mac->mac_intrhand[0]);
+ 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) {
+ device_printf(sc->sc_dev,
+ "couldn't setup interrupt (%d)\n", error);
+ break;
+ }
+ }
+ }
+
+ TAILQ_INSERT_TAIL(&sc->sc_maclist, mac, mac_list);
+
+ /*
+ * calls attach-post routine
+ */
+ if ((sc->sc_flags & BWN_FLAG_ATTACHED) != 0)
+ bwn_attach_post(sc);
+
+ return (0);
+fail1:
+ if (msic == BWN_MSI_MESSAGES && bwn_msi_disable == 0)
+ pci_release_msi(dev);
+fail0:
+ free(mac, M_DEVBUF);
+ return (error);
+}
+
+static int
+bwn_is_valid_ether_addr(uint8_t *addr)
+{
+ char zero_addr[6] = { 0, 0, 0, 0, 0, 0 };
+
+ if ((addr[0] & 1) || (!bcmp(addr, zero_addr, ETHER_ADDR_LEN)))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static int
+bwn_attach_post(struct bwn_softc *sc)
+{
+ struct ieee80211com *ic;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct siba_dev_softc *sd = sc->sc_sd;
+ struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
+#ifdef BWN_DEBUG
+ device_t dev = sc->sc_dev;
+#endif
+
+ ic = ifp->if_l2com;
+ ic->ic_ifp = ifp;
+ /* XXX not right but it's not used anywhere important */
+ ic->ic_phytype = IEEE80211_T_OFDM;
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_caps =
+ IEEE80211_C_STA /* station mode supported */
+ | IEEE80211_C_MONITOR /* monitor mode */
+ | IEEE80211_C_SHPREAMBLE /* short preamble supported */
+ | IEEE80211_C_SHSLOT /* short slot time supported */
+ | IEEE80211_C_WME /* WME/WMM supported */
+ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+ | IEEE80211_C_BGSCAN /* capable of bg scanning */
+ | IEEE80211_C_TXPMGT /* capable of txpow mgt */
+ ;
+
+ /* call MI attach routine. */
+ ieee80211_ifattach(ic,
+ bwn_is_valid_ether_addr(sprom->mac_80211a) ? sprom->mac_80211a :
+ sprom->mac_80211bg);
+
+ ic->ic_headroom = sizeof(struct bwn_txhdr);
+
+ /* override default methods */
+ ic->ic_raw_xmit = bwn_raw_xmit;
+ ic->ic_newassoc = bwn_newassoc;
+ ic->ic_updateslot = bwn_updateslot;
+ ic->ic_update_promisc = bwn_update_promisc;
+ ic->ic_wme.wme_update = bwn_wme_update;
+
+ ic->ic_node_alloc = bwn_node_alloc;
+ sc->sc_node_cleanup = ic->ic_node_cleanup;
+ ic->ic_node_cleanup = bwn_node_cleanup;
+
+ ic->ic_scan_start = bwn_scan_start;
+ ic->ic_scan_end = bwn_scan_end;
+ ic->ic_set_channel = bwn_set_channel;
+
+ ic->ic_vap_create = bwn_vap_create;
+ ic->ic_vap_delete = bwn_vap_delete;
+
+ ieee80211_radiotap_attach(ic,
+ &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
+ BWN_TX_RADIOTAP_PRESENT,
+ &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
+ BWN_RX_RADIOTAP_PRESENT);
+
+#ifdef BWN_DEBUG
+ SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev),
+ SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
+ "debug", CTLFLAG_RW, &sc->sc_debug, 0, "Debug flags");
+#endif
+
+ if (bootverbose)
+ ieee80211_announce(ic);
+ return (0);
+}
+
+static void
+bwn_phy_detach(struct bwn_mac *mac)
+{
+
+ if (mac->mac_phy.detach != NULL)
+ mac->mac_phy.detach(mac);
+}
+
+static int
+bwn_detach(device_t dev)
+{
+ struct bwn_softc *sc = device_get_softc(dev);
+ struct bwn_mac *mac = sc->sc_curmac;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ int i;
+
+ sc->sc_flags |= BWN_FLAG_INVALID;
+
+ if (device_is_attached(sc->sc_dev)) {
+ bwn_stop(sc, 1);
+ bwn_dma_free(mac);
+ callout_drain(&sc->sc_led_blink_ch);
+ callout_drain(&sc->sc_rfswitch_ch);
+ callout_drain(&sc->sc_task_ch);
+ callout_drain(&sc->sc_watchdog_ch);
+ bwn_phy_detach(mac);
+ if (ifp != NULL) {
+ ieee80211_draintask(ic, &mac->mac_hwreset);
+ ieee80211_draintask(ic, &mac->mac_txpower);
+ ieee80211_ifdetach(ic);
+ if_free(ifp);
+ }
+ }
+ taskqueue_drain(sc->sc_tq, &mac->mac_intrtask);
+ taskqueue_free(sc->sc_tq);
+
+ for (i = 0; i < BWN_MSI_MESSAGES; i++) {
+ if (mac->mac_intrhand[i] != NULL) {
+ bus_teardown_intr(dev, mac->mac_res_irq[i],
+ mac->mac_intrhand[i]);
+ mac->mac_intrhand[i] = NULL;
+ }
+ }
+ bus_release_resources(dev, mac->mac_intr_spec, mac->mac_res_irq);
+ if (mac->mac_msi != 0)
+ pci_release_msi(dev);
+
+ BWN_LOCK_DESTROY(sc);
+ return (0);
+}
+
+static int
+bwn_attach_pre(struct bwn_softc *sc)
+{
+ struct ifnet *ifp;
+ int error = 0;
+
+ BWN_LOCK_INIT(sc);
+ TAILQ_INIT(&sc->sc_maclist);
+ 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_watchdog_ch, &sc->sc_mtx, 0);
+
+ sc->sc_tq = taskqueue_create_fast("bwn_taskq", M_NOWAIT,
+ taskqueue_thread_enqueue, &sc->sc_tq);
+ taskqueue_start_threads(&sc->sc_tq, 1, PI_NET,
+ "%s taskq", device_get_nameunit(sc->sc_dev));
+
+ ifp = sc->sc_ifp = if_alloc(IFT_IEEE80211);
+ if (ifp == NULL) {
+ device_printf(sc->sc_dev, "can not if_alloc()\n");
+ error = ENOSPC;
+ goto fail;
+ }
+
+ /* set these up early for if_printf use */
+ if_initname(ifp, device_get_name(sc->sc_dev),
+ device_get_unit(sc->sc_dev));
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_init = bwn_init;
+ ifp->if_ioctl = bwn_ioctl;
+ ifp->if_start = bwn_start;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+
+ return (0);
+
+fail: BWN_LOCK_DESTROY(sc);
+ return (error);
+}
+
+static void
+bwn_sprom_bugfixes(struct siba_softc *siba)
+{
+#define BWN_ISDEV(_vendor, _device, _subvendor, _subdevice) \
+ ((siba->siba_pci_vid == PCI_VENDOR_##_vendor) && \
+ (siba->siba_pci_did == _device) && \
+ (siba->siba_pci_subvid == PCI_VENDOR_##_subvendor) && \
+ (siba->siba_pci_subdid == _subdevice))
+
+ if (siba->siba_board_vendor == PCI_VENDOR_APPLE &&
+ siba->siba_board_type == 0x4e && siba->siba_board_rev > 0x40)
+ siba->siba_sprom.bf_lo |= BWN_BFL_PACTRL;
+ if (siba->siba_board_vendor == SIBA_BOARDVENDOR_DELL &&
+ siba->siba_chipid == 0x4301 && siba->siba_board_rev == 0x74)
+ siba->siba_sprom.bf_lo |= BWN_BFL_BTCOEXIST;
+ if (siba->siba_type == SIBA_TYPE_PCI) {
+ if (BWN_ISDEV(BROADCOM, 0x4318, ASUSTEK, 0x100f) ||
+ BWN_ISDEV(BROADCOM, 0x4320, DELL, 0x0003) ||
+ BWN_ISDEV(BROADCOM, 0x4320, HP, 0x12f8) ||
+ BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0013) ||
+ BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0014) ||
+ BWN_ISDEV(BROADCOM, 0x4320, LINKSYS, 0x0015) ||
+ BWN_ISDEV(BROADCOM, 0x4320, MOTOROLA, 0x7010))
+ siba->siba_sprom.bf_lo &= ~BWN_BFL_BTCOEXIST;
+ }
+#undef BWN_ISDEV
+}
+
+static int
+bwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+#define IS_RUNNING(ifp) \
+ ((ifp->if_flags & IFF_UP) && (ifp->if_drv_flags & IFF_DRV_RUNNING))
+ struct bwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ifreq *ifr = (struct ifreq *)data;
+ int error = 0, startall;
+
+ switch (cmd) {
+ case SIOCSIFFLAGS:
+ startall = 0;
+ if (IS_RUNNING(ifp)) {
+ bwn_update_promisc(ifp);
+ } else if (ifp->if_flags & IFF_UP) {
+ if ((sc->sc_flags & BWN_FLAG_INVALID) == 0) {
+ bwn_init(sc);
+ startall = 1;
+ }
+ } else
+ bwn_stop(sc, 1);
+ if (startall)
+ ieee80211_start_all(ic);
+ break;
+ case SIOCGIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
+ break;
+ case SIOCGIFADDR:
+ error = ether_ioctl(ifp, cmd, data);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+static void
+bwn_start(struct ifnet *ifp)
+{
+ struct bwn_softc *sc = ifp->if_softc;
+
+ BWN_LOCK(sc);
+ bwn_start_locked(ifp);
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_start_locked(struct ifnet *ifp)
+{
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac = sc->sc_curmac;
+ struct ieee80211_frame *wh;
+ struct ieee80211_node *ni;
+ struct ieee80211_key *k;
+ struct mbuf *m;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || mac == NULL ||
+ mac->mac_status < BWN_MAC_STATUS_STARTED)
+ return;
+
+ for (;;) {
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m); /* XXX: LOCK */
+ if (m == NULL)
+ break;
+
+ if (bwn_tx_isfull(sc, m))
+ break;
+ ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
+ if (ni == NULL) {
+ device_printf(sc->sc_dev, "unexpected NULL ni\n");
+ m_freem(m);
+ ifp->if_oerrors++;
+ continue;
+ }
+ KASSERT(ni != NULL, ("%s:%d: fail", __func__, __LINE__));
+ wh = mtod(m, struct ieee80211_frame *);
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ k = ieee80211_crypto_encap(ni, m);
+ if (k == NULL) {
+ ieee80211_free_node(ni);
+ m_freem(m);
+ ifp->if_oerrors++;
+ continue;
+ }
+ }
+ wh = NULL; /* Catch any invalid use */
+
+ if (bwn_tx_start(sc, ni, m) != 0) {
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
+ continue;
+ }
+
+ sc->sc_watchdog_timer = 5;
+ }
+}
+
+static int
+bwn_tx_isfull(struct bwn_softc *sc, struct mbuf *m)
+{
+ struct bwn_dma_ring *dr;
+ struct bwn_mac *mac = sc->sc_curmac;
+ struct bwn_pio_txqueue *tq;
+ struct ifnet *ifp = sc->sc_ifp;
+ int pktlen = roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
+ dr = bwn_dma_select(mac, M_WME_GETAC(m));
+ if (dr->dr_stop == 1 ||
+ bwn_dma_freeslot(dr) < BWN_TX_SLOTS_PER_FRAME) {
+ dr->dr_stop = 1;
+ goto full;
+ }
+ } else {
+ tq = bwn_pio_select(mac, M_WME_GETAC(m));
+ if (tq->tq_free == 0 || pktlen > tq->tq_size ||
+ pktlen > (tq->tq_size - tq->tq_used)) {
+ tq->tq_stop = 1;
+ goto full;
+ }
+ }
+ return (0);
+full:
+ IFQ_DRV_PREPEND(&ifp->if_snd, m);
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ return (1);
+}
+
+static int
+bwn_tx_start(struct bwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m)
+{
+ struct bwn_mac *mac = sc->sc_curmac;
+ int error;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (m->m_pkthdr.len < IEEE80211_MIN_LEN || mac == NULL) {
+ m_freem(m);
+ return (ENXIO);
+ }
+
+ error = (mac->mac_flags & BWN_MAC_FLAG_DMA) ?
+ bwn_dma_tx_start(mac, ni, m) : bwn_pio_tx_start(mac, ni, m);
+ if (error) {
+ m_freem(m);
+ return (error);
+ }
+ return (0);
+}
+
+static int
+bwn_pio_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
+{
+ struct bwn_pio_txpkt *tp;
+ struct bwn_pio_txqueue *tq = bwn_pio_select(mac, M_WME_GETAC(m));
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_txhdr txhdr;
+ struct mbuf *m_new;
+ uint32_t ctl32;
+ int error;
+ uint16_t ctl16;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ /* XXX TODO send packets after DTIM */
+
+ KASSERT(!TAILQ_EMPTY(&tq->tq_pktlist), ("%s: fail", __func__));
+ tp = TAILQ_FIRST(&tq->tq_pktlist);
+ tp->tp_ni = ni;
+ tp->tp_m = m;
+
+ error = bwn_set_txhdr(mac, ni, m, &txhdr, BWN_PIO_COOKIE(tq, tp));
+ if (error) {
+ device_printf(sc->sc_dev, "tx fail\n");
+ return (error);
+ }
+
+ TAILQ_REMOVE(&tq->tq_pktlist, tp, tp_list);
+ tq->tq_used += roundup(m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
+ tq->tq_free--;
+
+ if (mac->mac_sd->sd_id.sd_rev >= 8) {
+ /*
+ * XXX please removes m_defrag(9)
+ */
+ m_new = m_defrag(m, M_DONTWAIT);
+ if (m_new == NULL) {
+ device_printf(sc->sc_dev,
+ "%s: can't defrag TX buffer\n",
+ __func__);
+ return (ENOBUFS);
+ }
+ if (m_new->m_next != NULL)
+ device_printf(sc->sc_dev,
+ "TODO: fragmented packets for PIO\n");
+ tp->tp_m = m_new;
+
+ /* send HEADER */
+ ctl32 = bwn_pio_write_multi_4(mac, tq,
+ (BWN_PIO_READ_4(mac, tq, BWN_PIO8_TXCTL) |
+ BWN_PIO8_TXCTL_FRAMEREADY) & ~BWN_PIO8_TXCTL_EOF,
+ (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
+ /* send BODY */
+ ctl32 = bwn_pio_write_multi_4(mac, tq, ctl32,
+ mtod(m_new, const void *), m_new->m_pkthdr.len);
+ bwn_pio_write_4(mac, tq, BWN_PIO_TXCTL,
+ ctl32 | BWN_PIO8_TXCTL_EOF);
+ } else {
+ ctl16 = bwn_pio_write_multi_2(mac, tq,
+ (bwn_pio_read_2(mac, tq, BWN_PIO_TXCTL) |
+ BWN_PIO_TXCTL_FRAMEREADY) & ~BWN_PIO_TXCTL_EOF,
+ (const uint8_t *)&txhdr, BWN_HDRSIZE(mac));
+ ctl16 = bwn_pio_write_mbuf_2(mac, tq, ctl16, m);
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL,
+ ctl16 | BWN_PIO_TXCTL_EOF);
+ }
+
+ return (0);
+}
+
+static struct bwn_pio_txqueue *
+bwn_pio_select(struct bwn_mac *mac, uint8_t prio)
+{
+
+ if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
+ return (&mac->mac_method.pio.wme[WME_AC_BE]);
+
+ switch (prio) {
+ case 0:
+ return (&mac->mac_method.pio.wme[WME_AC_BE]);
+ case 1:
+ return (&mac->mac_method.pio.wme[WME_AC_BK]);
+ case 2:
+ return (&mac->mac_method.pio.wme[WME_AC_VI]);
+ case 3:
+ return (&mac->mac_method.pio.wme[WME_AC_VO]);
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+}
+
+static int
+bwn_dma_tx_start(struct bwn_mac *mac, struct ieee80211_node *ni, struct mbuf *m)
+{
+#define BWN_GET_TXHDRCACHE(slot) \
+ &(txhdr_cache[(slot / BWN_TX_SLOTS_PER_FRAME) * BWN_HDRSIZE(mac)])
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_dma_ring *dr = bwn_dma_select(mac, M_WME_GETAC(m));
+ struct bwn_dmadesc_generic *desc;
+ struct bwn_dmadesc_meta *mt;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ uint8_t *txhdr_cache = (uint8_t *)dr->dr_txhdr_cache;
+ int error, slot, backup[2] = { dr->dr_curslot, dr->dr_usedslot };
+
+ BWN_ASSERT_LOCKED(sc);
+ KASSERT(!dr->dr_stop, ("%s:%d: fail", __func__, __LINE__));
+
+ /* XXX send after DTIM */
+
+ slot = bwn_dma_getslot(dr);
+ dr->getdesc(dr, slot, &desc, &mt);
+ KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_HEADER,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ error = bwn_set_txhdr(dr->dr_mac, ni, m,
+ (struct bwn_txhdr *)BWN_GET_TXHDRCACHE(slot),
+ BWN_DMA_COOKIE(dr, slot));
+ if (error)
+ goto fail;
+ error = bus_dmamap_load(dr->dr_txring_dtag, mt->mt_dmap,
+ BWN_GET_TXHDRCACHE(slot), BWN_HDRSIZE(mac), bwn_dma_ring_addr,
+ &mt->mt_paddr, BUS_DMA_NOWAIT);
+ if (error) {
+ if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
+ __func__, error);
+ goto fail;
+ }
+ bus_dmamap_sync(dr->dr_txring_dtag, mt->mt_dmap,
+ BUS_DMASYNC_PREWRITE);
+ dr->setdesc(dr, desc, mt->mt_paddr, BWN_HDRSIZE(mac), 1, 0, 0);
+ bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
+ BUS_DMASYNC_PREWRITE);
+
+ slot = bwn_dma_getslot(dr);
+ dr->getdesc(dr, slot, &desc, &mt);
+ KASSERT(mt->mt_txtype == BWN_DMADESC_METATYPE_BODY &&
+ mt->mt_islast == 1, ("%s:%d: fail", __func__, __LINE__));
+ mt->mt_m = m;
+ mt->mt_ni = ni;
+
+ error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap, m,
+ bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
+ if (error && error != EFBIG) {
+ if_printf(ifp, "%s: can't load TX buffer (1) %d\n",
+ __func__, error);
+ goto fail;
+ }
+ if (error) { /* error == EFBIG */
+ struct mbuf *m_new;
+
+ m_new = m_defrag(m, M_DONTWAIT);
+ if (m_new == NULL) {
+ if_printf(ifp, "%s: can't defrag TX buffer\n",
+ __func__);
+ error = ENOBUFS;
+ goto fail;
+ } else {
+ m = m_new;
+ }
+
+ mt->mt_m = m;
+ error = bus_dmamap_load_mbuf(dma->txbuf_dtag, mt->mt_dmap,
+ m, bwn_dma_buf_addr, &mt->mt_paddr, BUS_DMA_NOWAIT);
+ if (error) {
+ if_printf(ifp, "%s: can't load TX buffer (2) %d\n",
+ __func__, error);
+ goto fail;
+ }
+ }
+ bus_dmamap_sync(dma->txbuf_dtag, mt->mt_dmap, BUS_DMASYNC_PREWRITE);
+ dr->setdesc(dr, desc, mt->mt_paddr, m->m_pkthdr.len, 0, 1, 1);
+ bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
+ BUS_DMASYNC_PREWRITE);
+
+ /* XXX send after DTIM */
+
+ dr->start_transfer(dr, bwn_dma_nextslot(dr, slot));
+ return (0);
+fail:
+ dr->dr_curslot = backup[0];
+ dr->dr_usedslot = backup[1];
+ return (error);
+#undef BWN_GET_TXHDRCACHE
+}
+
+static void
+bwn_watchdog(void *arg)
+{
+ struct bwn_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ if (sc->sc_watchdog_timer != 0 && --sc->sc_watchdog_timer == 0) {
+ if_printf(ifp, "device timeout\n");
+ ifp->if_oerrors++;
+ }
+ callout_schedule(&sc->sc_watchdog_ch, hz);
+}
+
+static int
+bwn_attach_core(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ int error, have_bg = 0, have_a = 0;
+ uint32_t high;
+
+ KASSERT(sd->sd_id.sd_rev >= 5,
+ ("unsupported revision %d", sd->sd_id.sd_rev));
+
+ siba_powerup(siba, 0);
+
+ high = siba_read_4(sd, SIBA_TGSHIGH);
+ bwn_reset_core(mac,
+ (high & BWN_TGSHIGH_HAVE_2GHZ) ? BWN_TGSLOW_SUPPORT_G : 0);
+ error = bwn_phy_getinfo(mac, high);
+ if (error)
+ goto fail;
+
+ have_a = (high & BWN_TGSHIGH_HAVE_5GHZ) ? 1 : 0;
+ have_bg = (high & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
+ if (siba->siba_pci_did != 0x4312 && siba->siba_pci_did != 0x4319 &&
+ siba->siba_pci_did != 0x4324) {
+ have_a = have_bg = 0;
+ if (mac->mac_phy.type == BWN_PHYTYPE_A)
+ have_a = 1;
+ else if (mac->mac_phy.type == BWN_PHYTYPE_G ||
+ mac->mac_phy.type == BWN_PHYTYPE_N ||
+ mac->mac_phy.type == BWN_PHYTYPE_LP)
+ have_bg = 1;
+ else
+ KASSERT(0 == 1, ("%s: unknown phy type (%d)", __func__,
+ mac->mac_phy.type));
+ }
+ /* XXX turns off PHY A because it's not supported */
+ if (mac->mac_phy.type != BWN_PHYTYPE_LP &&
+ mac->mac_phy.type != BWN_PHYTYPE_N) {
+ have_a = 0;
+ have_bg = 1;
+ }
+
+ if (mac->mac_phy.type == BWN_PHYTYPE_G) {
+ mac->mac_phy.attach = bwn_phy_g_attach;
+ mac->mac_phy.detach = bwn_phy_g_detach;
+ mac->mac_phy.prepare_hw = bwn_phy_g_prepare_hw;
+ mac->mac_phy.init_pre = bwn_phy_g_init_pre;
+ mac->mac_phy.init = bwn_phy_g_init;
+ mac->mac_phy.exit = bwn_phy_g_exit;
+ mac->mac_phy.phy_read = bwn_phy_g_read;
+ mac->mac_phy.phy_write = bwn_phy_g_write;
+ mac->mac_phy.rf_read = bwn_phy_g_rf_read;
+ mac->mac_phy.rf_write = bwn_phy_g_rf_write;
+ mac->mac_phy.use_hwpctl = bwn_phy_g_hwpctl;
+ mac->mac_phy.rf_onoff = bwn_phy_g_rf_onoff;
+ mac->mac_phy.switch_analog = bwn_phy_switch_analog;
+ mac->mac_phy.switch_channel = bwn_phy_g_switch_channel;
+ mac->mac_phy.get_default_chan = bwn_phy_g_get_default_chan;
+ mac->mac_phy.set_antenna = bwn_phy_g_set_antenna;
+ mac->mac_phy.set_im = bwn_phy_g_im;
+ mac->mac_phy.recalc_txpwr = bwn_phy_g_recalc_txpwr;
+ mac->mac_phy.set_txpwr = bwn_phy_g_set_txpwr;
+ mac->mac_phy.task_15s = bwn_phy_g_task_15s;
+ mac->mac_phy.task_60s = bwn_phy_g_task_60s;
+ } else if (mac->mac_phy.type == BWN_PHYTYPE_LP) {
+ mac->mac_phy.init_pre = bwn_phy_lp_init_pre;
+ mac->mac_phy.init = bwn_phy_lp_init;
+ mac->mac_phy.phy_read = bwn_phy_lp_read;
+ mac->mac_phy.phy_write = bwn_phy_lp_write;
+ mac->mac_phy.phy_maskset = bwn_phy_lp_maskset;
+ mac->mac_phy.rf_read = bwn_phy_lp_rf_read;
+ mac->mac_phy.rf_write = bwn_phy_lp_rf_write;
+ mac->mac_phy.rf_onoff = bwn_phy_lp_rf_onoff;
+ mac->mac_phy.switch_analog = bwn_phy_lp_switch_analog;
+ mac->mac_phy.switch_channel = bwn_phy_lp_switch_channel;
+ mac->mac_phy.get_default_chan = bwn_phy_lp_get_default_chan;
+ mac->mac_phy.set_antenna = bwn_phy_lp_set_antenna;
+ mac->mac_phy.task_60s = bwn_phy_lp_task_60s;
+ } else {
+ device_printf(sc->sc_dev, "unsupported PHY type (%d)\n",
+ mac->mac_phy.type);
+ error = ENXIO;
+ goto fail;
+ }
+
+ mac->mac_phy.gmode = have_bg;
+ if (mac->mac_phy.attach != NULL) {
+ error = mac->mac_phy.attach(mac);
+ if (error) {
+ device_printf(sc->sc_dev, "failed\n");
+ goto fail;
+ }
+ }
+
+ bwn_reset_core(mac, have_bg ? BWN_TGSLOW_SUPPORT_G : 0);
+
+ error = bwn_chiptest(mac);
+ if (error)
+ goto fail;
+ error = bwn_setup_channels(mac, have_bg, have_a);
+ if (error) {
+ device_printf(sc->sc_dev, "failed to setup channels\n");
+ goto fail;
+ }
+
+ if (sc->sc_curmac == NULL)
+ sc->sc_curmac = mac;
+
+ error = bwn_dma_attach(mac);
+ if (error != 0) {
+ device_printf(sc->sc_dev, "failed to initialize DMA\n");
+ goto fail;
+ }
+
+ mac->mac_phy.switch_analog(mac, 0);
+
+ siba_dev_down(sd, 0);
+fail:
+ siba_powerdown(siba);
+ return (error);
+}
+
+static void
+bwn_reset_core(struct bwn_mac *mac, uint32_t flags)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ uint32_t low, ctl;
+
+ flags |= (BWN_TGSLOW_PHYCLOCK_ENABLE | BWN_TGSLOW_PHYRESET);
+
+ siba_dev_up(sd, flags);
+ DELAY(2000);
+
+ low = (siba_read_4(sd, SIBA_TGSLOW) | SIBA_TGSLOW_FGC) &
+ ~BWN_TGSLOW_PHYRESET;
+ siba_write_4(sd, SIBA_TGSLOW, low);
+ siba_read_4(sd, SIBA_TGSLOW);
+ DELAY(1000);
+ siba_write_4(sd, SIBA_TGSLOW, low & ~SIBA_TGSLOW_FGC);
+ siba_read_4(sd, SIBA_TGSLOW);
+ DELAY(1000);
+
+ if (mac->mac_phy.switch_analog != NULL)
+ mac->mac_phy.switch_analog(mac, 1);
+
+ ctl = BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GMODE;
+ if (flags & BWN_TGSLOW_SUPPORT_G)
+ ctl |= BWN_MACCTL_GMODE;
+ BWN_WRITE_4(mac, BWN_MACCTL, ctl | BWN_MACCTL_IHR_ON);
+}
+
+static int
+bwn_phy_getinfo(struct bwn_mac *mac, int tgshigh)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ uint32_t tmp;
+
+ /* PHY */
+ tmp = BWN_READ_2(mac, BWN_PHYVER);
+ phy->gmode = (tgshigh & BWN_TGSHIGH_HAVE_2GHZ) ? 1 : 0;
+ phy->rf_on = 1;
+ phy->analog = (tmp & BWN_PHYVER_ANALOG) >> 12;
+ phy->type = (tmp & BWN_PHYVER_TYPE) >> 8;
+ phy->rev = (tmp & BWN_PHYVER_VERSION);
+ if ((phy->type == BWN_PHYTYPE_A && phy->rev >= 4) ||
+ (phy->type == BWN_PHYTYPE_B && phy->rev != 2 &&
+ phy->rev != 4 && phy->rev != 6 && phy->rev != 7) ||
+ (phy->type == BWN_PHYTYPE_G && phy->rev > 9) ||
+ (phy->type == BWN_PHYTYPE_N && phy->rev > 4) ||
+ (phy->type == BWN_PHYTYPE_LP && phy->rev > 2))
+ goto unsupphy;
+
+ /* RADIO */
+ if (siba->siba_chipid == 0x4317) {
+ if (siba->siba_chiprev == 0)
+ tmp = 0x3205017f;
+ else if (siba->siba_chiprev == 1)
+ tmp = 0x4205017f;
+ else
+ tmp = 0x5205017f;
+ } else {
+ BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
+ tmp = BWN_READ_2(mac, BWN_RFDATALO);
+ BWN_WRITE_2(mac, BWN_RFCTL, BWN_RFCTL_ID);
+ tmp |= (uint32_t)BWN_READ_2(mac, BWN_RFDATAHI) << 16;
+ }
+ phy->rf_rev = (tmp & 0xf0000000) >> 28;
+ phy->rf_ver = (tmp & 0x0ffff000) >> 12;
+ phy->rf_manuf = (tmp & 0x00000fff);
+ if (phy->rf_manuf != 0x17f) /* 0x17f is broadcom */
+ goto unsupradio;
+ if ((phy->type == BWN_PHYTYPE_A && (phy->rf_ver != 0x2060 ||
+ phy->rf_rev != 1 || phy->rf_manuf != 0x17f)) ||
+ (phy->type == BWN_PHYTYPE_B && (phy->rf_ver & 0xfff0) != 0x2050) ||
+ (phy->type == BWN_PHYTYPE_G && phy->rf_ver != 0x2050) ||
+ (phy->type == BWN_PHYTYPE_N &&
+ phy->rf_ver != 0x2055 && phy->rf_ver != 0x2056) ||
+ (phy->type == BWN_PHYTYPE_LP &&
+ phy->rf_ver != 0x2062 && phy->rf_ver != 0x2063))
+ goto unsupradio;
+
+ return (0);
+unsupphy:
+ device_printf(sc->sc_dev, "unsupported PHY (type %#x, rev %#x, "
+ "analog %#x)\n",
+ phy->type, phy->rev, phy->analog);
+ return (ENXIO);
+unsupradio:
+ device_printf(sc->sc_dev, "unsupported radio (manuf %#x, ver %#x, "
+ "rev %#x)\n",
+ phy->rf_manuf, phy->rf_ver, phy->rf_rev);
+ return (ENXIO);
+}
+
+static int
+bwn_chiptest(struct bwn_mac *mac)
+{
+#define TESTVAL0 0x55aaaa55
+#define TESTVAL1 0xaa5555aa
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ uint32_t v, backup;
+
+ BWN_LOCK(sc);
+
+ backup = bwn_shm_read_4(mac, BWN_SHARED, 0);
+
+ bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL0);
+ if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL0)
+ goto error;
+ bwn_shm_write_4(mac, BWN_SHARED, 0, TESTVAL1);
+ if (bwn_shm_read_4(mac, BWN_SHARED, 0) != TESTVAL1)
+ goto error;
+
+ bwn_shm_write_4(mac, BWN_SHARED, 0, backup);
+
+ if ((sd->sd_id.sd_rev >= 3) && (sd->sd_id.sd_rev <= 10)) {
+ BWN_WRITE_2(mac, BWN_TSF_CFP_START, 0xaaaa);
+ BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0xccccbbbb);
+ if (BWN_READ_2(mac, BWN_TSF_CFP_START_LOW) != 0xbbbb)
+ goto error;
+ if (BWN_READ_2(mac, BWN_TSF_CFP_START_HIGH) != 0xcccc)
+ goto error;
+ }
+ BWN_WRITE_4(mac, BWN_TSF_CFP_START, 0);
+
+ v = BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_GMODE;
+ if (v != (BWN_MACCTL_GMODE | BWN_MACCTL_IHR_ON))
+ goto error;
+
+ BWN_UNLOCK(sc);
+ return (0);
+error:
+ BWN_UNLOCK(sc);
+ device_printf(sc->sc_dev, "failed to validate the chipaccess\n");
+ return (ENODEV);
+}
+
+#define IEEE80211_CHAN_HTG (IEEE80211_CHAN_HT | IEEE80211_CHAN_G)
+#define IEEE80211_CHAN_HTA (IEEE80211_CHAN_HT | IEEE80211_CHAN_A)
+
+static int
+bwn_setup_channels(struct bwn_mac *mac, int have_bg, int have_a)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ memset(ic->ic_channels, 0, sizeof(ic->ic_channels));
+ ic->ic_nchans = 0;
+
+ if (have_bg)
+ bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
+ &ic->ic_nchans, &bwn_chantable_bg, IEEE80211_CHAN_G);
+ if (mac->mac_phy.type == BWN_PHYTYPE_N) {
+ if (have_a)
+ bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
+ &ic->ic_nchans, &bwn_chantable_n,
+ IEEE80211_CHAN_HTA);
+ } else {
+ if (have_a)
+ bwn_addchannels(ic->ic_channels, IEEE80211_CHAN_MAX,
+ &ic->ic_nchans, &bwn_chantable_a,
+ IEEE80211_CHAN_A);
+ }
+
+ mac->mac_phy.supports_2ghz = have_bg;
+ mac->mac_phy.supports_5ghz = have_a;
+
+ return (ic->ic_nchans == 0 ? ENXIO : 0);
+}
+
+static uint32_t
+bwn_shm_read_4(struct bwn_mac *mac, uint16_t way, uint16_t offset)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint32_t ret;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (way == BWN_SHARED) {
+ KASSERT((offset & 0x0001) == 0,
+ ("%s:%d warn", __func__, __LINE__));
+ if (offset & 0x0003) {
+ bwn_shm_ctlword(mac, way, offset >> 2);
+ ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
+ ret <<= 16;
+ bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
+ ret |= BWN_READ_2(mac, BWN_SHM_DATA);
+ goto out;
+ }
+ offset >>= 2;
+ }
+ bwn_shm_ctlword(mac, way, offset);
+ ret = BWN_READ_4(mac, BWN_SHM_DATA);
+out:
+ return (ret);
+}
+
+static uint16_t
+bwn_shm_read_2(struct bwn_mac *mac, uint16_t way, uint16_t offset)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t ret;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (way == BWN_SHARED) {
+ KASSERT((offset & 0x0001) == 0,
+ ("%s:%d warn", __func__, __LINE__));
+ if (offset & 0x0003) {
+ bwn_shm_ctlword(mac, way, offset >> 2);
+ ret = BWN_READ_2(mac, BWN_SHM_DATA_UNALIGNED);
+ goto out;
+ }
+ offset >>= 2;
+ }
+ bwn_shm_ctlword(mac, way, offset);
+ ret = BWN_READ_2(mac, BWN_SHM_DATA);
+out:
+
+ return (ret);
+}
+
+static void
+bwn_shm_ctlword(struct bwn_mac *mac, uint16_t way,
+ uint16_t offset)
+{
+ uint32_t control;
+
+ control = way;
+ control <<= 16;
+ control |= offset;
+ BWN_WRITE_4(mac, BWN_SHM_CONTROL, control);
+}
+
+static void
+bwn_shm_write_4(struct bwn_mac *mac, uint16_t way, uint16_t offset,
+ uint32_t value)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (way == BWN_SHARED) {
+ KASSERT((offset & 0x0001) == 0,
+ ("%s:%d warn", __func__, __LINE__));
+ if (offset & 0x0003) {
+ bwn_shm_ctlword(mac, way, offset >> 2);
+ BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED,
+ (value >> 16) & 0xffff);
+ bwn_shm_ctlword(mac, way, (offset >> 2) + 1);
+ BWN_WRITE_2(mac, BWN_SHM_DATA, value & 0xffff);
+ return;
+ }
+ offset >>= 2;
+ }
+ bwn_shm_ctlword(mac, way, offset);
+ BWN_WRITE_4(mac, BWN_SHM_DATA, value);
+}
+
+static void
+bwn_shm_write_2(struct bwn_mac *mac, uint16_t way, uint16_t offset,
+ uint16_t value)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (way == BWN_SHARED) {
+ KASSERT((offset & 0x0001) == 0,
+ ("%s:%d warn", __func__, __LINE__));
+ if (offset & 0x0003) {
+ bwn_shm_ctlword(mac, way, offset >> 2);
+ BWN_WRITE_2(mac, BWN_SHM_DATA_UNALIGNED, value);
+ return;
+ }
+ offset >>= 2;
+ }
+ bwn_shm_ctlword(mac, way, offset);
+ BWN_WRITE_2(mac, BWN_SHM_DATA, value);
+}
+
+static void
+bwn_addchan(struct ieee80211_channel *c, int freq, int flags, int ieee,
+ int txpow)
+{
+
+ c->ic_freq = freq;
+ c->ic_flags = flags;
+ c->ic_ieee = ieee;
+ c->ic_minpower = 0;
+ c->ic_maxpower = 2 * txpow;
+ c->ic_maxregpower = txpow;
+}
+
+static void
+bwn_addchannels(struct ieee80211_channel chans[], int maxchans, int *nchans,
+ const struct bwn_channelinfo *ci, int flags)
+{
+ struct ieee80211_channel *c;
+ int i;
+
+ c = &chans[*nchans];
+
+ for (i = 0; i < ci->nchannels; i++) {
+ const struct bwn_channel *hc;
+
+ hc = &ci->channels[i];
+ if (*nchans >= maxchans)
+ break;
+ bwn_addchan(c, hc->freq, flags, hc->ieee, hc->maxTxPow);
+ c++, (*nchans)++;
+ if (flags == IEEE80211_CHAN_G || flags == IEEE80211_CHAN_HTG) {
+ /* g channel have a separate b-only entry */
+ if (*nchans >= maxchans)
+ break;
+ c[0] = c[-1];
+ c[-1].ic_flags = IEEE80211_CHAN_B;
+ c++, (*nchans)++;
+ }
+ if (flags == IEEE80211_CHAN_HTG) {
+ /* HT g channel have a separate g-only entry */
+ if (*nchans >= maxchans)
+ break;
+ c[-1].ic_flags = IEEE80211_CHAN_G;
+ c[0] = c[-1];
+ c[0].ic_flags &= ~IEEE80211_CHAN_HT;
+ c[0].ic_flags |= IEEE80211_CHAN_HT20; /* HT20 */
+ c++, (*nchans)++;
+ }
+ if (flags == IEEE80211_CHAN_HTA) {
+ /* HT a channel have a separate a-only entry */
+ if (*nchans >= maxchans)
+ break;
+ c[-1].ic_flags = IEEE80211_CHAN_A;
+ c[0] = c[-1];
+ c[0].ic_flags &= ~IEEE80211_CHAN_HT;
+ c[0].ic_flags |= IEEE80211_CHAN_HT20; /* HT20 */
+ c++, (*nchans)++;
+ }
+ }
+}
+
+static int
+bwn_phy_g_attach(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_sprom *sprom = &sd->sd_bus->siba_sprom;
+ unsigned int i;
+ int16_t pab0 = (int16_t)(sprom->pa0b0), pab1 = (int16_t)(sprom->pa0b1),
+ pab2 = (int16_t)(sprom->pa0b2);
+ static int8_t bwn_phy_g_tssi2dbm_table[] = BWN_PHY_G_TSSI2DBM_TABLE;
+ int8_t bg = (int8_t)sprom->tssi_bg;
+
+ if ((sd->sd_bus->siba_chipid == 0x4301) && (phy->rf_ver != 0x2050))
+ device_printf(sc->sc_dev, "not supported anymore\n");
+
+ pg->pg_flags = 0;
+ if (pab0 == 0 || pab1 == 0 || pab2 == 0 || pab0 == -1 || pab1 == -1 ||
+ pab2 == -1) {
+ pg->pg_idletssi = 52;
+ pg->pg_tssi2dbm = bwn_phy_g_tssi2dbm_table;
+ return (0);
+ }
+
+ pg->pg_idletssi = (bg == 0 || bg == -1) ? 62 : bg;
+ pg->pg_tssi2dbm = (uint8_t *)malloc(64, M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (pg->pg_tssi2dbm == NULL) {
+ device_printf(sc->sc_dev, "failed to allocate buffer\n");
+ return (ENOMEM);
+ }
+ for (i = 0; i < 64; i++) {
+ int32_t m1, m2, f, q, delta;
+ int8_t j = 0;
+
+ m1 = BWN_TSSI2DBM(16 * pab0 + i * pab1, 32);
+ m2 = MAX(BWN_TSSI2DBM(32768 + i * pab2, 256), 1);
+ f = 256;
+
+ do {
+ if (j > 15) {
+ device_printf(sc->sc_dev,
+ "failed to generate tssi2dBm\n");
+ free(pg->pg_tssi2dbm, M_DEVBUF);
+ return (ENOMEM);
+ }
+ q = BWN_TSSI2DBM(f * 4096 - BWN_TSSI2DBM(m2 * f, 16) *
+ f, 2048);
+ delta = abs(q - f);
+ f = q;
+ j++;
+ } while (delta >= 2);
+
+ pg->pg_tssi2dbm[i] = MIN(MAX(BWN_TSSI2DBM(m1 * f, 8192), -127),
+ 128);
+ }
+
+ pg->pg_flags |= BWN_PHY_G_FLAG_TSSITABLE_ALLOC;
+ return (0);
+}
+
+static void
+bwn_phy_g_detach(struct bwn_mac *mac)
+{
+ struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
+
+ if (pg->pg_flags & BWN_PHY_G_FLAG_TSSITABLE_ALLOC) {
+ free(pg->pg_tssi2dbm, M_DEVBUF);
+ pg->pg_tssi2dbm = NULL;
+ }
+ pg->pg_flags = 0;
+}
+
+static void
+bwn_phy_g_init_pre(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ void *tssi2dbm;
+ int idletssi;
+ unsigned int i;
+
+ tssi2dbm = pg->pg_tssi2dbm;
+ idletssi = pg->pg_idletssi;
+
+ memset(pg, 0, sizeof(*pg));
+
+ pg->pg_tssi2dbm = tssi2dbm;
+ pg->pg_idletssi = idletssi;
+
+ memset(pg->pg_minlowsig, 0xff, sizeof(pg->pg_minlowsig));
+
+ for (i = 0; i < N(pg->pg_nrssi); i++)
+ pg->pg_nrssi[i] = -1000;
+ for (i = 0; i < N(pg->pg_nrssi_lt); i++)
+ pg->pg_nrssi_lt[i] = i;
+ pg->pg_lofcal = 0xffff;
+ pg->pg_initval = 0xffff;
+ pg->pg_immode = BWN_IMMODE_NONE;
+ pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_UNKNOWN;
+ pg->pg_avgtssi = 0xff;
+
+ pg->pg_loctl.tx_bias = 0xff;
+ TAILQ_INIT(&pg->pg_loctl.calib_list);
+}
+
+static int
+bwn_phy_g_prepare_hw(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ struct siba_softc *bus = mac->mac_sd->sd_bus;
+ static const struct bwn_rfatt rfatt0[] = {
+ { 3, 0 }, { 1, 0 }, { 5, 0 }, { 7, 0 }, { 9, 0 }, { 2, 0 },
+ { 0, 0 }, { 4, 0 }, { 6, 0 }, { 8, 0 }, { 1, 1 }, { 2, 1 },
+ { 3, 1 }, { 4, 1 }
+ };
+ static const struct bwn_rfatt rfatt1[] = {
+ { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 10, 1 }, { 12, 1 },
+ { 14, 1 }
+ };
+ static const struct bwn_rfatt rfatt2[] = {
+ { 0, 1 }, { 2, 1 }, { 4, 1 }, { 6, 1 }, { 8, 1 }, { 9, 1 },
+ { 9, 1 }
+ };
+ static const struct bwn_bbatt bbatt_0[] = {
+ { 0 }, { 1 }, { 2 }, { 3 }, { 4 }, { 5 }, { 6 }, { 7 }, { 8 }
+ };
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
+
+ if (phy->rf_ver == 0x2050 && phy->rf_rev < 6)
+ pg->pg_bbatt.att = 0;
+ else
+ pg->pg_bbatt.att = 2;
+
+ /* prepare Radio Attenuation */
+ pg->pg_rfatt.padmix = 0;
+
+ if (bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
+ bus->siba_board_type == SIBA_BOARD_BCM4309G) {
+ if (bus->siba_board_rev < 0x43) {
+ pg->pg_rfatt.att = 2;
+ goto done;
+ } else if (bus->siba_board_rev < 0x51) {
+ pg->pg_rfatt.att = 3;
+ goto done;
+ }
+ }
+
+ if (phy->type == BWN_PHYTYPE_A) {
+ pg->pg_rfatt.att = 0x60;
+ goto done;
+ }
+
+ switch (phy->rf_ver) {
+ case 0x2050:
+ switch (phy->rf_rev) {
+ case 0:
+ pg->pg_rfatt.att = 5;
+ goto done;
+ case 1:
+ if (phy->type == BWN_PHYTYPE_G) {
+ if (bus->siba_board_vendor ==
+ SIBA_BOARDVENDOR_BCM &&
+ bus->siba_board_type ==
+ SIBA_BOARD_BCM4309G &&
+ bus->siba_board_rev >= 30)
+ pg->pg_rfatt.att = 3;
+ else if (bus->siba_board_vendor ==
+ SIBA_BOARDVENDOR_BCM &&
+ bus->siba_board_type == SIBA_BOARD_BU4306)
+ pg->pg_rfatt.att = 3;
+ else
+ pg->pg_rfatt.att = 1;
+ } else {
+ if (bus->siba_board_vendor ==
+ SIBA_BOARDVENDOR_BCM &&
+ bus->siba_board_type ==
+ SIBA_BOARD_BCM4309G &&
+ bus->siba_board_rev >= 30)
+ pg->pg_rfatt.att = 7;
+ else
+ pg->pg_rfatt.att = 6;
+ }
+ goto done;
+ case 2:
+ if (phy->type == BWN_PHYTYPE_G) {
+ if (bus->siba_board_vendor ==
+ SIBA_BOARDVENDOR_BCM &&
+ bus->siba_board_type ==
+ SIBA_BOARD_BCM4309G &&
+ bus->siba_board_rev >= 30)
+ pg->pg_rfatt.att = 3;
+ else if (bus->siba_board_vendor ==
+ SIBA_BOARDVENDOR_BCM &&
+ bus->siba_board_type == SIBA_BOARD_BU4306)
+ pg->pg_rfatt.att = 5;
+ else if (bus->siba_chipid == 0x4320)
+ pg->pg_rfatt.att = 4;
+ else
+ pg->pg_rfatt.att = 3;
+ } else
+ pg->pg_rfatt.att = 6;
+ goto done;
+ case 3:
+ pg->pg_rfatt.att = 5;
+ goto done;
+ case 4:
+ case 5:
+ pg->pg_rfatt.att = 1;
+ goto done;
+ case 6:
+ case 7:
+ pg->pg_rfatt.att = 5;
+ goto done;
+ case 8:
+ pg->pg_rfatt.att = 0xa;
+ pg->pg_rfatt.padmix = 1;
+ goto done;
+ case 9:
+ default:
+ pg->pg_rfatt.att = 5;
+ goto done;
+ }
+ break;
+ case 0x2053:
+ switch (phy->rf_rev) {
+ case 1:
+ pg->pg_rfatt.att = 6;
+ goto done;
+ }
+ break;
+ }
+ pg->pg_rfatt.att = 5;
+done:
+ pg->pg_txctl = (bwn_phy_g_txctl(mac) << 4);
+
+ if (!bwn_has_hwpctl(mac)) {
+ lo->rfatt.array = rfatt0;
+ lo->rfatt.len = N(rfatt0);
+ lo->rfatt.min = 0;
+ lo->rfatt.max = 9;
+ goto genbbatt;
+ }
+ if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
+ lo->rfatt.array = rfatt1;
+ lo->rfatt.len = N(rfatt1);
+ lo->rfatt.min = 0;
+ lo->rfatt.max = 14;
+ goto genbbatt;
+ }
+ lo->rfatt.array = rfatt2;
+ lo->rfatt.len = N(rfatt2);
+ lo->rfatt.min = 0;
+ lo->rfatt.max = 9;
+genbbatt:
+ lo->bbatt.array = bbatt_0;
+ lo->bbatt.len = N(bbatt_0);
+ lo->bbatt.min = 0;
+ lo->bbatt.max = 8;
+
+ BWN_READ_4(mac, BWN_MACCTL);
+ if (phy->rev == 1) {
+ phy->gmode = 0;
+ bwn_reset_core(mac, 0);
+ bwn_phy_g_init_sub(mac);
+ phy->gmode = 1;
+ bwn_reset_core(mac, BWN_TGSLOW_SUPPORT_G);
+ }
+ return (0);
+}
+
+static uint16_t
+bwn_phy_g_txctl(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+
+ if (phy->rf_ver != 0x2050)
+ return (0);
+ if (phy->rf_rev == 1)
+ return (BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX);
+ if (phy->rf_rev < 6)
+ return (BWN_TXCTL_PA2DB);
+ if (phy->rf_rev == 8)
+ return (BWN_TXCTL_TXMIX);
+ return (0);
+}
+
+static int
+bwn_phy_g_init(struct bwn_mac *mac)
+{
+
+ bwn_phy_g_init_sub(mac);
+ return (0);
+}
+
+static void
+bwn_phy_g_exit(struct bwn_mac *mac)
+{
+ struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
+ struct bwn_lo_calib *cal, *tmp;
+
+ if (lo == NULL)
+ return;
+ TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
+ TAILQ_REMOVE(&lo->calib_list, cal, list);
+ free(cal, M_DEVBUF);
+ }
+}
+
+static uint16_t
+bwn_phy_g_read(struct bwn_mac *mac, uint16_t reg)
+{
+
+ BWN_WRITE_2(mac, BWN_PHYCTL, reg);
+ return (BWN_READ_2(mac, BWN_PHYDATA));
+}
+
+static void
+bwn_phy_g_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
+{
+
+ BWN_WRITE_2(mac, BWN_PHYCTL, reg);
+ BWN_WRITE_2(mac, BWN_PHYDATA, value);
+}
+
+static uint16_t
+bwn_phy_g_rf_read(struct bwn_mac *mac, uint16_t reg)
+{
+
+ KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
+ BWN_WRITE_2(mac, BWN_RFCTL, reg | 0x80);
+ return (BWN_READ_2(mac, BWN_RFDATALO));
+}
+
+static void
+bwn_phy_g_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
+{
+
+ KASSERT(reg != 1, ("%s:%d: fail", __func__, __LINE__));
+ BWN_WRITE_2(mac, BWN_RFCTL, reg);
+ BWN_WRITE_2(mac, BWN_RFDATALO, value);
+}
+
+static int
+bwn_phy_g_hwpctl(struct bwn_mac *mac)
+{
+
+ return (mac->mac_phy.rev >= 6);
+}
+
+static void
+bwn_phy_g_rf_onoff(struct bwn_mac *mac, int on)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ unsigned int channel;
+ uint16_t rfover, rfoverval;
+
+ if (on) {
+ if (phy->rf_on)
+ return;
+
+ BWN_PHY_WRITE(mac, 0x15, 0x8000);
+ BWN_PHY_WRITE(mac, 0x15, 0xcc00);
+ BWN_PHY_WRITE(mac, 0x15, (phy->gmode ? 0xc0 : 0x0));
+ if (pg->pg_flags & BWN_PHY_G_FLAG_RADIOCTX_VALID) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
+ pg->pg_radioctx_over);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ pg->pg_radioctx_overval);
+ pg->pg_flags &= ~BWN_PHY_G_FLAG_RADIOCTX_VALID;
+ }
+ channel = phy->chan;
+ bwn_phy_g_switch_chan(mac, 6, 1);
+ bwn_phy_g_switch_chan(mac, channel, 0);
+ return;
+ }
+
+ rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
+ rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
+ pg->pg_radioctx_over = rfover;
+ pg->pg_radioctx_overval = rfoverval;
+ pg->pg_flags |= BWN_PHY_G_FLAG_RADIOCTX_VALID;
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover | 0x008c);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval & 0xff73);
+}
+
+static int
+bwn_phy_g_switch_channel(struct bwn_mac *mac, uint32_t newchan)
+{
+
+ if ((newchan < 1) || (newchan > 14))
+ return (EINVAL);
+ bwn_phy_g_switch_chan(mac, newchan, 0);
+
+ return (0);
+}
+
+static uint32_t
+bwn_phy_g_get_default_chan(struct bwn_mac *mac)
+{
+
+ return (1);
+}
+
+static void
+bwn_phy_g_set_antenna(struct bwn_mac *mac, int antenna)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint64_t hf;
+ int autodiv = 0;
+ uint16_t tmp;
+
+ if (antenna == BWN_ANTAUTO0 || antenna == BWN_ANTAUTO1)
+ autodiv = 1;
+
+ hf = bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER;
+ bwn_hf_write(mac, hf);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_BBANDCFG,
+ (BWN_PHY_READ(mac, BWN_PHY_BBANDCFG) & ~BWN_PHY_BBANDCFG_RXANT) |
+ ((autodiv ? BWN_ANTAUTO1 : antenna)
+ << BWN_PHY_BBANDCFG_RXANT_SHIFT));
+
+ if (autodiv) {
+ tmp = BWN_PHY_READ(mac, BWN_PHY_ANTDWELL);
+ if (antenna == BWN_ANTAUTO1)
+ tmp &= ~BWN_PHY_ANTDWELL_AUTODIV1;
+ else
+ tmp |= BWN_PHY_ANTDWELL_AUTODIV1;
+ BWN_PHY_WRITE(mac, BWN_PHY_ANTDWELL, tmp);
+ }
+ tmp = BWN_PHY_READ(mac, BWN_PHY_ANTWRSETT);
+ if (autodiv)
+ tmp |= BWN_PHY_ANTWRSETT_ARXDIV;
+ else
+ tmp &= ~BWN_PHY_ANTWRSETT_ARXDIV;
+ BWN_PHY_WRITE(mac, BWN_PHY_ANTWRSETT, tmp);
+ if (phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM61,
+ BWN_PHY_READ(mac, BWN_PHY_OFDM61) | BWN_PHY_OFDM61_10);
+ BWN_PHY_WRITE(mac, BWN_PHY_DIVSRCHGAINBACK,
+ (BWN_PHY_READ(mac, BWN_PHY_DIVSRCHGAINBACK) & 0xff00) |
+ 0x15);
+ if (phy->rev == 2)
+ BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED, 8);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_ADIVRELATED,
+ (BWN_PHY_READ(mac, BWN_PHY_ADIVRELATED) & 0xff00) |
+ 8);
+ }
+ if (phy->rev >= 6)
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM9B, 0xdc);
+
+ hf |= BWN_HF_UCODE_ANTDIV_HELPER;
+ bwn_hf_write(mac, hf);
+}
+
+static int
+bwn_phy_g_im(struct bwn_mac *mac, int mode)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
+ KASSERT(mode == BWN_IMMODE_NONE, ("%s: fail", __func__));
+
+ if (phy->rev == 0 || !phy->gmode)
+ return (ENODEV);
+
+ pg->pg_aci_wlan_automatic = 0;
+ return (0);
+}
+
+static int
+bwn_phy_g_recalc_txpwr(struct bwn_mac *mac, int ignore_tssi)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+ unsigned int tssi;
+ int cck, ofdm;
+ int power;
+ int rfatt, bbatt;
+ unsigned int max;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
+
+ cck = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_CCK);
+ ofdm = bwn_phy_shm_tssi_read(mac, BWN_SHARED_TSSI_OFDM_G);
+ if (cck < 0 && ofdm < 0) {
+ if (ignore_tssi == 0)
+ return (BWN_TXPWR_RES_DONE);
+ cck = 0;
+ ofdm = 0;
+ }
+ tssi = (cck < 0) ? ofdm : ((ofdm < 0) ? cck : (cck + ofdm) / 2);
+ if (pg->pg_avgtssi != 0xff)
+ tssi = (tssi + pg->pg_avgtssi) / 2;
+ pg->pg_avgtssi = tssi;
+ KASSERT(tssi < BWN_TSSI_MAX, ("%s:%d: fail", __func__, __LINE__));
+
+ max = siba->siba_sprom.maxpwr_bg;
+ if (siba->siba_sprom.bf_lo & BWN_BFL_PACTRL)
+ max -= 3;
+ if (max >= 120) {
+ device_printf(sc->sc_dev, "invalid max TX-power value\n");
+ siba->siba_sprom.maxpwr_bg = max = 80;
+ }
+
+ power = MIN(MAX((phy->txpower < 0) ? 0 : (phy->txpower << 2), 0), max) -
+ (pg->pg_tssi2dbm[MIN(MAX(pg->pg_idletssi - pg->pg_curtssi +
+ tssi, 0x00), 0x3f)]);
+ if (power == 0)
+ return (BWN_TXPWR_RES_DONE);
+
+ rfatt = -((power + 7) / 8);
+ bbatt = (-(power / 2)) - (4 * rfatt);
+ if ((rfatt == 0) && (bbatt == 0))
+ return (BWN_TXPWR_RES_DONE);
+ pg->pg_bbatt_delta = bbatt;
+ pg->pg_rfatt_delta = rfatt;
+ return (BWN_TXPWR_RES_NEED_ADJUST);
+}
+
+static void
+bwn_phy_g_set_txpwr(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_softc *sc = mac->mac_sc;
+ int rfatt, bbatt;
+ uint8_t txctl;
+
+ bwn_mac_suspend(mac);
+
+ BWN_ASSERT_LOCKED(sc);
+
+ bbatt = pg->pg_bbatt.att;
+ bbatt += pg->pg_bbatt_delta;
+ rfatt = pg->pg_rfatt.att;
+ rfatt += pg->pg_rfatt_delta;
+
+ bwn_phy_g_setatt(mac, &bbatt, &rfatt);
+ txctl = pg->pg_txctl;
+ if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 2)) {
+ if (rfatt <= 1) {
+ if (txctl == 0) {
+ txctl = BWN_TXCTL_PA2DB | BWN_TXCTL_TXMIX;
+ rfatt += 2;
+ bbatt += 2;
+ } else if (mac->mac_sd->sd_bus->siba_sprom.
+ bf_lo &
+ BWN_BFL_PACTRL) {
+ bbatt += 4 * (rfatt - 2);
+ rfatt = 2;
+ }
+ } else if (rfatt > 4 && txctl) {
+ txctl = 0;
+ if (bbatt < 3) {
+ rfatt -= 3;
+ bbatt += 2;
+ } else {
+ rfatt -= 2;
+ bbatt -= 2;
+ }
+ }
+ }
+ pg->pg_txctl = txctl;
+ bwn_phy_g_setatt(mac, &bbatt, &rfatt);
+ pg->pg_rfatt.att = rfatt;
+ pg->pg_bbatt.att = bbatt;
+
+ DPRINTF(sc, BWN_DEBUG_TXPOW, "%s: adjust TX power\n", __func__);
+
+ bwn_phy_lock(mac);
+ bwn_rf_lock(mac);
+ bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
+ pg->pg_txctl);
+ bwn_rf_unlock(mac);
+ bwn_phy_unlock(mac);
+
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_phy_g_task_15s(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ unsigned long expire, now;
+ struct bwn_lo_calib *cal, *tmp;
+ uint8_t expired = 0;
+
+ bwn_mac_suspend(mac);
+
+ if (lo == NULL)
+ goto fail;
+
+ BWN_GETTIME(now);
+ if (bwn_has_hwpctl(mac)) {
+ expire = now - BWN_LO_PWRVEC_EXPIRE;
+ if (time_before(lo->pwr_vec_read_time, expire)) {
+ bwn_lo_get_powervector(mac);
+ bwn_phy_g_dc_lookup_init(mac, 0);
+ }
+ goto fail;
+ }
+
+ expire = now - BWN_LO_CALIB_EXPIRE;
+ TAILQ_FOREACH_SAFE(cal, &lo->calib_list, list, tmp) {
+ if (!time_before(cal->calib_time, expire))
+ continue;
+ if (BWN_BBATTCMP(&cal->bbatt, &pg->pg_bbatt) &&
+ BWN_RFATTCMP(&cal->rfatt, &pg->pg_rfatt)) {
+ KASSERT(!expired, ("%s:%d: fail", __func__, __LINE__));
+ expired = 1;
+ }
+
+ DPRINTF(sc, BWN_DEBUG_LO, "expired BB %u RF %u %u I %d Q %d\n",
+ cal->bbatt.att, cal->rfatt.att, cal->rfatt.padmix,
+ cal->ctl.i, cal->ctl.q);
+
+ TAILQ_REMOVE(&lo->calib_list, cal, list);
+ free(cal, M_DEVBUF);
+ }
+ if (expired || TAILQ_EMPTY(&lo->calib_list)) {
+ cal = bwn_lo_calibset(mac, &pg->pg_bbatt,
+ &pg->pg_rfatt);
+ if (cal == NULL) {
+ device_printf(sc->sc_dev,
+ "failed to recalibrate LO\n");
+ goto fail;
+ }
+ TAILQ_INSERT_TAIL(&lo->calib_list, cal, list);
+ bwn_lo_write(mac, &cal->ctl);
+ }
+
+fail:
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_phy_g_task_60s(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint8_t old = phy->chan;
+
+ if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI))
+ return;
+
+ bwn_mac_suspend(mac);
+ bwn_nrssi_slope_11g(mac);
+ if ((phy->rf_ver == 0x2050) && (phy->rf_rev == 8)) {
+ bwn_switch_channel(mac, (old >= 8) ? 1 : 13);
+ bwn_switch_channel(mac, old);
+ }
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_phy_switch_analog(struct bwn_mac *mac, int on)
+{
+
+ BWN_WRITE_2(mac, BWN_PHY0, on ? 0 : 0xf4);
+}
+
+static int
+bwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
+ const struct ieee80211_bpf_params *params)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac = sc->sc_curmac;
+
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
+ mac->mac_status < BWN_MAC_STATUS_STARTED) {
+ ieee80211_free_node(ni);
+ m_freem(m);
+ return (ENETDOWN);
+ }
+
+ BWN_LOCK(sc);
+ if (bwn_tx_isfull(sc, m)) {
+ ieee80211_free_node(ni);
+ m_freem(m);
+ ifp->if_oerrors++;
+ BWN_UNLOCK(sc);
+ return (ENOBUFS);
+ }
+
+ if (bwn_tx_start(sc, ni, m) != 0) {
+ if (ni != NULL)
+ ieee80211_free_node(ni);
+ ifp->if_oerrors++;
+ }
+ sc->sc_watchdog_timer = 5;
+ BWN_UNLOCK(sc);
+ return (0);
+}
+
+/*
+ * Setup driver-specific state for a newly associated node.
+ * Note that we're called also on a re-associate, the isnew
+ * param tells us if this is the first time or not.
+ */
+static void
+bwn_newassoc(struct ieee80211_node *ni, int isnew)
+{
+ struct ieee80211vap *vap = ni->ni_vap;
+
+ ieee80211_amrr_node_init(&BWN_VAP(vap)->bv_amrr,
+ &BWN_NODE(ni)->bn_amn, ni);
+}
+
+/*
+ * Callback from the 802.11 layer to update the slot time
+ * based on the current setting. We use it to notify the
+ * firmware of ERP changes and the f/w takes care of things
+ * like slot time and preamble.
+ */
+static void
+bwn_updateslot(struct ifnet *ifp)
+{
+ struct bwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct bwn_mac *mac;
+
+ BWN_LOCK(sc);
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
+ mac = (struct bwn_mac *)sc->sc_curmac;
+ bwn_set_slot_time(mac,
+ (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20);
+ }
+ BWN_UNLOCK(sc);
+}
+
+/*
+ * Callback from the 802.11 layer after a promiscuous mode change.
+ * Note this interface does not check the operating mode as this
+ * is an internal callback and we are expected to honor the current
+ * state (e.g. this is used for setting the interface in promiscuous
+ * mode when operating in hostap mode to do ACS).
+ */
+static void
+bwn_update_promisc(struct ifnet *ifp)
+{
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac = sc->sc_curmac;
+
+ BWN_LOCK(sc);
+ mac = sc->sc_curmac;
+ if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
+ if (ifp->if_flags & IFF_PROMISC)
+ sc->sc_filters |= BWN_MACCTL_PROMISC;
+ else
+ sc->sc_filters &= ~BWN_MACCTL_PROMISC;
+ bwn_set_opmode(mac);
+ }
+ BWN_UNLOCK(sc);
+}
+
+/*
+ * Callback from the 802.11 layer to update WME parameters.
+ */
+static int
+bwn_wme_update(struct ieee80211com *ic)
+{
+ struct bwn_softc *sc = ic->ic_ifp->if_softc;
+ struct bwn_mac *mac = sc->sc_curmac;
+ struct wmeParams *wmep;
+ int i;
+
+ BWN_LOCK(sc);
+ mac = sc->sc_curmac;
+ if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
+ bwn_mac_suspend(mac);
+ for (i = 0; i < N(sc->sc_wmeParams); i++) {
+ wmep = &ic->ic_wme.wme_chanParams.cap_wmeParams[i];
+ bwn_wme_loadparams(mac, wmep, bwn_wme_shm_offsets[i]);
+ }
+ bwn_mac_enable(mac);
+ }
+ BWN_UNLOCK(sc);
+ return (0);
+}
+
+static struct ieee80211_node *
+bwn_node_alloc(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
+{
+ struct ieee80211com *ic = vap->iv_ic;
+ struct bwn_softc *sc = ic->ic_ifp->if_softc;
+ const size_t space = sizeof(struct bwn_node);
+ struct bwn_node *bn;
+
+ bn = malloc(space, M_80211_NODE, M_NOWAIT|M_ZERO);
+ if (bn == NULL) {
+ /* XXX stat+msg */
+ return (NULL);
+ }
+ DPRINTF(sc, BWN_DEBUG_NODE, "%s: bn %p\n", __func__, bn);
+ return (&bn->bn_node);
+}
+
+static void
+bwn_node_cleanup(struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct bwn_softc *sc = ic->ic_ifp->if_softc;
+
+ sc->sc_node_cleanup(ni);
+}
+
+static void
+bwn_scan_start(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac;
+
+ BWN_LOCK(sc);
+ mac = sc->sc_curmac;
+ if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
+ sc->sc_filters |= BWN_MACCTL_BEACON_PROMISC;
+ bwn_set_opmode(mac);
+ /* disable CFP update during scan */
+ bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_SKIP_CFP_UPDATE);
+ }
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_scan_end(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac;
+
+ BWN_LOCK(sc);
+ mac = sc->sc_curmac;
+ if (mac != NULL && mac->mac_status >= BWN_MAC_STATUS_INITED) {
+ sc->sc_filters &= ~BWN_MACCTL_BEACON_PROMISC;
+ bwn_set_opmode(mac);
+ bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_SKIP_CFP_UPDATE);
+ }
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_set_channel(struct ieee80211com *ic)
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac = sc->sc_curmac;
+ struct bwn_phy *phy = &mac->mac_phy;
+ int chan, error;
+
+ BWN_LOCK(sc);
+
+ error = bwn_switch_band(sc, ic->ic_curchan);
+ if (error)
+ goto fail;;
+ bwn_mac_suspend(mac);
+ bwn_set_txretry(mac, BWN_RETRY_SHORT, BWN_RETRY_LONG);
+ chan = ieee80211_chan2ieee(ic, ic->ic_curchan);
+ if (chan != phy->chan)
+ bwn_switch_channel(mac, chan);
+
+ /* TX power level */
+ if (ic->ic_curchan->ic_maxpower != 0 &&
+ ic->ic_curchan->ic_maxpower != phy->txpower) {
+ phy->txpower = ic->ic_curchan->ic_maxpower / 2;
+ bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME |
+ BWN_TXPWR_IGNORE_TSSI);
+ }
+
+ bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
+ if (phy->set_antenna)
+ phy->set_antenna(mac, BWN_ANT_DEFAULT);
+
+ if (sc->sc_rf_enabled != phy->rf_on) {
+ if (sc->sc_rf_enabled) {
+ bwn_rf_turnon(mac);
+ if (!(mac->mac_flags & BWN_MAC_FLAG_RADIO_ON))
+ device_printf(sc->sc_dev,
+ "please turns on the RF switch\n");
+ } else
+ bwn_rf_turnoff(mac);
+ }
+
+ bwn_mac_enable(mac);
+
+fail:
+ /*
+ * Setup radio tap channel freq and flags
+ */
+ sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
+ htole16(ic->ic_curchan->ic_freq);
+ sc->sc_tx_th.wt_chan_flags = sc->sc_rx_th.wr_chan_flags =
+ htole16(ic->ic_curchan->ic_flags & 0xffff);
+
+ BWN_UNLOCK(sc);
+}
+
+static struct ieee80211vap *
+bwn_vap_create(struct ieee80211com *ic,
+ const char name[IFNAMSIZ], int unit, int opmode, int flags,
+ const uint8_t bssid[IEEE80211_ADDR_LEN],
+ const uint8_t mac0[IEEE80211_ADDR_LEN])
+{
+ struct ifnet *ifp = ic->ic_ifp;
+ struct bwn_softc *sc = ifp->if_softc;
+ struct ieee80211vap *vap;
+ struct bwn_vap *bvp;
+ uint8_t mac[IEEE80211_ADDR_LEN];
+
+ IEEE80211_ADDR_COPY(mac, mac0);
+ switch (opmode) {
+ case IEEE80211_M_HOSTAP:
+ case IEEE80211_M_MBSS:
+ case IEEE80211_M_STA:
+ case IEEE80211_M_WDS:
+ case IEEE80211_M_MONITOR:
+ case IEEE80211_M_IBSS:
+ case IEEE80211_M_AHDEMO:
+ break;
+ default:
+ return (NULL);
+ }
+
+ IEEE80211_ADDR_COPY(sc->sc_macaddr, mac0);
+
+ bvp = (struct bwn_vap *) malloc(sizeof(struct bwn_vap),
+ M_80211_VAP, M_NOWAIT | M_ZERO);
+ if (bvp == NULL) {
+ device_printf(sc->sc_dev, "failed to allocate a buffer\n");
+ return (NULL);
+ }
+ vap = &bvp->bv_vap;
+ ieee80211_vap_setup(ic, vap, name, unit, opmode, flags, bssid, mac);
+ IEEE80211_ADDR_COPY(vap->iv_myaddr, mac);
+ /* override with driver methods */
+ bvp->bv_newstate = vap->iv_newstate;
+ vap->iv_newstate = bwn_newstate;
+
+ /* override max aid so sta's cannot assoc when we're out of sta id's */
+ vap->iv_max_aid = BWN_STAID_MAX;
+
+ ieee80211_amrr_init(&bvp->bv_amrr, vap,
+ IEEE80211_AMRR_MIN_SUCCESS_THRESHOLD,
+ IEEE80211_AMRR_MAX_SUCCESS_THRESHOLD,
+ 500 /*ms*/);
+
+ /* complete setup */
+ ieee80211_vap_attach(vap, ieee80211_media_change,
+ ieee80211_media_status);
+ return (vap);
+}
+
+static void
+bwn_vap_delete(struct ieee80211vap *vap)
+{
+ struct bwn_vap *bvp = BWN_VAP(vap);
+
+ ieee80211_amrr_cleanup(&bvp->bv_amrr);
+ ieee80211_vap_detach(vap);
+ free(bvp, M_80211_VAP);
+}
+
+static void
+bwn_init(void *arg)
+{
+ struct bwn_softc *sc = arg;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ int error = 0;
+
+ DPRINTF(sc, BWN_DEBUG_ANY, "%s: if_flags 0x%x\n",
+ __func__, ifp->if_flags);
+
+ BWN_LOCK(sc);
+ error = bwn_init_locked(sc);
+ BWN_UNLOCK(sc);
+
+ if (error == 0)
+ ieee80211_start_all(ic); /* start all vap's */
+}
+
+static int
+bwn_init_locked(struct bwn_softc *sc)
+{
+ struct bwn_mac *mac;
+ struct ifnet *ifp = sc->sc_ifp;
+ int error;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ bzero(sc->sc_bssid, IEEE80211_ADDR_LEN);
+ sc->sc_flags |= BWN_FLAG_NEED_BEACON_TP;
+ sc->sc_filters = 0;
+ bwn_wme_clear(sc);
+ sc->sc_beacons[0] = sc->sc_beacons[1] = 0;
+ sc->sc_rf_enabled = 1;
+
+ mac = sc->sc_curmac;
+ if (mac->mac_status == BWN_MAC_STATUS_UNINIT) {
+ error = bwn_core_init(mac);
+ if (error != 0)
+ return (error);
+ }
+ if (mac->mac_status == BWN_MAC_STATUS_INITED)
+ bwn_core_start(mac);
+
+ bwn_set_opmode(mac);
+ bwn_set_pretbtt(mac);
+ bwn_spu_setdelay(mac, 0);
+ bwn_set_macaddr(mac);
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+ callout_reset(&sc->sc_rfswitch_ch, hz, bwn_rfswitch, sc);
+ callout_reset(&sc->sc_watchdog_ch, hz, bwn_watchdog, sc);
+
+ return (0);
+}
+
+static void
+bwn_stop(struct bwn_softc *sc, int statechg)
+{
+
+ BWN_LOCK(sc);
+ bwn_stop_locked(sc, statechg);
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_stop_locked(struct bwn_softc *sc, int statechg)
+{
+ struct bwn_mac *mac = sc->sc_curmac;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (mac->mac_status >= BWN_MAC_STATUS_INITED) {
+ /* XXX FIXME opmode not based on VAP */
+ bwn_set_opmode(mac);
+ bwn_set_macaddr(mac);
+ }
+
+ if (mac->mac_status >= BWN_MAC_STATUS_STARTED)
+ bwn_core_stop(mac);
+
+ callout_stop(&sc->sc_led_blink_ch);
+ sc->sc_led_blinking = 0;
+
+ bwn_core_exit(mac);
+ sc->sc_rf_enabled = 0;
+
+ ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
+}
+
+static void
+bwn_wme_clear(struct bwn_softc *sc)
+{
+#define MS(_v, _f) (((_v) & _f) >> _f##_S)
+ struct wmeParams *p;
+ unsigned int i;
+
+ KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
+ ("%s:%d: fail", __func__, __LINE__));
+
+ for (i = 0; i < N(sc->sc_wmeParams); i++) {
+ p = &(sc->sc_wmeParams[i]);
+
+ switch (bwn_wme_shm_offsets[i]) {
+ case BWN_WME_VOICE:
+ p->wmep_txopLimit = 0;
+ p->wmep_aifsn = 2;
+ /* XXX FIXME: log2(cwmin) */
+ p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
+ p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
+ break;
+ case BWN_WME_VIDEO:
+ p->wmep_txopLimit = 0;
+ p->wmep_aifsn = 2;
+ /* XXX FIXME: log2(cwmin) */
+ p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
+ p->wmep_logcwmax = MS(0x0001, WME_PARAM_LOGCWMAX);
+ break;
+ case BWN_WME_BESTEFFORT:
+ p->wmep_txopLimit = 0;
+ p->wmep_aifsn = 3;
+ /* XXX FIXME: log2(cwmin) */
+ p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
+ p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
+ break;
+ case BWN_WME_BACKGROUND:
+ p->wmep_txopLimit = 0;
+ p->wmep_aifsn = 7;
+ /* XXX FIXME: log2(cwmin) */
+ p->wmep_logcwmin = MS(0x0001, WME_PARAM_LOGCWMIN);
+ p->wmep_logcwmax = MS(0x03ff, WME_PARAM_LOGCWMAX);
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+ }
+}
+
+static int
+bwn_core_init(struct bwn_mac *mac)
+{
+#ifdef BWN_DEBUG
+ struct bwn_softc *sc = mac->mac_sc;
+#endif
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct siba_sprom *sprom = &siba->siba_sprom;
+ uint64_t hf;
+ int error;
+
+ KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ siba_powerup(siba, 0);
+ if (!siba_dev_isup(sd))
+ bwn_reset_core(mac,
+ mac->mac_phy.gmode ? BWN_TGSLOW_SUPPORT_G : 0);
+
+ mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
+ mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
+ mac->mac_phy.hwpctl = (bwn_hwpctl) ? 1 : 0;
+ BWN_GETTIME(mac->mac_phy.nexttime);
+ mac->mac_phy.txerrors = BWN_TXERROR_MAX;
+ bzero(&mac->mac_stats, sizeof(mac->mac_stats));
+ mac->mac_stats.link_noise = -95;
+ mac->mac_reason_intr = 0;
+ bzero(mac->mac_reason, sizeof(mac->mac_reason));
+ mac->mac_intr_mask = BWN_INTR_MASKTEMPLATE;
+#ifdef BWN_DEBUG
+ if (sc->sc_debug & BWN_DEBUG_XMIT)
+ mac->mac_intr_mask &= ~BWN_INTR_PHY_TXERR;
+#endif
+ mac->mac_suspended = 1;
+ mac->mac_task_state = 0;
+ memset(&mac->mac_noise, 0, sizeof(mac->mac_noise));
+
+ mac->mac_phy.init_pre(mac);
+
+ siba_pcicore_intr(&siba->siba_pci, sd);
+
+ bwn_fix_imcfglobug(mac);
+ bwn_bt_disable(mac);
+ if (mac->mac_phy.prepare_hw) {
+ error = mac->mac_phy.prepare_hw(mac);
+ if (error)
+ goto fail0;
+ }
+ error = bwn_chip_init(mac);
+ if (error)
+ goto fail0;
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_COREREV,
+ mac->mac_sd->sd_id.sd_rev);
+ hf = bwn_hf_read(mac);
+ if (mac->mac_phy.type == BWN_PHYTYPE_G) {
+ hf |= BWN_HF_GPHY_SYM_WORKAROUND;
+ if (sprom->bf_lo & BWN_BFL_PACTRL)
+ hf |= BWN_HF_PAGAINBOOST_OFDM_ON;
+ if (mac->mac_phy.rev == 1)
+ hf |= BWN_HF_GPHY_DC_CANCELFILTER;
+ }
+ if (mac->mac_phy.rf_ver == 0x2050) {
+ if (mac->mac_phy.rf_rev < 6)
+ hf |= BWN_HF_FORCE_VCO_RECALC;
+ if (mac->mac_phy.rf_rev == 6)
+ hf |= BWN_HF_4318_TSSI;
+ }
+ if (sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW)
+ hf |= BWN_HF_SLOWCLOCK_REQ_OFF;
+ if ((siba->siba_type == SIBA_TYPE_PCI) &&
+ (siba->siba_pci.spc_dev->sd_id.sd_rev <= 10))
+ hf |= BWN_HF_PCI_SLOWCLOCK_WORKAROUND;
+ hf &= ~BWN_HF_SKIP_CFP_UPDATE;
+ bwn_hf_write(mac, hf);
+
+ 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_LONG_RETRY_FALLBACK, 2);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_MAXTIME, 1);
+
+ bwn_rate_init(mac);
+ bwn_set_phytxctl(mac);
+
+ bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MIN,
+ (mac->mac_phy.type == BWN_PHYTYPE_B) ? 0x1f : 0xf);
+ bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_CONT_MAX, 0x3ff);
+
+ if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
+ bwn_pio_init(mac);
+ else
+ bwn_dma_init(mac);
+ if (error)
+ goto fail1;
+ bwn_wme_init(mac);
+ bwn_spu_setdelay(mac, 1);
+ bwn_bt_enable(mac);
+
+ siba_powerup(siba, !(sprom->bf_lo & BWN_BFL_CRYSTAL_NOSLOW));
+ bwn_set_macaddr(mac);
+ bwn_crypt_init(mac);
+
+ /* XXX LED initializatin */
+
+ mac->mac_status = BWN_MAC_STATUS_INITED;
+
+ return (error);
+
+fail1:
+ bwn_chip_exit(mac);
+fail0:
+ siba_powerdown(siba);
+ KASSERT(mac->mac_status == BWN_MAC_STATUS_UNINIT,
+ ("%s:%d: fail", __func__, __LINE__));
+ return (error);
+}
+
+static void
+bwn_core_start(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint32_t tmp;
+
+ KASSERT(mac->mac_status == BWN_MAC_STATUS_INITED,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if (mac->mac_sd->sd_id.sd_rev < 5)
+ return;
+
+ while (1) {
+ tmp = BWN_READ_4(mac, BWN_XMITSTAT_0);
+ if (!(tmp & 0x00000001))
+ break;
+ tmp = BWN_READ_4(mac, BWN_XMITSTAT_1);
+ }
+
+ bwn_mac_enable(mac);
+ BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
+ callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
+
+ mac->mac_status = BWN_MAC_STATUS_STARTED;
+}
+
+static void
+bwn_core_exit(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint32_t macctl;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ KASSERT(mac->mac_status <= BWN_MAC_STATUS_INITED,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if (mac->mac_status != BWN_MAC_STATUS_INITED)
+ return;
+ mac->mac_status = BWN_MAC_STATUS_UNINIT;
+
+ macctl = BWN_READ_4(mac, BWN_MACCTL);
+ macctl &= ~BWN_MACCTL_MCODE_RUN;
+ macctl |= BWN_MACCTL_MCODE_JMP0;
+ BWN_WRITE_4(mac, BWN_MACCTL, macctl);
+
+ bwn_dma_stop(mac);
+ bwn_pio_stop(mac);
+ bwn_chip_exit(mac);
+ mac->mac_phy.switch_analog(mac, 0);
+ siba_dev_down(mac->mac_sd, 0);
+ siba_powerdown(mac->mac_sd->sd_bus);
+}
+
+static void
+bwn_fix_imcfglobug(struct bwn_mac *mac)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ uint32_t tmp;
+
+ if (siba->siba_pci.spc_dev == NULL)
+ return;
+ if (siba->siba_pci.spc_dev->sd_id.sd_device != SIBA_DEVID_PCI ||
+ siba->siba_pci.spc_dev->sd_id.sd_rev > 5)
+ return;
+
+ tmp = siba_read_4(sd, SIBA_IMCFGLO) &
+ ~(SIBA_IMCFGLO_REQTO | SIBA_IMCFGLO_SERTO);
+ switch (siba->siba_type) {
+ case SIBA_TYPE_PCI:
+ case SIBA_TYPE_PCMCIA:
+ tmp |= 0x32;
+ break;
+ case SIBA_TYPE_SSB:
+ tmp |= 0x53;
+ break;
+ }
+ siba_write_4(sd, SIBA_IMCFGLO, tmp);
+}
+
+static void
+bwn_bt_disable(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+
+ (void)sc;
+ /* XXX do nothing yet */
+}
+
+static int
+bwn_chip_init(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint32_t macctl;
+ int error;
+
+ macctl = BWN_MACCTL_IHR_ON | BWN_MACCTL_SHM_ON | BWN_MACCTL_STA;
+ if (phy->gmode)
+ macctl |= BWN_MACCTL_GMODE;
+ BWN_WRITE_4(mac, BWN_MACCTL, macctl);
+
+ error = bwn_fw_fillinfo(mac);
+ if (error)
+ return (error);
+ error = bwn_fw_loaducode(mac);
+ if (error)
+ return (error);
+
+ error = bwn_gpio_init(mac);
+ if (error)
+ return (error);
+
+ error = bwn_fw_loadinitvals(mac);
+ if (error) {
+ bwn_gpio_cleanup(mac);
+ return (error);
+ }
+ phy->switch_analog(mac, 1);
+ error = bwn_phy_init(mac);
+ if (error) {
+ bwn_gpio_cleanup(mac);
+ return (error);
+ }
+ if (phy->set_im)
+ phy->set_im(mac, BWN_IMMODE_NONE);
+ if (phy->set_antenna)
+ phy->set_antenna(mac, BWN_ANT_DEFAULT);
+ bwn_set_txantenna(mac, BWN_ANT_DEFAULT);
+
+ if (phy->type == BWN_PHYTYPE_B)
+ BWN_WRITE_2(mac, 0x005e, BWN_READ_2(mac, 0x005e) | 0x0004);
+ BWN_WRITE_4(mac, 0x0100, 0x01000000);
+ if (mac->mac_sd->sd_id.sd_rev < 5)
+ BWN_WRITE_4(mac, 0x010c, 0x01000000);
+
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_STA);
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_STA);
+ bwn_shm_write_2(mac, BWN_SHARED, 0x0074, 0x0000);
+
+ bwn_set_opmode(mac);
+ if (mac->mac_sd->sd_id.sd_rev < 3) {
+ BWN_WRITE_2(mac, 0x060e, 0x0000);
+ BWN_WRITE_2(mac, 0x0610, 0x8000);
+ BWN_WRITE_2(mac, 0x0604, 0x0000);
+ BWN_WRITE_2(mac, 0x0606, 0x0200);
+ } else {
+ BWN_WRITE_4(mac, 0x0188, 0x80000000);
+ BWN_WRITE_4(mac, 0x018c, 0x02000000);
+ }
+ BWN_WRITE_4(mac, BWN_INTR_REASON, 0x00004000);
+ BWN_WRITE_4(mac, BWN_DMA0_INTR_MASK, 0x0001dc00);
+ BWN_WRITE_4(mac, BWN_DMA1_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_DMA4_INTR_MASK, 0x0000dc00);
+ BWN_WRITE_4(mac, BWN_DMA5_INTR_MASK, 0x0000dc00);
+ siba_write_4(mac->mac_sd, SIBA_TGSLOW,
+ siba_read_4(mac->mac_sd, SIBA_TGSLOW) | 0x00100000);
+ BWN_WRITE_2(mac, BWN_POWERUP_DELAY,
+ mac->mac_sd->sd_bus->siba_cc.scc_powerup_delay);
+ return (error);
+}
+
+/* read hostflags */
+static uint64_t
+bwn_hf_read(struct bwn_mac *mac)
+{
+ uint64_t ret;
+
+ ret = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFHI);
+ ret <<= 16;
+ ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFMI);
+ ret <<= 16;
+ ret |= bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO);
+ return (ret);
+}
+
+static void
+bwn_hf_write(struct bwn_mac *mac, uint64_t value)
+{
+
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFLO,
+ (value & 0x00000000ffffull));
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFMI,
+ (value & 0x0000ffff0000ull) >> 16);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_HFHI,
+ (value & 0xffff00000000ULL) >> 32);
+}
+
+static void
+bwn_set_txretry(struct bwn_mac *mac, int s, int l)
+{
+
+ bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_SHORT_RETRY, MIN(s, 0xf));
+ bwn_shm_write_2(mac, BWN_SCRATCH, BWN_SCRATCH_LONG_RETRY, MIN(l, 0xf));
+}
+
+static void
+bwn_rate_init(struct bwn_mac *mac)
+{
+
+ switch (mac->mac_phy.type) {
+ case BWN_PHYTYPE_A:
+ case BWN_PHYTYPE_G:
+ case BWN_PHYTYPE_LP:
+ case BWN_PHYTYPE_N:
+ bwn_rate_write(mac, BWN_OFDM_RATE_6MB, 1);
+ bwn_rate_write(mac, BWN_OFDM_RATE_12MB, 1);
+ bwn_rate_write(mac, BWN_OFDM_RATE_18MB, 1);
+ bwn_rate_write(mac, BWN_OFDM_RATE_24MB, 1);
+ bwn_rate_write(mac, BWN_OFDM_RATE_36MB, 1);
+ bwn_rate_write(mac, BWN_OFDM_RATE_48MB, 1);
+ bwn_rate_write(mac, BWN_OFDM_RATE_54MB, 1);
+ if (mac->mac_phy.type == BWN_PHYTYPE_A)
+ break;
+ /* FALLTHROUGH */
+ case BWN_PHYTYPE_B:
+ bwn_rate_write(mac, BWN_CCK_RATE_1MB, 0);
+ bwn_rate_write(mac, BWN_CCK_RATE_2MB, 0);
+ bwn_rate_write(mac, BWN_CCK_RATE_5MB, 0);
+ bwn_rate_write(mac, BWN_CCK_RATE_11MB, 0);
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+}
+
+static void
+bwn_rate_write(struct bwn_mac *mac, uint16_t rate, int ofdm)
+{
+ uint16_t offset;
+
+ if (ofdm) {
+ offset = 0x480;
+ offset += (bwn_plcp_getofdm(rate) & 0x000f) * 2;
+ } else {
+ offset = 0x4c0;
+ offset += (bwn_plcp_getcck(rate) & 0x000f) * 2;
+ }
+ bwn_shm_write_2(mac, BWN_SHARED, offset + 0x20,
+ bwn_shm_read_2(mac, BWN_SHARED, offset));
+}
+
+static uint8_t
+bwn_plcp_getcck(const uint8_t bitrate)
+{
+
+ switch (bitrate) {
+ case BWN_CCK_RATE_1MB:
+ return (0x0a);
+ case BWN_CCK_RATE_2MB:
+ return (0x14);
+ case BWN_CCK_RATE_5MB:
+ return (0x37);
+ case BWN_CCK_RATE_11MB:
+ return (0x6e);
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (0);
+}
+
+static uint8_t
+bwn_plcp_getofdm(const uint8_t bitrate)
+{
+
+ switch (bitrate) {
+ case BWN_OFDM_RATE_6MB:
+ return (0xb);
+ case BWN_OFDM_RATE_9MB:
+ return (0xf);
+ case BWN_OFDM_RATE_12MB:
+ return (0xa);
+ case BWN_OFDM_RATE_18MB:
+ return (0xe);
+ case BWN_OFDM_RATE_24MB:
+ return (0x9);
+ case BWN_OFDM_RATE_36MB:
+ return (0xd);
+ case BWN_OFDM_RATE_48MB:
+ return (0x8);
+ case BWN_OFDM_RATE_54MB:
+ return (0xc);
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (0);
+}
+
+static void
+bwn_set_phytxctl(struct bwn_mac *mac)
+{
+ uint16_t ctl;
+
+ ctl = (BWN_TX_PHY_ENC_CCK | BWN_TX_PHY_ANT01AUTO |
+ BWN_TX_PHY_TXPWR);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_BEACON_PHYCTL, ctl);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, ctl);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, ctl);
+}
+
+static void
+bwn_pio_init(struct bwn_mac *mac)
+{
+ struct bwn_pio *pio = &mac->mac_method.pio;
+
+ BWN_WRITE_4(mac, BWN_MACCTL, BWN_READ_4(mac, BWN_MACCTL)
+ & ~BWN_MACCTL_BIGENDIAN);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RX_PADOFFSET, 0);
+
+ bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BK], 0);
+ bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_BE], 1);
+ bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VI], 2);
+ bwn_pio_set_txqueue(mac, &pio->wme[WME_AC_VO], 3);
+ bwn_pio_set_txqueue(mac, &pio->mcast, 4);
+ bwn_pio_setupqueue_rx(mac, &pio->rx, 0);
+}
+
+static void
+bwn_pio_set_txqueue(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
+ int index)
+{
+ struct bwn_pio_txpkt *tp;
+ unsigned int i;
+
+ tq->tq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_TXQOFFSET(mac);
+ tq->tq_index = index;
+
+ tq->tq_free = BWN_PIO_MAX_TXPACKETS;
+ if (mac->mac_sd->sd_id.sd_rev >= 8)
+ tq->tq_size = 1920;
+ else {
+ tq->tq_size = bwn_pio_read_2(mac, tq, BWN_PIO_TXQBUFSIZE);
+ tq->tq_size -= 80;
+ }
+
+ TAILQ_INIT(&tq->tq_pktlist);
+ for (i = 0; i < N(tq->tq_pkts); i++) {
+ tp = &(tq->tq_pkts[i]);
+ tp->tp_index = i;
+ tp->tp_queue = tq;
+ TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
+ }
+}
+
+static uint16_t
+bwn_pio_idx2base(struct bwn_mac *mac, int index)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ static const uint16_t bases[] = {
+ BWN_PIO_BASE0,
+ BWN_PIO_BASE1,
+ BWN_PIO_BASE2,
+ BWN_PIO_BASE3,
+ BWN_PIO_BASE4,
+ BWN_PIO_BASE5,
+ BWN_PIO_BASE6,
+ BWN_PIO_BASE7,
+ };
+ static const uint16_t bases_rev11[] = {
+ BWN_PIO11_BASE0,
+ BWN_PIO11_BASE1,
+ BWN_PIO11_BASE2,
+ BWN_PIO11_BASE3,
+ BWN_PIO11_BASE4,
+ BWN_PIO11_BASE5,
+ };
+
+ if (mac->mac_sd->sd_id.sd_rev >= 11) {
+ if (index >= N(bases_rev11))
+ device_printf(sc->sc_dev, "%s: warning\n", __func__);
+ return (bases_rev11[index]);
+ }
+ if (index >= N(bases))
+ device_printf(sc->sc_dev, "%s: warning\n", __func__);
+ return (bases[index]);
+}
+
+static void
+bwn_pio_setupqueue_rx(struct bwn_mac *mac, struct bwn_pio_rxqueue *prq,
+ int index)
+{
+
+ prq->prq_mac = mac;
+ prq->prq_rev = mac->mac_sd->sd_id.sd_rev;
+ prq->prq_base = bwn_pio_idx2base(mac, index) + BWN_PIO_RXQOFFSET(mac);
+ bwn_dma_rxdirectfifo(mac, index, 1);
+}
+
+static void
+bwn_destroy_pioqueue_tx(struct bwn_pio_txqueue *tq)
+{
+ if (tq == NULL)
+ return;
+ bwn_pio_cancel_tx_packets(tq);
+}
+
+static void
+bwn_destroy_queue_tx(struct bwn_pio_txqueue *pio)
+{
+
+ bwn_destroy_pioqueue_tx(pio);
+}
+
+static uint16_t
+bwn_pio_read_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
+ uint16_t offset)
+{
+
+ return (BWN_READ_2(mac, tq->tq_base + offset));
+}
+
+static void
+bwn_dma_rxdirectfifo(struct bwn_mac *mac, int idx, uint8_t enable)
+{
+ uint32_t ctl;
+ int type;
+ uint16_t base;
+
+ type = bwn_dma_mask2type(bwn_dma_mask(mac));
+ base = bwn_dma_base(type, idx);
+ if (type == BWN_DMA_64BIT) {
+ ctl = BWN_READ_4(mac, base + BWN_DMA64_RXCTL);
+ ctl &= ~BWN_DMA64_RXDIRECTFIFO;
+ if (enable)
+ ctl |= BWN_DMA64_RXDIRECTFIFO;
+ BWN_WRITE_4(mac, base + BWN_DMA64_RXCTL, ctl);
+ } else {
+ ctl = BWN_READ_4(mac, base + BWN_DMA32_RXCTL);
+ ctl &= ~BWN_DMA32_RXDIRECTFIFO;
+ if (enable)
+ ctl |= BWN_DMA32_RXDIRECTFIFO;
+ 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
+bwn_pio_cancel_tx_packets(struct bwn_pio_txqueue *tq)
+{
+ struct bwn_pio_txpkt *tp;
+ unsigned int i;
+
+ for (i = 0; i < N(tq->tq_pkts); i++) {
+ tp = &(tq->tq_pkts[i]);
+ if (tp->tp_m) {
+ m_freem(tp->tp_m);
+ tp->tp_m = NULL;
+ }
+ }
+}
+
+static uint16_t
+bwn_dma_base(int type, int controller_idx)
+{
+ static const uint16_t map64[] = {
+ BWN_DMA64_BASE0,
+ BWN_DMA64_BASE1,
+ BWN_DMA64_BASE2,
+ BWN_DMA64_BASE3,
+ BWN_DMA64_BASE4,
+ BWN_DMA64_BASE5,
+ };
+ static const uint16_t map32[] = {
+ BWN_DMA32_BASE0,
+ BWN_DMA32_BASE1,
+ BWN_DMA32_BASE2,
+ BWN_DMA32_BASE3,
+ BWN_DMA32_BASE4,
+ BWN_DMA32_BASE5,
+ };
+
+ if (type == BWN_DMA_64BIT) {
+ KASSERT(controller_idx >= 0 && controller_idx < N(map64),
+ ("%s:%d: fail", __func__, __LINE__));
+ return (map64[controller_idx]);
+ }
+ KASSERT(controller_idx >= 0 && controller_idx < N(map32),
+ ("%s:%d: fail", __func__, __LINE__));
+ return (map32[controller_idx]);
+}
+
+static void
+bwn_dma_init(struct bwn_mac *mac)
+{
+ struct bwn_dma *dma = &mac->mac_method.dma;
+
+ /* setup TX DMA channels. */
+ bwn_dma_setup(dma->wme[WME_AC_BK]);
+ bwn_dma_setup(dma->wme[WME_AC_BE]);
+ bwn_dma_setup(dma->wme[WME_AC_VI]);
+ bwn_dma_setup(dma->wme[WME_AC_VO]);
+ bwn_dma_setup(dma->mcast);
+ /* setup RX DMA channel. */
+ bwn_dma_setup(dma->rx);
+}
+
+static struct bwn_dma_ring *
+bwn_dma_ringsetup(struct bwn_mac *mac, int controller_index,
+ int for_tx, int type)
+{
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_dma_ring *dr;
+ struct bwn_dmadesc_generic *desc;
+ struct bwn_dmadesc_meta *mt;
+ struct bwn_softc *sc = mac->mac_sc;
+ int error, i;
+
+ dr = malloc(sizeof(*dr), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (dr == NULL)
+ goto out;
+ dr->dr_numslots = BWN_RXRING_SLOTS;
+ if (for_tx)
+ dr->dr_numslots = BWN_TXRING_SLOTS;
+
+ dr->dr_meta = malloc(dr->dr_numslots * sizeof(struct bwn_dmadesc_meta),
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (dr->dr_meta == NULL)
+ goto fail0;
+
+ dr->dr_type = type;
+ dr->dr_mac = mac;
+ dr->dr_base = bwn_dma_base(type, controller_index);
+ dr->dr_index = controller_index;
+ if (type == BWN_DMA_64BIT) {
+ dr->getdesc = bwn_dma_64_getdesc;
+ dr->setdesc = bwn_dma_64_setdesc;
+ dr->start_transfer = bwn_dma_64_start_transfer;
+ dr->suspend = bwn_dma_64_suspend;
+ dr->resume = bwn_dma_64_resume;
+ dr->get_curslot = bwn_dma_64_get_curslot;
+ dr->set_curslot = bwn_dma_64_set_curslot;
+ } else {
+ dr->getdesc = bwn_dma_32_getdesc;
+ dr->setdesc = bwn_dma_32_setdesc;
+ dr->start_transfer = bwn_dma_32_start_transfer;
+ dr->suspend = bwn_dma_32_suspend;
+ dr->resume = bwn_dma_32_resume;
+ dr->get_curslot = bwn_dma_32_get_curslot;
+ dr->set_curslot = bwn_dma_32_set_curslot;
+ }
+ if (for_tx) {
+ dr->dr_tx = 1;
+ dr->dr_curslot = -1;
+ } else {
+ if (dr->dr_index == 0) {
+ dr->dr_rx_bufsize = BWN_DMA0_RX_BUFFERSIZE;
+ dr->dr_frameoffset = BWN_DMA0_RX_FRAMEOFFSET;
+ } else
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+
+ error = bwn_dma_allocringmemory(dr);
+ if (error)
+ goto fail2;
+
+ if (for_tx) {
+ /*
+ * Assumption: BWN_TXRING_SLOTS can be divided by
+ * BWN_TX_SLOTS_PER_FRAME
+ */
+ KASSERT(BWN_TXRING_SLOTS % BWN_TX_SLOTS_PER_FRAME == 0,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ dr->dr_txhdr_cache =
+ malloc((dr->dr_numslots / BWN_TX_SLOTS_PER_FRAME) *
+ BWN_HDRSIZE(mac), M_DEVBUF, M_NOWAIT | M_ZERO);
+ KASSERT(dr->dr_txhdr_cache != NULL,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ /*
+ * Create TX ring DMA stuffs
+ */
+ error = bus_dma_tag_create(dma->parent_dtag,
+ BWN_ALIGN, 0,
+ BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ BWN_HDRSIZE(mac),
+ 1,
+ BUS_SPACE_MAXSIZE_32BIT,
+ 0,
+ NULL, NULL,
+ &dr->dr_txring_dtag);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't create TX ring DMA tag: TODO frees\n");
+ goto fail1;
+ }
+
+ for (i = 0; i < dr->dr_numslots; i += 2) {
+ dr->getdesc(dr, i, &desc, &mt);
+
+ mt->mt_txtype = BWN_DMADESC_METATYPE_HEADER;
+ mt->mt_m = NULL;
+ mt->mt_ni = NULL;
+ mt->mt_islast = 0;
+ error = bus_dmamap_create(dr->dr_txring_dtag, 0,
+ &mt->mt_dmap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't create RX buf DMA map\n");
+ goto fail1;
+ }
+
+ dr->getdesc(dr, i + 1, &desc, &mt);
+
+ mt->mt_txtype = BWN_DMADESC_METATYPE_BODY;
+ mt->mt_m = NULL;
+ mt->mt_ni = NULL;
+ mt->mt_islast = 1;
+ error = bus_dmamap_create(dma->txbuf_dtag, 0,
+ &mt->mt_dmap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't create RX buf DMA map\n");
+ goto fail1;
+ }
+ }
+ } else {
+ error = bus_dmamap_create(dma->rxbuf_dtag, 0,
+ &dr->dr_spare_dmap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't create RX buf DMA map\n");
+ goto out; /* XXX wrong! */
+ }
+
+ for (i = 0; i < dr->dr_numslots; i++) {
+ dr->getdesc(dr, i, &desc, &mt);
+
+ error = bus_dmamap_create(dma->rxbuf_dtag, 0,
+ &mt->mt_dmap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't create RX buf DMA map\n");
+ goto out; /* XXX wrong! */
+ }
+ error = bwn_dma_newbuf(dr, desc, mt, 1);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "failed to allocate RX buf\n");
+ goto out; /* XXX wrong! */
+ }
+ }
+
+ bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
+ BUS_DMASYNC_PREWRITE);
+
+ dr->dr_usedslot = dr->dr_numslots;
+ }
+
+ out:
+ return (dr);
+
+fail2:
+ free(dr->dr_txhdr_cache, M_DEVBUF);
+fail1:
+ free(dr->dr_meta, M_DEVBUF);
+fail0:
+ free(dr, M_DEVBUF);
+ return (NULL);
+}
+
+static void
+bwn_dma_ringfree(struct bwn_dma_ring **dr)
+{
+
+ if (dr == NULL)
+ return;
+
+ bwn_dma_free_descbufs(*dr);
+ bwn_dma_free_ringmemory(*dr);
+
+ free((*dr)->dr_txhdr_cache, M_DEVBUF);
+ free((*dr)->dr_meta, M_DEVBUF);
+ free(*dr, M_DEVBUF);
+
+ *dr = NULL;
+}
+
+static void
+bwn_dma_32_getdesc(struct bwn_dma_ring *dr, int slot,
+ struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
+{
+ struct bwn_dmadesc32 *desc;
+
+ *meta = &(dr->dr_meta[slot]);
+ desc = dr->dr_ring_descbase;
+ desc = &(desc[slot]);
+
+ *gdesc = (struct bwn_dmadesc_generic *)desc;
+}
+
+static void
+bwn_dma_32_setdesc(struct bwn_dma_ring *dr,
+ struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
+ int start, int end, int irq)
+{
+ struct bwn_dmadesc32 *descbase = dr->dr_ring_descbase;
+ uint32_t addr, addrext, ctl;
+ int slot;
+
+ slot = (int)(&(desc->dma.dma32) - descbase);
+ KASSERT(slot >= 0 && slot < dr->dr_numslots,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ addr = (uint32_t) (dmaaddr & ~SIBA_DMA_TRANSLATION_MASK);
+ addrext = (uint32_t) (dmaaddr & SIBA_DMA_TRANSLATION_MASK) >> 30;
+ addr |= siba_dma_translation(dr->dr_mac->mac_sd);
+ ctl = bufsize & BWN_DMA32_DCTL_BYTECNT;
+ if (slot == dr->dr_numslots - 1)
+ ctl |= BWN_DMA32_DCTL_DTABLEEND;
+ if (start)
+ ctl |= BWN_DMA32_DCTL_FRAMESTART;
+ if (end)
+ ctl |= BWN_DMA32_DCTL_FRAMEEND;
+ if (irq)
+ ctl |= BWN_DMA32_DCTL_IRQ;
+ ctl |= (addrext << BWN_DMA32_DCTL_ADDREXT_SHIFT)
+ & BWN_DMA32_DCTL_ADDREXT_MASK;
+
+ desc->dma.dma32.control = htole32(ctl);
+ desc->dma.dma32.address = htole32(addr);
+}
+
+static void
+bwn_dma_32_start_transfer(struct bwn_dma_ring *dr, int slot)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA32_TXINDEX,
+ (uint32_t)(slot * sizeof(struct bwn_dmadesc32)));
+}
+
+static void
+bwn_dma_32_suspend(struct bwn_dma_ring *dr)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
+ BWN_DMA_READ(dr, BWN_DMA32_TXCTL) | BWN_DMA32_TXSUSPEND);
+}
+
+static void
+bwn_dma_32_resume(struct bwn_dma_ring *dr)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL,
+ BWN_DMA_READ(dr, BWN_DMA32_TXCTL) & ~BWN_DMA32_TXSUSPEND);
+}
+
+static int
+bwn_dma_32_get_curslot(struct bwn_dma_ring *dr)
+{
+ uint32_t val;
+
+ val = BWN_DMA_READ(dr, BWN_DMA32_RXSTATUS);
+ val &= BWN_DMA32_RXDPTR;
+
+ return (val / sizeof(struct bwn_dmadesc32));
+}
+
+static void
+bwn_dma_32_set_curslot(struct bwn_dma_ring *dr, int slot)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX,
+ (uint32_t) (slot * sizeof(struct bwn_dmadesc32)));
+}
+
+static void
+bwn_dma_64_getdesc(struct bwn_dma_ring *dr, int slot,
+ struct bwn_dmadesc_generic **gdesc, struct bwn_dmadesc_meta **meta)
+{
+ struct bwn_dmadesc64 *desc;
+
+ *meta = &(dr->dr_meta[slot]);
+ desc = dr->dr_ring_descbase;
+ desc = &(desc[slot]);
+
+ *gdesc = (struct bwn_dmadesc_generic *)desc;
+}
+
+static void
+bwn_dma_64_setdesc(struct bwn_dma_ring *dr,
+ struct bwn_dmadesc_generic *desc, bus_addr_t dmaaddr, uint16_t bufsize,
+ int start, int end, int irq)
+{
+ struct bwn_dmadesc64 *descbase = dr->dr_ring_descbase;
+ int slot;
+ uint32_t ctl0 = 0, ctl1 = 0;
+ uint32_t addrlo, addrhi;
+ uint32_t addrext;
+
+ slot = (int)(&(desc->dma.dma64) - descbase);
+ KASSERT(slot >= 0 && slot < dr->dr_numslots,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ addrlo = (uint32_t) (dmaaddr & 0xffffffff);
+ addrhi = (((uint64_t) dmaaddr >> 32) & ~SIBA_DMA_TRANSLATION_MASK);
+ addrext = (((uint64_t) dmaaddr >> 32) & SIBA_DMA_TRANSLATION_MASK) >>
+ 30;
+ addrhi |= (siba_dma_translation(dr->dr_mac->mac_sd) << 1);
+ if (slot == dr->dr_numslots - 1)
+ ctl0 |= BWN_DMA64_DCTL0_DTABLEEND;
+ if (start)
+ ctl0 |= BWN_DMA64_DCTL0_FRAMESTART;
+ if (end)
+ ctl0 |= BWN_DMA64_DCTL0_FRAMEEND;
+ if (irq)
+ ctl0 |= BWN_DMA64_DCTL0_IRQ;
+ ctl1 |= bufsize & BWN_DMA64_DCTL1_BYTECNT;
+ ctl1 |= (addrext << BWN_DMA64_DCTL1_ADDREXT_SHIFT)
+ & BWN_DMA64_DCTL1_ADDREXT_MASK;
+
+ desc->dma.dma64.control0 = htole32(ctl0);
+ desc->dma.dma64.control1 = htole32(ctl1);
+ desc->dma.dma64.address_low = htole32(addrlo);
+ desc->dma.dma64.address_high = htole32(addrhi);
+}
+
+static void
+bwn_dma_64_start_transfer(struct bwn_dma_ring *dr, int slot)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXINDEX,
+ (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
+}
+
+static void
+bwn_dma_64_suspend(struct bwn_dma_ring *dr)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
+ BWN_DMA_READ(dr, BWN_DMA64_TXCTL) | BWN_DMA64_TXSUSPEND);
+}
+
+static void
+bwn_dma_64_resume(struct bwn_dma_ring *dr)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL,
+ BWN_DMA_READ(dr, BWN_DMA64_TXCTL) & ~BWN_DMA64_TXSUSPEND);
+}
+
+static int
+bwn_dma_64_get_curslot(struct bwn_dma_ring *dr)
+{
+ uint32_t val;
+
+ val = BWN_DMA_READ(dr, BWN_DMA64_RXSTATUS);
+ val &= BWN_DMA64_RXSTATDPTR;
+
+ return (val / sizeof(struct bwn_dmadesc64));
+}
+
+static void
+bwn_dma_64_set_curslot(struct bwn_dma_ring *dr, int slot)
+{
+
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX,
+ (uint32_t)(slot * sizeof(struct bwn_dmadesc64)));
+}
+
+static int
+bwn_dma_allocringmemory(struct bwn_dma_ring *dr)
+{
+ struct bwn_mac *mac = dr->dr_mac;
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_softc *sc = mac->mac_sc;
+ int error;
+
+ error = bus_dma_tag_create(dma->parent_dtag,
+ BWN_ALIGN, 0,
+ BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ BWN_DMA_RINGMEMSIZE,
+ 1,
+ BUS_SPACE_MAXSIZE_32BIT,
+ 0,
+ NULL, NULL,
+ &dr->dr_ring_dtag);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't create TX ring DMA tag: TODO frees\n");
+ return (-1);
+ }
+
+ error = bus_dmamem_alloc(dr->dr_ring_dtag,
+ &dr->dr_ring_descbase, BUS_DMA_WAITOK | BUS_DMA_ZERO,
+ &dr->dr_ring_dmap);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't allocate DMA mem: TODO frees\n");
+ return (-1);
+ }
+ error = bus_dmamap_load(dr->dr_ring_dtag, dr->dr_ring_dmap,
+ dr->dr_ring_descbase, BWN_DMA_RINGMEMSIZE,
+ bwn_dma_ring_addr, &dr->dr_ring_dmabase, BUS_DMA_NOWAIT);
+ if (error) {
+ device_printf(sc->sc_dev,
+ "can't load DMA mem: TODO free\n");
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void
+bwn_dma_setup(struct bwn_dma_ring *dr)
+{
+ uint64_t ring64;
+ uint32_t addrext, ring32, value;
+ uint32_t trans = siba_dma_translation(dr->dr_mac->mac_sd);
+
+ if (dr->dr_tx) {
+ dr->dr_curslot = -1;
+
+ if (dr->dr_type == BWN_DMA_64BIT) {
+ ring64 = (uint64_t)(dr->dr_ring_dmabase);
+ addrext = ((ring64 >> 32) & SIBA_DMA_TRANSLATION_MASK)
+ >> 30;
+ value = BWN_DMA64_TXENABLE;
+ value |= (addrext << BWN_DMA64_TXADDREXT_SHIFT)
+ & BWN_DMA64_TXADDREXT_MASK;
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXCTL, value);
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO,
+ (ring64 & 0xffffffff));
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI,
+ ((ring64 >> 32) &
+ ~SIBA_DMA_TRANSLATION_MASK) | (trans << 1));
+ } else {
+ ring32 = (uint32_t)(dr->dr_ring_dmabase);
+ addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
+ value = BWN_DMA32_TXENABLE;
+ value |= (addrext << BWN_DMA32_TXADDREXT_SHIFT)
+ & BWN_DMA32_TXADDREXT_MASK;
+ BWN_DMA_WRITE(dr, BWN_DMA32_TXCTL, value);
+ BWN_DMA_WRITE(dr, BWN_DMA32_TXRING,
+ (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
+ }
+ return;
+ }
+
+ /*
+ * set for RX
+ */
+ dr->dr_usedslot = dr->dr_numslots;
+
+ if (dr->dr_type == BWN_DMA_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 |= BWN_DMA64_RXENABLE;
+ value |= (addrext << BWN_DMA64_RXADDREXT_SHIFT)
+ & BWN_DMA64_RXADDREXT_MASK;
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXCTL, value);
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, (ring64 & 0xffffffff));
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI,
+ ((ring64 >> 32) & ~SIBA_DMA_TRANSLATION_MASK)
+ | (trans << 1));
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXINDEX, dr->dr_numslots *
+ sizeof(struct bwn_dmadesc64));
+ } else {
+ ring32 = (uint32_t)(dr->dr_ring_dmabase);
+ addrext = (ring32 & SIBA_DMA_TRANSLATION_MASK) >> 30;
+ value = (dr->dr_frameoffset << BWN_DMA32_RXFROFF_SHIFT);
+ value |= BWN_DMA32_RXENABLE;
+ value |= (addrext << BWN_DMA32_RXADDREXT_SHIFT)
+ & BWN_DMA32_RXADDREXT_MASK;
+ BWN_DMA_WRITE(dr, BWN_DMA32_RXCTL, value);
+ BWN_DMA_WRITE(dr, BWN_DMA32_RXRING,
+ (ring32 & ~SIBA_DMA_TRANSLATION_MASK) | trans);
+ BWN_DMA_WRITE(dr, BWN_DMA32_RXINDEX, dr->dr_numslots *
+ sizeof(struct bwn_dmadesc32));
+ }
+}
+
+static void
+bwn_dma_free_ringmemory(struct bwn_dma_ring *dr)
+{
+
+ bus_dmamap_unload(dr->dr_ring_dtag, dr->dr_ring_dmap);
+ bus_dmamem_free(dr->dr_ring_dtag, dr->dr_ring_descbase,
+ dr->dr_ring_dmap);
+}
+
+static void
+bwn_dma_cleanup(struct bwn_dma_ring *dr)
+{
+
+ if (dr->dr_tx) {
+ bwn_dma_tx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
+ if (dr->dr_type == BWN_DMA_64BIT) {
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGLO, 0);
+ BWN_DMA_WRITE(dr, BWN_DMA64_TXRINGHI, 0);
+ } else
+ BWN_DMA_WRITE(dr, BWN_DMA32_TXRING, 0);
+ } else {
+ bwn_dma_rx_reset(dr->dr_mac, dr->dr_base, dr->dr_type);
+ if (dr->dr_type == BWN_DMA_64BIT) {
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGLO, 0);
+ BWN_DMA_WRITE(dr, BWN_DMA64_RXRINGHI, 0);
+ } else
+ BWN_DMA_WRITE(dr, BWN_DMA32_RXRING, 0);
+ }
+}
+
+static void
+bwn_dma_free_descbufs(struct bwn_dma_ring *dr)
+{
+ struct bwn_dmadesc_generic *desc;
+ struct bwn_dmadesc_meta *meta;
+ struct bwn_mac *mac = dr->dr_mac;
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_softc *sc = mac->mac_sc;
+ int i;
+
+ if (!dr->dr_usedslot)
+ return;
+ for (i = 0; i < dr->dr_numslots; i++) {
+ dr->getdesc(dr, i, &desc, &meta);
+
+ if (meta->mt_m == NULL) {
+ if (!dr->dr_tx)
+ device_printf(sc->sc_dev, "%s: not TX?\n",
+ __func__);
+ continue;
+ }
+ if (dr->dr_tx) {
+ if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
+ bus_dmamap_unload(dr->dr_txring_dtag,
+ meta->mt_dmap);
+ else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
+ bus_dmamap_unload(dma->txbuf_dtag,
+ meta->mt_dmap);
+ } else
+ bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
+ bwn_dma_free_descbuf(dr, meta);
+ }
+}
+
+static int
+bwn_dma_tx_reset(struct bwn_mac *mac, uint16_t base,
+ int type)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint32_t value;
+ int i;
+ uint16_t offset;
+
+ for (i = 0; i < 10; i++) {
+ offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
+ BWN_DMA32_TXSTATUS;
+ value = BWN_READ_4(mac, base + offset);
+ if (type == BWN_DMA_64BIT) {
+ value &= BWN_DMA64_TXSTAT;
+ if (value == BWN_DMA64_TXSTAT_DISABLED ||
+ value == BWN_DMA64_TXSTAT_IDLEWAIT ||
+ value == BWN_DMA64_TXSTAT_STOPPED)
+ break;
+ } else {
+ value &= BWN_DMA32_TXSTATE;
+ if (value == BWN_DMA32_TXSTAT_DISABLED ||
+ value == BWN_DMA32_TXSTAT_IDLEWAIT ||
+ value == BWN_DMA32_TXSTAT_STOPPED)
+ break;
+ }
+ DELAY(1000);
+ }
+ offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXCTL : BWN_DMA32_TXCTL;
+ BWN_WRITE_4(mac, base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_TXSTATUS :
+ BWN_DMA32_TXSTATUS;
+ value = BWN_READ_4(mac, base + offset);
+ if (type == BWN_DMA_64BIT) {
+ value &= BWN_DMA64_TXSTAT;
+ if (value == BWN_DMA64_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= BWN_DMA32_TXSTATE;
+ if (value == BWN_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ DELAY(1000);
+ }
+ if (i != -1) {
+ device_printf(sc->sc_dev, "%s: timed out\n", __func__);
+ return (ENODEV);
+ }
+ DELAY(1000);
+
+ return (0);
+}
+
+static int
+bwn_dma_rx_reset(struct bwn_mac *mac, uint16_t base,
+ int type)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint32_t value;
+ int i;
+ uint16_t offset;
+
+ offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXCTL : BWN_DMA32_RXCTL;
+ BWN_WRITE_4(mac, base + offset, 0);
+ for (i = 0; i < 10; i++) {
+ offset = (type == BWN_DMA_64BIT) ? BWN_DMA64_RXSTATUS :
+ BWN_DMA32_RXSTATUS;
+ value = BWN_READ_4(mac, base + offset);
+ if (type == BWN_DMA_64BIT) {
+ value &= BWN_DMA64_RXSTAT;
+ if (value == BWN_DMA64_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= BWN_DMA32_RXSTATE;
+ if (value == BWN_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ }
+ DELAY(1000);
+ }
+ if (i != -1) {
+ device_printf(sc->sc_dev, "%s: timed out\n", __func__);
+ return (ENODEV);
+ }
+
+ return (0);
+}
+
+static void
+bwn_dma_free_descbuf(struct bwn_dma_ring *dr,
+ struct bwn_dmadesc_meta *meta)
+{
+
+ if (meta->mt_m != NULL) {
+ m_freem(meta->mt_m);
+ meta->mt_m = NULL;
+ }
+ if (meta->mt_ni != NULL) {
+ ieee80211_free_node(meta->mt_ni);
+ meta->mt_ni = NULL;
+ }
+}
+
+static void
+bwn_dma_set_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
+{
+ struct bwn_rxhdr4 *rxhdr;
+ unsigned char *frame;
+
+ rxhdr = mtod(m, struct bwn_rxhdr4 *);
+ rxhdr->frame_len = 0;
+
+ KASSERT(dr->dr_rx_bufsize >= dr->dr_frameoffset +
+ sizeof(struct bwn_plcp6) + 2,
+ ("%s:%d: fail", __func__, __LINE__));
+ frame = mtod(m, char *) + dr->dr_frameoffset;
+ memset(frame, 0xff, sizeof(struct bwn_plcp6) + 2 /* padding */);
+}
+
+static uint8_t
+bwn_dma_check_redzone(struct bwn_dma_ring *dr, struct mbuf *m)
+{
+ unsigned char *f = mtod(m, char *) + dr->dr_frameoffset;
+
+ return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7])
+ == 0xff);
+}
+
+static void
+bwn_wme_init(struct bwn_mac *mac)
+{
+
+ bwn_wme_load(mac);
+
+ /* enable WME support. */
+ bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_EDCF);
+ BWN_WRITE_2(mac, BWN_IFSCTL, BWN_READ_2(mac, BWN_IFSCTL) |
+ BWN_IFSCTL_USE_EDCF);
+}
+
+static void
+bwn_spu_setdelay(struct bwn_mac *mac, int idle)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint16_t delay; /* microsec */
+
+ delay = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 3700 : 1050;
+ if (ic->ic_opmode == IEEE80211_M_IBSS || idle)
+ delay = 500;
+ if ((mac->mac_phy.rf_ver == 0x2050) && (mac->mac_phy.rf_rev == 8))
+ delay = max(delay, (uint16_t)2400);
+
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_SPU_WAKEUP, delay);
+}
+
+static void
+bwn_bt_enable(struct bwn_mac *mac)
+{
+ struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
+ uint64_t hf;
+
+ if (bwn_bluetooth == 0)
+ return;
+ if ((sprom->bf_lo & BWN_BFL_BTCOEXIST) == 0)
+ return;
+ if (mac->mac_phy.type != BWN_PHYTYPE_B && !mac->mac_phy.gmode)
+ return;
+
+ hf = bwn_hf_read(mac);
+ if (sprom->bf_lo & BWN_BFL_BTCMOD)
+ hf |= BWN_HF_BT_COEXISTALT;
+ else
+ hf |= BWN_HF_BT_COEXIST;
+ bwn_hf_write(mac, hf);
+}
+
+static void
+bwn_set_macaddr(struct bwn_mac *mac)
+{
+
+ bwn_mac_write_bssid(mac);
+ bwn_mac_setfilter(mac, BWN_MACFILTER_SELF, mac->mac_sc->sc_macaddr);
+}
+
+static void
+bwn_clear_keys(struct bwn_mac *mac)
+{
+ int i;
+
+ for (i = 0; i < mac->mac_max_nr_keys; i++) {
+ KASSERT(i >= 0 && i < mac->mac_max_nr_keys,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ bwn_key_dowrite(mac, i, BWN_SEC_ALGO_NONE,
+ NULL, BWN_SEC_KEYSIZE, NULL);
+ if ((i <= 3) && !BWN_SEC_NEWAPI(mac)) {
+ bwn_key_dowrite(mac, i + 4, BWN_SEC_ALGO_NONE,
+ NULL, BWN_SEC_KEYSIZE, NULL);
+ }
+ mac->mac_key[i].keyconf = NULL;
+ }
+}
+
+static void
+bwn_crypt_init(struct bwn_mac *mac)
+{
+
+ mac->mac_max_nr_keys = (mac->mac_sd->sd_id.sd_rev >= 5) ? 58 : 20;
+ KASSERT(mac->mac_max_nr_keys <= N(mac->mac_key),
+ ("%s:%d: fail", __func__, __LINE__));
+ mac->mac_ktp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_KEY_TABLEP);
+ mac->mac_ktp *= 2;
+ if (mac->mac_sd->sd_id.sd_rev >= 5) {
+ BWN_WRITE_2(mac, BWN_RCMTA_COUNT,
+ mac->mac_max_nr_keys - 8);
+ }
+ bwn_clear_keys(mac);
+}
+
+static void
+bwn_chip_exit(struct bwn_mac *mac)
+{
+
+ bwn_phy_exit(mac);
+ bwn_gpio_cleanup(mac);
+}
+
+static int
+bwn_fw_fillinfo(struct bwn_mac *mac)
+{
+ int error;
+
+ error = bwn_fw_gets(mac, BWN_FWTYPE_DEFAULT);
+ if (error == 0)
+ return (0);
+ error = bwn_fw_gets(mac, BWN_FWTYPE_OPENSOURCE);
+ if (error == 0)
+ return (0);
+ return (error);
+}
+
+static int
+bwn_gpio_init(struct bwn_mac *mac)
+{
+ struct siba_softc *bus = mac->mac_sd->sd_bus;
+ struct siba_dev_softc *sd;
+ uint32_t mask = 0x0000001f, set = 0x0000000f;
+
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_GPOUT_MASK);
+ BWN_WRITE_2(mac, BWN_GPIO_MASK,
+ BWN_READ_2(mac, BWN_GPIO_MASK) | 0x000f);
+
+ if (bus->siba_chipid == 0x4301) {
+ mask |= 0x0060;
+ set |= 0x0060;
+ }
+ if (bus->siba_sprom.bf_lo & BWN_BFL_PACTRL) {
+ BWN_WRITE_2(mac, BWN_GPIO_MASK,
+ BWN_READ_2(mac, BWN_GPIO_MASK) | 0x0200);
+ mask |= 0x0200;
+ set |= 0x0200;
+ }
+ if (mac->mac_sd->sd_id.sd_rev >= 2)
+ mask |= 0x0010;
+ sd = (bus->siba_cc.scc_dev != NULL) ? bus->siba_cc.scc_dev :
+ bus->siba_pci.spc_dev;
+ if (sd == NULL)
+ return (0);
+ siba_write_4(sd, BWN_GPIOCTL,
+ (siba_read_4(sd, BWN_GPIOCTL) & mask) | set);
+
+ return (0);
+}
+
+static int
+bwn_fw_loadinitvals(struct bwn_mac *mac)
+{
+#define GETFWOFFSET(fwp, offset) \
+ ((const struct bwn_fwinitvals *)((const char *)fwp.fw->data + offset))
+ const size_t hdr_len = sizeof(struct bwn_fwhdr);
+ const struct bwn_fwhdr *hdr;
+ struct bwn_fw *fw = &mac->mac_fw;
+ int error;
+
+ hdr = (const struct bwn_fwhdr *)(fw->initvals.fw->data);
+ error = bwn_fwinitvals_write(mac, GETFWOFFSET(fw->initvals, hdr_len),
+ be32toh(hdr->size), fw->initvals.fw->datasize - hdr_len);
+ if (error)
+ return (error);
+ if (fw->initvals_band.fw) {
+ hdr = (const struct bwn_fwhdr *)(fw->initvals_band.fw->data);
+ error = bwn_fwinitvals_write(mac,
+ GETFWOFFSET(fw->initvals_band, hdr_len),
+ be32toh(hdr->size),
+ fw->initvals_band.fw->datasize - hdr_len);
+ }
+ return (error);
+#undef GETFWOFFSET
+}
+
+static int
+bwn_phy_init(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ int error;
+
+ mac->mac_phy.chan = mac->mac_phy.get_default_chan(mac);
+ mac->mac_phy.rf_onoff(mac, 1);
+ error = mac->mac_phy.init(mac);
+ if (error) {
+ device_printf(sc->sc_dev, "PHY init failed\n");
+ goto fail0;
+ }
+ error = bwn_switch_channel(mac,
+ mac->mac_phy.get_default_chan(mac));
+ if (error) {
+ device_printf(sc->sc_dev,
+ "failed to switch default channel\n");
+ goto fail1;
+ }
+ return (0);
+fail1:
+ if (mac->mac_phy.exit)
+ mac->mac_phy.exit(mac);
+fail0:
+ mac->mac_phy.rf_onoff(mac, 0);
+
+ return (error);
+}
+
+static void
+bwn_set_txantenna(struct bwn_mac *mac, int antenna)
+{
+ uint16_t ant;
+ uint16_t tmp;
+
+ ant = bwn_ant2phy(antenna);
+
+ /* For ACK/CTS */
+ tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL);
+ tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_ACKCTS_PHYCTL, tmp);
+ /* For Probe Resposes */
+ tmp = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL);
+ tmp = (tmp & ~BWN_TX_PHY_ANT) | ant;
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PROBE_RESP_PHYCTL, tmp);
+}
+
+static void
+bwn_set_opmode(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint32_t ctl;
+ uint16_t cfp_pretbtt;
+
+ ctl = BWN_READ_4(mac, BWN_MACCTL);
+ ctl &= ~(BWN_MACCTL_HOSTAP | BWN_MACCTL_PASS_CTL |
+ BWN_MACCTL_PASS_BADPLCP | BWN_MACCTL_PASS_BADFCS |
+ BWN_MACCTL_PROMISC | BWN_MACCTL_BEACON_PROMISC);
+ ctl |= BWN_MACCTL_STA;
+
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_MBSS)
+ ctl |= BWN_MACCTL_HOSTAP;
+ else if (ic->ic_opmode == IEEE80211_M_IBSS)
+ ctl &= ~BWN_MACCTL_STA;
+ ctl |= sc->sc_filters;
+
+ if (mac->mac_sd->sd_id.sd_rev <= 4)
+ ctl |= BWN_MACCTL_PROMISC;
+
+ BWN_WRITE_4(mac, BWN_MACCTL, ctl);
+
+ cfp_pretbtt = 2;
+ if ((ctl & BWN_MACCTL_STA) && !(ctl & BWN_MACCTL_HOSTAP)) {
+ if (mac->mac_sd->sd_bus->siba_chipid == 0x4306 &&
+ mac->mac_sd->sd_bus->siba_chiprev == 3)
+ cfp_pretbtt = 100;
+ else
+ cfp_pretbtt = 50;
+ }
+ BWN_WRITE_2(mac, 0x612, cfp_pretbtt);
+}
+
+static void
+bwn_gpio_cleanup(struct bwn_mac *mac)
+{
+ struct siba_softc *bus = mac->mac_sd->sd_bus;
+ struct siba_dev_softc *gpiodev, *pcidev = NULL;
+
+ pcidev = bus->siba_pci.spc_dev;
+ gpiodev = bus->siba_cc.scc_dev ? bus->siba_cc.scc_dev : pcidev;
+ if (!gpiodev)
+ return;
+ siba_write_4(gpiodev, BWN_GPIOCTL, 0);
+}
+
+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
+bwn_dma_ring_addr(void *arg, bus_dma_segment_t *seg, int nseg, int error)
+{
+ if (!error) {
+ KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
+ *((bus_addr_t *)arg) = seg->ds_addr;
+ }
+}
+
+static void
+bwn_phy_g_init_sub(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ uint16_t i, tmp;
+
+ if (phy->rev == 1)
+ bwn_phy_init_b5(mac);
+ else
+ bwn_phy_init_b6(mac);
+
+ if (phy->rev >= 2 || phy->gmode)
+ bwn_phy_init_a(mac);
+
+ if (phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, 0);
+ }
+ if (phy->rev == 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
+ }
+ if (phy->rev > 5) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x400);
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xc0);
+ }
+ if (phy->gmode || phy->rev >= 2) {
+ tmp = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
+ tmp &= BWN_PHYVER_VERSION;
+ if (tmp == 3 || tmp == 5) {
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc2), 0x1816);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc3), 0x8006);
+ }
+ if (tmp == 5) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xcc), 0x00ff,
+ 0x1f00);
+ }
+ }
+ if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x7e), 0x78);
+ if (phy->rf_rev == 8) {
+ BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x80);
+ BWN_PHY_SET(mac, BWN_PHY_OFDM(0x3e), 0x4);
+ }
+ if (BWN_HAS_LOOPBACK(phy))
+ bwn_loopback_calcgain(mac);
+
+ if (phy->rf_rev != 8) {
+ if (pg->pg_initval == 0xffff)
+ pg->pg_initval = bwn_rf_init_bcm2050(mac);
+ else
+ BWN_RF_WRITE(mac, 0x0078, pg->pg_initval);
+ }
+ bwn_lo_g_init(mac);
+ if (BWN_HAS_TXMAG(phy)) {
+ BWN_RF_WRITE(mac, 0x52,
+ (BWN_RF_READ(mac, 0x52) & 0xff00)
+ | pg->pg_loctl.tx_bias |
+ pg->pg_loctl.tx_magn);
+ } else {
+ BWN_RF_SETMASK(mac, 0x52, 0xfff0, pg->pg_loctl.tx_bias);
+ }
+ if (phy->rev >= 6) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x36), 0x0fff,
+ (pg->pg_loctl.tx_bias << 12));
+ }
+ if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL)
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8075);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x807f);
+ if (phy->rev < 2)
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x101);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x202);
+ if (phy->gmode || phy->rev >= 2) {
+ bwn_lo_g_adjust(mac);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
+ }
+
+ if (!(mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
+ for (i = 0; i < 64; i++) {
+ BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, i);
+ BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_DATA,
+ (uint16_t)MIN(MAX(bwn_nrssi_read(mac, i) - 0xffff,
+ -32), 31));
+ }
+ bwn_nrssi_threshold(mac);
+ } else if (phy->gmode || phy->rev >= 2) {
+ if (pg->pg_nrssi[0] == -1000) {
+ KASSERT(pg->pg_nrssi[1] == -1000,
+ ("%s:%d: fail", __func__, __LINE__));
+ bwn_nrssi_slope_11g(mac);
+ } else
+ bwn_nrssi_threshold(mac);
+ }
+ if (phy->rf_rev == 8)
+ BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x05), 0x3230);
+ bwn_phy_hwpctl_init(mac);
+ if ((mac->mac_sd->sd_bus->siba_chipid == 0x4306
+ && mac->mac_sd->sd_bus->siba_chippkg == 2) || 0) {
+ BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0xbfff);
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xc3), 0x7fff);
+ }
+}
+
+static uint8_t
+bwn_has_hwpctl(struct bwn_mac *mac)
+{
+
+ if (mac->mac_phy.hwpctl == 0 || mac->mac_phy.use_hwpctl == NULL)
+ return (0);
+ return (mac->mac_phy.use_hwpctl(mac));
+}
+
+static void
+bwn_phy_init_b5(struct bwn_mac *mac)
+{
+ struct siba_softc *bus = mac->mac_sd->sd_bus;
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ uint16_t offset, value;
+ uint8_t old_channel;
+
+ if (phy->analog == 1)
+ BWN_RF_SET(mac, 0x007a, 0x0050);
+ if ((bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM) &&
+ (bus->siba_board_type != SIBA_BOARD_BU4306)) {
+ value = 0x2120;
+ for (offset = 0x00a8; offset < 0x00c7; offset++) {
+ BWN_PHY_WRITE(mac, offset, value);
+ value += 0x202;
+ }
+ }
+ BWN_PHY_SETMASK(mac, 0x0035, 0xf0ff, 0x0700);
+ if (phy->rf_ver == 0x2050)
+ BWN_PHY_WRITE(mac, 0x0038, 0x0667);
+
+ if (phy->gmode || phy->rev >= 2) {
+ if (phy->rf_ver == 0x2050) {
+ BWN_RF_SET(mac, 0x007a, 0x0020);
+ BWN_RF_SET(mac, 0x0051, 0x0004);
+ }
+ BWN_WRITE_2(mac, BWN_PHY_RADIO, 0x0000);
+
+ BWN_PHY_SET(mac, 0x0802, 0x0100);
+ BWN_PHY_SET(mac, 0x042b, 0x2000);
+
+ BWN_PHY_WRITE(mac, 0x001c, 0x186a);
+
+ BWN_PHY_SETMASK(mac, 0x0013, 0x00ff, 0x1900);
+ BWN_PHY_SETMASK(mac, 0x0035, 0xffc0, 0x0064);
+ BWN_PHY_SETMASK(mac, 0x005d, 0xff80, 0x000a);
+ }
+
+ if (mac->mac_flags & BWN_MAC_FLAG_BADFRAME_PREEMP)
+ BWN_PHY_SET(mac, BWN_PHY_RADIO_BITFIELD, (1 << 11));
+
+ if (phy->analog == 1) {
+ BWN_PHY_WRITE(mac, 0x0026, 0xce00);
+ BWN_PHY_WRITE(mac, 0x0021, 0x3763);
+ BWN_PHY_WRITE(mac, 0x0022, 0x1bc3);
+ BWN_PHY_WRITE(mac, 0x0023, 0x06f9);
+ BWN_PHY_WRITE(mac, 0x0024, 0x037e);
+ } else
+ BWN_PHY_WRITE(mac, 0x0026, 0xcc00);
+ BWN_PHY_WRITE(mac, 0x0030, 0x00c6);
+ BWN_WRITE_2(mac, 0x03ec, 0x3f22);
+
+ if (phy->analog == 1)
+ BWN_PHY_WRITE(mac, 0x0020, 0x3e1c);
+ else
+ BWN_PHY_WRITE(mac, 0x0020, 0x301c);
+
+ if (phy->analog == 0)
+ BWN_WRITE_2(mac, 0x03e4, 0x3000);
+
+ old_channel = phy->chan;
+ bwn_phy_g_switch_chan(mac, 7, 0);
+
+ if (phy->rf_ver != 0x2050) {
+ BWN_RF_WRITE(mac, 0x0075, 0x0080);
+ BWN_RF_WRITE(mac, 0x0079, 0x0081);
+ }
+
+ BWN_RF_WRITE(mac, 0x0050, 0x0020);
+ BWN_RF_WRITE(mac, 0x0050, 0x0023);
+
+ if (phy->rf_ver == 0x2050) {
+ BWN_RF_WRITE(mac, 0x0050, 0x0020);
+ BWN_RF_WRITE(mac, 0x005a, 0x0070);
+ }
+
+ BWN_RF_WRITE(mac, 0x005b, 0x007b);
+ BWN_RF_WRITE(mac, 0x005c, 0x00b0);
+ BWN_RF_SET(mac, 0x007a, 0x0007);
+
+ bwn_phy_g_switch_chan(mac, old_channel, 0);
+ BWN_PHY_WRITE(mac, 0x0014, 0x0080);
+ BWN_PHY_WRITE(mac, 0x0032, 0x00ca);
+ BWN_PHY_WRITE(mac, 0x002a, 0x88a3);
+
+ bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
+ pg->pg_txctl);
+
+ if (phy->rf_ver == 0x2050)
+ BWN_RF_WRITE(mac, 0x005d, 0x000d);
+
+ BWN_WRITE_2(mac, 0x03e4, (BWN_READ_2(mac, 0x03e4) & 0xffc0) | 0x0004);
+}
+
+static void
+bwn_loopback_calcgain(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ uint16_t backup_phy[16] = { 0 };
+ uint16_t backup_radio[3];
+ uint16_t backup_bband;
+ uint16_t i, j, loop_i_max;
+ uint16_t trsw_rx;
+ uint16_t loop1_outer_done, loop1_inner_done;
+
+ backup_phy[0] = BWN_PHY_READ(mac, BWN_PHY_CRS0);
+ backup_phy[1] = BWN_PHY_READ(mac, BWN_PHY_CCKBBANDCFG);
+ backup_phy[2] = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
+ backup_phy[3] = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
+ if (phy->rev != 1) {
+ backup_phy[4] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
+ backup_phy[5] = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
+ }
+ backup_phy[6] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
+ backup_phy[7] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
+ backup_phy[8] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
+ backup_phy[9] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x0a));
+ backup_phy[10] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x03));
+ backup_phy[11] = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
+ backup_phy[12] = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
+ backup_phy[13] = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2b));
+ backup_phy[14] = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
+ backup_phy[15] = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
+ backup_bband = pg->pg_bbatt.att;
+ backup_radio[0] = BWN_RF_READ(mac, 0x52);
+ backup_radio[1] = BWN_RF_READ(mac, 0x43);
+ backup_radio[2] = BWN_RF_READ(mac, 0x7a);
+
+ BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x3fff);
+ BWN_PHY_SET(mac, BWN_PHY_CCKBBANDCFG, 0x8000);
+ BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0002);
+ BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffd);
+ BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0001);
+ BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xfffe);
+ if (phy->rev != 1) {
+ BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0001);
+ BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffe);
+ BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0002);
+ BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffd);
+ }
+ BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x000c);
+ BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x000c);
+ BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0030);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xffcf, 0x10);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0780);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
+
+ BWN_PHY_SET(mac, BWN_PHY_CCK(0x0a), 0x2000);
+ if (phy->rev != 1) {
+ BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0004);
+ BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffb);
+ }
+ BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xff9f, 0x40);
+
+ if (phy->rf_rev == 8)
+ BWN_RF_WRITE(mac, 0x43, 0x000f);
+ else {
+ BWN_RF_WRITE(mac, 0x52, 0);
+ BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x9);
+ }
+ bwn_phy_g_set_bbatt(mac, 11);
+
+ if (phy->rev >= 3)
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xffc0, 0x01);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x2b), 0xc0ff, 0x800);
+
+ BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0100);
+ BWN_PHY_MASK(mac, BWN_PHY_RFOVERVAL, 0xcfff);
+
+ if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) {
+ if (phy->rev >= 7) {
+ BWN_PHY_SET(mac, BWN_PHY_RFOVER, 0x0800);
+ BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x8000);
+ }
+ }
+ BWN_RF_MASK(mac, 0x7a, 0x00f7);
+
+ j = 0;
+ loop_i_max = (phy->rf_rev == 8) ? 15 : 9;
+ for (i = 0; i < loop_i_max; i++) {
+ for (j = 0; j < 16; j++) {
+ BWN_RF_WRITE(mac, 0x43, i);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff,
+ (j << 8));
+ BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
+ BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
+ DELAY(20);
+ if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
+ goto done0;
+ }
+ }
+done0:
+ loop1_outer_done = i;
+ loop1_inner_done = j;
+ if (j >= 8) {
+ BWN_PHY_SET(mac, BWN_PHY_RFOVERVAL, 0x30);
+ trsw_rx = 0x1b;
+ for (j = j - 8; j < 16; j++) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_RFOVERVAL, 0xf0ff, j << 8);
+ BWN_PHY_SETMASK(mac, BWN_PHY_PGACTL, 0x0fff, 0xa000);
+ BWN_PHY_SET(mac, BWN_PHY_PGACTL, 0xf000);
+ DELAY(20);
+ trsw_rx -= 3;
+ if (BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE) >= 0xdfc)
+ goto done1;
+ }
+ } else
+ trsw_rx = 0x18;
+done1:
+
+ if (phy->rev != 1) {
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, backup_phy[4]);
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL, backup_phy[5]);
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), backup_phy[6]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), backup_phy[7]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), backup_phy[8]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x0a), backup_phy[9]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x03), backup_phy[10]);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, backup_phy[11]);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, backup_phy[12]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), backup_phy[13]);
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, backup_phy[14]);
+
+ bwn_phy_g_set_bbatt(mac, backup_bband);
+
+ BWN_RF_WRITE(mac, 0x52, backup_radio[0]);
+ BWN_RF_WRITE(mac, 0x43, backup_radio[1]);
+ BWN_RF_WRITE(mac, 0x7a, backup_radio[2]);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2] | 0x0003);
+ DELAY(10);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, backup_phy[2]);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, backup_phy[3]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRS0, backup_phy[0]);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCKBBANDCFG, backup_phy[1]);
+
+ pg->pg_max_lb_gain =
+ ((loop1_inner_done * 6) - (loop1_outer_done * 4)) - 11;
+ pg->pg_trsw_rx_gain = trsw_rx * 2;
+}
+
+static uint16_t
+bwn_rf_init_bcm2050(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint32_t tmp1 = 0, tmp2 = 0;
+ uint16_t rcc, i, j, pgactl, cck0, cck1, cck2, cck3, rfover, rfoverval,
+ analogover, analogoverval, crs0, classctl, lomask, loctl, syncctl,
+ radio0, radio1, radio2, reg0, reg1, reg2, radio78, reg, index;
+ static const uint8_t rcc_table[] = {
+ 0x02, 0x03, 0x01, 0x0f,
+ 0x06, 0x07, 0x05, 0x0f,
+ 0x0a, 0x0b, 0x09, 0x0f,
+ 0x0e, 0x0f, 0x0d, 0x0f,
+ };
+
+ radio0 = BWN_RF_READ(mac, 0x43);
+ radio1 = BWN_RF_READ(mac, 0x51);
+ radio2 = BWN_RF_READ(mac, 0x52);
+ pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
+ cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x5a));
+ cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x59));
+ cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x58));
+
+ if (phy->type == BWN_PHYTYPE_B) {
+ cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
+ reg0 = BWN_READ_2(mac, 0x3ec);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0xff);
+ BWN_WRITE_2(mac, 0x3ec, 0x3f3f);
+ } else if (phy->gmode || phy->rev >= 2) {
+ rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
+ rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
+ analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
+ analogoverval = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
+ crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
+ classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
+
+ BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
+ BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
+ BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
+ BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
+ if (BWN_HAS_LOOPBACK(phy)) {
+ lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
+ loctl = BWN_PHY_READ(mac, BWN_PHY_LO_CTL);
+ if (phy->rev >= 3)
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc020);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8020);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, 0);
+ }
+
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
+ BWN_LPD(0, 1, 1)));
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER,
+ bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVER, 0));
+ }
+ BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2) | 0x8000);
+
+ syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
+ BWN_PHY_MASK(mac, BWN_PHY_SYNCCTL, 0xff7f);
+ reg1 = BWN_READ_2(mac, 0x3e6);
+ reg2 = BWN_READ_2(mac, 0x3f4);
+
+ if (phy->analog == 0)
+ BWN_WRITE_2(mac, 0x03e6, 0x0122);
+ else {
+ if (phy->analog >= 2)
+ BWN_PHY_SETMASK(mac, BWN_PHY_CCK(0x03), 0xffbf, 0x40);
+ BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
+ (BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000));
+ }
+
+ reg = BWN_RF_READ(mac, 0x60);
+ index = (reg & 0x001e) >> 1;
+ rcc = (((rcc_table[index] << 1) | (reg & 0x0001)) | 0x0020);
+
+ if (phy->type == BWN_PHYTYPE_B)
+ BWN_RF_WRITE(mac, 0x78, 0x26);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
+ BWN_LPD(0, 1, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfaf);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1403);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac, BWN_PHY_RFOVERVAL,
+ BWN_LPD(0, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xbfa0);
+ BWN_RF_SET(mac, 0x51, 0x0004);
+ if (phy->rf_rev == 8)
+ BWN_RF_WRITE(mac, 0x43, 0x1f);
+ else {
+ BWN_RF_WRITE(mac, 0x52, 0);
+ BWN_RF_SETMASK(mac, 0x43, 0xfff0, 0x0009);
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
+
+ for (i = 0; i < 16; i++) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0480);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
+ DELAY(10);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
+ DELAY(10);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
+ DELAY(20);
+ tmp1 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
+ }
+ DELAY(10);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
+ tmp1++;
+ tmp1 >>= 9;
+
+ for (i = 0; i < 16; i++) {
+ radio78 = (BWN_BITREV4(i) << 1) | 0x0020;
+ BWN_RF_WRITE(mac, 0x78, radio78);
+ DELAY(10);
+ for (j = 0; j < 16; j++) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), 0x0d80);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), 0xc810);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0x000d);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
+ DELAY(10);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xefb0);
+ DELAY(10);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 0)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xfff0);
+ DELAY(10);
+ tmp2 += BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), 0);
+ if (phy->gmode || phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL,
+ bwn_rf_2050_rfoverval(mac,
+ BWN_PHY_RFOVERVAL, BWN_LPD(1, 0, 1)));
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xafb0);
+ }
+ tmp2++;
+ tmp2 >>= 8;
+ if (tmp1 < tmp2)
+ break;
+ }
+
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pgactl);
+ BWN_RF_WRITE(mac, 0x51, radio1);
+ BWN_RF_WRITE(mac, 0x52, radio2);
+ BWN_RF_WRITE(mac, 0x43, radio0);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x5a), cck0);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x59), cck1);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x58), cck2);
+ BWN_WRITE_2(mac, 0x3e6, reg1);
+ if (phy->analog != 0)
+ BWN_WRITE_2(mac, 0x3f4, reg2);
+ BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, syncctl);
+ bwn_spu_workaround(mac, phy->chan);
+ if (phy->type == BWN_PHYTYPE_B) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), cck3);
+ BWN_WRITE_2(mac, 0x3ec, reg0);
+ } else if (phy->gmode) {
+ BWN_WRITE_2(mac, BWN_PHY_RADIO,
+ BWN_READ_2(mac, BWN_PHY_RADIO)
+ & 0x7fff);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, rfover);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfoverval);
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, analogover);
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
+ analogoverval);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRS0, crs0);
+ BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, classctl);
+ if (BWN_HAS_LOOPBACK(phy)) {
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, lomask);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, loctl);
+ }
+ }
+
+ return ((i > 15) ? radio78 : rcc);
+}
+
+static void
+bwn_phy_init_b6(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ uint16_t offset, val;
+ uint8_t old_channel;
+
+ KASSERT(!(phy->rf_rev == 6 || phy->rf_rev == 7),
+ ("%s:%d: fail", __func__, __LINE__));
+
+ BWN_PHY_WRITE(mac, 0x003e, 0x817a);
+ BWN_RF_WRITE(mac, 0x007a, BWN_RF_READ(mac, 0x007a) | 0x0058);
+ if (phy->rf_rev == 4 || phy->rf_rev == 5) {
+ BWN_RF_WRITE(mac, 0x51, 0x37);
+ BWN_RF_WRITE(mac, 0x52, 0x70);
+ BWN_RF_WRITE(mac, 0x53, 0xb3);
+ BWN_RF_WRITE(mac, 0x54, 0x9b);
+ BWN_RF_WRITE(mac, 0x5a, 0x88);
+ BWN_RF_WRITE(mac, 0x5b, 0x88);
+ BWN_RF_WRITE(mac, 0x5d, 0x88);
+ BWN_RF_WRITE(mac, 0x5e, 0x88);
+ BWN_RF_WRITE(mac, 0x7d, 0x88);
+ bwn_hf_write(mac,
+ bwn_hf_read(mac) | BWN_HF_TSSI_RESET_PSM_WORKAROUN);
+ }
+ if (phy->rf_rev == 8) {
+ BWN_RF_WRITE(mac, 0x51, 0);
+ BWN_RF_WRITE(mac, 0x52, 0x40);
+ BWN_RF_WRITE(mac, 0x53, 0xb7);
+ BWN_RF_WRITE(mac, 0x54, 0x98);
+ BWN_RF_WRITE(mac, 0x5a, 0x88);
+ BWN_RF_WRITE(mac, 0x5b, 0x6b);
+ BWN_RF_WRITE(mac, 0x5c, 0x0f);
+ if (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_ALTIQ) {
+ BWN_RF_WRITE(mac, 0x5d, 0xfa);
+ BWN_RF_WRITE(mac, 0x5e, 0xd8);
+ } else {
+ BWN_RF_WRITE(mac, 0x5d, 0xf5);
+ BWN_RF_WRITE(mac, 0x5e, 0xb8);
+ }
+ BWN_RF_WRITE(mac, 0x0073, 0x0003);
+ BWN_RF_WRITE(mac, 0x007d, 0x00a8);
+ BWN_RF_WRITE(mac, 0x007c, 0x0001);
+ BWN_RF_WRITE(mac, 0x007e, 0x0008);
+ }
+ for (val = 0x1e1f, offset = 0x0088; offset < 0x0098; offset++) {
+ BWN_PHY_WRITE(mac, offset, val);
+ val -= 0x0202;
+ }
+ for (val = 0x3e3f, offset = 0x0098; offset < 0x00a8; offset++) {
+ BWN_PHY_WRITE(mac, offset, val);
+ val -= 0x0202;
+ }
+ for (val = 0x2120, offset = 0x00a8; offset < 0x00c8; offset++) {
+ BWN_PHY_WRITE(mac, offset, (val & 0x3f3f));
+ val += 0x0202;
+ }
+ if (phy->type == BWN_PHYTYPE_G) {
+ BWN_RF_SET(mac, 0x007a, 0x0020);
+ BWN_RF_SET(mac, 0x0051, 0x0004);
+ BWN_PHY_SET(mac, 0x0802, 0x0100);
+ BWN_PHY_SET(mac, 0x042b, 0x2000);
+ BWN_PHY_WRITE(mac, 0x5b, 0);
+ BWN_PHY_WRITE(mac, 0x5c, 0);
+ }
+
+ old_channel = phy->chan;
+ bwn_phy_g_switch_chan(mac, (old_channel >= 8) ? 1 : 13, 0);
+
+ BWN_RF_WRITE(mac, 0x0050, 0x0020);
+ BWN_RF_WRITE(mac, 0x0050, 0x0023);
+ DELAY(40);
+ if (phy->rf_rev < 6 || phy->rf_rev == 8) {
+ BWN_RF_WRITE(mac, 0x7c, BWN_RF_READ(mac, 0x7c) | 0x0002);
+ BWN_RF_WRITE(mac, 0x50, 0x20);
+ }
+ if (phy->rf_rev <= 2) {
+ BWN_RF_WRITE(mac, 0x7c, 0x20);
+ BWN_RF_WRITE(mac, 0x5a, 0x70);
+ BWN_RF_WRITE(mac, 0x5b, 0x7b);
+ BWN_RF_WRITE(mac, 0x5c, 0xb0);
+ }
+ BWN_RF_SETMASK(mac, 0x007a, 0x00f8, 0x0007);
+
+ bwn_phy_g_switch_chan(mac, old_channel, 0);
+
+ BWN_PHY_WRITE(mac, 0x0014, 0x0200);
+ if (phy->rf_rev >= 6)
+ BWN_PHY_WRITE(mac, 0x2a, 0x88c2);
+ else
+ BWN_PHY_WRITE(mac, 0x2a, 0x8ac0);
+ BWN_PHY_WRITE(mac, 0x0038, 0x0668);
+ bwn_phy_g_set_txpwr_sub(mac, &pg->pg_bbatt, &pg->pg_rfatt,
+ pg->pg_txctl);
+ if (phy->rf_rev <= 5)
+ BWN_PHY_SETMASK(mac, 0x5d, 0xff80, 0x0003);
+ if (phy->rf_rev <= 2)
+ BWN_RF_WRITE(mac, 0x005d, 0x000d);
+
+ if (phy->analog == 4) {
+ BWN_WRITE_2(mac, 0x3e4, 9);
+ BWN_PHY_MASK(mac, 0x61, 0x0fff);
+ } else
+ BWN_PHY_SETMASK(mac, 0x0002, 0xffc0, 0x0004);
+ if (phy->type == BWN_PHYTYPE_B)
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ else if (phy->type == BWN_PHYTYPE_G)
+ BWN_WRITE_2(mac, 0x03e6, 0x0);
+}
+
+static void
+bwn_phy_init_a(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+
+ KASSERT(phy->type == BWN_PHYTYPE_A || phy->type == BWN_PHYTYPE_G,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if (phy->rev >= 6) {
+ if (phy->type == BWN_PHYTYPE_A)
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x1000);
+ if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) & BWN_PHY_ENCORE_EN)
+ BWN_PHY_SET(mac, BWN_PHY_ENCORE, 0x0010);
+ else
+ BWN_PHY_MASK(mac, BWN_PHY_ENCORE, ~0x1010);
+ }
+
+ bwn_wa_init(mac);
+
+ if (phy->type == BWN_PHYTYPE_G &&
+ (mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_PACTRL))
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x6e), 0xe000, 0x3cf);
+}
+
+static void
+bwn_wa_write_noisescale(struct bwn_mac *mac, const uint16_t *nst)
+{
+ int i;
+
+ for (i = 0; i < BWN_TAB_NOISESCALE_SIZE; i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_NOISESCALE, i, nst[i]);
+}
+
+static void
+bwn_wa_agc(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+
+ if (phy->rev == 1) {
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 0, 254);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 1, 13);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 2, 19);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1_R1, 3, 25);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 0, 0x2710);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 1, 0x9b83);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 2, 0x9b83);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, 3, 0x0f8d);
+ BWN_PHY_WRITE(mac, BWN_PHY_LMS, 4);
+ } else {
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 0, 254);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 1, 13);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 2, 19);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC1, 3, 25);
+ }
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_CCKSHIFTBITS_WA, (uint16_t)~0xff00,
+ 0x5700);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x007f, 0x000f);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1a), ~0x3f80, 0x2b80);
+ BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, 0xf0ff, 0x0300);
+ BWN_RF_SET(mac, 0x7a, 0x0008);
+ BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x000f, 0x0008);
+ BWN_PHY_SETMASK(mac, BWN_PHY_P1P2GAIN, ~0x0f00, 0x0600);
+ BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x0f00, 0x0700);
+ BWN_PHY_SETMASK(mac, BWN_PHY_N1P1GAIN, ~0x0f00, 0x0100);
+ if (phy->rev == 1)
+ BWN_PHY_SETMASK(mac, BWN_PHY_N1N2GAIN, ~0x000f, 0x0007);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x00ff, 0x001c);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x88), ~0x3f00, 0x0200);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), ~0x00ff, 0x001c);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x00ff, 0x0020);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x89), ~0x3f00, 0x0200);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x82), ~0x00ff, 0x002e);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x96), (uint16_t)~0xff00, 0x1a00);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), ~0x00ff, 0x0028);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x81), (uint16_t)~0xff00, 0x2c00);
+ if (phy->rev == 1) {
+ BWN_PHY_WRITE(mac, BWN_PHY_PEAK_COUNT, 0x092b);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e, 0x0002);
+ } else {
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x1b), ~0x001e);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x1f), 0x287a);
+ BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL, ~0x000f, 0x0004);
+ if (phy->rev >= 6) {
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x22), 0x287a);
+ BWN_PHY_SETMASK(mac, BWN_PHY_LPFGAINCTL,
+ (uint16_t)~0xf000, 0x3000);
+ }
+ }
+ BWN_PHY_SETMASK(mac, BWN_PHY_DIVSRCHIDX, 0x8080, 0x7874);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8e), 0x1c00);
+ if (phy->rev == 1) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_DIVP1P2GAIN, ~0x0f00, 0x0600);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8b), 0x005e);
+ BWN_PHY_SETMASK(mac, BWN_PHY_ANTWRSETT, ~0x00ff, 0x001e);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x8d), 0x0002);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 0, 0);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 1, 7);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 2, 16);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3_R1, 3, 28);
+ } else {
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 0, 0);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 1, 7);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 2, 16);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC3, 3, 28);
+ }
+ if (phy->rev >= 6) {
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x0003);
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0x26), ~0x1000);
+ }
+ BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM);
+}
+
+static void
+bwn_wa_grev1(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ int i;
+ static const uint16_t bwn_tab_finefreqg[] = BWN_TAB_FINEFREQ_G;
+ static const uint32_t bwn_tab_retard[] = BWN_TAB_RETARD;
+ static const uint32_t bwn_tab_rotor[] = BWN_TAB_ROTOR;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
+
+ /* init CRSTHRES and ANTDWELL */
+ if (phy->rev == 1) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
+ } else if (phy->rev == 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
+ BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
+ } else {
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
+ BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
+ }
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRS0, ~0x03c0, 0xd000);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0x2c), 0x005a);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCKSHIFTBITS, 0x0026);
+
+ /* XXX support PHY-A??? */
+ for (i = 0; i < N(bwn_tab_finefreqg); i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DACRFPABB, i,
+ bwn_tab_finefreqg[i]);
+
+ /* XXX support PHY-A??? */
+ if (phy->rev == 1)
+ for (i = 0; i < N(bwn_tab_noise_g1); i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
+ bwn_tab_noise_g1[i]);
+ else
+ for (i = 0; i < N(bwn_tab_noise_g2); i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
+ bwn_tab_noise_g2[i]);
+
+
+ for (i = 0; i < N(bwn_tab_rotor); i++)
+ bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ROTOR, i,
+ bwn_tab_rotor[i]);
+
+ /* XXX support PHY-A??? */
+ if (phy->rev >= 6) {
+ if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
+ BWN_PHY_ENCORE_EN)
+ bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
+ else
+ bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
+ } else
+ bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
+
+ for (i = 0; i < N(bwn_tab_retard); i++)
+ bwn_ofdmtab_write_4(mac, BWN_OFDMTAB_ADVRETARD, i,
+ bwn_tab_retard[i]);
+
+ if (phy->rev == 1) {
+ for (i = 0; i < 16; i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1,
+ i, 0x0020);
+ } else {
+ for (i = 0; i < 32; i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
+ }
+
+ bwn_wa_agc(mac);
+}
+
+static void
+bwn_wa_grev26789(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ int i;
+ static const uint16_t bwn_tab_sigmasqr2[] = BWN_TAB_SIGMASQR2;
+ uint16_t ofdmrev;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
+
+ bwn_gtab_write(mac, BWN_GTAB_ORIGTR, 0, 0xc480);
+
+ /* init CRSTHRES and ANTDWELL */
+ if (phy->rev == 1)
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1_R1, 0x4f19);
+ else if (phy->rev == 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x1861);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0271);
+ BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
+ } else {
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES1, 0x0098);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRSTHRES2, 0x0070);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xc9), 0x0080);
+ BWN_PHY_SET(mac, BWN_PHY_ANTDWELL, 0x0800);
+ }
+
+ for (i = 0; i < 64; i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_RSSI, i, i);
+
+ /* XXX support PHY-A??? */
+ if (phy->rev == 1)
+ for (i = 0; i < N(bwn_tab_noise_g1); i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
+ bwn_tab_noise_g1[i]);
+ else
+ for (i = 0; i < N(bwn_tab_noise_g2); i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_AGC2, i,
+ bwn_tab_noise_g2[i]);
+
+ /* XXX support PHY-A??? */
+ if (phy->rev >= 6) {
+ if (BWN_PHY_READ(mac, BWN_PHY_ENCORE) &
+ BWN_PHY_ENCORE_EN)
+ bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g3);
+ else
+ bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g2);
+ } else
+ bwn_wa_write_noisescale(mac, bwn_tab_noisescale_g1);
+
+ for (i = 0; i < N(bwn_tab_sigmasqr2); i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_MINSIGSQ, i,
+ bwn_tab_sigmasqr2[i]);
+
+ if (phy->rev == 1) {
+ for (i = 0; i < 16; i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI_R1, i,
+ 0x0020);
+ } else {
+ for (i = 0; i < 32; i++)
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_WRSSI, i, 0x0820);
+ }
+
+ bwn_wa_agc(mac);
+
+ ofdmrev = BWN_PHY_READ(mac, BWN_PHY_VERSION_OFDM) & BWN_PHYVER_VERSION;
+ if (ofdmrev > 2) {
+ if (phy->type == BWN_PHYTYPE_A)
+ BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1808);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_PWRDOWN, 0x1000);
+ } else {
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 3, 0x1044);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 4, 0x7201);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_DAC, 6, 0x0040);
+ }
+
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 2, 15);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_0F, 3, 20);
+}
+
+static void
+bwn_wa_init(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct siba_softc *bus = mac->mac_sd->sd_bus;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s fail", __func__));
+
+ switch (phy->rev) {
+ case 1:
+ bwn_wa_grev1(mac);
+ break;
+ case 2:
+ case 6:
+ case 7:
+ case 8:
+ case 9:
+ bwn_wa_grev26789(mac);
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+
+ if (bus->siba_board_vendor != SIBA_BOARDVENDOR_BCM ||
+ bus->siba_board_type != SIBA_BOARD_BU4306 ||
+ bus->siba_board_rev != 0x17) {
+ if (phy->rev < 2) {
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 1,
+ 0x0002);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX_R1, 2,
+ 0x0001);
+ } else {
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 1, 0x0002);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX, 2, 0x0001);
+ if ((bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA) &&
+ (phy->rev >= 7)) {
+ BWN_PHY_MASK(mac, BWN_PHY_EXTG(0x11), 0xf7ff);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
+ 0x0020, 0x0001);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
+ 0x0021, 0x0001);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
+ 0x0022, 0x0001);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
+ 0x0023, 0x0000);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
+ 0x0000, 0x0000);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_GAINX,
+ 0x0003, 0x0002);
+ }
+ }
+ }
+ if (bus->siba_sprom.bf_lo & BWN_BFL_FEM) {
+ BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, 0x3120);
+ BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, 0xc480);
+ }
+
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 0, 0);
+ bwn_ofdmtab_write_2(mac, BWN_OFDMTAB_UNKNOWN_11, 1, 0);
+}
+
+static void
+bwn_ofdmtab_write_2(struct bwn_mac *mac, uint16_t table, uint16_t offset,
+ uint16_t value)
+{
+ struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
+ uint16_t addr;
+
+ addr = table + offset;
+ if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
+ (addr - 1 != pg->pg_ofdmtab_addr)) {
+ BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
+ pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
+ }
+ pg->pg_ofdmtab_addr = addr;
+ BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
+}
+
+static void
+bwn_ofdmtab_write_4(struct bwn_mac *mac, uint16_t table, uint16_t offset,
+ uint32_t value)
+{
+ struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
+ uint16_t addr;
+
+ addr = table + offset;
+ if ((pg->pg_ofdmtab_dir != BWN_OFDMTAB_DIR_WRITE) ||
+ (addr - 1 != pg->pg_ofdmtab_addr)) {
+ BWN_PHY_WRITE(mac, BWN_PHY_OTABLECTL, addr);
+ pg->pg_ofdmtab_dir = BWN_OFDMTAB_DIR_WRITE;
+ }
+ pg->pg_ofdmtab_addr = addr;
+
+ BWN_PHY_WRITE(mac, BWN_PHY_OTABLEI, value);
+ BWN_PHY_WRITE(mac, BWN_PHY_OTABLEQ, (value >> 16));
+}
+
+static void
+bwn_gtab_write(struct bwn_mac *mac, uint16_t table, uint16_t offset,
+ uint16_t value)
+{
+
+ BWN_PHY_WRITE(mac, BWN_PHY_GTABCTL, table + offset);
+ BWN_PHY_WRITE(mac, BWN_PHY_GTABDATA, value);
+}
+
+static void
+bwn_dummy_transmission(struct bwn_mac *mac, int ofdm, int paon)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_softc *sc = mac->mac_sc;
+ unsigned int i, max_loop;
+ uint16_t value;
+ uint32_t buffer[5] = {
+ 0x00000000, 0x00d40000, 0x00000000, 0x01000000, 0x00000000
+ };
+
+ if (ofdm) {
+ max_loop = 0x1e;
+ buffer[0] = 0x000201cc;
+ } else {
+ max_loop = 0xfa;
+ buffer[0] = 0x000b846e;
+ }
+
+ BWN_ASSERT_LOCKED(sc);
+
+ for (i = 0; i < 5; i++)
+ bwn_ram_write(mac, i * 4, buffer[i]);
+
+ BWN_WRITE_2(mac, 0x0568, 0x0000);
+ BWN_WRITE_2(mac, 0x07c0,
+ (mac->mac_sd->sd_id.sd_rev < 11) ? 0x0000 : 0x0100);
+ value = ((phy->type == BWN_PHYTYPE_A) ? 0x41 : 0x40);
+ BWN_WRITE_2(mac, 0x050c, value);
+ if (phy->type == BWN_PHYTYPE_LP)
+ BWN_WRITE_2(mac, 0x0514, 0x1a02);
+ BWN_WRITE_2(mac, 0x0508, 0x0000);
+ BWN_WRITE_2(mac, 0x050a, 0x0000);
+ BWN_WRITE_2(mac, 0x054c, 0x0000);
+ BWN_WRITE_2(mac, 0x056a, 0x0014);
+ BWN_WRITE_2(mac, 0x0568, 0x0826);
+ BWN_WRITE_2(mac, 0x0500, 0x0000);
+ if (phy->type == BWN_PHYTYPE_LP)
+ BWN_WRITE_2(mac, 0x0502, 0x0050);
+ else
+ BWN_WRITE_2(mac, 0x0502, 0x0030);
+
+ if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
+ BWN_RF_WRITE(mac, 0x0051, 0x0017);
+ for (i = 0x00; i < max_loop; i++) {
+ value = BWN_READ_2(mac, 0x050e);
+ if (value & 0x0080)
+ break;
+ DELAY(10);
+ }
+ for (i = 0x00; i < 0x0a; i++) {
+ value = BWN_READ_2(mac, 0x050e);
+ if (value & 0x0400)
+ break;
+ DELAY(10);
+ }
+ for (i = 0x00; i < 0x19; i++) {
+ value = BWN_READ_2(mac, 0x0690);
+ if (!(value & 0x0100))
+ break;
+ DELAY(10);
+ }
+ if (phy->rf_ver == 0x2050 && phy->rf_rev <= 0x5)
+ BWN_RF_WRITE(mac, 0x0051, 0x0037);
+}
+
+static void
+bwn_ram_write(struct bwn_mac *mac, uint16_t offset, uint32_t val)
+{
+ uint32_t macctl;
+
+ KASSERT(offset % 4 == 0, ("%s:%d: fail", __func__, __LINE__));
+
+ macctl = BWN_READ_4(mac, BWN_MACCTL);
+ if (macctl & BWN_MACCTL_BIGENDIAN)
+ printf("TODO: need swap\n");
+
+ BWN_WRITE_4(mac, BWN_RAM_CONTROL, offset);
+ BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
+ BWN_WRITE_4(mac, BWN_RAM_DATA, val);
+}
+
+static void
+bwn_lo_write(struct bwn_mac *mac, struct bwn_loctl *ctl)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint16_t value;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ value = (uint8_t) (ctl->q);
+ value |= ((uint8_t) (ctl->i)) << 8;
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_CTL, value);
+}
+
+static uint16_t
+bwn_lo_calcfeed(struct bwn_mac *mac,
+ uint16_t lna, uint16_t pga, uint16_t trsw_rx)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint16_t rfover;
+ uint16_t feedthrough;
+
+ if (phy->gmode) {
+ lna <<= BWN_PHY_RFOVERVAL_LNA_SHIFT;
+ pga <<= BWN_PHY_RFOVERVAL_PGA_SHIFT;
+
+ KASSERT((lna & ~BWN_PHY_RFOVERVAL_LNA) == 0,
+ ("%s:%d: fail", __func__, __LINE__));
+ KASSERT((pga & ~BWN_PHY_RFOVERVAL_PGA) == 0,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ trsw_rx &= (BWN_PHY_RFOVERVAL_TRSWRX | BWN_PHY_RFOVERVAL_BW);
+
+ rfover = BWN_PHY_RFOVERVAL_UNK | pga | lna | trsw_rx;
+ if ((mac->mac_sd->sd_bus->siba_sprom.bf_lo & BWN_BFL_EXTLNA)
+ && phy->rev > 6)
+ rfover |= BWN_PHY_RFOVERVAL_EXTLNA;
+
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
+ DELAY(10);
+ rfover |= BWN_PHY_RFOVERVAL_BW_LBW;
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
+ DELAY(10);
+ rfover |= BWN_PHY_RFOVERVAL_BW_LPF;
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, rfover);
+ DELAY(10);
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xf300);
+ } else {
+ pga |= BWN_PHY_PGACTL_UNKNOWN;
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
+ DELAY(10);
+ pga |= BWN_PHY_PGACTL_LOWBANDW;
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
+ DELAY(10);
+ pga |= BWN_PHY_PGACTL_LPF;
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, pga);
+ }
+ DELAY(21);
+ feedthrough = BWN_PHY_READ(mac, BWN_PHY_LO_LEAKAGE);
+
+ return (feedthrough);
+}
+
+static uint16_t
+bwn_lo_txctl_regtable(struct bwn_mac *mac,
+ uint16_t *value, uint16_t *pad_mix_gain)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint16_t reg, v, padmix;
+
+ if (phy->type == BWN_PHYTYPE_B) {
+ v = 0x30;
+ if (phy->rf_rev <= 5) {
+ reg = 0x43;
+ padmix = 0;
+ } else {
+ reg = 0x52;
+ padmix = 5;
+ }
+ } else {
+ if (phy->rev >= 2 && phy->rf_rev == 8) {
+ reg = 0x43;
+ v = 0x10;
+ padmix = 2;
+ } else {
+ reg = 0x52;
+ v = 0x30;
+ padmix = 5;
+ }
+ }
+ if (value)
+ *value = v;
+ if (pad_mix_gain)
+ *pad_mix_gain = padmix;
+
+ return (reg);
+}
+
+static void
+bwn_lo_measure_txctl_values(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ uint16_t reg, mask;
+ uint16_t trsw_rx, pga;
+ uint16_t rf_pctl_reg;
+
+ static const uint8_t tx_bias_values[] = {
+ 0x09, 0x08, 0x0a, 0x01, 0x00,
+ 0x02, 0x05, 0x04, 0x06,
+ };
+ static const uint8_t tx_magn_values[] = {
+ 0x70, 0x40,
+ };
+
+ if (!BWN_HAS_LOOPBACK(phy)) {
+ rf_pctl_reg = 6;
+ trsw_rx = 2;
+ pga = 0;
+ } else {
+ int lb_gain;
+
+ trsw_rx = 0;
+ lb_gain = pg->pg_max_lb_gain / 2;
+ if (lb_gain > 10) {
+ rf_pctl_reg = 0;
+ pga = abs(10 - lb_gain) / 6;
+ pga = MIN(MAX(pga, 0), 15);
+ } else {
+ int cmp_val;
+ int tmp;
+
+ pga = 0;
+ cmp_val = 0x24;
+ if ((phy->rev >= 2) &&
+ (phy->rf_ver == 0x2050) && (phy->rf_rev == 8))
+ cmp_val = 0x3c;
+ tmp = lb_gain;
+ if ((10 - lb_gain) < cmp_val)
+ tmp = (10 - lb_gain);
+ if (tmp < 0)
+ tmp += 6;
+ else
+ tmp += 3;
+ cmp_val /= 4;
+ tmp /= 4;
+ if (tmp >= cmp_val)
+ rf_pctl_reg = cmp_val;
+ else
+ rf_pctl_reg = tmp;
+ }
+ }
+ BWN_RF_SETMASK(mac, 0x43, 0xfff0, rf_pctl_reg);
+ bwn_phy_g_set_bbatt(mac, 2);
+
+ reg = bwn_lo_txctl_regtable(mac, &mask, NULL);
+ mask = ~mask;
+ BWN_RF_MASK(mac, reg, mask);
+
+ if (BWN_HAS_TXMAG(phy)) {
+ int i, j;
+ int feedthrough;
+ int min_feedth = 0xffff;
+ uint8_t tx_magn, tx_bias;
+
+ for (i = 0; i < N(tx_magn_values); i++) {
+ tx_magn = tx_magn_values[i];
+ BWN_RF_SETMASK(mac, 0x52, 0xff0f, tx_magn);
+ for (j = 0; j < N(tx_bias_values); j++) {
+ tx_bias = tx_bias_values[j];
+ BWN_RF_SETMASK(mac, 0x52, 0xfff0, tx_bias);
+ feedthrough = bwn_lo_calcfeed(mac, 0, pga,
+ trsw_rx);
+ if (feedthrough < min_feedth) {
+ lo->tx_bias = tx_bias;
+ lo->tx_magn = tx_magn;
+ min_feedth = feedthrough;
+ }
+ if (lo->tx_bias == 0)
+ break;
+ }
+ BWN_RF_WRITE(mac, 0x52,
+ (BWN_RF_READ(mac, 0x52)
+ & 0xff00) | lo->tx_bias | lo->
+ tx_magn);
+ }
+ } else {
+ lo->tx_magn = 0;
+ lo->tx_bias = 0;
+ BWN_RF_MASK(mac, 0x52, 0xfff0);
+ }
+
+ BWN_GETTIME(lo->txctl_measured_time);
+}
+
+static void
+bwn_lo_get_powervector(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ int i;
+ uint64_t tmp;
+ uint64_t power_vector = 0;
+
+ for (i = 0; i < 8; i += 2) {
+ tmp = bwn_shm_read_2(mac, BWN_SHARED, 0x310 + i);
+ power_vector |= (tmp << (i * 8));
+ bwn_shm_write_2(mac, BWN_SHARED, 0x310 + i, 0);
+ }
+ if (power_vector)
+ lo->power_vector = power_vector;
+
+ BWN_GETTIME(lo->pwr_vec_read_time);
+}
+
+static void
+bwn_lo_measure_gain_values(struct bwn_mac *mac, int16_t max_rx_gain,
+ int use_trsw_rx)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ uint16_t tmp;
+
+ if (max_rx_gain < 0)
+ max_rx_gain = 0;
+
+ if (BWN_HAS_LOOPBACK(phy)) {
+ int trsw_rx = 0;
+ int trsw_rx_gain;
+
+ if (use_trsw_rx) {
+ trsw_rx_gain = pg->pg_trsw_rx_gain / 2;
+ if (max_rx_gain >= trsw_rx_gain) {
+ trsw_rx_gain = max_rx_gain - trsw_rx_gain;
+ trsw_rx = 0x20;
+ }
+ } else
+ trsw_rx_gain = max_rx_gain;
+ if (trsw_rx_gain < 9) {
+ pg->pg_lna_lod_gain = 0;
+ } else {
+ pg->pg_lna_lod_gain = 1;
+ trsw_rx_gain -= 8;
+ }
+ trsw_rx_gain = MIN(MAX(trsw_rx_gain, 0), 0x2d);
+ pg->pg_pga_gain = trsw_rx_gain / 3;
+ if (pg->pg_pga_gain >= 5) {
+ pg->pg_pga_gain -= 5;
+ pg->pg_lna_gain = 2;
+ } else
+ pg->pg_lna_gain = 0;
+ } else {
+ pg->pg_lna_gain = 0;
+ pg->pg_trsw_rx_gain = 0x20;
+ if (max_rx_gain >= 0x14) {
+ pg->pg_lna_lod_gain = 1;
+ pg->pg_pga_gain = 2;
+ } else if (max_rx_gain >= 0x12) {
+ pg->pg_lna_lod_gain = 1;
+ pg->pg_pga_gain = 1;
+ } else if (max_rx_gain >= 0xf) {
+ pg->pg_lna_lod_gain = 1;
+ pg->pg_pga_gain = 0;
+ } else {
+ pg->pg_lna_lod_gain = 0;
+ pg->pg_pga_gain = 0;
+ }
+ }
+
+ tmp = BWN_RF_READ(mac, 0x7a);
+ if (pg->pg_lna_lod_gain == 0)
+ tmp &= ~0x0008;
+ else
+ tmp |= 0x0008;
+ BWN_RF_WRITE(mac, 0x7a, tmp);
+}
+
+static void
+bwn_lo_save(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
+{
+ struct siba_sprom *sprom = &mac->mac_sd->sd_bus->siba_sprom;
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ struct timespec ts;
+ uint16_t tmp;
+
+ if (bwn_has_hwpctl(mac)) {
+ sav->phy_lomask = BWN_PHY_READ(mac, BWN_PHY_LO_MASK);
+ sav->phy_extg = BWN_PHY_READ(mac, BWN_PHY_EXTG(0x01));
+ sav->phy_dacctl_hwpctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
+ sav->phy_cck4 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x14));
+ sav->phy_hpwr_tssictl = BWN_PHY_READ(mac, BWN_PHY_HPWR_TSSICTL);
+
+ BWN_PHY_SET(mac, BWN_PHY_HPWR_TSSICTL, 0x100);
+ BWN_PHY_SET(mac, BWN_PHY_EXTG(0x01), 0x40);
+ BWN_PHY_SET(mac, BWN_PHY_DACCTL, 0x40);
+ BWN_PHY_SET(mac, BWN_PHY_CCK(0x14), 0x200);
+ }
+ if (phy->type == BWN_PHYTYPE_B &&
+ phy->rf_ver == 0x2050 && phy->rf_rev < 6) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x16), 0x410);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x17), 0x820);
+ }
+ if (phy->rev >= 2) {
+ sav->phy_analogover = BWN_PHY_READ(mac, BWN_PHY_ANALOGOVER);
+ sav->phy_analogoverval =
+ BWN_PHY_READ(mac, BWN_PHY_ANALOGOVERVAL);
+ sav->phy_rfover = BWN_PHY_READ(mac, BWN_PHY_RFOVER);
+ sav->phy_rfoverval = BWN_PHY_READ(mac, BWN_PHY_RFOVERVAL);
+ sav->phy_classctl = BWN_PHY_READ(mac, BWN_PHY_CLASSCTL);
+ sav->phy_cck3 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x3e));
+ sav->phy_crs0 = BWN_PHY_READ(mac, BWN_PHY_CRS0);
+
+ BWN_PHY_MASK(mac, BWN_PHY_CLASSCTL, 0xfffc);
+ BWN_PHY_MASK(mac, BWN_PHY_CRS0, 0x7fff);
+ BWN_PHY_SET(mac, BWN_PHY_ANALOGOVER, 0x0003);
+ BWN_PHY_MASK(mac, BWN_PHY_ANALOGOVERVAL, 0xfffc);
+ if (phy->type == BWN_PHYTYPE_G) {
+ if ((phy->rev >= 7) &&
+ (sprom->bf_lo & BWN_BFL_EXTLNA)) {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x933);
+ } else {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0x133);
+ }
+ } else {
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, 0);
+ }
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), 0);
+ }
+ sav->reg0 = BWN_READ_2(mac, 0x3f4);
+ sav->reg1 = BWN_READ_2(mac, 0x3e2);
+ sav->rf0 = BWN_RF_READ(mac, 0x43);
+ sav->rf1 = BWN_RF_READ(mac, 0x7a);
+ sav->phy_pgactl = BWN_PHY_READ(mac, BWN_PHY_PGACTL);
+ sav->phy_cck2 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x2a));
+ sav->phy_syncctl = BWN_PHY_READ(mac, BWN_PHY_SYNCCTL);
+ sav->phy_dacctl = BWN_PHY_READ(mac, BWN_PHY_DACCTL);
+
+ if (!BWN_HAS_TXMAG(phy)) {
+ sav->rf2 = BWN_RF_READ(mac, 0x52);
+ sav->rf2 &= 0x00f0;
+ }
+ if (phy->type == BWN_PHYTYPE_B) {
+ sav->phy_cck0 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x30));
+ sav->phy_cck1 = BWN_PHY_READ(mac, BWN_PHY_CCK(0x06));
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), 0x00ff);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), 0x3f3f);
+ } else {
+ BWN_WRITE_2(mac, 0x3e2, BWN_READ_2(mac, 0x3e2)
+ | 0x8000);
+ }
+ BWN_WRITE_2(mac, 0x3f4, BWN_READ_2(mac, 0x3f4)
+ & 0xf000);
+
+ tmp =
+ (phy->type == BWN_PHYTYPE_G) ? BWN_PHY_LO_MASK : BWN_PHY_CCK(0x2e);
+ BWN_PHY_WRITE(mac, tmp, 0x007f);
+
+ tmp = sav->phy_syncctl;
+ BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, tmp & 0xff7f);
+ tmp = sav->rf1;
+ BWN_RF_WRITE(mac, 0x007a, tmp & 0xfff0);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), 0x8a3);
+ if (phy->type == BWN_PHYTYPE_G ||
+ (phy->type == BWN_PHYTYPE_B &&
+ phy->rf_ver == 0x2050 && phy->rf_rev >= 6)) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x1003);
+ } else
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2b), 0x0802);
+ if (phy->rev >= 2)
+ bwn_dummy_transmission(mac, 0, 1);
+ bwn_phy_g_switch_chan(mac, 6, 0);
+ BWN_RF_READ(mac, 0x51);
+ if (phy->type == BWN_PHYTYPE_G)
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0);
+
+ nanouptime(&ts);
+ if (time_before(lo->txctl_measured_time,
+ (ts.tv_nsec / 1000000 + ts.tv_sec * 1000) - BWN_LO_TXCTL_EXPIRE))
+ bwn_lo_measure_txctl_values(mac);
+
+ if (phy->type == BWN_PHYTYPE_G && phy->rev >= 3)
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0xc078);
+ else {
+ if (phy->type == BWN_PHYTYPE_B)
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, 0x8078);
+ }
+}
+
+static void
+bwn_lo_restore(struct bwn_mac *mac, struct bwn_lo_g_value *sav)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ uint16_t tmp;
+
+ if (phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, 0xe300);
+ tmp = (pg->pg_pga_gain << 8);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa0);
+ DELAY(5);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa2);
+ DELAY(2);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, tmp | 0xa3);
+ } else {
+ tmp = (pg->pg_pga_gain | 0xefa0);
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, tmp);
+ }
+ if (phy->type == BWN_PHYTYPE_G) {
+ if (phy->rev >= 3)
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0xc078);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2e), 0x8078);
+ if (phy->rev >= 2)
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0202);
+ else
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2f), 0x0101);
+ }
+ BWN_WRITE_2(mac, 0x3f4, sav->reg0);
+ BWN_PHY_WRITE(mac, BWN_PHY_PGACTL, sav->phy_pgactl);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x2a), sav->phy_cck2);
+ BWN_PHY_WRITE(mac, BWN_PHY_SYNCCTL, sav->phy_syncctl);
+ BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl);
+ BWN_RF_WRITE(mac, 0x43, sav->rf0);
+ BWN_RF_WRITE(mac, 0x7a, sav->rf1);
+ if (!BWN_HAS_TXMAG(phy)) {
+ tmp = sav->rf2;
+ BWN_RF_SETMASK(mac, 0x52, 0xff0f, tmp);
+ }
+ BWN_WRITE_2(mac, 0x3e2, sav->reg1);
+ if (phy->type == BWN_PHYTYPE_B &&
+ phy->rf_ver == 0x2050 && phy->rf_rev <= 5) {
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x30), sav->phy_cck0);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x06), sav->phy_cck1);
+ }
+ if (phy->rev >= 2) {
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVER, sav->phy_analogover);
+ BWN_PHY_WRITE(mac, BWN_PHY_ANALOGOVERVAL,
+ sav->phy_analogoverval);
+ BWN_PHY_WRITE(mac, BWN_PHY_CLASSCTL, sav->phy_classctl);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVER, sav->phy_rfover);
+ BWN_PHY_WRITE(mac, BWN_PHY_RFOVERVAL, sav->phy_rfoverval);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x3e), sav->phy_cck3);
+ BWN_PHY_WRITE(mac, BWN_PHY_CRS0, sav->phy_crs0);
+ }
+ if (bwn_has_hwpctl(mac)) {
+ tmp = (sav->phy_lomask & 0xbfff);
+ BWN_PHY_WRITE(mac, BWN_PHY_LO_MASK, tmp);
+ BWN_PHY_WRITE(mac, BWN_PHY_EXTG(0x01), sav->phy_extg);
+ BWN_PHY_WRITE(mac, BWN_PHY_DACCTL, sav->phy_dacctl_hwpctl);
+ BWN_PHY_WRITE(mac, BWN_PHY_CCK(0x14), sav->phy_cck4);
+ BWN_PHY_WRITE(mac, BWN_PHY_HPWR_TSSICTL, sav->phy_hpwr_tssictl);
+ }
+ bwn_phy_g_switch_chan(mac, sav->old_channel, 1);
+}
+
+static int
+bwn_lo_probe_loctl(struct bwn_mac *mac,
+ struct bwn_loctl *probe, struct bwn_lo_g_sm *d)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_loctl orig, test;
+ struct bwn_loctl prev = { -100, -100 };
+ static const struct bwn_loctl modifiers[] = {
+ { 1, 1,}, { 1, 0,}, { 1, -1,}, { 0, -1,},
+ { -1, -1,}, { -1, 0,}, { -1, 1,}, { 0, 1,}
+ };
+ int begin, end, lower = 0, i;
+ uint16_t feedth;
+
+ if (d->curstate == 0) {
+ begin = 1;
+ end = 8;
+ } else if (d->curstate % 2 == 0) {
+ begin = d->curstate - 1;
+ end = d->curstate + 1;
+ } else {
+ begin = d->curstate - 2;
+ end = d->curstate + 2;
+ }
+ if (begin < 1)
+ begin += 8;
+ if (end > 8)
+ end -= 8;
+
+ memcpy(&orig, probe, sizeof(struct bwn_loctl));
+ i = begin;
+ d->curstate = i;
+ while (1) {
+ KASSERT(i >= 1 && i <= 8, ("%s:%d: fail", __func__, __LINE__));
+ memcpy(&test, &orig, sizeof(struct bwn_loctl));
+ test.i += modifiers[i - 1].i * d->multipler;
+ test.q += modifiers[i - 1].q * d->multipler;
+ if ((test.i != prev.i || test.q != prev.q) &&
+ (abs(test.i) <= 16 && abs(test.q) <= 16)) {
+ bwn_lo_write(mac, &test);
+ feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
+ pg->pg_pga_gain, pg->pg_trsw_rx_gain);
+ if (feedth < d->feedth) {
+ memcpy(probe, &test,
+ sizeof(struct bwn_loctl));
+ lower = 1;
+ d->feedth = feedth;
+ if (d->nmeasure < 2 && !BWN_HAS_LOOPBACK(phy))
+ break;
+ }
+ }
+ memcpy(&prev, &test, sizeof(prev));
+ if (i == end)
+ break;
+ if (i == 8)
+ i = 1;
+ else
+ i++;
+ d->curstate = i;
+ }
+
+ return (lower);
+}
+
+static void
+bwn_lo_probe_sm(struct bwn_mac *mac, struct bwn_loctl *loctl, int *rxgain)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_lo_g_sm d;
+ struct bwn_loctl probe;
+ int lower, repeat, cnt = 0;
+ uint16_t feedth;
+
+ d.nmeasure = 0;
+ d.multipler = 1;
+ if (BWN_HAS_LOOPBACK(phy))
+ d.multipler = 3;
+
+ memcpy(&d.loctl, loctl, sizeof(struct bwn_loctl));
+ repeat = (BWN_HAS_LOOPBACK(phy)) ? 4 : 1;
+
+ do {
+ bwn_lo_write(mac, &d.loctl);
+ feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
+ pg->pg_pga_gain, pg->pg_trsw_rx_gain);
+ if (feedth < 0x258) {
+ if (feedth >= 0x12c)
+ *rxgain += 6;
+ else
+ *rxgain += 3;
+ feedth = bwn_lo_calcfeed(mac, pg->pg_lna_gain,
+ pg->pg_pga_gain, pg->pg_trsw_rx_gain);
+ }
+ d.feedth = feedth;
+ d.curstate = 0;
+ do {
+ KASSERT(d.curstate >= 0 && d.curstate <= 8,
+ ("%s:%d: fail", __func__, __LINE__));
+ memcpy(&probe, &d.loctl,
+ sizeof(struct bwn_loctl));
+ lower = bwn_lo_probe_loctl(mac, &probe, &d);
+ if (!lower)
+ break;
+ if ((probe.i == d.loctl.i) && (probe.q == d.loctl.q))
+ break;
+ memcpy(&d.loctl, &probe, sizeof(struct bwn_loctl));
+ d.nmeasure++;
+ } while (d.nmeasure < 24);
+ memcpy(loctl, &d.loctl, sizeof(struct bwn_loctl));
+
+ if (BWN_HAS_LOOPBACK(phy)) {
+ if (d.feedth > 0x1194)
+ *rxgain -= 6;
+ else if (d.feedth < 0x5dc)
+ *rxgain += 3;
+ if (cnt == 0) {
+ if (d.feedth <= 0x5dc) {
+ d.multipler = 1;
+ cnt++;
+ } else
+ d.multipler = 2;
+ } else if (cnt == 2)
+ d.multipler = 1;
+ }
+ bwn_lo_measure_gain_values(mac, *rxgain, BWN_HAS_LOOPBACK(phy));
+ } while (++cnt < repeat);
+}
+
+static struct bwn_lo_calib *
+bwn_lo_calibset(struct bwn_mac *mac,
+ const struct bwn_bbatt *bbatt, const struct bwn_rfatt *rfatt)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_loctl loctl = { 0, 0 };
+ struct bwn_lo_calib *cal;
+ struct bwn_lo_g_value sval;
+ int rxgain;
+ uint16_t pad, reg, value;
+
+ sval.old_channel = phy->chan;
+ bwn_mac_suspend(mac);
+ bwn_lo_save(mac, &sval);
+
+ reg = bwn_lo_txctl_regtable(mac, &value, &pad);
+ BWN_RF_SETMASK(mac, 0x43, 0xfff0, rfatt->att);
+ BWN_RF_SETMASK(mac, reg, ~value, (rfatt->padmix ? value :0));
+
+ rxgain = (rfatt->att * 2) + (bbatt->att / 2);
+ if (rfatt->padmix)
+ rxgain -= pad;
+ if (BWN_HAS_LOOPBACK(phy))
+ rxgain += pg->pg_max_lb_gain;
+ bwn_lo_measure_gain_values(mac, rxgain, BWN_HAS_LOOPBACK(phy));
+ bwn_phy_g_set_bbatt(mac, bbatt->att);
+ bwn_lo_probe_sm(mac, &loctl, &rxgain);
+
+ bwn_lo_restore(mac, &sval);
+ bwn_mac_enable(mac);
+
+ cal = malloc(sizeof(*cal), M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (!cal) {
+ device_printf(mac->mac_sc->sc_dev, "out of memory\n");
+ return (NULL);
+ }
+ memcpy(&cal->bbatt, bbatt, sizeof(*bbatt));
+ memcpy(&cal->rfatt, rfatt, sizeof(*rfatt));
+ memcpy(&cal->ctl, &loctl, sizeof(loctl));
+
+ BWN_GETTIME(cal->calib_time);
+
+ return (cal);
+}
+
+static struct bwn_lo_calib *
+bwn_lo_get_calib(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
+ const struct bwn_rfatt *rfatt)
+{
+ struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
+ struct bwn_lo_calib *c;
+
+ TAILQ_FOREACH(c, &lo->calib_list, list) {
+ if (!BWN_BBATTCMP(&c->bbatt, bbatt))
+ continue;
+ if (!BWN_RFATTCMP(&c->rfatt, rfatt))
+ continue;
+ return (c);
+ }
+
+ c = bwn_lo_calibset(mac, bbatt, rfatt);
+ if (!c)
+ return (NULL);
+ TAILQ_INSERT_TAIL(&lo->calib_list, c, list);
+
+ return (c);
+}
+
+static void
+bwn_phy_g_dc_lookup_init(struct bwn_mac *mac, uint8_t update)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ const struct bwn_rfatt *rfatt;
+ const struct bwn_bbatt *bbatt;
+ uint64_t pvector;
+ int i;
+ int rf_offset, bb_offset;
+ uint8_t changed = 0;
+
+ KASSERT(BWN_DC_LT_SIZE == 32, ("%s:%d: fail", __func__, __LINE__));
+ KASSERT(lo->rfatt.len * lo->bbatt.len <= 64,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ pvector = lo->power_vector;
+ if (!update && !pvector)
+ return;
+
+ bwn_mac_suspend(mac);
+
+ for (i = 0; i < BWN_DC_LT_SIZE * 2; i++) {
+ struct bwn_lo_calib *cal;
+ int idx;
+ uint16_t val;
+
+ if (!update && !(pvector & (((uint64_t)1ULL) << i)))
+ continue;
+ bb_offset = i / lo->rfatt.len;
+ rf_offset = i % lo->rfatt.len;
+ bbatt = &(lo->bbatt.array[bb_offset]);
+ rfatt = &(lo->rfatt.array[rf_offset]);
+
+ cal = bwn_lo_calibset(mac, bbatt, rfatt);
+ if (!cal) {
+ device_printf(sc->sc_dev, "LO: Could not "
+ "calibrate DC table entry\n");
+ continue;
+ }
+ val = (uint8_t)(cal->ctl.q);
+ val |= ((uint8_t)(cal->ctl.i)) << 4;
+ free(cal, M_DEVBUF);
+
+ idx = i / 2;
+ if (i % 2)
+ lo->dc_lt[idx] = (lo->dc_lt[idx] & 0x00ff)
+ | ((val & 0x00ff) << 8);
+ else
+ lo->dc_lt[idx] = (lo->dc_lt[idx] & 0xff00)
+ | (val & 0x00ff);
+ changed = 1;
+ }
+ if (changed) {
+ for (i = 0; i < BWN_DC_LT_SIZE; i++)
+ BWN_PHY_WRITE(mac, 0x3a0 + i, lo->dc_lt[i]);
+ }
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_lo_fixup_rfatt(struct bwn_rfatt *rf)
+{
+
+ if (!rf->padmix)
+ return;
+ if ((rf->att != 1) && (rf->att != 2) && (rf->att != 3))
+ rf->att = 4;
+}
+
+static void
+bwn_lo_g_adjust(struct bwn_mac *mac)
+{
+ struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
+ struct bwn_lo_calib *cal;
+ struct bwn_rfatt rf;
+
+ memcpy(&rf, &pg->pg_rfatt, sizeof(rf));
+ bwn_lo_fixup_rfatt(&rf);
+
+ cal = bwn_lo_get_calib(mac, &pg->pg_bbatt, &rf);
+ if (!cal)
+ return;
+ bwn_lo_write(mac, &cal->ctl);
+}
+
+static void
+bwn_lo_g_init(struct bwn_mac *mac)
+{
+
+ if (!bwn_has_hwpctl(mac))
+ return;
+
+ bwn_lo_get_powervector(mac);
+ bwn_phy_g_dc_lookup_init(mac, 1);
+}
+
+static void
+bwn_mac_suspend(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ int i;
+ uint32_t tmp;
+
+ KASSERT(mac->mac_suspended >= 0,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if (mac->mac_suspended == 0) {
+ bwn_psctl(mac, BWN_PS_AWAKE);
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL)
+ & ~BWN_MACCTL_ON);
+ BWN_READ_4(mac, BWN_MACCTL);
+ for (i = 35; i; i--) {
+ tmp = BWN_READ_4(mac, BWN_INTR_REASON);
+ if (tmp & BWN_INTR_MAC_SUSPENDED)
+ goto out;
+ DELAY(10);
+ }
+ for (i = 40; i; i--) {
+ tmp = BWN_READ_4(mac, BWN_INTR_REASON);
+ if (tmp & BWN_INTR_MAC_SUSPENDED)
+ goto out;
+ DELAY(1000);
+ }
+ device_printf(sc->sc_dev, "MAC suspend failed\n");
+ }
+out:
+ mac->mac_suspended++;
+}
+
+static void
+bwn_mac_enable(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t state;
+
+ state = bwn_shm_read_2(mac, BWN_SHARED,
+ BWN_SHARED_UCODESTAT);
+ if (state != BWN_SHARED_UCODESTAT_SUSPEND &&
+ state != BWN_SHARED_UCODESTAT_SLEEP)
+ device_printf(sc->sc_dev, "warn: firmware state (%d)\n", state);
+
+ mac->mac_suspended--;
+ KASSERT(mac->mac_suspended >= 0,
+ ("%s:%d: fail", __func__, __LINE__));
+ if (mac->mac_suspended == 0) {
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_ON);
+ BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_MAC_SUSPENDED);
+ BWN_READ_4(mac, BWN_MACCTL);
+ BWN_READ_4(mac, BWN_INTR_REASON);
+ bwn_psctl(mac, 0);
+ }
+}
+
+static void
+bwn_psctl(struct bwn_mac *mac, uint32_t flags)
+{
+ int i;
+ uint16_t ucstat;
+
+ KASSERT(!((flags & BWN_PS_ON) && (flags & BWN_PS_OFF)),
+ ("%s:%d: fail", __func__, __LINE__));
+ KASSERT(!((flags & BWN_PS_AWAKE) && (flags & BWN_PS_ASLEEP)),
+ ("%s:%d: fail", __func__, __LINE__));
+
+ /* XXX forcibly awake and hwps-off */
+
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ (BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_AWAKE) &
+ ~BWN_MACCTL_HWPS);
+ BWN_READ_4(mac, BWN_MACCTL);
+ if (mac->mac_sd->sd_id.sd_rev >= 5) {
+ for (i = 0; i < 100; i++) {
+ ucstat = bwn_shm_read_2(mac, BWN_SHARED,
+ BWN_SHARED_UCODESTAT);
+ if (ucstat != BWN_SHARED_UCODESTAT_SLEEP)
+ break;
+ DELAY(10);
+ }
+ }
+}
+
+static int16_t
+bwn_nrssi_read(struct bwn_mac *mac, uint16_t offset)
+{
+
+ BWN_PHY_WRITE(mac, BWN_PHY_NRSSI_CTRL, offset);
+ return ((int16_t)BWN_PHY_READ(mac, BWN_PHY_NRSSI_DATA));
+}
+
+static void
+bwn_nrssi_threshold(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+ int32_t a, b;
+ int16_t tmp16;
+ uint16_t tmpu16;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G, ("%s: fail", __func__));
+
+ if (phy->gmode && (siba->siba_sprom.bf_lo & BWN_BFL_RSSI)) {
+ if (!pg->pg_aci_wlan_automatic && pg->pg_aci_enable) {
+ a = 0x13;
+ b = 0x12;
+ } else {
+ a = 0xe;
+ b = 0x11;
+ }
+
+ a = a * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
+ a += (pg->pg_nrssi[0] << 6);
+ a += (a < 32) ? 31 : 32;
+ a = a >> 6;
+ a = MIN(MAX(a, -31), 31);
+
+ b = b * (pg->pg_nrssi[1] - pg->pg_nrssi[0]);
+ b += (pg->pg_nrssi[0] << 6);
+ if (b < 32)
+ b += 31;
+ else
+ b += 32;
+ b = b >> 6;
+ b = MIN(MAX(b, -31), 31);
+
+ tmpu16 = BWN_PHY_READ(mac, 0x048a) & 0xf000;
+ tmpu16 |= ((uint32_t)b & 0x0000003f);
+ tmpu16 |= (((uint32_t)a & 0x0000003f) << 6);
+ BWN_PHY_WRITE(mac, 0x048a, tmpu16);
+ return;
+ }
+
+ tmp16 = bwn_nrssi_read(mac, 0x20);
+ if (tmp16 >= 0x20)
+ tmp16 -= 0x40;
+ BWN_PHY_SETMASK(mac, 0x048a, 0xf000, (tmp16 < 3) ? 0x09eb : 0x0aed);
+}
+
+static void
+bwn_nrssi_slope_11g(struct bwn_mac *mac)
+{
+#define SAVE_RF_MAX 3
+#define SAVE_PHY_COMM_MAX 4
+#define SAVE_PHY3_MAX 8
+ static const uint16_t save_rf_regs[SAVE_RF_MAX] =
+ { 0x7a, 0x52, 0x43 };
+ static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] =
+ { 0x15, 0x5a, 0x59, 0x58 };
+ static const uint16_t save_phy3_regs[SAVE_PHY3_MAX] = {
+ 0x002e, 0x002f, 0x080f, BWN_PHY_G_LOCTL,
+ 0x0801, 0x0060, 0x0014, 0x0478
+ };
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ int32_t i, tmp32, phy3_idx = 0;
+ uint16_t delta, tmp;
+ uint16_t save_rf[SAVE_RF_MAX];
+ uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
+ uint16_t save_phy3[SAVE_PHY3_MAX];
+ uint16_t ant_div, phy0, chan_ex;
+ int16_t nrssi0, nrssi1;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if (phy->rf_rev >= 9)
+ return;
+ if (phy->rf_rev == 8)
+ bwn_nrssi_offset(mac);
+
+ BWN_PHY_MASK(mac, BWN_PHY_G_CRS, 0x7fff);
+ BWN_PHY_MASK(mac, 0x0802, 0xfffc);
+
+ /*
+ * Save RF/PHY registers for later restoration
+ */
+ ant_div = BWN_READ_2(mac, 0x03e2);
+ BWN_WRITE_2(mac, 0x03e2, BWN_READ_2(mac, 0x03e2) | 0x8000);
+ for (i = 0; i < SAVE_RF_MAX; ++i)
+ save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
+ for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
+ save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
+
+ phy0 = BWN_READ_2(mac, BWN_PHY0);
+ chan_ex = BWN_READ_2(mac, BWN_CHANNEL_EXT);
+ if (phy->rev >= 3) {
+ for (i = 0; i < SAVE_PHY3_MAX; ++i)
+ save_phy3[i] = BWN_PHY_READ(mac, save_phy3_regs[i]);
+ BWN_PHY_WRITE(mac, 0x002e, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_G_LOCTL, 0);
+ switch (phy->rev) {
+ case 4:
+ case 6:
+ case 7:
+ BWN_PHY_SET(mac, 0x0478, 0x0100);
+ BWN_PHY_SET(mac, 0x0801, 0x0040);
+ break;
+ case 3:
+ case 5:
+ BWN_PHY_MASK(mac, 0x0801, 0xffbf);
+ break;
+ }
+ BWN_PHY_SET(mac, 0x0060, 0x0040);
+ BWN_PHY_SET(mac, 0x0014, 0x0200);
+ }
+ /*
+ * Calculate nrssi0
+ */
+ BWN_RF_SET(mac, 0x007a, 0x0070);
+ bwn_set_all_gains(mac, 0, 8, 0);
+ BWN_RF_MASK(mac, 0x007a, 0x00f7);
+ if (phy->rev >= 2) {
+ BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0030);
+ BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0010);
+ }
+ BWN_RF_SET(mac, 0x007a, 0x0080);
+ DELAY(20);
+
+ nrssi0 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
+ if (nrssi0 >= 0x0020)
+ nrssi0 -= 0x0040;
+
+ /*
+ * Calculate nrssi1
+ */
+ BWN_RF_MASK(mac, 0x007a, 0x007f);
+ if (phy->rev >= 2)
+ BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
+
+ BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
+ BWN_READ_2(mac, BWN_CHANNEL_EXT) | 0x2000);
+ BWN_RF_SET(mac, 0x007a, 0x000f);
+ BWN_PHY_WRITE(mac, 0x0015, 0xf330);
+ if (phy->rev >= 2) {
+ BWN_PHY_SETMASK(mac, 0x0812, 0xffcf, 0x0020);
+ BWN_PHY_SETMASK(mac, 0x0811, 0xffcf, 0x0020);
+ }
+
+ bwn_set_all_gains(mac, 3, 0, 1);
+ if (phy->rf_rev == 8) {
+ BWN_RF_WRITE(mac, 0x0043, 0x001f);
+ } else {
+ tmp = BWN_RF_READ(mac, 0x0052) & 0xff0f;
+ BWN_RF_WRITE(mac, 0x0052, tmp | 0x0060);
+ tmp = BWN_RF_READ(mac, 0x0043) & 0xfff0;
+ BWN_RF_WRITE(mac, 0x0043, tmp | 0x0009);
+ }
+ BWN_PHY_WRITE(mac, 0x005a, 0x0480);
+ BWN_PHY_WRITE(mac, 0x0059, 0x0810);
+ BWN_PHY_WRITE(mac, 0x0058, 0x000d);
+ DELAY(20);
+ nrssi1 = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
+
+ /*
+ * Install calculated narrow RSSI values
+ */
+ if (nrssi1 >= 0x0020)
+ nrssi1 -= 0x0040;
+ if (nrssi0 == nrssi1)
+ pg->pg_nrssi_slope = 0x00010000;
+ else
+ pg->pg_nrssi_slope = 0x00400000 / (nrssi0 - nrssi1);
+ if (nrssi0 >= -4) {
+ pg->pg_nrssi[0] = nrssi1;
+ pg->pg_nrssi[1] = nrssi0;
+ }
+
+ /*
+ * Restore saved RF/PHY registers
+ */
+ if (phy->rev >= 3) {
+ for (phy3_idx = 0; phy3_idx < 4; ++phy3_idx) {
+ BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
+ save_phy3[phy3_idx]);
+ }
+ }
+ if (phy->rev >= 2) {
+ BWN_PHY_MASK(mac, 0x0812, 0xffcf);
+ BWN_PHY_MASK(mac, 0x0811, 0xffcf);
+ }
+
+ for (i = 0; i < SAVE_RF_MAX; ++i)
+ BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
+
+ BWN_WRITE_2(mac, 0x03e2, ant_div);
+ BWN_WRITE_2(mac, 0x03e6, phy0);
+ BWN_WRITE_2(mac, BWN_CHANNEL_EXT, chan_ex);
+
+ for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
+ BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
+
+ bwn_spu_workaround(mac, phy->chan);
+ BWN_PHY_SET(mac, 0x0802, (0x0001 | 0x0002));
+ bwn_set_original_gains(mac);
+ BWN_PHY_SET(mac, BWN_PHY_G_CRS, 0x8000);
+ if (phy->rev >= 3) {
+ for (; phy3_idx < SAVE_PHY3_MAX; ++phy3_idx) {
+ BWN_PHY_WRITE(mac, save_phy3_regs[phy3_idx],
+ save_phy3[phy3_idx]);
+ }
+ }
+
+ delta = 0x1f - pg->pg_nrssi[0];
+ for (i = 0; i < 64; i++) {
+ tmp32 = (((i - delta) * pg->pg_nrssi_slope) / 0x10000) + 0x3a;
+ tmp32 = MIN(MAX(tmp32, 0), 0x3f);
+ pg->pg_nrssi_lt[i] = tmp32;
+ }
+
+ bwn_nrssi_threshold(mac);
+#undef SAVE_RF_MAX
+#undef SAVE_PHY_COMM_MAX
+#undef SAVE_PHY3_MAX
+}
+
+static void
+bwn_nrssi_offset(struct bwn_mac *mac)
+{
+#define SAVE_RF_MAX 2
+#define SAVE_PHY_COMM_MAX 10
+#define SAVE_PHY6_MAX 8
+ static const uint16_t save_rf_regs[SAVE_RF_MAX] =
+ { 0x7a, 0x43 };
+ static const uint16_t save_phy_comm_regs[SAVE_PHY_COMM_MAX] = {
+ 0x0001, 0x0811, 0x0812, 0x0814,
+ 0x0815, 0x005a, 0x0059, 0x0058,
+ 0x000a, 0x0003
+ };
+ static const uint16_t save_phy6_regs[SAVE_PHY6_MAX] = {
+ 0x002e, 0x002f, 0x080f, 0x0810,
+ 0x0801, 0x0060, 0x0014, 0x0478
+ };
+ struct bwn_phy *phy = &mac->mac_phy;
+ int i, phy6_idx = 0;
+ uint16_t save_rf[SAVE_RF_MAX];
+ uint16_t save_phy_comm[SAVE_PHY_COMM_MAX];
+ uint16_t save_phy6[SAVE_PHY6_MAX];
+ int16_t nrssi;
+ uint16_t saved = 0xffff;
+
+ for (i = 0; i < SAVE_PHY_COMM_MAX; ++i)
+ save_phy_comm[i] = BWN_PHY_READ(mac, save_phy_comm_regs[i]);
+ for (i = 0; i < SAVE_RF_MAX; ++i)
+ save_rf[i] = BWN_RF_READ(mac, save_rf_regs[i]);
+
+ BWN_PHY_MASK(mac, 0x0429, 0x7fff);
+ BWN_PHY_SETMASK(mac, 0x0001, 0x3fff, 0x4000);
+ BWN_PHY_SET(mac, 0x0811, 0x000c);
+ BWN_PHY_SETMASK(mac, 0x0812, 0xfff3, 0x0004);
+ BWN_PHY_MASK(mac, 0x0802, ~(0x1 | 0x2));
+ if (phy->rev >= 6) {
+ for (i = 0; i < SAVE_PHY6_MAX; ++i)
+ save_phy6[i] = BWN_PHY_READ(mac, save_phy6_regs[i]);
+
+ BWN_PHY_WRITE(mac, 0x002e, 0);
+ BWN_PHY_WRITE(mac, 0x002f, 0);
+ BWN_PHY_WRITE(mac, 0x080f, 0);
+ BWN_PHY_WRITE(mac, 0x0810, 0);
+ BWN_PHY_SET(mac, 0x0478, 0x0100);
+ BWN_PHY_SET(mac, 0x0801, 0x0040);
+ BWN_PHY_SET(mac, 0x0060, 0x0040);
+ BWN_PHY_SET(mac, 0x0014, 0x0200);
+ }
+ BWN_RF_SET(mac, 0x007a, 0x0070);
+ BWN_RF_SET(mac, 0x007a, 0x0080);
+ DELAY(30);
+
+ nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
+ if (nrssi >= 0x20)
+ nrssi -= 0x40;
+ if (nrssi == 31) {
+ for (i = 7; i >= 4; i--) {
+ BWN_RF_WRITE(mac, 0x007b, i);
+ DELAY(20);
+ nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) &
+ 0x003f);
+ if (nrssi >= 0x20)
+ nrssi -= 0x40;
+ if (nrssi < 31 && saved == 0xffff)
+ saved = i;
+ }
+ if (saved == 0xffff)
+ saved = 4;
+ } else {
+ BWN_RF_MASK(mac, 0x007a, 0x007f);
+ if (phy->rev != 1) {
+ BWN_PHY_SET(mac, 0x0814, 0x0001);
+ BWN_PHY_MASK(mac, 0x0815, 0xfffe);
+ }
+ BWN_PHY_SET(mac, 0x0811, 0x000c);
+ BWN_PHY_SET(mac, 0x0812, 0x000c);
+ BWN_PHY_SET(mac, 0x0811, 0x0030);
+ BWN_PHY_SET(mac, 0x0812, 0x0030);
+ BWN_PHY_WRITE(mac, 0x005a, 0x0480);
+ BWN_PHY_WRITE(mac, 0x0059, 0x0810);
+ BWN_PHY_WRITE(mac, 0x0058, 0x000d);
+ if (phy->rev == 0)
+ BWN_PHY_WRITE(mac, 0x0003, 0x0122);
+ else
+ BWN_PHY_SET(mac, 0x000a, 0x2000);
+ if (phy->rev != 1) {
+ BWN_PHY_SET(mac, 0x0814, 0x0004);
+ BWN_PHY_MASK(mac, 0x0815, 0xfffb);
+ }
+ BWN_PHY_SETMASK(mac, 0x0003, 0xff9f, 0x0040);
+ BWN_RF_SET(mac, 0x007a, 0x000f);
+ bwn_set_all_gains(mac, 3, 0, 1);
+ BWN_RF_SETMASK(mac, 0x0043, 0x00f0, 0x000f);
+ DELAY(30);
+ nrssi = (int16_t) ((BWN_PHY_READ(mac, 0x047f) >> 8) & 0x003f);
+ if (nrssi >= 0x20)
+ nrssi -= 0x40;
+ if (nrssi == -32) {
+ for (i = 0; i < 4; i++) {
+ BWN_RF_WRITE(mac, 0x007b, i);
+ DELAY(20);
+ nrssi = (int16_t)((BWN_PHY_READ(mac,
+ 0x047f) >> 8) & 0x003f);
+ if (nrssi >= 0x20)
+ nrssi -= 0x40;
+ if (nrssi > -31 && saved == 0xffff)
+ saved = i;
+ }
+ if (saved == 0xffff)
+ saved = 3;
+ } else
+ saved = 0;
+ }
+ BWN_RF_WRITE(mac, 0x007b, saved);
+
+ /*
+ * Restore saved RF/PHY registers
+ */
+ if (phy->rev >= 6) {
+ for (phy6_idx = 0; phy6_idx < 4; ++phy6_idx) {
+ BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
+ save_phy6[phy6_idx]);
+ }
+ }
+ if (phy->rev != 1) {
+ for (i = 3; i < 5; i++)
+ BWN_PHY_WRITE(mac, save_phy_comm_regs[i],
+ save_phy_comm[i]);
+ }
+ for (i = 5; i < SAVE_PHY_COMM_MAX; i++)
+ BWN_PHY_WRITE(mac, save_phy_comm_regs[i], save_phy_comm[i]);
+
+ for (i = SAVE_RF_MAX - 1; i >= 0; --i)
+ BWN_RF_WRITE(mac, save_rf_regs[i], save_rf[i]);
+
+ BWN_PHY_WRITE(mac, 0x0802, BWN_PHY_READ(mac, 0x0802) | 0x1 | 0x2);
+ BWN_PHY_SET(mac, 0x0429, 0x8000);
+ bwn_set_original_gains(mac);
+ if (phy->rev >= 6) {
+ for (; phy6_idx < SAVE_PHY6_MAX; ++phy6_idx) {
+ BWN_PHY_WRITE(mac, save_phy6_regs[phy6_idx],
+ save_phy6[phy6_idx]);
+ }
+ }
+
+ BWN_PHY_WRITE(mac, save_phy_comm_regs[0], save_phy_comm[0]);
+ BWN_PHY_WRITE(mac, save_phy_comm_regs[2], save_phy_comm[2]);
+ BWN_PHY_WRITE(mac, save_phy_comm_regs[1], save_phy_comm[1]);
+}
+
+static void
+bwn_set_all_gains(struct bwn_mac *mac, int16_t first, int16_t second,
+ int16_t third)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint16_t i;
+ uint16_t start = 0x08, end = 0x18;
+ uint16_t tmp;
+ uint16_t table;
+
+ if (phy->rev <= 1) {
+ start = 0x10;
+ end = 0x20;
+ }
+
+ table = BWN_OFDMTAB_GAINX;
+ if (phy->rev <= 1)
+ table = BWN_OFDMTAB_GAINX_R1;
+ for (i = 0; i < 4; i++)
+ bwn_ofdmtab_write_2(mac, table, i, first);
+
+ for (i = start; i < end; i++)
+ bwn_ofdmtab_write_2(mac, table, i, second);
+
+ if (third != -1) {
+ tmp = ((uint16_t) third << 14) | ((uint16_t) third << 6);
+ BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, tmp);
+ BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, tmp);
+ BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, tmp);
+ }
+ bwn_dummy_transmission(mac, 0, 1);
+}
+
+static void
+bwn_set_original_gains(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ uint16_t i, tmp;
+ uint16_t table;
+ uint16_t start = 0x0008, end = 0x0018;
+
+ if (phy->rev <= 1) {
+ start = 0x0010;
+ end = 0x0020;
+ }
+
+ table = BWN_OFDMTAB_GAINX;
+ if (phy->rev <= 1)
+ table = BWN_OFDMTAB_GAINX_R1;
+ for (i = 0; i < 4; i++) {
+ tmp = (i & 0xfffc);
+ tmp |= (i & 0x0001) << 1;
+ tmp |= (i & 0x0002) >> 1;
+
+ bwn_ofdmtab_write_2(mac, table, i, tmp);
+ }
+
+ for (i = start; i < end; i++)
+ bwn_ofdmtab_write_2(mac, table, i, i - start);
+
+ BWN_PHY_SETMASK(mac, 0x04a0, 0xbfbf, 0x4040);
+ BWN_PHY_SETMASK(mac, 0x04a1, 0xbfbf, 0x4040);
+ BWN_PHY_SETMASK(mac, 0x04a2, 0xbfbf, 0x4000);
+ bwn_dummy_transmission(mac, 0, 1);
+}
+
+static void
+bwn_phy_hwpctl_init(struct bwn_mac *mac)
+{
+ struct siba_softc *bus = mac->mac_sd->sd_bus;
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_rfatt old_rfatt, rfatt;
+ struct bwn_bbatt old_bbatt, bbatt;
+ uint8_t old_txctl = 0;
+
+ KASSERT(phy->type == BWN_PHYTYPE_G,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if ((bus->siba_board_vendor == SIBA_BOARDVENDOR_BCM) &&
+ (bus->siba_board_type == SIBA_BOARD_BU4306))
+ return;
+
+ BWN_PHY_WRITE(mac, 0x0028, 0x8018);
+
+ BWN_WRITE_2(mac, BWN_PHY0, BWN_READ_2(mac, BWN_PHY0) & 0xffdf);
+
+ if (!phy->gmode)
+ return;
+ bwn_hwpctl_early_init(mac);
+ if (pg->pg_curtssi == 0) {
+ if (phy->rf_ver == 0x2050 && phy->analog == 0) {
+ BWN_RF_SETMASK(mac, 0x0076, 0x00f7, 0x0084);
+ } else {
+ memcpy(&old_rfatt, &pg->pg_rfatt, sizeof(old_rfatt));
+ memcpy(&old_bbatt, &pg->pg_bbatt, sizeof(old_bbatt));
+ old_txctl = pg->pg_txctl;
+
+ bbatt.att = 11;
+ if (phy->rf_rev == 8) {
+ rfatt.att = 15;
+ rfatt.padmix = 1;
+ } else {
+ rfatt.att = 9;
+ rfatt.padmix = 0;
+ }
+ bwn_phy_g_set_txpwr_sub(mac, &bbatt, &rfatt, 0);
+ }
+ bwn_dummy_transmission(mac, 0, 1);
+ pg->pg_curtssi = BWN_PHY_READ(mac, BWN_PHY_TSSI);
+ if (phy->rf_ver == 0x2050 && phy->analog == 0)
+ BWN_RF_MASK(mac, 0x0076, 0xff7b);
+ else
+ bwn_phy_g_set_txpwr_sub(mac, &old_bbatt,
+ &old_rfatt, old_txctl);
+ }
+ bwn_hwpctl_init_gphy(mac);
+
+ /* clear TSSI */
+ bwn_shm_write_2(mac, BWN_SHARED, 0x0058, 0x7f7f);
+ bwn_shm_write_2(mac, BWN_SHARED, 0x005a, 0x7f7f);
+ bwn_shm_write_2(mac, BWN_SHARED, 0x0070, 0x7f7f);
+ bwn_shm_write_2(mac, BWN_SHARED, 0x0072, 0x7f7f);
+}
+
+static void
+bwn_hwpctl_early_init(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+
+ if (!bwn_has_hwpctl(mac)) {
+ BWN_PHY_WRITE(mac, 0x047a, 0xc111);
+ return;
+ }
+
+ BWN_PHY_MASK(mac, 0x0036, 0xfeff);
+ BWN_PHY_WRITE(mac, 0x002f, 0x0202);
+ BWN_PHY_SET(mac, 0x047c, 0x0002);
+ BWN_PHY_SET(mac, 0x047a, 0xf000);
+ if (phy->rf_ver == 0x2050 && phy->rf_rev == 8) {
+ BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
+ BWN_PHY_SET(mac, 0x005d, 0x8000);
+ BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
+ BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
+ BWN_PHY_SET(mac, 0x0036, 0x0400);
+ } else {
+ BWN_PHY_SET(mac, 0x0036, 0x0200);
+ BWN_PHY_SET(mac, 0x0036, 0x0400);
+ BWN_PHY_MASK(mac, 0x005d, 0x7fff);
+ BWN_PHY_MASK(mac, 0x004f, 0xfffe);
+ BWN_PHY_SETMASK(mac, 0x004e, 0xffc0, 0x0010);
+ BWN_PHY_WRITE(mac, 0x002e, 0xc07f);
+ BWN_PHY_SETMASK(mac, 0x047a, 0xff0f, 0x0010);
+ }
+}
+
+static void
+bwn_hwpctl_init_gphy(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ int i;
+ uint16_t nr_written = 0, tmp, value;
+ uint8_t rf, bb;
+
+ if (!bwn_has_hwpctl(mac)) {
+ bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_HW_POWERCTL);
+ return;
+ }
+
+ BWN_PHY_SETMASK(mac, 0x0036, 0xffc0,
+ (pg->pg_idletssi - pg->pg_curtssi));
+ BWN_PHY_SETMASK(mac, 0x0478, 0xff00,
+ (pg->pg_idletssi - pg->pg_curtssi));
+
+ for (i = 0; i < 32; i++)
+ bwn_ofdmtab_write_2(mac, 0x3c20, i, pg->pg_tssi2dbm[i]);
+ for (i = 32; i < 64; i++)
+ bwn_ofdmtab_write_2(mac, 0x3c00, i - 32, pg->pg_tssi2dbm[i]);
+ for (i = 0; i < 64; i += 2) {
+ value = (uint16_t) pg->pg_tssi2dbm[i];
+ value |= ((uint16_t) pg->pg_tssi2dbm[i + 1]) << 8;
+ BWN_PHY_WRITE(mac, 0x380 + (i / 2), value);
+ }
+
+ for (rf = 0; rf < lo->rfatt.len; rf++) {
+ for (bb = 0; bb < lo->bbatt.len; bb++) {
+ if (nr_written >= 0x40)
+ return;
+ tmp = lo->bbatt.array[bb].att;
+ tmp <<= 8;
+ if (phy->rf_rev == 8)
+ tmp |= 0x50;
+ else
+ tmp |= 0x40;
+ tmp |= lo->rfatt.array[rf].att;
+ BWN_PHY_WRITE(mac, 0x3c0 + nr_written, tmp);
+ nr_written++;
+ }
+ }
+
+ BWN_PHY_MASK(mac, 0x0060, 0xffbf);
+ BWN_PHY_WRITE(mac, 0x0014, 0x0000);
+
+ KASSERT(phy->rev >= 6, ("%s:%d: fail", __func__, __LINE__));
+ BWN_PHY_SET(mac, 0x0478, 0x0800);
+ BWN_PHY_MASK(mac, 0x0478, 0xfeff);
+ BWN_PHY_MASK(mac, 0x0801, 0xffbf);
+
+ bwn_phy_g_dc_lookup_init(mac, 1);
+ bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_HW_POWERCTL);
+}
+
+static void
+bwn_phy_g_switch_chan(struct bwn_mac *mac, int channel, uint8_t spu)
+{
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+
+ if (spu != 0)
+ bwn_spu_workaround(mac, channel);
+
+ BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
+
+ if (channel == 14) {
+ if (siba->siba_sprom.ccode == SIBA_CCODE_JAPAN)
+ bwn_hf_write(mac,
+ bwn_hf_read(mac) & ~BWN_HF_JAPAN_CHAN14_OFF);
+ else
+ bwn_hf_write(mac,
+ bwn_hf_read(mac) | BWN_HF_JAPAN_CHAN14_OFF);
+ BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
+ BWN_READ_2(mac, BWN_CHANNEL_EXT) | (1 << 11));
+ return;
+ }
+
+ BWN_WRITE_2(mac, BWN_CHANNEL_EXT,
+ BWN_READ_2(mac, BWN_CHANNEL_EXT) & 0xf7bf);
+}
+
+static uint16_t
+bwn_phy_g_chan2freq(uint8_t channel)
+{
+ static const uint8_t bwn_phy_g_rf_channels[] = BWN_PHY_G_RF_CHANNELS;
+
+ KASSERT(channel >= 1 && channel <= 14,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ return (bwn_phy_g_rf_channels[channel - 1]);
+}
+
+static void
+bwn_phy_g_set_txpwr_sub(struct bwn_mac *mac, const struct bwn_bbatt *bbatt,
+ const struct bwn_rfatt *rfatt, uint8_t txctl)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct bwn_txpwr_loctl *lo = &pg->pg_loctl;
+ uint16_t bb, rf;
+ uint16_t tx_bias, tx_magn;
+
+ bb = bbatt->att;
+ rf = rfatt->att;
+ tx_bias = lo->tx_bias;
+ tx_magn = lo->tx_magn;
+ if (tx_bias == 0xff)
+ tx_bias = 0;
+
+ pg->pg_txctl = txctl;
+ memmove(&pg->pg_rfatt, rfatt, sizeof(*rfatt));
+ pg->pg_rfatt.padmix = (txctl & BWN_TXCTL_TXMIX) ? 1 : 0;
+ memmove(&pg->pg_bbatt, bbatt, sizeof(*bbatt));
+ bwn_phy_g_set_bbatt(mac, bb);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_RADIO_ATT, rf);
+ if (phy->rf_ver == 0x2050 && phy->rf_rev == 8)
+ BWN_RF_WRITE(mac, 0x43, (rf & 0x000f) | (txctl & 0x0070));
+ else {
+ BWN_RF_SETMASK(mac, 0x43, 0xfff0, (rf & 0x000f));
+ BWN_RF_SETMASK(mac, 0x52, ~0x0070, (txctl & 0x0070));
+ }
+ if (BWN_HAS_TXMAG(phy))
+ BWN_RF_WRITE(mac, 0x52, tx_magn | tx_bias);
+ else
+ BWN_RF_SETMASK(mac, 0x52, 0xfff0, (tx_bias & 0x000f));
+ bwn_lo_g_adjust(mac);
+}
+
+static void
+bwn_phy_g_set_bbatt(struct bwn_mac *mac,
+ uint16_t bbatt)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+
+ if (phy->analog == 0) {
+ BWN_WRITE_2(mac, BWN_PHY0,
+ (BWN_READ_2(mac, BWN_PHY0) & 0xfff0) | bbatt);
+ return;
+ }
+ if (phy->analog > 1) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xffc3, bbatt << 2);
+ return;
+ }
+ BWN_PHY_SETMASK(mac, BWN_PHY_DACCTL, 0xff87, bbatt << 3);
+}
+
+static uint16_t
+bwn_rf_2050_rfoverval(struct bwn_mac *mac, uint16_t reg, uint32_t lpd)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_g *pg = &phy->phy_g;
+ struct siba_sprom *sprom = &(mac->mac_sd->sd_bus->siba_sprom);
+ int max_lb_gain;
+ uint16_t extlna;
+ uint16_t i;
+
+ if (phy->gmode == 0)
+ return (0);
+
+ if (BWN_HAS_LOOPBACK(phy)) {
+ max_lb_gain = pg->pg_max_lb_gain;
+ max_lb_gain += (phy->rf_rev == 8) ? 0x3e : 0x26;
+ if (max_lb_gain >= 0x46) {
+ extlna = 0x3000;
+ max_lb_gain -= 0x46;
+ } else if (max_lb_gain >= 0x3a) {
+ extlna = 0x1000;
+ max_lb_gain -= 0x3a;
+ } else if (max_lb_gain >= 0x2e) {
+ extlna = 0x2000;
+ max_lb_gain -= 0x2e;
+ } else {
+ extlna = 0;
+ max_lb_gain -= 0x10;
+ }
+
+ for (i = 0; i < 16; i++) {
+ max_lb_gain -= (i * 6);
+ if (max_lb_gain < 6)
+ break;
+ }
+
+ if ((phy->rev < 7) || !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
+ if (reg == BWN_PHY_RFOVER) {
+ return (0x1b3);
+ } else if (reg == BWN_PHY_RFOVERVAL) {
+ extlna |= (i << 8);
+ switch (lpd) {
+ case BWN_LPD(0, 1, 1):
+ return (0x0f92);
+ case BWN_LPD(0, 0, 1):
+ case BWN_LPD(1, 0, 1):
+ return (0x0092 | extlna);
+ case BWN_LPD(1, 0, 0):
+ return (0x0093 | extlna);
+ }
+ KASSERT(0 == 1,
+ ("%s:%d: fail", __func__, __LINE__));
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ } else {
+ if (reg == BWN_PHY_RFOVER)
+ return (0x9b3);
+ if (reg == BWN_PHY_RFOVERVAL) {
+ if (extlna)
+ extlna |= 0x8000;
+ extlna |= (i << 8);
+ switch (lpd) {
+ case BWN_LPD(0, 1, 1):
+ return (0x8f92);
+ case BWN_LPD(0, 0, 1):
+ return (0x8092 | extlna);
+ case BWN_LPD(1, 0, 1):
+ return (0x2092 | extlna);
+ case BWN_LPD(1, 0, 0):
+ return (0x2093 | extlna);
+ }
+ KASSERT(0 == 1,
+ ("%s:%d: fail", __func__, __LINE__));
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+ return (0);
+ }
+
+ if ((phy->rev < 7) ||
+ !(sprom->bf_lo & BWN_BFL_EXTLNA)) {
+ if (reg == BWN_PHY_RFOVER) {
+ return (0x1b3);
+ } else if (reg == BWN_PHY_RFOVERVAL) {
+ switch (lpd) {
+ case BWN_LPD(0, 1, 1):
+ return (0x0fb2);
+ case BWN_LPD(0, 0, 1):
+ return (0x00b2);
+ case BWN_LPD(1, 0, 1):
+ return (0x30b2);
+ case BWN_LPD(1, 0, 0):
+ return (0x30b3);
+ }
+ KASSERT(0 == 1,
+ ("%s:%d: fail", __func__, __LINE__));
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ } else {
+ if (reg == BWN_PHY_RFOVER) {
+ return (0x9b3);
+ } else if (reg == BWN_PHY_RFOVERVAL) {
+ switch (lpd) {
+ case BWN_LPD(0, 1, 1):
+ return (0x8fb2);
+ case BWN_LPD(0, 0, 1):
+ return (0x80b2);
+ case BWN_LPD(1, 0, 1):
+ return (0x20b2);
+ case BWN_LPD(1, 0, 0):
+ return (0x20b3);
+ }
+ KASSERT(0 == 1,
+ ("%s:%d: fail", __func__, __LINE__));
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+ return (0);
+}
+
+static void
+bwn_spu_workaround(struct bwn_mac *mac, uint8_t channel)
+{
+
+ if (mac->mac_phy.rf_ver != 0x2050 || mac->mac_phy.rf_rev >= 6)
+ return;
+ BWN_WRITE_2(mac, BWN_CHANNEL, (channel <= 10) ?
+ bwn_phy_g_chan2freq(channel + 4) : bwn_phy_g_chan2freq(1));
+ DELAY(1000);
+ BWN_WRITE_2(mac, BWN_CHANNEL, bwn_phy_g_chan2freq(channel));
+}
+
+static int
+bwn_fw_gets(struct bwn_mac *mac, enum bwn_fwtype type)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_fw *fw = &mac->mac_fw;
+ const uint8_t rev = mac->mac_sd->sd_id.sd_rev;
+ const char *filename;
+ uint32_t high;
+ int error;
+
+ /* microcode */
+ if (rev >= 5 && rev <= 10)
+ filename = "ucode5";
+ else if (rev >= 11 && rev <= 12)
+ filename = "ucode11";
+ else if (rev == 13)
+ filename = "ucode13";
+ else if (rev == 14)
+ filename = "ucode14";
+ else if (rev >= 15)
+ filename = "ucode15";
+ else {
+ device_printf(sc->sc_dev, "no ucode for rev %d\n", rev);
+ bwn_release_firmware(mac);
+ return (EOPNOTSUPP);
+ }
+ error = bwn_fw_get(mac, type, filename, &fw->ucode);
+ if (error) {
+ bwn_release_firmware(mac);
+ return (error);
+ }
+
+ /* PCM */
+ KASSERT(fw->no_pcmfile == 0, ("%s:%d fail", __func__, __LINE__));
+ if (rev >= 5 && rev <= 10) {
+ error = bwn_fw_get(mac, type, "pcm5", &fw->pcm);
+ if (error == ENOENT)
+ fw->no_pcmfile = 1;
+ else if (error) {
+ bwn_release_firmware(mac);
+ return (error);
+ }
+ } else if (rev < 11) {
+ device_printf(sc->sc_dev, "no PCM for rev %d\n", rev);
+ return (EOPNOTSUPP);
+ }
+
+ /* initvals */
+ high = siba_read_4(mac->mac_sd, SIBA_TGSHIGH);
+ switch (mac->mac_phy.type) {
+ case BWN_PHYTYPE_A:
+ if (rev < 5 || rev > 10)
+ goto fail1;
+ if (high & BWN_TGSHIGH_HAVE_2GHZ)
+ filename = "a0g1initvals5";
+ else
+ filename = "a0g0initvals5";
+ break;
+ case BWN_PHYTYPE_G:
+ if (rev >= 5 && rev <= 10)
+ filename = "b0g0initvals5";
+ else if (rev >= 13)
+ filename = "b0g0initvals13";
+ else
+ goto fail1;
+ break;
+ case BWN_PHYTYPE_LP:
+ if (rev == 13)
+ filename = "lp0initvals13";
+ else if (rev == 14)
+ filename = "lp0initvals14";
+ else if (rev >= 15)
+ filename = "lp0initvals15";
+ else
+ goto fail1;
+ break;
+ case BWN_PHYTYPE_N:
+ if (rev >= 11 && rev <= 12)
+ filename = "n0initvals11";
+ else
+ goto fail1;
+ break;
+ default:
+ goto fail1;
+ }
+ error = bwn_fw_get(mac, type, filename, &fw->initvals);
+ if (error) {
+ bwn_release_firmware(mac);
+ return (error);
+ }
+
+ /* bandswitch initvals */
+ switch (mac->mac_phy.type) {
+ case BWN_PHYTYPE_A:
+ if (rev >= 5 && rev <= 10) {
+ if (high & BWN_TGSHIGH_HAVE_2GHZ)
+ filename = "a0g1bsinitvals5";
+ else
+ filename = "a0g0bsinitvals5";
+ } else if (rev >= 11)
+ filename = NULL;
+ else
+ goto fail1;
+ break;
+ case BWN_PHYTYPE_G:
+ if (rev >= 5 && rev <= 10)
+ filename = "b0g0bsinitvals5";
+ else if (rev >= 11)
+ filename = NULL;
+ else
+ goto fail1;
+ break;
+ case BWN_PHYTYPE_LP:
+ if (rev == 13)
+ filename = "lp0bsinitvals13";
+ else if (rev == 14)
+ filename = "lp0bsinitvals14";
+ else if (rev >= 15)
+ filename = "lp0bsinitvals15";
+ else
+ goto fail1;
+ break;
+ case BWN_PHYTYPE_N:
+ if (rev >= 11 && rev <= 12)
+ filename = "n0bsinitvals11";
+ else
+ goto fail1;
+ break;
+ default:
+ goto fail1;
+ }
+ error = bwn_fw_get(mac, type, filename, &fw->initvals_band);
+ if (error) {
+ bwn_release_firmware(mac);
+ return (error);
+ }
+ return (0);
+fail1:
+ device_printf(sc->sc_dev, "no INITVALS for rev %d\n", rev);
+ bwn_release_firmware(mac);
+ return (EOPNOTSUPP);
+}
+
+static int
+bwn_fw_get(struct bwn_mac *mac, enum bwn_fwtype type,
+ const char *name, struct bwn_fwfile *bfw)
+{
+ const struct bwn_fwhdr *hdr;
+ struct bwn_softc *sc = mac->mac_sc;
+ const struct firmware *fw;
+ char namebuf[64];
+
+ if (name == NULL) {
+ bwn_do_release_fw(bfw);
+ return (0);
+ }
+ if (bfw->filename != NULL) {
+ if (bfw->type == type && (strcmp(bfw->filename, name) == 0))
+ return (0);
+ bwn_do_release_fw(bfw);
+ }
+
+ snprintf(namebuf, sizeof(namebuf), "bwn%s_v4_%s",
+ (type == BWN_FWTYPE_OPENSOURCE) ? "-open" : "", name);
+ /* XXX Sleeping on "fwload" with the non-sleepable locks held */
+ fw = firmware_get(namebuf);
+ if (fw == NULL) {
+ device_printf(sc->sc_dev, "the fw file(%s) not found\n",
+ namebuf);
+ return (ENOENT);
+ }
+ if (fw->datasize < sizeof(struct bwn_fwhdr))
+ goto fail;
+ hdr = (const struct bwn_fwhdr *)(fw->data);
+ switch (hdr->type) {
+ case BWN_FWTYPE_UCODE:
+ case BWN_FWTYPE_PCM:
+ if (be32toh(hdr->size) !=
+ (fw->datasize - sizeof(struct bwn_fwhdr)))
+ goto fail;
+ /* FALLTHROUGH */
+ case BWN_FWTYPE_IV:
+ if (hdr->ver != 1)
+ goto fail;
+ break;
+ default:
+ goto fail;
+ }
+ bfw->filename = name;
+ bfw->fw = fw;
+ bfw->type = type;
+ return (0);
+fail:
+ device_printf(sc->sc_dev, "the fw file(%s) format error\n", namebuf);
+ if (fw != NULL)
+ firmware_put(fw, FIRMWARE_UNLOAD);
+ return (EPROTO);
+}
+
+static void
+bwn_release_firmware(struct bwn_mac *mac)
+{
+
+ bwn_do_release_fw(&mac->mac_fw.ucode);
+ bwn_do_release_fw(&mac->mac_fw.pcm);
+ bwn_do_release_fw(&mac->mac_fw.initvals);
+ bwn_do_release_fw(&mac->mac_fw.initvals_band);
+}
+
+static void
+bwn_do_release_fw(struct bwn_fwfile *bfw)
+{
+
+ if (bfw->fw != NULL)
+ firmware_put(bfw->fw, FIRMWARE_UNLOAD);
+ bfw->fw = NULL;
+ bfw->filename = NULL;
+}
+
+static int
+bwn_fw_loaducode(struct bwn_mac *mac)
+{
+#define GETFWOFFSET(fwp, offset) \
+ ((const uint32_t *)((const char *)fwp.fw->data + offset))
+#define GETFWSIZE(fwp, offset) \
+ ((fwp.fw->datasize - offset) / sizeof(uint32_t))
+ struct bwn_softc *sc = mac->mac_sc;
+ const uint32_t *data;
+ unsigned int i;
+ uint32_t ctl;
+ uint16_t date, fwcaps, time;
+ int error = 0;
+
+ ctl = BWN_READ_4(mac, BWN_MACCTL);
+ ctl |= BWN_MACCTL_MCODE_JMP0;
+ KASSERT(!(ctl & BWN_MACCTL_MCODE_RUN), ("%s:%d: fail", __func__,
+ __LINE__));
+ BWN_WRITE_4(mac, BWN_MACCTL, ctl);
+ for (i = 0; i < 64; i++)
+ bwn_shm_write_2(mac, BWN_SCRATCH, i, 0);
+ for (i = 0; i < 4096; i += 2)
+ bwn_shm_write_2(mac, BWN_SHARED, i, 0);
+
+ data = GETFWOFFSET(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
+ bwn_shm_ctlword(mac, BWN_UCODE | BWN_SHARED_AUTOINC, 0x0000);
+ for (i = 0; i < GETFWSIZE(mac->mac_fw.ucode, sizeof(struct bwn_fwhdr));
+ i++) {
+ BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
+ DELAY(10);
+ }
+
+ if (mac->mac_fw.pcm.fw) {
+ data = GETFWOFFSET(mac->mac_fw.pcm, sizeof(struct bwn_fwhdr));
+ bwn_shm_ctlword(mac, BWN_HW, 0x01ea);
+ BWN_WRITE_4(mac, BWN_SHM_DATA, 0x00004000);
+ bwn_shm_ctlword(mac, BWN_HW, 0x01eb);
+ for (i = 0; i < GETFWSIZE(mac->mac_fw.pcm,
+ sizeof(struct bwn_fwhdr)); i++) {
+ BWN_WRITE_4(mac, BWN_SHM_DATA, be32toh(data[i]));
+ DELAY(10);
+ }
+ }
+
+ BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_ALL);
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_JMP0) |
+ BWN_MACCTL_MCODE_RUN);
+
+ for (i = 0; i < 21; i++) {
+ if (BWN_READ_4(mac, BWN_INTR_REASON) == BWN_INTR_MAC_SUSPENDED)
+ break;
+ if (i >= 20) {
+ device_printf(sc->sc_dev, "ucode timeout\n");
+ error = ENXIO;
+ goto error;
+ }
+ DELAY(50000);
+ }
+ BWN_READ_4(mac, BWN_INTR_REASON);
+
+ mac->mac_fw.rev = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_REV);
+ if (mac->mac_fw.rev <= 0x128) {
+ device_printf(sc->sc_dev, "the firmware is too old\n");
+ error = EOPNOTSUPP;
+ goto error;
+ }
+ mac->mac_fw.patch = bwn_shm_read_2(mac, BWN_SHARED,
+ BWN_SHARED_UCODE_PATCH);
+ date = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_DATE);
+ mac->mac_fw.opensource = (date == 0xffff);
+ if (bwn_wme != 0)
+ mac->mac_flags |= BWN_MAC_FLAG_WME;
+ mac->mac_flags |= BWN_MAC_FLAG_HWCRYPTO;
+
+ time = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_UCODE_TIME);
+ if (mac->mac_fw.opensource == 0) {
+ device_printf(sc->sc_dev,
+ "firmware version (rev %u patch %u date %#x time %#x)\n",
+ mac->mac_fw.rev, mac->mac_fw.patch, date, time);
+ if (mac->mac_fw.no_pcmfile)
+ device_printf(sc->sc_dev,
+ "no HW crypto acceleration due to pcm5\n");
+ } else {
+ mac->mac_fw.patch = time;
+ fwcaps = bwn_fwcaps_read(mac);
+ if (!(fwcaps & BWN_FWCAPS_HWCRYPTO) || mac->mac_fw.no_pcmfile) {
+ device_printf(sc->sc_dev,
+ "disabling HW crypto acceleration\n");
+ mac->mac_flags &= ~BWN_MAC_FLAG_HWCRYPTO;
+ }
+ if (!(fwcaps & BWN_FWCAPS_WME)) {
+ device_printf(sc->sc_dev, "disabling WME support\n");
+ mac->mac_flags &= ~BWN_MAC_FLAG_WME;
+ }
+ }
+
+ if (BWN_ISOLDFMT(mac))
+ device_printf(sc->sc_dev, "using old firmware image\n");
+
+ return (0);
+
+error:
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ (BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_MCODE_RUN) |
+ BWN_MACCTL_MCODE_JMP0);
+
+ return (error);
+#undef GETFWSIZE
+#undef GETFWOFFSET
+}
+
+/* OpenFirmware only */
+static uint16_t
+bwn_fwcaps_read(struct bwn_mac *mac)
+{
+
+ KASSERT(mac->mac_fw.opensource == 1,
+ ("%s:%d: fail", __func__, __LINE__));
+ return (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_FWCAPS));
+}
+
+static int
+bwn_fwinitvals_write(struct bwn_mac *mac, const struct bwn_fwinitvals *ivals,
+ size_t count, size_t array_size)
+{
+#define GET_NEXTIV16(iv) \
+ ((const struct bwn_fwinitvals *)((const uint8_t *)(iv) + \
+ sizeof(uint16_t) + sizeof(uint16_t)))
+#define GET_NEXTIV32(iv) \
+ ((const struct bwn_fwinitvals *)((const uint8_t *)(iv) + \
+ sizeof(uint16_t) + sizeof(uint32_t)))
+ struct bwn_softc *sc = mac->mac_sc;
+ const struct bwn_fwinitvals *iv;
+ uint16_t offset;
+ size_t i;
+ uint8_t bit32;
+
+ KASSERT(sizeof(struct bwn_fwinitvals) == 6,
+ ("%s:%d: fail", __func__, __LINE__));
+ iv = ivals;
+ for (i = 0; i < count; i++) {
+ if (array_size < sizeof(iv->offset_size))
+ goto fail;
+ array_size -= sizeof(iv->offset_size);
+ offset = be16toh(iv->offset_size);
+ bit32 = (offset & BWN_FWINITVALS_32BIT) ? 1 : 0;
+ offset &= BWN_FWINITVALS_OFFSET_MASK;
+ if (offset >= 0x1000)
+ goto fail;
+ if (bit32) {
+ if (array_size < sizeof(iv->data.d32))
+ goto fail;
+ array_size -= sizeof(iv->data.d32);
+ BWN_WRITE_4(mac, offset, be32toh(iv->data.d32));
+ iv = GET_NEXTIV32(iv);
+ } else {
+
+ if (array_size < sizeof(iv->data.d16))
+ goto fail;
+ array_size -= sizeof(iv->data.d16);
+ BWN_WRITE_2(mac, offset, be16toh(iv->data.d16));
+
+ iv = GET_NEXTIV16(iv);
+ }
+ }
+ if (array_size != 0)
+ goto fail;
+ return (0);
+fail:
+ device_printf(sc->sc_dev, "initvals: invalid format\n");
+ return (EPROTO);
+#undef GET_NEXTIV16
+#undef GET_NEXTIV32
+}
+
+static int
+bwn_switch_channel(struct bwn_mac *mac, int chan)
+{
+ struct bwn_phy *phy = &(mac->mac_phy);
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint16_t channelcookie, savedcookie;
+ int error;
+
+ if (chan == 0xffff)
+ chan = phy->get_default_chan(mac);
+
+ channelcookie = chan;
+ if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
+ channelcookie |= 0x100;
+ savedcookie = bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_CHAN);
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, channelcookie);
+ error = phy->switch_channel(mac, chan);
+ if (error)
+ goto fail;
+
+ mac->mac_phy.chan = chan;
+ DELAY(8000);
+ return (0);
+fail:
+ device_printf(sc->sc_dev, "failed to switch channel\n");
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_CHAN, savedcookie);
+ return (error);
+}
+
+static uint16_t
+bwn_ant2phy(int antenna)
+{
+
+ switch (antenna) {
+ case BWN_ANT0:
+ return (BWN_TX_PHY_ANT0);
+ case BWN_ANT1:
+ return (BWN_TX_PHY_ANT1);
+ case BWN_ANT2:
+ return (BWN_TX_PHY_ANT2);
+ case BWN_ANT3:
+ return (BWN_TX_PHY_ANT3);
+ case BWN_ANTAUTO:
+ return (BWN_TX_PHY_ANT01AUTO);
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (0);
+}
+
+static void
+bwn_wme_load(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ int i;
+
+ KASSERT(N(bwn_wme_shm_offsets) == N(sc->sc_wmeParams),
+ ("%s:%d: fail", __func__, __LINE__));
+
+ bwn_mac_suspend(mac);
+ for (i = 0; i < N(sc->sc_wmeParams); i++)
+ bwn_wme_loadparams(mac, &(sc->sc_wmeParams[i]),
+ bwn_wme_shm_offsets[i]);
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_wme_loadparams(struct bwn_mac *mac,
+ const struct wmeParams *p, uint16_t shm_offset)
+{
+#define SM(_v, _f) (((_v) << _f##_S) & _f)
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t params[BWN_NR_WMEPARAMS];
+ int slot, tmp;
+ unsigned int i;
+
+ slot = BWN_READ_2(mac, BWN_RNG) &
+ SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
+
+ memset(&params, 0, sizeof(params));
+
+ DPRINTF(sc, BWN_DEBUG_WME, "wmep_txopLimit %d wmep_logcwmin %d "
+ "wmep_logcwmax %d wmep_aifsn %d\n", p->wmep_txopLimit,
+ p->wmep_logcwmin, p->wmep_logcwmax, p->wmep_aifsn);
+
+ params[BWN_WMEPARAM_TXOP] = p->wmep_txopLimit * 32;
+ params[BWN_WMEPARAM_CWMIN] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
+ params[BWN_WMEPARAM_CWMAX] = SM(p->wmep_logcwmax, WME_PARAM_LOGCWMAX);
+ params[BWN_WMEPARAM_CWCUR] = SM(p->wmep_logcwmin, WME_PARAM_LOGCWMIN);
+ params[BWN_WMEPARAM_AIFS] = p->wmep_aifsn;
+ params[BWN_WMEPARAM_BSLOTS] = slot;
+ params[BWN_WMEPARAM_REGGAP] = slot + p->wmep_aifsn;
+
+ for (i = 0; i < N(params); i++) {
+ if (i == BWN_WMEPARAM_STATUS) {
+ tmp = bwn_shm_read_2(mac, BWN_SHARED,
+ shm_offset + (i * 2));
+ tmp |= 0x100;
+ bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
+ tmp);
+ } else {
+ bwn_shm_write_2(mac, BWN_SHARED, shm_offset + (i * 2),
+ params[i]);
+ }
+ }
+}
+
+static void
+bwn_mac_write_bssid(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint32_t tmp;
+ int i;
+ uint8_t mac_bssid[IEEE80211_ADDR_LEN * 2];
+
+ bwn_mac_setfilter(mac, BWN_MACFILTER_BSSID, sc->sc_bssid);
+ memcpy(mac_bssid, sc->sc_macaddr, IEEE80211_ADDR_LEN);
+ memcpy(mac_bssid + IEEE80211_ADDR_LEN, sc->sc_bssid,
+ IEEE80211_ADDR_LEN);
+
+ for (i = 0; i < N(mac_bssid); i += sizeof(uint32_t)) {
+ tmp = (uint32_t) (mac_bssid[i + 0]);
+ tmp |= (uint32_t) (mac_bssid[i + 1]) << 8;
+ tmp |= (uint32_t) (mac_bssid[i + 2]) << 16;
+ tmp |= (uint32_t) (mac_bssid[i + 3]) << 24;
+ bwn_ram_write(mac, 0x20 + i, tmp);
+ }
+}
+
+static void
+bwn_mac_setfilter(struct bwn_mac *mac, uint16_t offset,
+ const uint8_t *macaddr)
+{
+ static const uint8_t zero[IEEE80211_ADDR_LEN] = { 0 };
+ uint16_t data;
+
+ if (!mac)
+ macaddr = zero;
+
+ offset |= 0x0020;
+ BWN_WRITE_2(mac, BWN_MACFILTER_CONTROL, offset);
+
+ data = macaddr[0];
+ data |= macaddr[1] << 8;
+ BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
+ data = macaddr[2];
+ data |= macaddr[3] << 8;
+ BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
+ data = macaddr[4];
+ data |= macaddr[5] << 8;
+ BWN_WRITE_2(mac, BWN_MACFILTER_DATA, data);
+}
+
+static void
+bwn_key_dowrite(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
+ const uint8_t *key, size_t key_len, const uint8_t *mac_addr)
+{
+ uint8_t buf[BWN_SEC_KEYSIZE] = { 0, };
+ uint8_t per_sta_keys_start = 8;
+
+ if (BWN_SEC_NEWAPI(mac))
+ per_sta_keys_start = 4;
+
+ KASSERT(index < mac->mac_max_nr_keys,
+ ("%s:%d: fail", __func__, __LINE__));
+ KASSERT(key_len <= BWN_SEC_KEYSIZE,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ if (index >= per_sta_keys_start)
+ bwn_key_macwrite(mac, index, NULL);
+ if (key)
+ memcpy(buf, key, key_len);
+ bwn_key_write(mac, index, algorithm, buf);
+ if (index >= per_sta_keys_start)
+ bwn_key_macwrite(mac, index, mac_addr);
+
+ mac->mac_key[index].algorithm = algorithm;
+}
+
+static void
+bwn_key_macwrite(struct bwn_mac *mac, uint8_t index, const uint8_t *addr)
+{
+ uint32_t addrtmp[2] = { 0, 0 };
+ uint8_t start = 8;
+
+ if (BWN_SEC_NEWAPI(mac))
+ start = 4;
+
+ KASSERT(index >= start,
+ ("%s:%d: fail", __func__, __LINE__));
+ index -= start;
+
+ if (addr) {
+ addrtmp[0] = addr[0];
+ addrtmp[0] |= ((uint32_t) (addr[1]) << 8);
+ addrtmp[0] |= ((uint32_t) (addr[2]) << 16);
+ addrtmp[0] |= ((uint32_t) (addr[3]) << 24);
+ addrtmp[1] = addr[4];
+ addrtmp[1] |= ((uint32_t) (addr[5]) << 8);
+ }
+
+ if (mac->mac_sd->sd_id.sd_rev >= 5) {
+ bwn_shm_write_4(mac, BWN_RCMTA, (index * 2) + 0, addrtmp[0]);
+ bwn_shm_write_2(mac, BWN_RCMTA, (index * 2) + 1, addrtmp[1]);
+ } else {
+ if (index >= 8) {
+ bwn_shm_write_4(mac, BWN_SHARED,
+ BWN_SHARED_PSM + (index * 6) + 0, addrtmp[0]);
+ bwn_shm_write_2(mac, BWN_SHARED,
+ BWN_SHARED_PSM + (index * 6) + 4, addrtmp[1]);
+ }
+ }
+}
+
+static void
+bwn_key_write(struct bwn_mac *mac, uint8_t index, uint8_t algorithm,
+ const uint8_t *key)
+{
+ unsigned int i;
+ uint32_t offset;
+ uint16_t kidx, value;
+
+ kidx = BWN_SEC_KEY2FW(mac, index);
+ bwn_shm_write_2(mac, BWN_SHARED,
+ BWN_SHARED_KEYIDX_BLOCK + (kidx * 2), (kidx << 4) | algorithm);
+
+ offset = mac->mac_ktp + (index * BWN_SEC_KEYSIZE);
+ for (i = 0; i < BWN_SEC_KEYSIZE; i += 2) {
+ value = key[i];
+ value |= (uint16_t)(key[i + 1]) << 8;
+ bwn_shm_write_2(mac, BWN_SHARED, offset + i, value);
+ }
+}
+
+static void
+bwn_phy_exit(struct bwn_mac *mac)
+{
+
+ mac->mac_phy.rf_onoff(mac, 0);
+ if (mac->mac_phy.exit != NULL)
+ mac->mac_phy.exit(mac);
+}
+
+static void
+bwn_dma_free(struct bwn_mac *mac)
+{
+ struct bwn_dma *dma;
+
+ if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
+ return;
+ dma = &mac->mac_method.dma;
+
+ bwn_dma_ringfree(&dma->rx);
+ bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
+ bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
+ bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
+ bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
+ bwn_dma_ringfree(&dma->mcast);
+}
+
+static void
+bwn_core_stop(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (mac->mac_status < BWN_MAC_STATUS_STARTED)
+ return;
+
+ callout_stop(&sc->sc_rfswitch_ch);
+ callout_stop(&sc->sc_task_ch);
+ callout_stop(&sc->sc_watchdog_ch);
+ sc->sc_watchdog_timer = 0;
+ BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
+ BWN_READ_4(mac, BWN_INTR_MASK);
+ bwn_mac_suspend(mac);
+
+ mac->mac_status = BWN_MAC_STATUS_INITED;
+}
+
+static int
+bwn_switch_band(struct bwn_softc *sc, struct ieee80211_channel *chan)
+{
+ struct bwn_mac *up_dev = NULL;
+ struct bwn_mac *down_dev;
+ struct bwn_mac *mac;
+ int err, status;
+ uint8_t gmode;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ TAILQ_FOREACH(mac, &sc->sc_maclist, mac_list) {
+ if (IEEE80211_IS_CHAN_2GHZ(chan) &&
+ mac->mac_phy.supports_2ghz) {
+ up_dev = mac;
+ gmode = 1;
+ } else if (IEEE80211_IS_CHAN_5GHZ(chan) &&
+ mac->mac_phy.supports_5ghz) {
+ up_dev = mac;
+ gmode = 0;
+ } else {
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (EINVAL);
+ }
+ if (up_dev != NULL)
+ break;
+ }
+ if (up_dev == NULL) {
+ device_printf(sc->sc_dev, "Could not find a device\n");
+ return (ENODEV);
+ }
+ if (up_dev == sc->sc_curmac && sc->sc_curmac->mac_phy.gmode == gmode)
+ return (0);
+
+ device_printf(sc->sc_dev, "switching to %s-GHz band\n",
+ IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
+
+ down_dev = sc->sc_curmac;;
+ status = down_dev->mac_status;
+ if (status >= BWN_MAC_STATUS_STARTED)
+ bwn_core_stop(down_dev);
+ if (status >= BWN_MAC_STATUS_INITED)
+ bwn_core_exit(down_dev);
+
+ if (down_dev != up_dev)
+ bwn_phy_reset(down_dev);
+
+ up_dev->mac_phy.gmode = gmode;
+ if (status >= BWN_MAC_STATUS_INITED) {
+ err = bwn_core_init(up_dev);
+ if (err) {
+ device_printf(sc->sc_dev,
+ "fatal: failed to initialize for %s-GHz\n",
+ IEEE80211_IS_CHAN_2GHZ(chan) ? "2" : "5");
+ goto fail;
+ }
+ }
+ if (status >= BWN_MAC_STATUS_STARTED)
+ bwn_core_start(up_dev);
+ KASSERT(up_dev->mac_status == status, ("%s: fail", __func__));
+ sc->sc_curmac = up_dev;
+
+ return (0);
+fail:
+ sc->sc_curmac = NULL;
+ return (err);
+}
+
+static void
+bwn_rf_turnon(struct bwn_mac *mac)
+{
+
+ bwn_mac_suspend(mac);
+ mac->mac_phy.rf_onoff(mac, 1);
+ mac->mac_phy.rf_on = 1;
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_rf_turnoff(struct bwn_mac *mac)
+{
+
+ bwn_mac_suspend(mac);
+ mac->mac_phy.rf_onoff(mac, 0);
+ mac->mac_phy.rf_on = 0;
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_phy_reset(struct bwn_mac *mac)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+
+ siba_write_4(sd, SIBA_TGSLOW,
+ ((siba_read_4(sd, SIBA_TGSLOW) & ~BWN_TGSLOW_SUPPORT_G) |
+ BWN_TGSLOW_PHYRESET) | SIBA_TGSLOW_FGC);
+ DELAY(1000);
+ siba_write_4(sd, SIBA_TGSLOW,
+ (siba_read_4(sd, SIBA_TGSLOW) & ~SIBA_TGSLOW_FGC) |
+ BWN_TGSLOW_PHYRESET);
+ DELAY(1000);
+}
+
+static int
+bwn_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
+{
+ struct bwn_vap *bvp = BWN_VAP(vap);
+ struct ieee80211com *ic= vap->iv_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+ enum ieee80211_state ostate = vap->iv_state;
+ struct bwn_softc *sc = ifp->if_softc;
+ struct bwn_mac *mac = sc->sc_curmac;
+ int error;
+
+ DPRINTF(sc, BWN_DEBUG_STATE, "%s: %s -> %s\n", __func__,
+ ieee80211_state_name[vap->iv_state],
+ ieee80211_state_name[nstate]);
+
+ error = bvp->bv_newstate(vap, nstate, arg);
+ if (error != 0)
+ return (error);
+
+ BWN_LOCK(sc);
+
+ bwn_led_newstate(mac, nstate);
+
+ /*
+ * Clear the BSSID when we stop a STA
+ */
+ if (vap->iv_opmode == IEEE80211_M_STA) {
+ if (ostate == IEEE80211_S_RUN && nstate != IEEE80211_S_RUN) {
+ /*
+ * Clear out the BSSID. If we reassociate to
+ * the same AP, this will reinialize things
+ * correctly...
+ */
+ if (ic->ic_opmode == IEEE80211_M_STA &&
+ (sc->sc_flags & BWN_FLAG_INVALID) == 0) {
+ memset(sc->sc_bssid, 0, IEEE80211_ADDR_LEN);
+ bwn_set_macaddr(mac);
+ }
+ }
+ }
+
+ if (vap->iv_opmode == IEEE80211_M_MONITOR) {
+ /* XXX nothing to do? */
+ } else if (nstate == IEEE80211_S_RUN) {
+ memcpy(sc->sc_bssid, vap->iv_bss->ni_bssid, IEEE80211_ADDR_LEN);
+ memcpy(sc->sc_macaddr, IF_LLADDR(ifp), IEEE80211_ADDR_LEN);
+ bwn_set_opmode(mac);
+ bwn_set_pretbtt(mac);
+ bwn_spu_setdelay(mac, 0);
+ bwn_set_macaddr(mac);
+ }
+
+ BWN_UNLOCK(sc);
+
+ return (error);
+}
+
+static void
+bwn_set_pretbtt(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint16_t pretbtt;
+
+ if (ic->ic_opmode == IEEE80211_M_IBSS)
+ pretbtt = 2;
+ else
+ pretbtt = (mac->mac_phy.type == BWN_PHYTYPE_A) ? 120 : 250;
+ bwn_shm_write_2(mac, BWN_SHARED, BWN_SHARED_PRETBTT, pretbtt);
+ BWN_WRITE_2(mac, BWN_TSF_CFP_PRETBTT, pretbtt);
+}
+
+static int
+bwn_intr(void *arg)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+ uint32_t reason;
+
+ if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid)
+ return (FILTER_STRAY);
+
+ reason = BWN_READ_4(mac, BWN_INTR_REASON);
+ if (reason == 0xffffffff) /* shared IRQ */
+ return (FILTER_STRAY);
+ reason &= mac->mac_intr_mask;
+ if (reason == 0)
+ return (FILTER_HANDLED);
+
+ mac->mac_reason[0] = BWN_READ_4(mac, BWN_DMA0_REASON) & 0x0001dc00;
+ mac->mac_reason[1] = BWN_READ_4(mac, BWN_DMA1_REASON) & 0x0000dc00;
+ mac->mac_reason[2] = BWN_READ_4(mac, BWN_DMA2_REASON) & 0x0000dc00;
+ mac->mac_reason[3] = BWN_READ_4(mac, BWN_DMA3_REASON) & 0x0001dc00;
+ mac->mac_reason[4] = BWN_READ_4(mac, BWN_DMA4_REASON) & 0x0000dc00;
+ BWN_WRITE_4(mac, BWN_INTR_REASON, reason);
+ BWN_WRITE_4(mac, BWN_DMA0_REASON, mac->mac_reason[0]);
+ BWN_WRITE_4(mac, BWN_DMA1_REASON, mac->mac_reason[1]);
+ BWN_WRITE_4(mac, BWN_DMA2_REASON, mac->mac_reason[2]);
+ BWN_WRITE_4(mac, BWN_DMA3_REASON, mac->mac_reason[3]);
+ BWN_WRITE_4(mac, BWN_DMA4_REASON, mac->mac_reason[4]);
+
+ /* Disable interrupts. */
+ BWN_WRITE_4(mac, BWN_INTR_MASK, 0);
+
+ mac->mac_reason_intr = reason;
+
+ BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
+ BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
+
+ taskqueue_enqueue_fast(sc->sc_tq, &mac->mac_intrtask);
+ return (FILTER_HANDLED);
+}
+
+static void
+bwn_intrtask(void *arg, int npending)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+ uint32_t merged = 0;
+ int i, tx = 0, rx = 0;
+
+ BWN_LOCK(sc);
+ if (mac->mac_status < BWN_MAC_STATUS_STARTED || siba->siba_invalid) {
+ BWN_UNLOCK(sc);
+ return;
+ }
+
+ for (i = 0; i < N(mac->mac_reason); i++)
+ merged |= mac->mac_reason[i];
+
+ if (mac->mac_reason_intr & BWN_INTR_MAC_TXERR)
+ device_printf(sc->sc_dev, "MAC trans error\n");
+
+ if (mac->mac_reason_intr & BWN_INTR_PHY_TXERR) {
+ DPRINTF(sc, BWN_DEBUG_INTR, "%s: PHY trans error\n", __func__);
+ mac->mac_phy.txerrors--;
+ if (mac->mac_phy.txerrors == 0) {
+ mac->mac_phy.txerrors = BWN_TXERROR_MAX;
+ bwn_restart(mac, "PHY TX errors");
+ }
+ }
+
+ if (merged & (BWN_DMAINTR_FATALMASK | BWN_DMAINTR_NONFATALMASK)) {
+ if (merged & BWN_DMAINTR_FATALMASK) {
+ device_printf(sc->sc_dev,
+ "Fatal DMA error: %#x %#x %#x %#x %#x %#x\n",
+ mac->mac_reason[0], mac->mac_reason[1],
+ mac->mac_reason[2], mac->mac_reason[3],
+ mac->mac_reason[4], mac->mac_reason[5]);
+ bwn_restart(mac, "DMA error");
+ BWN_UNLOCK(sc);
+ return;
+ }
+ if (merged & BWN_DMAINTR_NONFATALMASK) {
+ device_printf(sc->sc_dev,
+ "DMA error: %#x %#x %#x %#x %#x %#x\n",
+ mac->mac_reason[0], mac->mac_reason[1],
+ mac->mac_reason[2], mac->mac_reason[3],
+ mac->mac_reason[4], mac->mac_reason[5]);
+ }
+ }
+
+ if (mac->mac_reason_intr & BWN_INTR_UCODE_DEBUG)
+ bwn_intr_ucode_debug(mac);
+ if (mac->mac_reason_intr & BWN_INTR_TBTT_INDI)
+ bwn_intr_tbtt_indication(mac);
+ if (mac->mac_reason_intr & BWN_INTR_ATIM_END)
+ bwn_intr_atim_end(mac);
+ if (mac->mac_reason_intr & BWN_INTR_BEACON)
+ bwn_intr_beacon(mac);
+ if (mac->mac_reason_intr & BWN_INTR_PMQ)
+ bwn_intr_pmq(mac);
+ if (mac->mac_reason_intr & BWN_INTR_NOISESAMPLE_OK)
+ bwn_intr_noise(mac);
+
+ if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
+ if (mac->mac_reason[0] & BWN_DMAINTR_RX_DONE) {
+ bwn_dma_rx(mac->mac_method.dma.rx);
+ rx = 1;
+ }
+ } else
+ rx = bwn_pio_rx(&mac->mac_method.pio.rx);
+
+ KASSERT(!(mac->mac_reason[1] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
+ KASSERT(!(mac->mac_reason[2] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
+ KASSERT(!(mac->mac_reason[3] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
+ KASSERT(!(mac->mac_reason[4] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
+ KASSERT(!(mac->mac_reason[5] & BWN_DMAINTR_RX_DONE), ("%s", __func__));
+
+ if (mac->mac_reason_intr & BWN_INTR_TX_OK) {
+ bwn_intr_txeof(mac);
+ tx = 1;
+ }
+
+ BWN_WRITE_4(mac, BWN_INTR_MASK, mac->mac_intr_mask);
+
+ if (sc->sc_blink_led != NULL && sc->sc_led_blink) {
+ int evt = BWN_LED_EVENT_NONE;
+
+ if (tx && rx) {
+ if (sc->sc_rx_rate > sc->sc_tx_rate)
+ evt = BWN_LED_EVENT_RX;
+ else
+ evt = BWN_LED_EVENT_TX;
+ } else if (tx) {
+ evt = BWN_LED_EVENT_TX;
+ } else if (rx) {
+ evt = BWN_LED_EVENT_RX;
+ } else if (rx == 0) {
+ evt = BWN_LED_EVENT_POLL;
+ }
+
+ if (evt != BWN_LED_EVENT_NONE)
+ bwn_led_event(mac, evt);
+ }
+
+ if ((ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
+ if (!IFQ_IS_EMPTY(&ifp->if_snd))
+ bwn_start_locked(ifp);
+ }
+
+ BWN_BARRIER(mac, BUS_SPACE_BARRIER_READ);
+ BWN_BARRIER(mac, BUS_SPACE_BARRIER_WRITE);
+
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_restart(struct bwn_mac *mac, const char *msg)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ if (mac->mac_status < BWN_MAC_STATUS_INITED)
+ return;
+
+ device_printf(sc->sc_dev, "HW reset: %s\n", msg);
+ ieee80211_runtask(ic, &mac->mac_hwreset);
+}
+
+static void
+bwn_intr_ucode_debug(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t reason;
+
+ if (mac->mac_fw.opensource == 0)
+ return;
+
+ reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG);
+ switch (reason) {
+ case BWN_DEBUGINTR_PANIC:
+ bwn_handle_fwpanic(mac);
+ break;
+ case BWN_DEBUGINTR_DUMP_SHM:
+ device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_SHM\n");
+ break;
+ case BWN_DEBUGINTR_DUMP_REGS:
+ device_printf(sc->sc_dev, "BWN_DEBUGINTR_DUMP_REGS\n");
+ break;
+ case BWN_DEBUGINTR_MARKER:
+ device_printf(sc->sc_dev, "BWN_DEBUGINTR_MARKER\n");
+ break;
+ default:
+ device_printf(sc->sc_dev,
+ "ucode debug unknown reason: %#x\n", reason);
+ }
+
+ bwn_shm_write_2(mac, BWN_SCRATCH, BWN_DEBUGINTR_REASON_REG,
+ BWN_DEBUGINTR_ACK);
+}
+
+static void
+bwn_intr_tbtt_indication(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP)
+ bwn_psctl(mac, 0);
+ if (ic->ic_opmode == IEEE80211_M_IBSS)
+ mac->mac_flags |= BWN_MAC_FLAG_DFQVALID;
+}
+
+static void
+bwn_intr_atim_end(struct bwn_mac *mac)
+{
+
+ if (mac->mac_flags & BWN_MAC_FLAG_DFQVALID) {
+ BWN_WRITE_4(mac, BWN_MACCMD,
+ BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_DFQ_VALID);
+ mac->mac_flags &= ~BWN_MAC_FLAG_DFQVALID;
+ }
+}
+
+static void
+bwn_intr_beacon(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ uint32_t cmd, beacon0, beacon1;
+
+ if (ic->ic_opmode == IEEE80211_M_HOSTAP ||
+ ic->ic_opmode == IEEE80211_M_MBSS)
+ return;
+
+ mac->mac_intr_mask &= ~BWN_INTR_BEACON;
+
+ cmd = BWN_READ_4(mac, BWN_MACCMD);
+ beacon0 = (cmd & BWN_MACCMD_BEACON0_VALID);
+ beacon1 = (cmd & BWN_MACCMD_BEACON1_VALID);
+
+ if (beacon0 && beacon1) {
+ BWN_WRITE_4(mac, BWN_INTR_REASON, BWN_INTR_BEACON);
+ mac->mac_intr_mask |= BWN_INTR_BEACON;
+ return;
+ }
+
+ if (sc->sc_flags & BWN_FLAG_NEED_BEACON_TP) {
+ sc->sc_flags &= ~BWN_FLAG_NEED_BEACON_TP;
+ bwn_load_beacon0(mac);
+ bwn_load_beacon1(mac);
+ cmd = BWN_READ_4(mac, BWN_MACCMD);
+ cmd |= BWN_MACCMD_BEACON0_VALID;
+ BWN_WRITE_4(mac, BWN_MACCMD, cmd);
+ } else {
+ if (!beacon0) {
+ bwn_load_beacon0(mac);
+ cmd = BWN_READ_4(mac, BWN_MACCMD);
+ cmd |= BWN_MACCMD_BEACON0_VALID;
+ BWN_WRITE_4(mac, BWN_MACCMD, cmd);
+ } else if (!beacon1) {
+ bwn_load_beacon1(mac);
+ cmd = BWN_READ_4(mac, BWN_MACCMD);
+ cmd |= BWN_MACCMD_BEACON1_VALID;
+ BWN_WRITE_4(mac, BWN_MACCMD, cmd);
+ }
+ }
+}
+
+static void
+bwn_intr_pmq(struct bwn_mac *mac)
+{
+ uint32_t tmp;
+
+ while (1) {
+ tmp = BWN_READ_4(mac, BWN_PS_STATUS);
+ if (!(tmp & 0x00000008))
+ break;
+ }
+ BWN_WRITE_2(mac, BWN_PS_STATUS, 0x0002);
+}
+
+static void
+bwn_intr_noise(struct bwn_mac *mac)
+{
+ struct bwn_phy_g *pg = &mac->mac_phy.phy_g;
+ uint16_t tmp;
+ uint8_t noise[4];
+ uint8_t i, j;
+ int32_t average;
+
+ if (mac->mac_phy.type != BWN_PHYTYPE_G)
+ return;
+
+ KASSERT(mac->mac_noise.noi_running, ("%s: fail", __func__));
+ *((uint32_t *)noise) = htole32(bwn_jssi_read(mac));
+ if (noise[0] == 0x7f || noise[1] == 0x7f || noise[2] == 0x7f ||
+ noise[3] == 0x7f)
+ goto new;
+
+ KASSERT(mac->mac_noise.noi_nsamples < 8,
+ ("%s:%d: fail", __func__, __LINE__));
+ i = mac->mac_noise.noi_nsamples;
+ noise[0] = MIN(MAX(noise[0], 0), N(pg->pg_nrssi_lt) - 1);
+ noise[1] = MIN(MAX(noise[1], 0), N(pg->pg_nrssi_lt) - 1);
+ noise[2] = MIN(MAX(noise[2], 0), N(pg->pg_nrssi_lt) - 1);
+ noise[3] = MIN(MAX(noise[3], 0), N(pg->pg_nrssi_lt) - 1);
+ mac->mac_noise.noi_samples[i][0] = pg->pg_nrssi_lt[noise[0]];
+ mac->mac_noise.noi_samples[i][1] = pg->pg_nrssi_lt[noise[1]];
+ mac->mac_noise.noi_samples[i][2] = pg->pg_nrssi_lt[noise[2]];
+ mac->mac_noise.noi_samples[i][3] = pg->pg_nrssi_lt[noise[3]];
+ mac->mac_noise.noi_nsamples++;
+ if (mac->mac_noise.noi_nsamples == 8) {
+ average = 0;
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < 4; j++)
+ average += mac->mac_noise.noi_samples[i][j];
+ }
+ average = (((average / 32) * 125) + 64) / 128;
+ tmp = (bwn_shm_read_2(mac, BWN_SHARED, 0x40c) / 128) & 0x1f;
+ if (tmp >= 8)
+ average += 2;
+ else
+ average -= 25;
+ average -= (tmp == 8) ? 72 : 48;
+
+ mac->mac_stats.link_noise = average;
+ mac->mac_noise.noi_running = 0;
+ return;
+ }
+new:
+ bwn_noise_gensample(mac);
+}
+
+static int
+bwn_pio_rx(struct bwn_pio_rxqueue *prq)
+{
+ struct bwn_mac *mac = prq->prq_mac;
+ struct bwn_softc *sc = mac->mac_sc;
+ unsigned int i;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ if (mac->mac_status < BWN_MAC_STATUS_STARTED)
+ return (0);
+
+ for (i = 0; i < 5000; i++) {
+ if (bwn_pio_rxeof(prq) == 0)
+ break;
+ }
+ if (i >= 5000)
+ device_printf(sc->sc_dev, "too many RX frames in PIO mode\n");
+ return ((i > 0) ? 1 : 0);
+}
+
+static void
+bwn_dma_rx(struct bwn_dma_ring *dr)
+{
+ int slot, curslot;
+
+ KASSERT(!dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
+ curslot = dr->get_curslot(dr);
+ KASSERT(curslot >= 0 && curslot < dr->dr_numslots,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ slot = dr->dr_curslot;
+ for (; slot != curslot; slot = bwn_dma_nextslot(dr, slot))
+ bwn_dma_rxeof(dr, &slot);
+
+ bus_dmamap_sync(dr->dr_ring_dtag, dr->dr_ring_dmap,
+ BUS_DMASYNC_PREWRITE);
+
+ dr->set_curslot(dr, slot);
+ dr->dr_curslot = slot;
+}
+
+static void
+bwn_intr_txeof(struct bwn_mac *mac)
+{
+ struct bwn_txstatus stat;
+ uint32_t stat0, stat1;
+ uint16_t tmp;
+
+ BWN_ASSERT_LOCKED(mac->mac_sc);
+
+ while (1) {
+ stat0 = BWN_READ_4(mac, BWN_XMITSTAT_0);
+ if (!(stat0 & 0x00000001))
+ break;
+ stat1 = BWN_READ_4(mac, BWN_XMITSTAT_1);
+
+ stat.cookie = (stat0 >> 16);
+ stat.seq = (stat1 & 0x0000ffff);
+ stat.phy_stat = ((stat1 & 0x00ff0000) >> 16);
+ tmp = (stat0 & 0x0000ffff);
+ stat.framecnt = ((tmp & 0xf000) >> 12);
+ stat.rtscnt = ((tmp & 0x0f00) >> 8);
+ stat.sreason = ((tmp & 0x001c) >> 2);
+ stat.pm = (tmp & 0x0080) ? 1 : 0;
+ stat.im = (tmp & 0x0040) ? 1 : 0;
+ stat.ampdu = (tmp & 0x0020) ? 1 : 0;
+ stat.ack = (tmp & 0x0002) ? 1 : 0;
+
+ bwn_handle_txeof(mac, &stat);
+ }
+}
+
+static void
+bwn_hwreset(void *arg, int npending)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+ int error = 0;
+ int prev_status;
+
+ BWN_LOCK(sc);
+
+ prev_status = mac->mac_status;
+ if (prev_status >= BWN_MAC_STATUS_STARTED)
+ bwn_core_stop(mac);
+ if (prev_status >= BWN_MAC_STATUS_INITED)
+ bwn_core_exit(mac);
+
+ if (prev_status >= BWN_MAC_STATUS_INITED) {
+ error = bwn_core_init(mac);
+ if (error)
+ goto out;
+ }
+ if (prev_status >= BWN_MAC_STATUS_STARTED)
+ bwn_core_start(mac);
+out:
+ if (error) {
+ device_printf(sc->sc_dev, "%s: failed (%d)\n", __func__, error);
+ sc->sc_curmac = NULL;
+ }
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_handle_fwpanic(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t reason;
+
+ reason = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_FWPANIC_REASON_REG);
+ device_printf(sc->sc_dev,"fw panic (%u)\n", reason);
+
+ if (reason == BWN_FWPANIC_RESTART)
+ bwn_restart(mac, "ucode panic");
+}
+
+static void
+bwn_load_beacon0(struct bwn_mac *mac)
+{
+
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+}
+
+static void
+bwn_load_beacon1(struct bwn_mac *mac)
+{
+
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+}
+
+static uint32_t
+bwn_jssi_read(struct bwn_mac *mac)
+{
+ uint32_t val = 0;
+
+ val = bwn_shm_read_2(mac, BWN_SHARED, 0x08a);
+ val <<= 16;
+ val |= bwn_shm_read_2(mac, BWN_SHARED, 0x088);
+
+ return (val);
+}
+
+static void
+bwn_noise_gensample(struct bwn_mac *mac)
+{
+ uint32_t jssi = 0x7f7f7f7f;
+
+ bwn_shm_write_2(mac, BWN_SHARED, 0x088, (jssi & 0x0000ffff));
+ bwn_shm_write_2(mac, BWN_SHARED, 0x08a, (jssi & 0xffff0000) >> 16);
+ BWN_WRITE_4(mac, BWN_MACCMD,
+ BWN_READ_4(mac, BWN_MACCMD) | BWN_MACCMD_BGNOISE);
+}
+
+static int
+bwn_dma_freeslot(struct bwn_dma_ring *dr)
+{
+ struct bwn_mac *mac = dr->dr_mac;
+
+ BWN_ASSERT_LOCKED(mac->mac_sc);
+
+ return (dr->dr_numslots - dr->dr_usedslot);
+}
+
+static int
+bwn_dma_nextslot(struct bwn_dma_ring *dr, int slot)
+{
+ struct bwn_mac *mac = dr->dr_mac;
+
+ BWN_ASSERT_LOCKED(mac->mac_sc);
+
+ KASSERT(slot >= -1 && slot <= dr->dr_numslots - 1,
+ ("%s:%d: fail", __func__, __LINE__));
+ if (slot == dr->dr_numslots - 1)
+ return (0);
+ return (slot + 1);
+}
+
+static void
+bwn_dma_rxeof(struct bwn_dma_ring *dr, int *slot)
+{
+ struct bwn_mac *mac = dr->dr_mac;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_dmadesc_generic *desc;
+ struct bwn_dmadesc_meta *meta;
+ struct bwn_rxhdr4 *rxhdr;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ uint32_t macstat;
+ int32_t tmp;
+ int cnt = 0;
+ uint16_t len;
+
+ dr->getdesc(dr, *slot, &desc, &meta);
+
+ bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap, BUS_DMASYNC_POSTREAD);
+ m = meta->mt_m;
+
+ if (bwn_dma_newbuf(dr, desc, meta, 0)) {
+ ifp->if_ierrors++;
+ return;
+ }
+
+ rxhdr = mtod(m, struct bwn_rxhdr4 *);
+ len = le16toh(rxhdr->frame_len);
+ if (len <= 0) {
+ ifp->if_ierrors++;
+ return;
+ }
+ if (bwn_dma_check_redzone(dr, m)) {
+ device_printf(sc->sc_dev, "redzone error.\n");
+ bwn_dma_set_redzone(dr, m);
+ bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
+ BUS_DMASYNC_PREWRITE);
+ return;
+ }
+ if (len > dr->dr_rx_bufsize) {
+ tmp = len;
+ while (1) {
+ dr->getdesc(dr, *slot, &desc, &meta);
+ bwn_dma_set_redzone(dr, meta->mt_m);
+ bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
+ BUS_DMASYNC_PREWRITE);
+ *slot = bwn_dma_nextslot(dr, *slot);
+ cnt++;
+ tmp -= dr->dr_rx_bufsize;
+ if (tmp <= 0)
+ break;
+ }
+ device_printf(sc->sc_dev, "too small buffer "
+ "(len %u buffer %u dropped %d)\n",
+ len, dr->dr_rx_bufsize, cnt);
+ return;
+ }
+ macstat = le32toh(rxhdr->mac_status);
+ if (macstat & BWN_RX_MAC_FCSERR) {
+ if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
+ device_printf(sc->sc_dev, "RX drop\n");
+ return;
+ }
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_len = m->m_pkthdr.len = len + dr->dr_frameoffset;
+ m_adj(m, dr->dr_frameoffset);
+
+ bwn_rxeof(dr->dr_mac, m, rxhdr);
+}
+
+static void
+bwn_handle_txeof(struct bwn_mac *mac, const struct bwn_txstatus *status)
+{
+ struct bwn_dma_ring *dr;
+ struct bwn_dmadesc_generic *desc;
+ struct bwn_dmadesc_meta *meta;
+ struct bwn_node *bn;
+ struct bwn_pio_txqueue *tq;
+ struct bwn_pio_txpkt *tp = NULL;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211_node *ni;
+ int slot;
+
+ BWN_ASSERT_LOCKED(mac->mac_sc);
+
+ if (status->im)
+ device_printf(sc->sc_dev, "TODO: STATUS IM\n");
+ if (status->ampdu)
+ device_printf(sc->sc_dev, "TODO: STATUS AMPDU\n");
+ if (status->rtscnt) {
+ if (status->rtscnt == 0xf)
+ device_printf(sc->sc_dev, "TODO: RTS fail\n");
+ else
+ device_printf(sc->sc_dev, "TODO: RTS ok\n");
+ }
+
+ if (mac->mac_flags & BWN_MAC_FLAG_DMA) {
+ if (status->ack) {
+ dr = bwn_dma_parse_cookie(mac, status,
+ status->cookie, &slot);
+ if (dr == NULL) {
+ device_printf(sc->sc_dev,
+ "failed to parse cookie\n");
+ return;
+ }
+ while (1) {
+ dr->getdesc(dr, slot, &desc, &meta);
+ if (meta->mt_islast) {
+ ni = meta->mt_ni;
+ bn = (struct bwn_node *)ni;
+ ieee80211_amrr_tx_complete(&bn->bn_amn,
+ status->ack, 0);
+ break;
+ }
+ slot = bwn_dma_nextslot(dr, slot);
+ }
+ }
+ bwn_dma_handle_txeof(mac, status);
+ } else {
+ if (status->ack) {
+ tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
+ if (tq == NULL) {
+ device_printf(sc->sc_dev,
+ "failed to parse cookie\n");
+ return;
+ }
+ ni = tp->tp_ni;
+ bn = (struct bwn_node *)ni;
+ ieee80211_amrr_tx_complete(&bn->bn_amn, status->ack, 0);
+ }
+ bwn_pio_handle_txeof(mac, status);
+ }
+
+ bwn_phy_txpower_check(mac, 0);
+}
+
+static uint8_t
+bwn_pio_rxeof(struct bwn_pio_rxqueue *prq)
+{
+ struct bwn_mac *mac = prq->prq_mac;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_rxhdr4 rxhdr;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ uint32_t ctl32, macstat, v32;
+ unsigned int i, padding;
+ uint16_t ctl16, len, v16;
+ unsigned char *mp;
+ char *data;
+
+ memset(&rxhdr, 0, sizeof(rxhdr));
+
+ if (prq->prq_rev >= 8) {
+ ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
+ if (!(ctl32 & BWN_PIO8_RXCTL_FRAMEREADY))
+ return (0);
+ bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
+ BWN_PIO8_RXCTL_FRAMEREADY);
+ for (i = 0; i < 10; i++) {
+ ctl32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXCTL);
+ if (ctl32 & BWN_PIO8_RXCTL_DATAREADY)
+ goto ready;
+ DELAY(10);
+ }
+ } else {
+ ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
+ if (!(ctl16 & BWN_PIO_RXCTL_FRAMEREADY))
+ return (0);
+ bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL,
+ BWN_PIO_RXCTL_FRAMEREADY);
+ for (i = 0; i < 10; i++) {
+ ctl16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXCTL);
+ if (ctl16 & BWN_PIO_RXCTL_DATAREADY)
+ goto ready;
+ DELAY(10);
+ }
+ }
+ device_printf(sc->sc_dev, "%s: timed out\n", __func__);
+ return (1);
+ready:
+ if (prq->prq_rev >= 8)
+ siba_read_multi_4(mac->mac_sd, &rxhdr, sizeof(rxhdr),
+ prq->prq_base + BWN_PIO8_RXDATA);
+ else
+ siba_read_multi_2(mac->mac_sd, &rxhdr, sizeof(rxhdr),
+ prq->prq_base + BWN_PIO_RXDATA);
+ len = le16toh(rxhdr.frame_len);
+ if (len > 0x700) {
+ device_printf(sc->sc_dev, "%s: len is too big\n", __func__);
+ goto error;
+ }
+ if (len == 0) {
+ device_printf(sc->sc_dev, "%s: len is 0\n", __func__);
+ goto error;
+ }
+
+ macstat = le32toh(rxhdr.mac_status);
+ if (macstat & BWN_RX_MAC_FCSERR) {
+ if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADFCS)) {
+ device_printf(sc->sc_dev, "%s: FCS error", __func__);
+ goto error;
+ }
+ }
+
+ padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
+ KASSERT(len + padding <= MCLBYTES, ("too big..\n"));
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
+ device_printf(sc->sc_dev, "%s: out of memory", __func__);
+ goto error;
+ }
+ mp = mtod(m, unsigned char *);
+ if (prq->prq_rev >= 8) {
+ siba_read_multi_4(mac->mac_sd, mp + padding, (len & ~3),
+ prq->prq_base + BWN_PIO8_RXDATA);
+ if (len & 3) {
+ v32 = bwn_pio_rx_read_4(prq, BWN_PIO8_RXDATA);
+ data = &(mp[len + padding - 1]);
+ switch (len & 3) {
+ case 3:
+ *data = (v32 >> 16);
+ data--;
+ case 2:
+ *data = (v32 >> 8);
+ data--;
+ case 1:
+ *data = v32;
+ }
+ }
+ } else {
+ siba_read_multi_2(mac->mac_sd, mp + padding, (len & ~1),
+ prq->prq_base + BWN_PIO_RXDATA);
+ if (len & 1) {
+ v16 = bwn_pio_rx_read_2(prq, BWN_PIO_RXDATA);
+ mp[len + padding - 1] = v16;
+ }
+ }
+
+ m->m_pkthdr.rcvif = ifp;
+ m->m_len = m->m_pkthdr.len = len + padding;
+
+ bwn_rxeof(prq->prq_mac, m, &rxhdr);
+
+ return (1);
+error:
+ if (prq->prq_rev >= 8)
+ bwn_pio_rx_write_4(prq, BWN_PIO8_RXCTL,
+ BWN_PIO8_RXCTL_DATAREADY);
+ else
+ bwn_pio_rx_write_2(prq, BWN_PIO_RXCTL, BWN_PIO_RXCTL_DATAREADY);
+ return (1);
+}
+
+static int
+bwn_dma_newbuf(struct bwn_dma_ring *dr, struct bwn_dmadesc_generic *desc,
+ struct bwn_dmadesc_meta *meta, int init)
+{
+ struct bwn_mac *mac = dr->dr_mac;
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_rxhdr4 *hdr;
+ bus_dmamap_t map;
+ bus_addr_t paddr;
+ struct mbuf *m;
+ int error;
+
+ m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+ if (m == NULL) {
+ error = ENOBUFS;
+
+ /*
+ * If the NIC is up and running, we need to:
+ * - Clear RX buffer's header.
+ * - Restore RX descriptor settings.
+ */
+ if (init)
+ return (error);
+ else
+ goto back;
+ }
+ m->m_len = m->m_pkthdr.len = MCLBYTES;
+
+ bwn_dma_set_redzone(dr, m);
+
+ /*
+ * Try to load RX buf into temporary DMA map
+ */
+ error = bus_dmamap_load_mbuf(dma->rxbuf_dtag, dr->dr_spare_dmap, m,
+ bwn_dma_buf_addr, &paddr, BUS_DMA_NOWAIT);
+ if (error) {
+ m_freem(m);
+
+ /*
+ * See the comment above
+ */
+ if (init)
+ return (error);
+ else
+ goto back;
+ }
+
+ if (!init)
+ bus_dmamap_unload(dma->rxbuf_dtag, meta->mt_dmap);
+ meta->mt_m = m;
+ meta->mt_paddr = paddr;
+
+ /*
+ * Swap RX buf's DMA map with the loaded temporary one
+ */
+ map = meta->mt_dmap;
+ meta->mt_dmap = dr->dr_spare_dmap;
+ dr->dr_spare_dmap = map;
+
+back:
+ /*
+ * Clear RX buf header
+ */
+ hdr = mtod(meta->mt_m, struct bwn_rxhdr4 *);
+ bzero(hdr, sizeof(*hdr));
+ bus_dmamap_sync(dma->rxbuf_dtag, meta->mt_dmap,
+ BUS_DMASYNC_PREWRITE);
+
+ /*
+ * Setup RX buf descriptor
+ */
+ dr->setdesc(dr, desc, paddr, meta->mt_m->m_len -
+ sizeof(*hdr), 0, 0, 0);
+ return (error);
+}
+
+static void
+bwn_dma_buf_addr(void *arg, bus_dma_segment_t *seg, int nseg,
+ bus_size_t mapsz __unused, int error)
+{
+
+ if (!error) {
+ KASSERT(nseg == 1, ("too many segments(%d)\n", nseg));
+ *((bus_addr_t *)arg) = seg->ds_addr;
+ }
+}
+
+static int
+bwn_hwrate2ieeerate(int rate)
+{
+
+ switch (rate) {
+ case BWN_CCK_RATE_1MB:
+ return (2);
+ case BWN_CCK_RATE_2MB:
+ return (4);
+ case BWN_CCK_RATE_5MB:
+ return (11);
+ case BWN_CCK_RATE_11MB:
+ return (22);
+ case BWN_OFDM_RATE_6MB:
+ return (12);
+ case BWN_OFDM_RATE_9MB:
+ return (18);
+ case BWN_OFDM_RATE_12MB:
+ return (24);
+ case BWN_OFDM_RATE_18MB:
+ return (36);
+ case BWN_OFDM_RATE_24MB:
+ return (48);
+ case BWN_OFDM_RATE_36MB:
+ return (72);
+ case BWN_OFDM_RATE_48MB:
+ return (96);
+ case BWN_OFDM_RATE_54MB:
+ return (108);
+ default:
+ printf("Ooops\n");
+ return (0);
+ }
+}
+
+static void
+bwn_rxeof(struct bwn_mac *mac, struct mbuf *m, const void *_rxhdr)
+{
+ const struct bwn_rxhdr4 *rxhdr = _rxhdr;
+ struct bwn_plcp6 *plcp;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211_frame_min *wh;
+ struct ieee80211_node *ni;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint32_t macstat;
+ int padding, rate, rssi, noise, type;
+ uint16_t phytype, phystat0, phystat3, chanstat;
+ unsigned char *mp = mtod(m, unsigned char *);
+
+ BWN_ASSERT_LOCKED(sc);
+
+ phystat0 = le16toh(rxhdr->phy_status0);
+ phystat3 = le16toh(rxhdr->phy_status3);
+ macstat = le32toh(rxhdr->mac_status);
+ chanstat = le16toh(rxhdr->channel);
+ phytype = chanstat & BWN_RX_CHAN_PHYTYPE;
+
+ if (macstat & BWN_RX_MAC_FCSERR)
+ device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_FCS_CRC\n");
+ if (phystat0 & (BWN_RX_PHYST0_PLCPHCF | BWN_RX_PHYST0_PLCPFV))
+ device_printf(sc->sc_dev, "TODO RX: RX_FLAG_FAILED_PLCP_CRC\n");
+ if (phystat0 & BWN_RX_PHYST0_SHORTPRMBL)
+ device_printf(sc->sc_dev, "TODO RX: RX_FLAG_SHORTPRE\n");
+ if (macstat & BWN_RX_MAC_DECERR)
+ goto drop;
+
+ padding = (macstat & BWN_RX_MAC_PADDING) ? 2 : 0;
+ if (m->m_pkthdr.len < (sizeof(struct bwn_plcp6) + padding)) {
+ device_printf(sc->sc_dev, "RX: Packet size underrun (1)\n");
+ goto drop;
+ }
+ plcp = (struct bwn_plcp6 *)(mp + padding);
+ m_adj(m, sizeof(struct bwn_plcp6) + padding);
+ if (m->m_pkthdr.len < IEEE80211_MIN_LEN) {
+ device_printf(sc->sc_dev, "RX: Packet size underrun (2)\n");
+ goto drop;
+ }
+ wh = mtod(m, struct ieee80211_frame_min *);
+
+ if (macstat & BWN_RX_MAC_DEC)
+ device_printf(sc->sc_dev, "TODO: BWN_RX_MAC_DEC\n");
+
+ /* XXX calculating RSSI & noise & antenna */
+
+ if (phystat0 & BWN_RX_PHYST0_OFDM)
+ rate = bwn_plcp_get_ofdmrate(mac, plcp,
+ phytype == BWN_PHYTYPE_A);
+ else
+ rate = bwn_plcp_get_cckrate(mac, plcp);
+ if (rate == -1) {
+ if (!(mac->mac_sc->sc_filters & BWN_MACCTL_PASS_BADPLCP))
+ goto drop;
+ }
+ sc->sc_rx_rate = bwn_hwrate2ieeerate(rate);
+
+ /* RX radio tap */
+ if (ieee80211_radiotap_active(ic))
+ bwn_rx_radiotap(mac, m, rxhdr, plcp, rate, rssi, noise);
+ m_adj(m, -IEEE80211_CRC_LEN);
+
+ rssi = rxhdr->phy.abg.rssi; /* XXX incorrect RSSI calculation? */
+ noise = mac->mac_stats.link_noise;
+
+ BWN_UNLOCK(sc);
+
+ ni = ieee80211_find_rxnode(ic, wh);
+ if (ni != NULL) {
+ type = ieee80211_input(ni, m, rssi, noise);
+ ieee80211_free_node(ni);
+ } else
+ type = ieee80211_input_all(ic, m, rssi, noise);
+
+ BWN_LOCK(sc);
+ return;
+drop:
+ device_printf(sc->sc_dev, "%s: dropped\n", __func__);
+}
+
+static void
+bwn_dma_handle_txeof(struct bwn_mac *mac,
+ const struct bwn_txstatus *status)
+{
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_dma_ring *dr;
+ struct bwn_dmadesc_generic *desc;
+ struct bwn_dmadesc_meta *meta;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211_node *ni;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct mbuf *m;
+ int slot;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ dr = bwn_dma_parse_cookie(mac, status, status->cookie, &slot);
+ if (dr == NULL) {
+ device_printf(sc->sc_dev, "failed to parse cookie\n");
+ return;
+ }
+ KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
+
+ while (1) {
+ KASSERT(slot >= 0 && slot < dr->dr_numslots,
+ ("%s:%d: fail", __func__, __LINE__));
+ dr->getdesc(dr, slot, &desc, &meta);
+
+ if (meta->mt_txtype == BWN_DMADESC_METATYPE_HEADER)
+ bus_dmamap_unload(dr->dr_txring_dtag, meta->mt_dmap);
+ else if (meta->mt_txtype == BWN_DMADESC_METATYPE_BODY)
+ bus_dmamap_unload(dma->txbuf_dtag, meta->mt_dmap);
+
+ if (meta->mt_islast) {
+ KASSERT(meta->mt_m != NULL,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ ni = meta->mt_ni;
+ m = meta->mt_m;
+ if (ni != NULL) {
+ /*
+ * Do any tx complete callback. Note this must
+ * be done before releasing the node reference.
+ */
+ if (m->m_flags & M_TXCB)
+ ieee80211_process_callback(ni, m, 0);
+ ieee80211_free_node(ni);
+ meta->mt_ni = NULL;
+ }
+ m_freem(m);
+ meta->mt_m = NULL;
+ } else {
+ KASSERT(meta->mt_m == NULL,
+ ("%s:%d: fail", __func__, __LINE__));
+ }
+
+ dr->dr_usedslot--;
+ if (meta->mt_islast) {
+ ifp->if_opackets++;
+ break;
+ }
+ slot = bwn_dma_nextslot(dr, slot);
+ }
+ sc->sc_watchdog_timer = 0;
+ if (dr->dr_stop) {
+ KASSERT(bwn_dma_freeslot(dr) >= BWN_TX_SLOTS_PER_FRAME,
+ ("%s:%d: fail", __func__, __LINE__));
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ dr->dr_stop = 0;
+ }
+}
+
+static void
+bwn_pio_handle_txeof(struct bwn_mac *mac,
+ const struct bwn_txstatus *status)
+{
+ struct bwn_pio_txqueue *tq;
+ struct bwn_pio_txpkt *tp = NULL;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+
+ BWN_ASSERT_LOCKED(sc);
+
+ tq = bwn_pio_parse_cookie(mac, status->cookie, &tp);
+ if (tq == NULL)
+ return;
+
+ tq->tq_used -= roundup(tp->tp_m->m_pkthdr.len + BWN_HDRSIZE(mac), 4);
+ tq->tq_free++;
+
+ if (tp->tp_ni != NULL) {
+ /*
+ * Do any tx complete callback. Note this must
+ * be done before releasing the node reference.
+ */
+ if (tp->tp_m->m_flags & M_TXCB)
+ ieee80211_process_callback(tp->tp_ni, tp->tp_m, 0);
+ ieee80211_free_node(tp->tp_ni);
+ tp->tp_ni = NULL;
+ }
+ m_freem(tp->tp_m);
+ tp->tp_m = NULL;
+ TAILQ_INSERT_TAIL(&tq->tq_pktlist, tp, tp_list);
+
+ ifp->if_opackets++;
+
+ sc->sc_watchdog_timer = 0;
+ if (tq->tq_stop) {
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+ tq->tq_stop = 0;
+ }
+}
+
+static void
+bwn_phy_txpower_check(struct bwn_mac *mac, uint32_t flags)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+ unsigned long now;
+ int result;
+
+ BWN_GETTIME(now);
+
+ if (!(flags & BWN_TXPWR_IGNORE_TIME) && time_before(now, phy->nexttime))
+ return;
+ phy->nexttime = now + 2 * 1000;
+
+ if (siba->siba_board_vendor == SIBA_BOARDVENDOR_BCM &&
+ siba->siba_board_type == SIBA_BOARD_BU4306)
+ return;
+
+ if (phy->recalc_txpwr != NULL) {
+ result = phy->recalc_txpwr(mac,
+ (flags & BWN_TXPWR_IGNORE_TSSI) ? 1 : 0);
+ if (result == BWN_TXPWR_RES_DONE)
+ return;
+ KASSERT(result == BWN_TXPWR_RES_NEED_ADJUST,
+ ("%s: fail", __func__));
+ KASSERT(phy->set_txpwr != NULL, ("%s: fail", __func__));
+
+ ieee80211_runtask(ic, &mac->mac_txpower);
+ }
+}
+
+static uint16_t
+bwn_pio_rx_read_2(struct bwn_pio_rxqueue *prq, uint16_t offset)
+{
+
+ return (BWN_READ_2(prq->prq_mac, prq->prq_base + offset));
+}
+
+static uint32_t
+bwn_pio_rx_read_4(struct bwn_pio_rxqueue *prq, uint16_t offset)
+{
+
+ return (BWN_READ_4(prq->prq_mac, prq->prq_base + offset));
+}
+
+static void
+bwn_pio_rx_write_2(struct bwn_pio_rxqueue *prq, uint16_t offset, uint16_t value)
+{
+
+ BWN_WRITE_2(prq->prq_mac, prq->prq_base + offset, value);
+}
+
+static void
+bwn_pio_rx_write_4(struct bwn_pio_rxqueue *prq, uint16_t offset, uint32_t value)
+{
+
+ BWN_WRITE_4(prq->prq_mac, prq->prq_base + offset, value);
+}
+
+static int
+bwn_ieeerate2hwrate(struct bwn_softc *sc, int rate)
+{
+
+ switch (rate) {
+ /* OFDM rates (cf IEEE Std 802.11a-1999, pp. 14 Table 80) */
+ case 12:
+ return (BWN_OFDM_RATE_6MB);
+ case 18:
+ return (BWN_OFDM_RATE_9MB);
+ case 24:
+ return (BWN_OFDM_RATE_12MB);
+ case 36:
+ return (BWN_OFDM_RATE_18MB);
+ case 48:
+ return (BWN_OFDM_RATE_24MB);
+ case 72:
+ return (BWN_OFDM_RATE_36MB);
+ case 96:
+ return (BWN_OFDM_RATE_48MB);
+ case 108:
+ return (BWN_OFDM_RATE_54MB);
+ /* CCK rates (NB: not IEEE std, device-specific) */
+ case 2:
+ return (BWN_CCK_RATE_1MB);
+ case 4:
+ return (BWN_CCK_RATE_2MB);
+ case 11:
+ return (BWN_CCK_RATE_5MB);
+ case 22:
+ return (BWN_CCK_RATE_11MB);
+ }
+
+ device_printf(sc->sc_dev, "unsupported rate %d\n", rate);
+ return (BWN_CCK_RATE_1MB);
+}
+
+static int
+bwn_set_txhdr(struct bwn_mac *mac, struct ieee80211_node *ni,
+ struct mbuf *m, struct bwn_txhdr *txhdr, uint16_t cookie)
+{
+ const struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211_frame *wh;
+ struct ieee80211_frame *protwh;
+ struct ieee80211_frame_cts *cts;
+ struct ieee80211_frame_rts *rts;
+ const struct ieee80211_txparam *tp;
+ struct ieee80211vap *vap = ni->ni_vap;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct mbuf *mprot;
+ unsigned int len;
+ uint32_t macctl = 0;
+ int protdur, rts_rate, rts_rate_fb, ismcast, isshort, rix, type;
+ uint16_t phyctl = 0;
+ uint8_t rate, rate_fb;
+
+ wh = mtod(m, struct ieee80211_frame *);
+ memset(txhdr, 0, sizeof(*txhdr));
+
+ type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
+ ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+ isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
+
+ /*
+ * Find TX rate
+ */
+ tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)];
+ if (type != IEEE80211_FC0_TYPE_DATA || (m->m_flags & M_EAPOL))
+ rate = rate_fb = tp->mgmtrate;
+ else if (ismcast)
+ rate = rate_fb = tp->mcastrate;
+ else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
+ rate = rate_fb = tp->ucastrate;
+ else {
+ rix = ieee80211_amrr_choose(ni, &BWN_NODE(ni)->bn_amn);
+ rate = ni->ni_txrate;
+
+ if (rix > 0)
+ rate_fb = ni->ni_rates.rs_rates[rix - 1] &
+ IEEE80211_RATE_VAL;
+ else
+ rate_fb = rate;
+ }
+
+ sc->sc_tx_rate = rate;
+
+ rate = bwn_ieeerate2hwrate(sc, rate);
+ rate_fb = bwn_ieeerate2hwrate(sc, rate_fb);
+
+ txhdr->phyrate = (BWN_ISOFDMRATE(rate)) ? bwn_plcp_getofdm(rate) :
+ bwn_plcp_getcck(rate);
+ bcopy(wh->i_fc, txhdr->macfc, sizeof(txhdr->macfc));
+ bcopy(wh->i_addr1, txhdr->addr1, IEEE80211_ADDR_LEN);
+
+ if ((rate_fb == rate) ||
+ (*(u_int16_t *)wh->i_dur & htole16(0x8000)) ||
+ (*(u_int16_t *)wh->i_dur == htole16(0)))
+ txhdr->dur_fb = *(u_int16_t *)wh->i_dur;
+ else
+ txhdr->dur_fb = ieee80211_compute_duration(ic->ic_rt,
+ m->m_pkthdr.len, rate, isshort);
+
+ /* XXX TX encryption */
+ bwn_plcp_genhdr(BWN_ISOLDFMT(mac) ?
+ (struct bwn_plcp4 *)(&txhdr->body.old.plcp) :
+ (struct bwn_plcp4 *)(&txhdr->body.new.plcp),
+ m->m_pkthdr.len + IEEE80211_CRC_LEN, rate);
+ bwn_plcp_genhdr((struct bwn_plcp4 *)(&txhdr->plcp_fb),
+ m->m_pkthdr.len + IEEE80211_CRC_LEN, rate_fb);
+
+ txhdr->eftypes |= (BWN_ISOFDMRATE(rate_fb)) ? BWN_TX_EFT_FB_OFDM :
+ BWN_TX_EFT_FB_CCK;
+ txhdr->chan = phy->chan;
+ phyctl |= (BWN_ISOFDMRATE(rate)) ? BWN_TX_PHY_ENC_OFDM :
+ BWN_TX_PHY_ENC_CCK;
+ if (isshort && (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
+ rate == BWN_CCK_RATE_11MB))
+ phyctl |= BWN_TX_PHY_SHORTPRMBL;
+
+ /* XXX TX antenna selection */
+
+ switch (bwn_antenna_sanitize(mac, 0)) {
+ case 0:
+ phyctl |= BWN_TX_PHY_ANT01AUTO;
+ break;
+ case 1:
+ phyctl |= BWN_TX_PHY_ANT0;
+ break;
+ case 2:
+ phyctl |= BWN_TX_PHY_ANT1;
+ break;
+ case 3:
+ phyctl |= BWN_TX_PHY_ANT2;
+ break;
+ case 4:
+ phyctl |= BWN_TX_PHY_ANT3;
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+
+ if (!ismcast)
+ macctl |= BWN_TX_MAC_ACK;
+
+ macctl |= (BWN_TX_MAC_HWSEQ | BWN_TX_MAC_START_MSDU);
+ if (!IEEE80211_IS_MULTICAST(wh->i_addr1) &&
+ m->m_pkthdr.len + IEEE80211_CRC_LEN > vap->iv_rtsthreshold)
+ macctl |= BWN_TX_MAC_LONGFRAME;
+
+ if (ic->ic_flags & IEEE80211_F_USEPROT) {
+ /* XXX RTS rate is always 1MB??? */
+ rts_rate = BWN_CCK_RATE_1MB;
+ rts_rate_fb = bwn_get_fbrate(rts_rate);
+
+ protdur = ieee80211_compute_duration(ic->ic_rt,
+ m->m_pkthdr.len, rate, isshort) +
+ + ieee80211_ack_duration(ic->ic_rt, rate, isshort);
+
+ if (ic->ic_protmode == IEEE80211_PROT_CTSONLY) {
+ cts = (struct ieee80211_frame_cts *)(BWN_ISOLDFMT(mac) ?
+ (txhdr->body.old.rts_frame) :
+ (txhdr->body.new.rts_frame));
+ mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr,
+ protdur);
+ KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
+ bcopy(mtod(mprot, uint8_t *), (uint8_t *)cts,
+ mprot->m_pkthdr.len);
+ m_freem(mprot);
+ macctl |= BWN_TX_MAC_SEND_CTSTOSELF;
+ len = sizeof(struct ieee80211_frame_cts);
+ } else {
+ rts = (struct ieee80211_frame_rts *)(BWN_ISOLDFMT(mac) ?
+ (txhdr->body.old.rts_frame) :
+ (txhdr->body.new.rts_frame));
+ protdur += ieee80211_ack_duration(ic->ic_rt, rate,
+ isshort);
+ mprot = ieee80211_alloc_rts(ic, wh->i_addr1,
+ wh->i_addr2, protdur);
+ KASSERT(mprot != NULL, ("failed to alloc mbuf\n"));
+ bcopy(mtod(mprot, uint8_t *), (uint8_t *)rts,
+ mprot->m_pkthdr.len);
+ m_freem(mprot);
+ macctl |= BWN_TX_MAC_SEND_RTSCTS;
+ len = sizeof(struct ieee80211_frame_rts);
+ }
+ len += IEEE80211_CRC_LEN;
+ bwn_plcp_genhdr((struct bwn_plcp4 *)((BWN_ISOLDFMT(mac)) ?
+ &txhdr->body.old.rts_plcp :
+ &txhdr->body.new.rts_plcp), len, rts_rate);
+ bwn_plcp_genhdr((struct bwn_plcp4 *)&txhdr->rts_plcp_fb, len,
+ rts_rate_fb);
+
+ protwh = (struct ieee80211_frame *)(BWN_ISOLDFMT(mac) ?
+ (&txhdr->body.old.rts_frame) :
+ (&txhdr->body.new.rts_frame));
+ txhdr->rts_dur_fb = *(u_int16_t *)protwh->i_dur;
+
+ if (BWN_ISOFDMRATE(rts_rate)) {
+ txhdr->eftypes |= BWN_TX_EFT_RTS_OFDM;
+ txhdr->phyrate_rts = bwn_plcp_getofdm(rts_rate);
+ } else {
+ txhdr->eftypes |= BWN_TX_EFT_RTS_CCK;
+ txhdr->phyrate_rts = bwn_plcp_getcck(rts_rate);
+ }
+ txhdr->eftypes |= (BWN_ISOFDMRATE(rts_rate_fb)) ?
+ BWN_TX_EFT_RTS_FBOFDM : BWN_TX_EFT_RTS_FBCCK;
+ }
+
+ if (BWN_ISOLDFMT(mac))
+ txhdr->body.old.cookie = htole16(cookie);
+ else
+ txhdr->body.new.cookie = htole16(cookie);
+
+ txhdr->macctl = htole32(macctl);
+ txhdr->phyctl = htole16(phyctl);
+
+ /*
+ * TX radio tap
+ */
+ if (ieee80211_radiotap_active_vap(vap)) {
+ sc->sc_tx_th.wt_flags = 0;
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+ sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_WEP;
+ if (isshort &&
+ (rate == BWN_CCK_RATE_2MB || rate == BWN_CCK_RATE_5MB ||
+ rate == BWN_CCK_RATE_11MB))
+ sc->sc_tx_th.wt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+ sc->sc_tx_th.wt_rate = rate;
+
+ ieee80211_radiotap_tx(vap, m);
+ }
+
+ return (0);
+}
+
+static void
+bwn_plcp_genhdr(struct bwn_plcp4 *plcp, const uint16_t octets,
+ const uint8_t rate)
+{
+ uint32_t d, plen;
+ uint8_t *raw = plcp->o.raw;
+
+ if (BWN_ISOFDMRATE(rate)) {
+ d = bwn_plcp_getofdm(rate);
+ KASSERT(!(octets & 0xf000),
+ ("%s:%d: fail", __func__, __LINE__));
+ d |= (octets << 5);
+ plcp->o.data = htole32(d);
+ } else {
+ plen = octets * 16 / rate;
+ if ((octets * 16 % rate) > 0) {
+ plen++;
+ if ((rate == BWN_CCK_RATE_11MB)
+ && ((octets * 8 % 11) < 4)) {
+ raw[1] = 0x84;
+ } else
+ raw[1] = 0x04;
+ } else
+ raw[1] = 0x04;
+ plcp->o.data |= htole32(plen << 16);
+ raw[0] = bwn_plcp_getcck(rate);
+ }
+}
+
+static uint8_t
+bwn_antenna_sanitize(struct bwn_mac *mac, uint8_t n)
+{
+ uint8_t mask;
+
+ if (n == 0)
+ return (0);
+ if (mac->mac_phy.gmode)
+ mask = mac->mac_sd->sd_bus->siba_sprom.ant_bg;
+ else
+ mask = mac->mac_sd->sd_bus->siba_sprom.ant_a;
+ if (!(mask & (1 << (n - 1))))
+ return (0);
+ return (n);
+}
+
+static uint8_t
+bwn_get_fbrate(uint8_t bitrate)
+{
+ switch (bitrate) {
+ case BWN_CCK_RATE_1MB:
+ return (BWN_CCK_RATE_1MB);
+ case BWN_CCK_RATE_2MB:
+ return (BWN_CCK_RATE_1MB);
+ case BWN_CCK_RATE_5MB:
+ return (BWN_CCK_RATE_2MB);
+ case BWN_CCK_RATE_11MB:
+ return (BWN_CCK_RATE_5MB);
+ case BWN_OFDM_RATE_6MB:
+ return (BWN_CCK_RATE_5MB);
+ case BWN_OFDM_RATE_9MB:
+ return (BWN_OFDM_RATE_6MB);
+ case BWN_OFDM_RATE_12MB:
+ return (BWN_OFDM_RATE_9MB);
+ case BWN_OFDM_RATE_18MB:
+ return (BWN_OFDM_RATE_12MB);
+ case BWN_OFDM_RATE_24MB:
+ return (BWN_OFDM_RATE_18MB);
+ case BWN_OFDM_RATE_36MB:
+ return (BWN_OFDM_RATE_24MB);
+ case BWN_OFDM_RATE_48MB:
+ return (BWN_OFDM_RATE_36MB);
+ case BWN_OFDM_RATE_54MB:
+ return (BWN_OFDM_RATE_48MB);
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ return (0);
+}
+
+static uint32_t
+bwn_pio_write_multi_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
+ uint32_t ctl, const void *_data, int len)
+{
+ uint32_t value = 0;
+ const uint8_t *data = _data;
+
+ ctl |= BWN_PIO8_TXCTL_0_7 | BWN_PIO8_TXCTL_8_15 |
+ BWN_PIO8_TXCTL_16_23 | BWN_PIO8_TXCTL_24_31;
+ bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
+
+ siba_write_multi_4(mac->mac_sd, data, (len & ~3),
+ tq->tq_base + BWN_PIO8_TXDATA);
+ if (len & 3) {
+ ctl &= ~(BWN_PIO8_TXCTL_8_15 | BWN_PIO8_TXCTL_16_23 |
+ BWN_PIO8_TXCTL_24_31);
+ data = &(data[len - 1]);
+ switch (len & 3) {
+ case 3:
+ ctl |= BWN_PIO8_TXCTL_16_23;
+ value |= (uint32_t)(*data) << 16;
+ data--;
+ case 2:
+ ctl |= BWN_PIO8_TXCTL_8_15;
+ value |= (uint32_t)(*data) << 8;
+ data--;
+ case 1:
+ value |= (uint32_t)(*data);
+ }
+ bwn_pio_write_4(mac, tq, BWN_PIO8_TXCTL, ctl);
+ bwn_pio_write_4(mac, tq, BWN_PIO8_TXDATA, value);
+ }
+
+ return (ctl);
+}
+
+static void
+bwn_pio_write_4(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
+ uint16_t offset, uint32_t value)
+{
+
+ BWN_WRITE_4(mac, tq->tq_base + offset, value);
+}
+
+static uint16_t
+bwn_pio_write_multi_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
+ uint16_t ctl, const void *_data, int len)
+{
+ const uint8_t *data = _data;
+
+ ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
+
+ siba_write_multi_2(mac->mac_sd, data, (len & ~1),
+ tq->tq_base + BWN_PIO_TXDATA);
+ if (len & 1) {
+ ctl &= ~BWN_PIO_TXCTL_WRITEHI;
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data[len - 1]);
+ }
+
+ return (ctl);
+}
+
+static uint16_t
+bwn_pio_write_mbuf_2(struct bwn_mac *mac, struct bwn_pio_txqueue *tq,
+ uint16_t ctl, struct mbuf *m0)
+{
+ int i, j = 0;
+ uint16_t data = 0;
+ const uint8_t *buf;
+ struct mbuf *m = m0;
+
+ ctl |= BWN_PIO_TXCTL_WRITELO | BWN_PIO_TXCTL_WRITEHI;
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
+
+ for (; m != NULL; m = m->m_next) {
+ buf = mtod(m, const uint8_t *);
+ for (i = 0; i < m->m_len; i++) {
+ if (!((j++) % 2))
+ data |= buf[i];
+ else {
+ data |= (buf[i] << 8);
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
+ data = 0;
+ }
+ }
+ }
+ if (m0->m_pkthdr.len % 2) {
+ ctl &= ~BWN_PIO_TXCTL_WRITEHI;
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXCTL, ctl);
+ BWN_PIO_WRITE_2(mac, tq, BWN_PIO_TXDATA, data);
+ }
+
+ return (ctl);
+}
+
+static void
+bwn_set_slot_time(struct bwn_mac *mac, uint16_t time)
+{
+
+ if (mac->mac_phy.type != BWN_PHYTYPE_G)
+ return;
+ BWN_WRITE_2(mac, 0x684, 510 + time);
+ bwn_shm_write_2(mac, BWN_SHARED, 0x0010, time);
+}
+
+static struct bwn_dma_ring *
+bwn_dma_select(struct bwn_mac *mac, uint8_t prio)
+{
+
+ if ((mac->mac_flags & BWN_MAC_FLAG_WME) == 0)
+ return (mac->mac_method.dma.wme[WME_AC_BE]);
+
+ switch (prio) {
+ case 3:
+ return (mac->mac_method.dma.wme[WME_AC_VO]);
+ case 2:
+ return (mac->mac_method.dma.wme[WME_AC_VI]);
+ case 0:
+ return (mac->mac_method.dma.wme[WME_AC_BE]);
+ case 1:
+ return (mac->mac_method.dma.wme[WME_AC_BK]);
+ }
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+}
+
+static int
+bwn_dma_getslot(struct bwn_dma_ring *dr)
+{
+ struct bwn_mac *mac = dr->dr_mac;
+ int slot;
+
+ BWN_ASSERT_LOCKED(mac->mac_sc);
+
+ KASSERT(dr->dr_tx, ("%s:%d: fail", __func__, __LINE__));
+ KASSERT(!(dr->dr_stop), ("%s:%d: fail", __func__, __LINE__));
+ KASSERT(bwn_dma_freeslot(dr) != 0, ("%s:%d: fail", __func__, __LINE__));
+
+ slot = bwn_dma_nextslot(dr, dr->dr_curslot);
+ KASSERT(!(slot & ~0x0fff), ("%s:%d: fail", __func__, __LINE__));
+ dr->dr_curslot = slot;
+ dr->dr_usedslot++;
+
+ return (slot);
+}
+
+static int
+bwn_phy_shm_tssi_read(struct bwn_mac *mac, uint16_t shm_offset)
+{
+ const uint8_t ofdm = (shm_offset != BWN_SHARED_TSSI_CCK);
+ unsigned int a, b, c, d;
+ unsigned int avg;
+ uint32_t tmp;
+
+ tmp = bwn_shm_read_4(mac, BWN_SHARED, shm_offset);
+ a = tmp & 0xff;
+ b = (tmp >> 8) & 0xff;
+ c = (tmp >> 16) & 0xff;
+ d = (tmp >> 24) & 0xff;
+ if (a == 0 || a == BWN_TSSI_MAX || b == 0 || b == BWN_TSSI_MAX ||
+ c == 0 || c == BWN_TSSI_MAX || d == 0 || d == BWN_TSSI_MAX)
+ return (ENOENT);
+ bwn_shm_write_4(mac, BWN_SHARED, shm_offset,
+ BWN_TSSI_MAX | (BWN_TSSI_MAX << 8) |
+ (BWN_TSSI_MAX << 16) | (BWN_TSSI_MAX << 24));
+
+ if (ofdm) {
+ a = (a + 32) & 0x3f;
+ b = (b + 32) & 0x3f;
+ c = (c + 32) & 0x3f;
+ d = (d + 32) & 0x3f;
+ }
+
+ avg = (a + b + c + d + 2) / 4;
+ if (ofdm) {
+ if (bwn_shm_read_2(mac, BWN_SHARED, BWN_SHARED_HFLO)
+ & BWN_HF_4DB_CCK_POWERBOOST)
+ avg = (avg >= 13) ? (avg - 13) : 0;
+ }
+ return (avg);
+}
+
+static void
+bwn_phy_g_setatt(struct bwn_mac *mac, int *bbattp, int *rfattp)
+{
+ struct bwn_txpwr_loctl *lo = &mac->mac_phy.phy_g.pg_loctl;
+ int rfatt = *rfattp;
+ int bbatt = *bbattp;
+
+ while (1) {
+ if (rfatt > lo->rfatt.max && bbatt > lo->bbatt.max - 4)
+ break;
+ if (rfatt < lo->rfatt.min && bbatt < lo->bbatt.min + 4)
+ break;
+ if (bbatt > lo->bbatt.max && rfatt > lo->rfatt.max - 1)
+ break;
+ if (bbatt < lo->bbatt.min && rfatt < lo->rfatt.min + 1)
+ break;
+ if (bbatt > lo->bbatt.max) {
+ bbatt -= 4;
+ rfatt += 1;
+ continue;
+ }
+ if (bbatt < lo->bbatt.min) {
+ bbatt += 4;
+ rfatt -= 1;
+ continue;
+ }
+ if (rfatt > lo->rfatt.max) {
+ rfatt -= 1;
+ bbatt += 4;
+ continue;
+ }
+ if (rfatt < lo->rfatt.min) {
+ rfatt += 1;
+ bbatt -= 4;
+ continue;
+ }
+ break;
+ }
+
+ *rfattp = MIN(MAX(rfatt, lo->rfatt.min), lo->rfatt.max);
+ *bbattp = MIN(MAX(bbatt, lo->bbatt.min), lo->bbatt.max);
+}
+
+static void
+bwn_phy_lock(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+
+ KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
+ ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP)
+ bwn_psctl(mac, BWN_PS_AWAKE);
+}
+
+static void
+bwn_phy_unlock(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+
+ KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
+ ("%s: unsupported rev %d", __func__, mac->mac_sd->sd_id.sd_rev));
+
+ if (ic->ic_opmode != IEEE80211_M_HOSTAP)
+ bwn_psctl(mac, 0);
+}
+
+static void
+bwn_rf_lock(struct bwn_mac *mac)
+{
+
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL) | BWN_MACCTL_RADIO_LOCK);
+ BWN_READ_4(mac, BWN_MACCTL);
+ DELAY(10);
+}
+
+static void
+bwn_rf_unlock(struct bwn_mac *mac)
+{
+
+ BWN_READ_2(mac, BWN_PHYVER);
+ BWN_WRITE_4(mac, BWN_MACCTL,
+ BWN_READ_4(mac, BWN_MACCTL) & ~BWN_MACCTL_RADIO_LOCK);
+}
+
+static struct bwn_pio_txqueue *
+bwn_pio_parse_cookie(struct bwn_mac *mac, uint16_t cookie,
+ struct bwn_pio_txpkt **pack)
+{
+ struct bwn_pio *pio = &mac->mac_method.pio;
+ struct bwn_pio_txqueue *tq = NULL;
+ unsigned int index;
+
+ switch (cookie & 0xf000) {
+ case 0x1000:
+ tq = &pio->wme[WME_AC_BK];
+ break;
+ case 0x2000:
+ tq = &pio->wme[WME_AC_BE];
+ break;
+ case 0x3000:
+ tq = &pio->wme[WME_AC_VI];
+ break;
+ case 0x4000:
+ tq = &pio->wme[WME_AC_VO];
+ break;
+ case 0x5000:
+ tq = &pio->mcast;
+ break;
+ }
+ KASSERT(tq != NULL, ("%s:%d: fail", __func__, __LINE__));
+ if (tq == NULL)
+ return (NULL);
+ index = (cookie & 0x0fff);
+ KASSERT(index < N(tq->tq_pkts), ("%s:%d: fail", __func__, __LINE__));
+ if (index >= N(tq->tq_pkts))
+ return (NULL);
+ *pack = &tq->tq_pkts[index];
+ KASSERT(*pack != NULL, ("%s:%d: fail", __func__, __LINE__));
+ return (tq);
+}
+
+static void
+bwn_txpwr(void *arg, int npending)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+
+ BWN_LOCK(sc);
+ if (mac && mac->mac_status >= BWN_MAC_STATUS_STARTED &&
+ mac->mac_phy.set_txpwr != NULL)
+ mac->mac_phy.set_txpwr(mac);
+ BWN_UNLOCK(sc);
+}
+
+static void
+bwn_task_15s(struct bwn_mac *mac)
+{
+ uint16_t reg;
+
+ if (mac->mac_fw.opensource) {
+ reg = bwn_shm_read_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG);
+ if (reg) {
+ bwn_restart(mac, "fw watchdog");
+ return;
+ }
+ bwn_shm_write_2(mac, BWN_SCRATCH, BWN_WATCHDOG_REG, 1);
+ }
+ if (mac->mac_phy.task_15s)
+ mac->mac_phy.task_15s(mac);
+
+ mac->mac_phy.txerrors = BWN_TXERROR_MAX;
+}
+
+static void
+bwn_task_30s(struct bwn_mac *mac)
+{
+
+ if (mac->mac_phy.type != BWN_PHYTYPE_G || mac->mac_noise.noi_running)
+ return;
+ mac->mac_noise.noi_running = 1;
+ mac->mac_noise.noi_nsamples = 0;
+
+ bwn_noise_gensample(mac);
+}
+
+static void
+bwn_task_60s(struct bwn_mac *mac)
+{
+
+ if (mac->mac_phy.task_60s)
+ mac->mac_phy.task_60s(mac);
+ bwn_phy_txpower_check(mac, BWN_TXPWR_IGNORE_TIME);
+}
+
+static void
+bwn_tasks(void *arg)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+
+ BWN_ASSERT_LOCKED(sc);
+ if (mac->mac_status != BWN_MAC_STATUS_STARTED)
+ return;
+
+ if (mac->mac_task_state % 4 == 0)
+ bwn_task_60s(mac);
+ if (mac->mac_task_state % 2 == 0)
+ bwn_task_30s(mac);
+ bwn_task_15s(mac);
+
+ mac->mac_task_state++;
+ callout_reset(&sc->sc_task_ch, hz * 15, bwn_tasks, mac);
+}
+
+static int
+bwn_plcp_get_ofdmrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp, uint8_t a)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+
+ KASSERT(a == 0, ("not support APHY\n"));
+
+ switch (plcp->o.raw[0] & 0xf) {
+ case 0xb:
+ return (BWN_OFDM_RATE_6MB);
+ case 0xf:
+ return (BWN_OFDM_RATE_9MB);
+ case 0xa:
+ return (BWN_OFDM_RATE_12MB);
+ case 0xe:
+ return (BWN_OFDM_RATE_18MB);
+ case 0x9:
+ return (BWN_OFDM_RATE_24MB);
+ case 0xd:
+ return (BWN_OFDM_RATE_36MB);
+ case 0x8:
+ return (BWN_OFDM_RATE_48MB);
+ case 0xc:
+ return (BWN_OFDM_RATE_54MB);
+ }
+ device_printf(sc->sc_dev, "incorrect OFDM rate %d\n",
+ plcp->o.raw[0] & 0xf);
+ return (-1);
+}
+
+static int
+bwn_plcp_get_cckrate(struct bwn_mac *mac, struct bwn_plcp6 *plcp)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+
+ switch (plcp->o.raw[0]) {
+ case 0x0a:
+ return (BWN_CCK_RATE_1MB);
+ case 0x14:
+ return (BWN_CCK_RATE_2MB);
+ case 0x37:
+ return (BWN_CCK_RATE_5MB);
+ case 0x6e:
+ return (BWN_CCK_RATE_11MB);
+ }
+ device_printf(sc->sc_dev, "incorrect CCK rate %d\n", plcp->o.raw[0]);
+ return (-1);
+}
+
+static void
+bwn_rx_radiotap(struct bwn_mac *mac, struct mbuf *m,
+ const struct bwn_rxhdr4 *rxhdr, struct bwn_plcp6 *plcp, int rate,
+ int rssi, int noise)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ const struct ieee80211_frame_min *wh;
+ uint64_t tsf;
+ uint16_t low_mactime_now;
+
+ if (htole16(rxhdr->phy_status0) & BWN_RX_PHYST0_SHORTPRMBL)
+ sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
+
+ wh = mtod(m, const struct ieee80211_frame_min *);
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP)
+ sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ bwn_tsf_read(mac, &tsf);
+ low_mactime_now = tsf;
+ tsf = tsf & ~0xffffULL;
+ tsf += le16toh(rxhdr->mac_time);
+ if (low_mactime_now < le16toh(rxhdr->mac_time))
+ tsf -= 0x10000;
+
+ sc->sc_rx_th.wr_tsf = tsf;
+ sc->sc_rx_th.wr_rate = rate;
+ sc->sc_rx_th.wr_antsignal = rssi;
+ sc->sc_rx_th.wr_antnoise = noise;
+}
+
+static void
+bwn_tsf_read(struct bwn_mac *mac, uint64_t *tsf)
+{
+ uint32_t low, high;
+
+ KASSERT(mac->mac_sd->sd_id.sd_rev >= 3,
+ ("%s:%d: fail", __func__, __LINE__));
+
+ low = BWN_READ_4(mac, BWN_REV3PLUS_TSF_LOW);
+ high = BWN_READ_4(mac, BWN_REV3PLUS_TSF_HIGH);
+ *tsf = high;
+ *tsf <<= 32;
+ *tsf |= low;
+}
+
+static int
+bwn_dma_attach(struct bwn_mac *mac)
+{
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ bus_addr_t lowaddr = 0;
+ int error;
+
+ if (siba->siba_type == SIBA_TYPE_PCMCIA || bwn_usedma == 0)
+ return (0);
+
+ KASSERT(mac->mac_sd->sd_id.sd_rev >= 5, ("%s: fail", __func__));
+
+ mac->mac_flags |= BWN_MAC_FLAG_DMA;
+
+ dma->dmatype = bwn_dma_gettype(mac);
+ if (dma->dmatype == BWN_DMA_30BIT)
+ lowaddr = BWN_BUS_SPACE_MAXADDR_30BIT;
+ else if (dma->dmatype == BWN_DMA_32BIT)
+ lowaddr = BUS_SPACE_MAXADDR_32BIT;
+ else
+ lowaddr = BUS_SPACE_MAXADDR;
+
+ /*
+ * Create top level DMA tag
+ */
+ error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), /* parent */
+ BWN_ALIGN, 0, /* alignment, bounds */
+ lowaddr, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filter, filterarg */
+ MAXBSIZE, /* maxsize */
+ BUS_SPACE_UNRESTRICTED, /* nsegments */
+ BUS_SPACE_MAXSIZE, /* maxsegsize */
+ 0, /* flags */
+ NULL, NULL, /* lockfunc, lockarg */
+ &dma->parent_dtag);
+ if (error) {
+ device_printf(sc->sc_dev, "can't create parent DMA tag\n");
+ return (error);
+ }
+
+ /*
+ * Create TX/RX mbuf DMA tag
+ */
+ error = bus_dma_tag_create(dma->parent_dtag,
+ 1,
+ 0,
+ BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ MCLBYTES,
+ 1,
+ BUS_SPACE_MAXSIZE_32BIT,
+ 0,
+ NULL, NULL,
+ &dma->rxbuf_dtag);
+ if (error) {
+ device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
+ goto fail0;
+ }
+ error = bus_dma_tag_create(dma->parent_dtag,
+ 1,
+ 0,
+ BUS_SPACE_MAXADDR,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ MCLBYTES,
+ 1,
+ BUS_SPACE_MAXSIZE_32BIT,
+ 0,
+ NULL, NULL,
+ &dma->txbuf_dtag);
+ if (error) {
+ device_printf(sc->sc_dev, "can't create mbuf DMA tag\n");
+ goto fail1;
+ }
+
+ dma->wme[WME_AC_BK] = bwn_dma_ringsetup(mac, 0, 1, dma->dmatype);
+ if (!dma->wme[WME_AC_BK])
+ goto fail2;
+
+ dma->wme[WME_AC_BE] = bwn_dma_ringsetup(mac, 1, 1, dma->dmatype);
+ if (!dma->wme[WME_AC_BE])
+ goto fail3;
+
+ dma->wme[WME_AC_VI] = bwn_dma_ringsetup(mac, 2, 1, dma->dmatype);
+ if (!dma->wme[WME_AC_VI])
+ goto fail4;
+
+ dma->wme[WME_AC_VO] = bwn_dma_ringsetup(mac, 3, 1, dma->dmatype);
+ if (!dma->wme[WME_AC_VO])
+ goto fail5;
+
+ dma->mcast = bwn_dma_ringsetup(mac, 4, 1, dma->dmatype);
+ if (!dma->mcast)
+ goto fail6;
+ dma->rx = bwn_dma_ringsetup(mac, 0, 0, dma->dmatype);
+ if (!dma->rx)
+ goto fail7;
+
+ return (error);
+
+fail7: bwn_dma_ringfree(&dma->mcast);
+fail6: bwn_dma_ringfree(&dma->wme[WME_AC_VO]);
+fail5: bwn_dma_ringfree(&dma->wme[WME_AC_VI]);
+fail4: bwn_dma_ringfree(&dma->wme[WME_AC_BE]);
+fail3: bwn_dma_ringfree(&dma->wme[WME_AC_BK]);
+fail2: bus_dma_tag_destroy(dma->txbuf_dtag);
+fail1: bus_dma_tag_destroy(dma->rxbuf_dtag);
+fail0: bus_dma_tag_destroy(dma->parent_dtag);
+ return (error);
+}
+
+static struct bwn_dma_ring *
+bwn_dma_parse_cookie(struct bwn_mac *mac, const struct bwn_txstatus *status,
+ uint16_t cookie, int *slot)
+{
+ struct bwn_dma *dma = &mac->mac_method.dma;
+ struct bwn_dma_ring *dr;
+ struct bwn_softc *sc = mac->mac_sc;
+
+ BWN_ASSERT_LOCKED(mac->mac_sc);
+
+ switch (cookie & 0xf000) {
+ case 0x1000:
+ dr = dma->wme[WME_AC_BK];
+ break;
+ case 0x2000:
+ dr = dma->wme[WME_AC_BE];
+ break;
+ case 0x3000:
+ dr = dma->wme[WME_AC_VI];
+ break;
+ case 0x4000:
+ dr = dma->wme[WME_AC_VO];
+ break;
+ case 0x5000:
+ dr = dma->mcast;
+ break;
+ default:
+ KASSERT(0 == 1,
+ ("invalid cookie value %d", cookie & 0xf000));
+ }
+ *slot = (cookie & 0x0fff);
+ if (*slot < 0 || *slot >= dr->dr_numslots) {
+ /*
+ * XXX FIXME: sometimes H/W returns TX DONE events duplicately
+ * that it occurs events which have same H/W sequence numbers.
+ * When it's occurred just prints a WARNING msgs and ignores.
+ */
+ KASSERT(status->seq == dma->lastseq,
+ ("%s:%d: fail", __func__, __LINE__));
+ device_printf(sc->sc_dev,
+ "out of slot ranges (0 < %d < %d)\n", *slot,
+ dr->dr_numslots);
+ return (NULL);
+ }
+ dma->lastseq = status->seq;
+ return (dr);
+}
+
+static void
+bwn_dma_stop(struct bwn_mac *mac)
+{
+ struct bwn_dma *dma;
+
+ if ((mac->mac_flags & BWN_MAC_FLAG_DMA) == 0)
+ return;
+ dma = &mac->mac_method.dma;
+
+ bwn_dma_ringstop(&dma->rx);
+ bwn_dma_ringstop(&dma->wme[WME_AC_BK]);
+ bwn_dma_ringstop(&dma->wme[WME_AC_BE]);
+ bwn_dma_ringstop(&dma->wme[WME_AC_VI]);
+ bwn_dma_ringstop(&dma->wme[WME_AC_VO]);
+ bwn_dma_ringstop(&dma->mcast);
+}
+
+static void
+bwn_dma_ringstop(struct bwn_dma_ring **dr)
+{
+
+ if (dr == NULL)
+ return;
+
+ bwn_dma_cleanup(*dr);
+}
+
+static void
+bwn_pio_stop(struct bwn_mac *mac)
+{
+ struct bwn_pio *pio;
+
+ if (mac->mac_flags & BWN_MAC_FLAG_DMA)
+ return;
+ pio = &mac->mac_method.pio;
+
+ bwn_destroy_queue_tx(&pio->mcast);
+ 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_BE]);
+ bwn_destroy_queue_tx(&pio->wme[WME_AC_BK]);
+}
+
+static void
+bwn_led_attach(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct siba_softc *siba = mac->mac_sd->sd_bus;
+ const uint8_t *led_act = NULL;
+ uint16_t val[BWN_LED_MAX];
+ int i;
+
+ sc->sc_led_idle = (2350 * hz) / 1000;
+ sc->sc_led_blink = 1;
+
+ for (i = 0; i < N(bwn_vendor_led_act); ++i) {
+ if (siba->siba_pci_subvid == bwn_vendor_led_act[i].vid) {
+ led_act = bwn_vendor_led_act[i].led_act;
+ break;
+ }
+ }
+ if (led_act == NULL)
+ led_act = bwn_default_led_act;
+
+ val[0] = siba->siba_sprom.gpio0;
+ val[1] = siba->siba_sprom.gpio1;
+ val[2] = siba->siba_sprom.gpio2;
+ val[3] = siba->siba_sprom.gpio3;
+
+ for (i = 0; i < BWN_LED_MAX; ++i) {
+ struct bwn_led *led = &sc->sc_leds[i];
+
+ if (val[i] == 0xff) {
+ led->led_act = led_act[i];
+ } else {
+ if (val[i] & BWN_LED_ACT_LOW)
+ led->led_flags |= BWN_LED_F_ACTLOW;
+ led->led_act = val[i] & BWN_LED_ACT_MASK;
+ }
+ led->led_mask = (1 << i);
+
+ if (led->led_act == BWN_LED_ACT_BLINK_SLOW ||
+ led->led_act == BWN_LED_ACT_BLINK_POLL ||
+ led->led_act == BWN_LED_ACT_BLINK) {
+ led->led_flags |= BWN_LED_F_BLINK;
+ if (led->led_act == BWN_LED_ACT_BLINK_POLL)
+ led->led_flags |= BWN_LED_F_POLLABLE;
+ else if (led->led_act == BWN_LED_ACT_BLINK_SLOW)
+ led->led_flags |= BWN_LED_F_SLOW;
+
+ if (sc->sc_blink_led == NULL) {
+ sc->sc_blink_led = led;
+ if (led->led_flags & BWN_LED_F_SLOW)
+ BWN_LED_SLOWDOWN(sc->sc_led_idle);
+ }
+ }
+
+ DPRINTF(sc, BWN_DEBUG_LED,
+ "%dth led, act %d, lowact %d\n", i,
+ led->led_act, led->led_flags & BWN_LED_F_ACTLOW);
+ }
+ callout_init_mtx(&sc->sc_led_blink_ch, &sc->sc_mtx, 0);
+}
+
+static __inline uint16_t
+bwn_led_onoff(const struct bwn_led *led, uint16_t val, int on)
+{
+
+ if (led->led_flags & BWN_LED_F_ACTLOW)
+ on = !on;
+ if (on)
+ val |= led->led_mask;
+ else
+ val &= ~led->led_mask;
+ return val;
+}
+
+static void
+bwn_led_newstate(struct bwn_mac *mac, enum ieee80211_state nstate)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint16_t val;
+ int i;
+
+ if (nstate == IEEE80211_S_INIT) {
+ callout_stop(&sc->sc_led_blink_ch);
+ sc->sc_led_blinking = 0;
+ }
+
+ if ((ic->ic_ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
+ return;
+
+ val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
+ for (i = 0; i < BWN_LED_MAX; ++i) {
+ struct bwn_led *led = &sc->sc_leds[i];
+ int on;
+
+ if (led->led_act == BWN_LED_ACT_UNKN ||
+ led->led_act == BWN_LED_ACT_NULL)
+ continue;
+
+ if ((led->led_flags & BWN_LED_F_BLINK) &&
+ nstate != IEEE80211_S_INIT)
+ continue;
+
+ switch (led->led_act) {
+ case BWN_LED_ACT_ON: /* Always on */
+ on = 1;
+ break;
+ case BWN_LED_ACT_OFF: /* Always off */
+ case BWN_LED_ACT_5GHZ: /* TODO: 11A */
+ on = 0;
+ break;
+ default:
+ on = 1;
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ on = 0;
+ break;
+ case IEEE80211_S_RUN:
+ if (led->led_act == BWN_LED_ACT_11G &&
+ ic->ic_curmode != IEEE80211_MODE_11G)
+ on = 0;
+ break;
+ default:
+ if (led->led_act == BWN_LED_ACT_ASSOC)
+ on = 0;
+ break;
+ }
+ break;
+ }
+
+ val = bwn_led_onoff(led, val, on);
+ }
+ BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
+}
+
+static void
+bwn_led_event(struct bwn_mac *mac, int event)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_led *led = sc->sc_blink_led;
+ int rate;
+
+ if (event == BWN_LED_EVENT_POLL) {
+ if ((led->led_flags & BWN_LED_F_POLLABLE) == 0)
+ return;
+ if (ticks - sc->sc_led_ticks < sc->sc_led_idle)
+ return;
+ }
+
+ sc->sc_led_ticks = ticks;
+ if (sc->sc_led_blinking)
+ return;
+
+ switch (event) {
+ case BWN_LED_EVENT_RX:
+ rate = sc->sc_rx_rate;
+ break;
+ case BWN_LED_EVENT_TX:
+ rate = sc->sc_tx_rate;
+ break;
+ case BWN_LED_EVENT_POLL:
+ rate = 0;
+ break;
+ default:
+ panic("unknown LED event %d\n", event);
+ break;
+ }
+ bwn_led_blink_start(mac, bwn_led_duration[rate].on_dur,
+ bwn_led_duration[rate].off_dur);
+}
+
+static void
+bwn_led_blink_start(struct bwn_mac *mac, int on_dur, int off_dur)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_led *led = sc->sc_blink_led;
+ uint16_t val;
+
+ val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
+ val = bwn_led_onoff(led, val, 1);
+ BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
+
+ if (led->led_flags & BWN_LED_F_SLOW) {
+ BWN_LED_SLOWDOWN(on_dur);
+ BWN_LED_SLOWDOWN(off_dur);
+ }
+
+ sc->sc_led_blinking = 1;
+ sc->sc_led_blink_offdur = off_dur;
+
+ callout_reset(&sc->sc_led_blink_ch, on_dur, bwn_led_blink_next, mac);
+}
+
+static void
+bwn_led_blink_next(void *arg)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t val;
+
+ val = BWN_READ_2(mac, BWN_GPIO_CONTROL);
+ val = bwn_led_onoff(sc->sc_blink_led, val, 0);
+ BWN_WRITE_2(mac, BWN_GPIO_CONTROL, val);
+
+ callout_reset(&sc->sc_led_blink_ch, sc->sc_led_blink_offdur,
+ bwn_led_blink_end, mac);
+}
+
+static void
+bwn_led_blink_end(void *arg)
+{
+ struct bwn_mac *mac = arg;
+ struct bwn_softc *sc = mac->mac_sc;
+
+ sc->sc_led_blinking = 0;
+}
+
+static int
+bwn_suspend(device_t dev)
+{
+ struct bwn_softc *sc = device_get_softc(dev);
+
+ bwn_stop(sc, 1);
+ return (0);
+}
+
+static int
+bwn_resume(device_t dev)
+{
+ struct bwn_softc *sc = device_get_softc(dev);
+ struct ifnet *ifp = sc->sc_ifp;
+
+ if (ifp->if_flags & IFF_UP)
+ bwn_init(sc);
+ return (0);
+}
+
+static void
+bwn_rfswitch(void *arg)
+{
+ struct bwn_softc *sc = arg;
+ struct bwn_mac *mac = sc->sc_curmac;
+ int cur = 0, prev = 0;
+
+ KASSERT(mac->mac_status >= BWN_MAC_STATUS_STARTED,
+ ("%s: invalid MAC status %d", __func__, mac->mac_status));
+
+ if (mac->mac_phy.rf_rev >= 3 || mac->mac_phy.type == BWN_PHYTYPE_LP) {
+ if (!(BWN_READ_4(mac, BWN_RF_HWENABLED_HI)
+ & BWN_RF_HWENABLED_HI_MASK))
+ cur = 1;
+ } else {
+ if (BWN_READ_2(mac, BWN_RF_HWENABLED_LO)
+ & BWN_RF_HWENABLED_LO_MASK)
+ cur = 1;
+ }
+
+ if (mac->mac_flags & BWN_MAC_FLAG_RADIO_ON)
+ prev = 1;
+
+ if (cur != prev) {
+ if (cur)
+ mac->mac_flags |= BWN_MAC_FLAG_RADIO_ON;
+ else
+ mac->mac_flags &= ~BWN_MAC_FLAG_RADIO_ON;
+
+ device_printf(sc->sc_dev,
+ "status of RF switch is changed to %s\n",
+ cur ? "ON" : "OFF");
+ if (cur != mac->mac_phy.rf_on) {
+ if (cur)
+ bwn_rf_turnon(mac);
+ else
+ bwn_rf_turnoff(mac);
+ }
+ }
+
+ callout_schedule(&sc->sc_rfswitch_ch, hz);
+}
+
+static void
+bwn_phy_lp_init_pre(struct bwn_mac *mac)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_lp *plp = &phy->phy_lp;
+
+ plp->plp_antenna = BWN_ANT_DEFAULT;
+}
+
+static int
+bwn_phy_lp_init(struct bwn_mac *mac)
+{
+ static const struct bwn_stxtable tables[] = {
+ { 2, 6, 0x3d, 3, 0x01 }, { 1, 12, 0x4c, 1, 0x01 },
+ { 1, 8, 0x50, 0, 0x7f }, { 0, 8, 0x44, 0, 0xff },
+ { 1, 0, 0x4a, 0, 0xff }, { 0, 4, 0x4d, 0, 0xff },
+ { 1, 4, 0x4e, 0, 0xff }, { 0, 12, 0x4f, 0, 0x0f },
+ { 1, 0, 0x4f, 4, 0x0f }, { 3, 0, 0x49, 0, 0x0f },
+ { 4, 3, 0x46, 4, 0x07 }, { 3, 15, 0x46, 0, 0x01 },
+ { 4, 0, 0x46, 1, 0x07 }, { 3, 8, 0x48, 4, 0x07 },
+ { 3, 11, 0x48, 0, 0x0f }, { 3, 4, 0x49, 4, 0x0f },
+ { 2, 15, 0x45, 0, 0x01 }, { 5, 13, 0x52, 4, 0x07 },
+ { 6, 0, 0x52, 7, 0x01 }, { 5, 3, 0x41, 5, 0x07 },
+ { 5, 6, 0x41, 0, 0x0f }, { 5, 10, 0x42, 5, 0x07 },
+ { 4, 15, 0x42, 0, 0x01 }, { 5, 0, 0x42, 1, 0x07 },
+ { 4, 11, 0x43, 4, 0x0f }, { 4, 7, 0x43, 0, 0x0f },
+ { 4, 6, 0x45, 1, 0x01 }, { 2, 7, 0x40, 4, 0x0f },
+ { 2, 11, 0x40, 0, 0x0f }
+ };
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ const struct bwn_stxtable *st;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ int i, error;
+ uint16_t tmp;
+
+ bwn_phy_lp_readsprom(mac); /* XXX bad place */
+ bwn_phy_lp_bbinit(mac);
+
+ /* initialize RF */
+ BWN_PHY_SET(mac, BWN_PHY_4WIRECTL, 0x2);
+ DELAY(1);
+ BWN_PHY_MASK(mac, BWN_PHY_4WIRECTL, 0xfffd);
+ DELAY(1);
+
+ if (mac->mac_phy.rf_ver == 0x2062)
+ bwn_phy_lp_b2062_init(mac);
+ else {
+ bwn_phy_lp_b2063_init(mac);
+
+ /* synchronize stx table. */
+ for (i = 0; i < N(tables); i++) {
+ st = &tables[i];
+ tmp = BWN_RF_READ(mac, st->st_rfaddr);
+ tmp >>= st->st_rfshift;
+ tmp <<= st->st_physhift;
+ BWN_PHY_SETMASK(mac,
+ BWN_PHY_OFDM(0xf2 + st->st_phyoffset),
+ ~(st->st_mask << st->st_physhift), tmp);
+ }
+
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf0), 0x5f80);
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xf1), 0);
+ }
+
+ /* calibrate RC */
+ if (mac->mac_phy.rev >= 2)
+ bwn_phy_lp_rxcal_r2(mac);
+ else if (!plp->plp_rccap) {
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ bwn_phy_lp_rccal_r12(mac);
+ } else
+ bwn_phy_lp_set_rccap(mac);
+
+ error = bwn_phy_lp_switch_channel(mac, 7);
+ if (error)
+ device_printf(sc->sc_dev,
+ "failed to change channel 7 (%d)\n", error);
+ bwn_phy_lp_txpctl_init(mac);
+ bwn_phy_lp_calib(mac);
+ return (0);
+}
+
+static uint16_t
+bwn_phy_lp_read(struct bwn_mac *mac, uint16_t reg)
+{
+
+ BWN_WRITE_2(mac, BWN_PHYCTL, reg);
+ return (BWN_READ_2(mac, BWN_PHYDATA));
+}
+
+static void
+bwn_phy_lp_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
+{
+
+ BWN_WRITE_2(mac, BWN_PHYCTL, reg);
+ BWN_WRITE_2(mac, BWN_PHYDATA, value);
+}
+
+static void
+bwn_phy_lp_maskset(struct bwn_mac *mac, uint16_t reg, uint16_t mask,
+ uint16_t set)
+{
+
+ BWN_WRITE_2(mac, BWN_PHYCTL, reg);
+ BWN_WRITE_2(mac, BWN_PHYDATA,
+ (BWN_READ_2(mac, BWN_PHYDATA) & mask) | set);
+}
+
+static uint16_t
+bwn_phy_lp_rf_read(struct bwn_mac *mac, uint16_t reg)
+{
+
+ KASSERT(reg != 1, ("unaccessible register %d", reg));
+ if (mac->mac_phy.rev < 2 && reg != 0x4001)
+ reg |= 0x100;
+ if (mac->mac_phy.rev >= 2)
+ reg |= 0x200;
+ BWN_WRITE_2(mac, BWN_RFCTL, reg);
+ return BWN_READ_2(mac, BWN_RFDATALO);
+}
+
+static void
+bwn_phy_lp_rf_write(struct bwn_mac *mac, uint16_t reg, uint16_t value)
+{
+
+ KASSERT(reg != 1, ("unaccessible register %d", reg));
+ BWN_WRITE_2(mac, BWN_RFCTL, reg);
+ BWN_WRITE_2(mac, BWN_RFDATALO, value);
+}
+
+static void
+bwn_phy_lp_rf_onoff(struct bwn_mac *mac, int on)
+{
+
+ if (on) {
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xe0ff);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2,
+ (mac->mac_phy.rev >= 2) ? 0xf7f7 : 0xffe7);
+ return;
+ }
+
+ if (mac->mac_phy.rev >= 2) {
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x83ff);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0x80ff);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xdfff);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0808);
+ return;
+ }
+
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xe0ff);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1f00);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfcff);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x0018);
+}
+
+static int
+bwn_phy_lp_switch_channel(struct bwn_mac *mac, uint32_t chan)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_lp *plp = &phy->phy_lp;
+ int error;
+
+ if (phy->rf_ver == 0x2063) {
+ error = bwn_phy_lp_b2063_switch_channel(mac, chan);
+ if (error)
+ return (error);
+ } else {
+ error = bwn_phy_lp_b2062_switch_channel(mac, chan);
+ if (error)
+ return (error);
+ bwn_phy_lp_set_anafilter(mac, chan);
+ bwn_phy_lp_set_gaintbl(mac, ieee80211_ieee2mhz(chan, 0));
+ }
+
+ plp->plp_chan = chan;
+ BWN_WRITE_2(mac, BWN_CHANNEL, chan);
+ return (0);
+}
+
+static uint32_t
+bwn_phy_lp_get_default_chan(struct bwn_mac *mac)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ device_printf(sc->sc_dev, "correct?\n");
+
+ return (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 1 : 36);
+}
+
+static void
+bwn_phy_lp_set_antenna(struct bwn_mac *mac, int antenna)
+{
+ struct bwn_phy *phy = &mac->mac_phy;
+ struct bwn_phy_lp *plp = &phy->phy_lp;
+
+ if (phy->rev >= 2 || antenna > BWN_ANTAUTO1)
+ return;
+
+ bwn_hf_write(mac, bwn_hf_read(mac) & ~BWN_HF_UCODE_ANTDIV_HELPER);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffd, antenna & 0x2);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfffe, antenna & 0x1);
+ bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_UCODE_ANTDIV_HELPER);
+ plp->plp_antenna = antenna;
+}
+
+static void
+bwn_phy_lp_task_60s(struct bwn_mac *mac)
+{
+
+ bwn_phy_lp_calib(mac);
+}
+
+static void
+bwn_phy_lp_readsprom(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct siba_sprom *sprom = &siba->siba_sprom;
+
+ device_printf(sc->sc_dev, "XXX using %dghz\n",
+ IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? 2 : 5);
+
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ plp->plp_txisoband_m = sprom->tri2g;
+ plp->plp_bxarch = sprom->bxa2g;
+ plp->plp_rxpwroffset = sprom->rxpo2g;
+ plp->plp_rssivf = sprom->rssismf2g;
+ plp->plp_rssivc = sprom->rssismc2g;
+ plp->plp_rssigs = sprom->rssisav2g;
+ return;
+ }
+
+ plp->plp_txisoband_l = sprom->tri5gl;
+ plp->plp_txisoband_m = sprom->tri5g;
+ plp->plp_txisoband_h = sprom->tri5gh;
+ plp->plp_bxarch = sprom->bxa5g;
+ plp->plp_rxpwroffset = sprom->rxpo5g;
+ plp->plp_rssivf = sprom->rssismf5g;
+ plp->plp_rssivc = sprom->rssismc5g;
+ plp->plp_rssigs = sprom->rssisav5g;
+}
+
+static void
+bwn_phy_lp_bbinit(struct bwn_mac *mac)
+{
+
+ bwn_phy_lp_tblinit(mac);
+ if (mac->mac_phy.rev >= 2)
+ bwn_phy_lp_bbinit_r2(mac);
+ else
+ bwn_phy_lp_bbinit_r01(mac);
+}
+
+static void
+bwn_phy_lp_txpctl_init(struct bwn_mac *mac)
+{
+ struct bwn_txgain gain_2ghz = { 4, 12, 12, 0 };
+ struct bwn_txgain gain_5ghz = { 7, 15, 14, 0 };
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ bwn_phy_lp_set_txgain(mac,
+ IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan) ? &gain_2ghz : &gain_5ghz);
+ bwn_phy_lp_set_bbmult(mac, 150);
+}
+
+static void
+bwn_phy_lp_calib(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ const struct bwn_rxcompco *rc = NULL;
+ struct bwn_txgain ogain;
+ int i, omode, oafeovr, orf, obbmult;
+ uint8_t mode, fc = 0;
+
+ if (plp->plp_chanfullcal != plp->plp_chan) {
+ plp->plp_chanfullcal = plp->plp_chan;
+ fc = 1;
+ }
+
+ bwn_mac_suspend(mac);
+
+ /* BlueTooth Coexistance Override */
+ BWN_WRITE_2(mac, BWN_BTCOEX_CTL, 0x3);
+ BWN_WRITE_2(mac, BWN_BTCOEX_TXCTL, 0xff);
+
+ if (mac->mac_phy.rev >= 2)
+ bwn_phy_lp_digflt_save(mac);
+ bwn_phy_lp_get_txpctlmode(mac);
+ mode = plp->plp_txpctlmode;
+ bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
+ if (mac->mac_phy.rev == 0 && mode != BWN_PHYLP_TXPCTL_OFF)
+ bwn_phy_lp_bugfix(mac);
+ if (mac->mac_phy.rev >= 2 && fc == 1) {
+ bwn_phy_lp_get_txpctlmode(mac);
+ omode = plp->plp_txpctlmode;
+ oafeovr = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40;
+ if (oafeovr)
+ ogain = bwn_phy_lp_get_txgain(mac);
+ orf = BWN_PHY_READ(mac, BWN_PHY_RF_PWR_OVERRIDE) & 0xff;
+ obbmult = bwn_phy_lp_get_bbmult(mac);
+ bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
+ if (oafeovr)
+ bwn_phy_lp_set_txgain(mac, &ogain);
+ bwn_phy_lp_set_bbmult(mac, obbmult);
+ bwn_phy_lp_set_txpctlmode(mac, omode);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00, orf);
+ }
+ bwn_phy_lp_set_txpctlmode(mac, mode);
+ if (mac->mac_phy.rev >= 2)
+ bwn_phy_lp_digflt_restore(mac);
+
+ /* do RX IQ Calculation; assumes that noise is true. */
+ if (siba->siba_chipid == 0x5354) {
+ for (i = 0; i < N(bwn_rxcompco_5354); i++) {
+ if (bwn_rxcompco_5354[i].rc_chan == plp->plp_chan)
+ rc = &bwn_rxcompco_5354[i];
+ }
+ } else if (mac->mac_phy.rev >= 2)
+ rc = &bwn_rxcompco_r2;
+ else {
+ for (i = 0; i < N(bwn_rxcompco_r12); i++) {
+ if (bwn_rxcompco_r12[i].rc_chan == plp->plp_chan)
+ rc = &bwn_rxcompco_r12[i];
+ }
+ }
+ if (rc == NULL)
+ goto fail;
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, rc->rc_c1);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, rc->rc_c0 << 8);
+
+ bwn_phy_lp_set_trsw_over(mac, 1 /* TX */, 0 /* RX */);
+
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7, 0);
+ } else {
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf, 0);
+ }
+
+ bwn_phy_lp_set_rxgain(mac, 0x2d5d);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
+ bwn_phy_lp_set_deaf(mac, 0);
+ /* XXX no checking return value? */
+ (void)bwn_phy_lp_calc_rx_iq_comp(mac, 0xfff0);
+ bwn_phy_lp_clear_deaf(mac, 0);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffc);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfff7);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffdf);
+
+ /* disable RX GAIN override. */
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xfffe);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffef);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xffbf);
+ if (mac->mac_phy.rev >= 2) {
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfbff);
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xe5), 0xfff7);
+ }
+ } else {
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfdff);
+ }
+
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfffe);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xf7ff);
+fail:
+ bwn_mac_enable(mac);
+}
+
+static void
+bwn_phy_lp_switch_analog(struct bwn_mac *mac, int on)
+{
+
+ if (on) {
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xfff8);
+ return;
+ }
+
+ BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVRVAL, 0x0007);
+ BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x0007);
+}
+
+static int
+bwn_phy_lp_b2063_switch_channel(struct bwn_mac *mac, uint8_t chan)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ static const struct bwn_b206x_chan *bc = NULL;
+ uint32_t count, freqref, freqvco, freqxtal, val[3], timeout, timeoutref,
+ tmp[6];
+ uint16_t old, scale, tmp16;
+ int i, div;
+
+ for (i = 0; i < N(bwn_b2063_chantable); i++) {
+ if (bwn_b2063_chantable[i].bc_chan == chan) {
+ bc = &bwn_b2063_chantable[i];
+ break;
+ }
+ }
+ if (bc == NULL)
+ return (EINVAL);
+
+ BWN_RF_WRITE(mac, BWN_B2063_LOGEN_VCOBUF1, bc->bc_data[0]);
+ BWN_RF_WRITE(mac, BWN_B2063_LOGEN_MIXER2, bc->bc_data[1]);
+ BWN_RF_WRITE(mac, BWN_B2063_LOGEN_BUF2, bc->bc_data[2]);
+ BWN_RF_WRITE(mac, BWN_B2063_LOGEN_RCCR1, bc->bc_data[3]);
+ BWN_RF_WRITE(mac, BWN_B2063_A_RX_1ST3, bc->bc_data[4]);
+ BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND1, bc->bc_data[5]);
+ BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND4, bc->bc_data[6]);
+ BWN_RF_WRITE(mac, BWN_B2063_A_RX_2ND7, bc->bc_data[7]);
+ BWN_RF_WRITE(mac, BWN_B2063_A_RX_PS6, bc->bc_data[8]);
+ BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL2, bc->bc_data[9]);
+ BWN_RF_WRITE(mac, BWN_B2063_TX_RF_CTL5, bc->bc_data[10]);
+ BWN_RF_WRITE(mac, BWN_B2063_PA_CTL11, bc->bc_data[11]);
+
+ old = BWN_RF_READ(mac, BWN_B2063_COM15);
+ BWN_RF_SET(mac, BWN_B2063_COM15, 0x1e);
+
+ freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
+ freqvco = bc->bc_freq << ((bc->bc_freq > 4000) ? 1 : 2);
+ freqref = freqxtal * 3;
+ div = (freqxtal <= 26000000 ? 1 : 2);
+ timeout = ((((8 * freqxtal) / (div * 5000000)) + 1) >> 1) - 1;
+ timeoutref = ((((8 * freqxtal) / (div * (timeout + 1))) +
+ 999999) / 1000000) + 1;
+
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB3, 0x2);
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB6,
+ 0xfff8, timeout >> 2);
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
+ 0xff9f,timeout << 5);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB5, timeoutref);
+
+ val[0] = bwn_phy_lp_roundup(freqxtal, 1000000, 16);
+ val[1] = bwn_phy_lp_roundup(freqxtal, 1000000 * div, 16);
+ val[2] = bwn_phy_lp_roundup(freqvco, 3, 16);
+
+ count = (bwn_phy_lp_roundup(val[2], val[1] + 16, 16) * (timeout + 1) *
+ (timeoutref + 1)) - 1;
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_VCO_CALIB7,
+ 0xf0, count >> 8);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_VCO_CALIB8, count & 0xff);
+
+ tmp[0] = ((val[2] * 62500) / freqref) << 4;
+ tmp[1] = ((val[2] * 62500) % freqref) << 4;
+ while (tmp[1] >= freqref) {
+ tmp[0]++;
+ tmp[1] -= freqref;
+ }
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG1, 0xffe0, tmp[0] >> 4);
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfe0f, tmp[0] << 4);
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_SG2, 0xfff0, tmp[0] >> 16);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG3, (tmp[1] >> 8) & 0xff);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_SG4, tmp[1] & 0xff);
+
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF1, 0xb9);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF2, 0x88);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF3, 0x28);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_LF4, 0x63);
+
+ tmp[2] = ((41 * (val[2] - 3000)) /1200) + 27;
+ tmp[3] = bwn_phy_lp_roundup(132000 * tmp[0], 8451, 16);
+
+ if ((tmp[3] + tmp[2] - 1) / tmp[2] > 60) {
+ scale = 1;
+ tmp[4] = ((tmp[3] + tmp[2]) / (tmp[2] << 1)) - 8;
+ } else {
+ scale = 0;
+ tmp[4] = ((tmp[3] + (tmp[2] >> 1)) / tmp[2]) - 8;
+ }
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffc0, tmp[4]);
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP2, 0xffbf, scale << 6);
+
+ tmp[5] = bwn_phy_lp_roundup(100 * val[0], val[2], 16) * (tmp[4] * 8) *
+ (scale + 1);
+ if (tmp[5] > 150)
+ tmp[5] = 0;
+
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffe0, tmp[5]);
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_CP3, 0xffdf, scale << 5);
+
+ BWN_RF_SETMASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfffb, 0x4);
+ if (freqxtal > 26000000)
+ BWN_RF_SET(mac, BWN_B2063_JTAG_XTAL_12, 0x2);
+ else
+ BWN_RF_MASK(mac, BWN_B2063_JTAG_XTAL_12, 0xfd);
+
+ if (val[0] == 45)
+ BWN_RF_SET(mac, BWN_B2063_JTAG_VCO1, 0x2);
+ else
+ BWN_RF_MASK(mac, BWN_B2063_JTAG_VCO1, 0xfd);
+
+ BWN_RF_SET(mac, BWN_B2063_PLL_SP2, 0x3);
+ DELAY(1);
+ BWN_RF_MASK(mac, BWN_B2063_PLL_SP2, 0xfffc);
+
+ /* VCO Calibration */
+ BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, ~0x40);
+ tmp16 = BWN_RF_READ(mac, BWN_B2063_JTAG_CALNRST) & 0xf8;
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16);
+ DELAY(1);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x4);
+ DELAY(1);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x6);
+ DELAY(1);
+ BWN_RF_WRITE(mac, BWN_B2063_JTAG_CALNRST, tmp16 | 0x7);
+ DELAY(300);
+ BWN_RF_SET(mac, BWN_B2063_PLL_SP1, 0x40);
+
+ BWN_RF_WRITE(mac, BWN_B2063_COM15, old);
+ return (0);
+}
+
+static int
+bwn_phy_lp_b2062_switch_channel(struct bwn_mac *mac, uint8_t chan)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ const struct bwn_b206x_chan *bc = NULL;
+ uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
+ uint32_t tmp[9];
+ int i;
+
+ for (i = 0; i < N(bwn_b2062_chantable); i++) {
+ if (bwn_b2062_chantable[i].bc_chan == chan) {
+ bc = &bwn_b2062_chantable[i];
+ break;
+ }
+ }
+
+ if (bc == NULL)
+ return (EINVAL);
+
+ BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL14, 0x04);
+ BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE0, bc->bc_data[0]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE2, bc->bc_data[1]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_LGENATUNE3, bc->bc_data[2]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_TX_TUNE, bc->bc_data[3]);
+ BWN_RF_WRITE(mac, BWN_B2062_S_LGENG_CTL1, bc->bc_data[4]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL5, bc->bc_data[5]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_LGENACTL6, bc->bc_data[6]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_TX_PGA, bc->bc_data[7]);
+ BWN_RF_WRITE(mac, BWN_B2062_N_TX_PAD, bc->bc_data[8]);
+
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xcc);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0x07);
+ bwn_phy_lp_b2062_reset_pllbias(mac);
+ tmp[0] = freqxtal / 1000;
+ tmp[1] = plp->plp_div * 1000;
+ tmp[2] = tmp[1] * ieee80211_ieee2mhz(chan, 0);
+ if (ieee80211_ieee2mhz(chan, 0) < 4000)
+ tmp[2] *= 2;
+ tmp[3] = 48 * tmp[0];
+ tmp[5] = tmp[2] / tmp[3];
+ tmp[6] = tmp[2] % tmp[3];
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL26, tmp[5]);
+ tmp[4] = tmp[6] * 0x100;
+ tmp[5] = tmp[4] / tmp[3];
+ tmp[6] = tmp[4] % tmp[3];
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL27, tmp[5]);
+ tmp[4] = tmp[6] * 0x100;
+ tmp[5] = tmp[4] / tmp[3];
+ tmp[6] = tmp[4] % tmp[3];
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL28, tmp[5]);
+ tmp[4] = tmp[6] * 0x100;
+ tmp[5] = tmp[4] / tmp[3];
+ tmp[6] = tmp[4] % tmp[3];
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL29,
+ tmp[5] + ((2 * tmp[6]) / tmp[3]));
+ tmp[7] = BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL19);
+ tmp[8] = ((2 * tmp[2] * (tmp[7] + 1)) + (3 * tmp[0])) / (6 * tmp[0]);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL23, (tmp[8] >> 8) + 16);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL24, tmp[8] & 0xff);
+
+ bwn_phy_lp_b2062_vco_calib(mac);
+ if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL33, 0xfc);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL34, 0);
+ bwn_phy_lp_b2062_reset_pllbias(mac);
+ bwn_phy_lp_b2062_vco_calib(mac);
+ if (BWN_RF_READ(mac, BWN_B2062_S_RFPLLCTL3) & 0x10) {
+ BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
+ return (EIO);
+ }
+ }
+ BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL14, ~0x04);
+ return (0);
+}
+
+static void
+bwn_phy_lp_set_anafilter(struct bwn_mac *mac, uint8_t channel)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ uint16_t tmp = (channel == 14);
+
+ if (mac->mac_phy.rev < 2) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xfcff, tmp << 9);
+ if ((mac->mac_phy.rev == 1) && (plp->plp_rccap))
+ bwn_phy_lp_set_rccap(mac);
+ return;
+ }
+
+ BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, 0x3f);
+}
+
+static void
+bwn_phy_lp_set_gaintbl(struct bwn_mac *mac, uint32_t freq)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint16_t iso, tmp[3];
+
+ KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
+
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ iso = plp->plp_txisoband_m;
+ else if (freq <= 5320)
+ iso = plp->plp_txisoband_l;
+ else if (freq <= 5700)
+ iso = plp->plp_txisoband_m;
+ else
+ iso = plp->plp_txisoband_h;
+
+ tmp[0] = ((iso - 26) / 12) << 12;
+ tmp[1] = tmp[0] + 0x1000;
+ tmp[2] = tmp[0] + 0x2000;
+
+ bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), 3, tmp);
+ bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), 3, tmp);
+}
+
+static void
+bwn_phy_lp_digflt_save(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ int i;
+ static const uint16_t addr[] = {
+ BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
+ BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
+ BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
+ BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
+ BWN_PHY_OFDM(0xcf),
+ };
+ static const uint16_t val[] = {
+ 0xde5e, 0xe832, 0xe331, 0x4d26,
+ 0x0026, 0x1420, 0x0020, 0xfe08,
+ 0x0008,
+ };
+
+ for (i = 0; i < N(addr); i++) {
+ plp->plp_digfilt[i] = BWN_PHY_READ(mac, addr[i]);
+ BWN_PHY_WRITE(mac, addr[i], val[i]);
+ }
+}
+
+static void
+bwn_phy_lp_get_txpctlmode(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ uint16_t ctl;
+
+ ctl = BWN_PHY_READ(mac, BWN_PHY_TX_PWR_CTL_CMD);
+ switch (ctl & BWN_PHY_TX_PWR_CTL_CMD_MODE) {
+ case BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF:
+ plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_OFF;
+ break;
+ case BWN_PHY_TX_PWR_CTL_CMD_MODE_SW:
+ plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_SW;
+ break;
+ case BWN_PHY_TX_PWR_CTL_CMD_MODE_HW:
+ plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_ON_HW;
+ break;
+ default:
+ plp->plp_txpctlmode = BWN_PHYLP_TXPCTL_UNKNOWN;
+ device_printf(sc->sc_dev, "unknown command mode\n");
+ break;
+ }
+}
+
+static void
+bwn_phy_lp_set_txpctlmode(struct bwn_mac *mac, uint8_t mode)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ uint16_t ctl;
+ uint8_t old;
+
+ bwn_phy_lp_get_txpctlmode(mac);
+ old = plp->plp_txpctlmode;
+ if (old == mode)
+ return;
+ plp->plp_txpctlmode = mode;
+
+ if (old != BWN_PHYLP_TXPCTL_ON_HW && mode == BWN_PHYLP_TXPCTL_ON_HW) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD, 0xff80,
+ plp->plp_tssiidx);
+ BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_NNUM,
+ 0x8fff, ((uint16_t)plp->plp_tssinpt << 16));
+
+ /* disable TX GAIN override */
+ if (mac->mac_phy.rev < 2)
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfeff);
+ else {
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xff7f);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xbfff);
+ }
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVR, 0xffbf);
+
+ plp->plp_txpwridx = -1;
+ }
+ if (mac->mac_phy.rev >= 2) {
+ if (mode == BWN_PHYLP_TXPCTL_ON_HW)
+ BWN_PHY_SET(mac, BWN_PHY_OFDM(0xd0), 0x2);
+ else
+ BWN_PHY_MASK(mac, BWN_PHY_OFDM(0xd0), 0xfffd);
+ }
+
+ /* writes TX Power Control mode */
+ switch (plp->plp_txpctlmode) {
+ case BWN_PHYLP_TXPCTL_OFF:
+ ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF;
+ break;
+ case BWN_PHYLP_TXPCTL_ON_HW:
+ ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_HW;
+ break;
+ case BWN_PHYLP_TXPCTL_ON_SW:
+ ctl = BWN_PHY_TX_PWR_CTL_CMD_MODE_SW;
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+ BWN_PHY_SETMASK(mac, BWN_PHY_TX_PWR_CTL_CMD,
+ (uint16_t)~BWN_PHY_TX_PWR_CTL_CMD_MODE, ctl);
+}
+
+static void
+bwn_phy_lp_bugfix(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ const unsigned int size = 256;
+ struct bwn_txgain tg;
+ uint32_t rxcomp, txgain, coeff, rfpwr, *tabs;
+ uint16_t tssinpt, tssiidx, value[2];
+ uint8_t mode;
+ int8_t txpwridx;
+
+ tabs = (uint32_t *)malloc(sizeof(uint32_t) * size, M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (tabs == NULL) {
+ device_printf(sc->sc_dev, "failed to allocate buffer.\n");
+ return;
+ }
+
+ bwn_phy_lp_get_txpctlmode(mac);
+ mode = plp->plp_txpctlmode;
+ txpwridx = plp->plp_txpwridx;
+ tssinpt = plp->plp_tssinpt;
+ tssiidx = plp->plp_tssiidx;
+
+ bwn_tab_read_multi(mac,
+ (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
+ BWN_TAB_4(7, 0x140), size, tabs);
+
+ bwn_phy_lp_tblinit(mac);
+ bwn_phy_lp_bbinit(mac);
+ bwn_phy_lp_txpctl_init(mac);
+ bwn_phy_lp_rf_onoff(mac, 1);
+ bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
+
+ bwn_tab_write_multi(mac,
+ (mac->mac_phy.rev < 2) ? BWN_TAB_4(10, 0x140) :
+ BWN_TAB_4(7, 0x140), size, tabs);
+
+ BWN_WRITE_2(mac, BWN_CHANNEL, plp->plp_chan);
+ plp->plp_tssinpt = tssinpt;
+ plp->plp_tssiidx = tssiidx;
+ bwn_phy_lp_set_anafilter(mac, plp->plp_chan);
+ if (txpwridx != -1) {
+ /* set TX power by index */
+ plp->plp_txpwridx = txpwridx;
+ bwn_phy_lp_get_txpctlmode(mac);
+ if (plp->plp_txpctlmode != BWN_PHYLP_TXPCTL_OFF)
+ bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_ON_SW);
+ if (mac->mac_phy.rev >= 2) {
+ rxcomp = bwn_tab_read(mac,
+ BWN_TAB_4(7, txpwridx + 320));
+ txgain = bwn_tab_read(mac,
+ BWN_TAB_4(7, txpwridx + 192));
+ tg.tg_pad = (txgain >> 16) & 0xff;
+ tg.tg_gm = txgain & 0xff;
+ tg.tg_pga = (txgain >> 8) & 0xff;
+ tg.tg_dac = (rxcomp >> 28) & 0xff;
+ bwn_phy_lp_set_txgain(mac, &tg);
+ } else {
+ rxcomp = bwn_tab_read(mac,
+ BWN_TAB_4(10, txpwridx + 320));
+ txgain = bwn_tab_read(mac,
+ BWN_TAB_4(10, txpwridx + 192));
+ BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ 0xf800, (txgain >> 4) & 0x7fff);
+ bwn_phy_lp_set_txgain_dac(mac, txgain & 0x7);
+ bwn_phy_lp_set_txgain_pa(mac, (txgain >> 24) & 0x7f);
+ }
+ bwn_phy_lp_set_bbmult(mac, (rxcomp >> 20) & 0xff);
+
+ /* set TX IQCC */
+ value[0] = (rxcomp >> 10) & 0x3ff;
+ value[1] = rxcomp & 0x3ff;
+ bwn_tab_write_multi(mac, BWN_TAB_2(0, 80), 2, value);
+
+ coeff = bwn_tab_read(mac,
+ (mac->mac_phy.rev >= 2) ? BWN_TAB_4(7, txpwridx + 448) :
+ BWN_TAB_4(10, txpwridx + 448));
+ bwn_tab_write(mac, BWN_TAB_2(0, 85), coeff & 0xffff);
+ if (mac->mac_phy.rev >= 2) {
+ rfpwr = bwn_tab_read(mac,
+ BWN_TAB_4(7, txpwridx + 576));
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_PWR_OVERRIDE, 0xff00,
+ rfpwr & 0xffff);
+ }
+ bwn_phy_lp_set_txgain_override(mac);
+ }
+ if (plp->plp_rccap)
+ bwn_phy_lp_set_rccap(mac);
+ bwn_phy_lp_set_antenna(mac, plp->plp_antenna);
+ bwn_phy_lp_set_txpctlmode(mac, mode);
+ free(tabs, M_DEVBUF);
+}
+
+static void
+bwn_phy_lp_digflt_restore(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ int i;
+ static const uint16_t addr[] = {
+ BWN_PHY_OFDM(0xc1), BWN_PHY_OFDM(0xc2),
+ BWN_PHY_OFDM(0xc3), BWN_PHY_OFDM(0xc4),
+ BWN_PHY_OFDM(0xc5), BWN_PHY_OFDM(0xc6),
+ BWN_PHY_OFDM(0xc7), BWN_PHY_OFDM(0xc8),
+ BWN_PHY_OFDM(0xcf),
+ };
+
+ for (i = 0; i < N(addr); i++)
+ BWN_PHY_WRITE(mac, addr[i], plp->plp_digfilt[i]);
+}
+
+static void
+bwn_phy_lp_tblinit(struct bwn_mac *mac)
+{
+ uint32_t freq = ieee80211_ieee2mhz(bwn_phy_lp_get_default_chan(mac), 0);
+
+ if (mac->mac_phy.rev < 2) {
+ bwn_phy_lp_tblinit_r01(mac);
+ bwn_phy_lp_tblinit_txgain(mac);
+ bwn_phy_lp_set_gaintbl(mac, freq);
+ return;
+ }
+
+ bwn_phy_lp_tblinit_r2(mac);
+ bwn_phy_lp_tblinit_txgain(mac);
+}
+
+struct bwn_wpair {
+ uint16_t reg;
+ uint16_t value;
+};
+
+struct bwn_smpair {
+ uint16_t offset;
+ uint16_t mask;
+ uint16_t set;
+};
+
+static void
+bwn_phy_lp_bbinit_r2(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ static const struct bwn_wpair v1[] = {
+ { BWN_PHY_AFE_DAC_CTL, 0x50 },
+ { BWN_PHY_AFE_CTL, 0x8800 },
+ { BWN_PHY_AFE_CTL_OVR, 0 },
+ { BWN_PHY_AFE_CTL_OVRVAL, 0 },
+ { BWN_PHY_RF_OVERRIDE_0, 0 },
+ { BWN_PHY_RF_OVERRIDE_2, 0 },
+ { BWN_PHY_OFDM(0xf9), 0 },
+ { BWN_PHY_TR_LOOKUP_1, 0 }
+ };
+ static const struct bwn_smpair v2[] = {
+ { BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0xb4 },
+ { BWN_PHY_DCOFFSETTRANSIENT, 0xf8ff, 0x200 },
+ { BWN_PHY_DCOFFSETTRANSIENT, 0xff00, 0x7f },
+ { BWN_PHY_GAINDIRECTMISMATCH, 0xff0f, 0x40 },
+ { BWN_PHY_PREAMBLECONFIRMTO, 0xff00, 0x2 }
+ };
+ static const struct bwn_smpair v3[] = {
+ { BWN_PHY_OFDM(0xfe), 0xffe0, 0x1f },
+ { BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
+ { BWN_PHY_OFDM(0x100), 0xff00, 0x19 },
+ { BWN_PHY_OFDM(0xff), 0x03ff, 0x3c00 },
+ { BWN_PHY_OFDM(0xfe), 0xfc1f, 0x3e0 },
+ { BWN_PHY_OFDM(0xff), 0xffe0, 0xc },
+ { BWN_PHY_OFDM(0x100), 0x00ff, 0x1900 },
+ { BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800 },
+ { BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x12 },
+ { BWN_PHY_GAINMISMATCH, 0x0fff, 0x9000 },
+
+ };
+ int i;
+
+ for (i = 0; i < N(v1); i++)
+ BWN_PHY_WRITE(mac, v1[i].reg, v1[i].value);
+ BWN_PHY_SET(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x10);
+ for (i = 0; i < N(v2); i++)
+ BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask, v2[i].set);
+
+ BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x4000);
+ BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x2000);
+ BWN_PHY_SET(mac, BWN_PHY_OFDM(0x10a), 0x1);
+ if (siba->siba_board_rev >= 0x18) {
+ bwn_tab_write(mac, BWN_TAB_4(17, 65), 0xec);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x14);
+ } else {
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0x10a), 0xff01, 0x10);
+ }
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0xff00, 0xf4);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xdf), 0x00ff, 0xf100);
+ BWN_PHY_WRITE(mac, BWN_PHY_CLIPTHRESH, 0x48);
+ BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0xff00, 0x46);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe4), 0xff00, 0x10);
+ BWN_PHY_SETMASK(mac, BWN_PHY_PWR_THRESH1, 0xfff0, 0x9);
+ BWN_PHY_MASK(mac, BWN_PHY_GAINDIRECTMISMATCH, ~0xf);
+ BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5500);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0xa0);
+ BWN_PHY_SETMASK(mac, BWN_PHY_GAINDIRECTMISMATCH, 0xe0ff, 0x300);
+ BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2a00);
+ if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
+ BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xa);
+ } else {
+ BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x1e00);
+ BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0xd);
+ }
+ for (i = 0; i < N(v3); i++)
+ BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask, v3[i].set);
+ if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
+ bwn_tab_write(mac, BWN_TAB_2(0x08, 0x14), 0);
+ bwn_tab_write(mac, BWN_TAB_2(0x08, 0x12), 0x40);
+ }
+
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x40);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0xb00);
+ BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x6);
+ BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0x9d00);
+ BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0xff00, 0xa1);
+ BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
+ } else
+ BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, ~0x40);
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0xff00, 0xb3);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00);
+ BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB, 0xff00, plp->plp_rxpwroffset);
+ BWN_PHY_SET(mac, BWN_PHY_RESET_CTL, 0x44);
+ BWN_PHY_WRITE(mac, BWN_PHY_RESET_CTL, 0x80);
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, 0xa954);
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_1,
+ 0x2000 | ((uint16_t)plp->plp_rssigs << 10) |
+ ((uint16_t)plp->plp_rssivc << 4) | plp->plp_rssivf);
+
+ if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
+ BWN_PHY_SET(mac, BWN_PHY_AFE_ADC_CTL_0, 0x1c);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_CTL, 0x00ff, 0x8800);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_1, 0xfc3c, 0x0400);
+ }
+
+ bwn_phy_lp_digflt_save(mac);
+}
+
+static void
+bwn_phy_lp_bbinit_r01(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ static const struct bwn_smpair v1[] = {
+ { BWN_PHY_CLIPCTRTHRESH, 0xffe0, 0x0005 },
+ { BWN_PHY_CLIPCTRTHRESH, 0xfc1f, 0x0180 },
+ { BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x3c00 },
+ { BWN_PHY_GAINDIRECTMISMATCH, 0xfff0, 0x0005 },
+ { BWN_PHY_GAIN_MISMATCH_LIMIT, 0xffc0, 0x001a },
+ { BWN_PHY_CRS_ED_THRESH, 0xff00, 0x00b3 },
+ { BWN_PHY_CRS_ED_THRESH, 0x00ff, 0xad00 }
+ };
+ static const struct bwn_smpair v2[] = {
+ { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_1, 0x3f00, 0x0900 },
+ { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
+ { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0400 },
+ { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0b00 },
+ { BWN_PHY_TR_LOOKUP_5, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_5, 0xc0ff, 0x0900 },
+ { BWN_PHY_TR_LOOKUP_6, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_6, 0xc0ff, 0x0b00 },
+ { BWN_PHY_TR_LOOKUP_7, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_7, 0xc0ff, 0x0900 },
+ { BWN_PHY_TR_LOOKUP_8, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_8, 0xc0ff, 0x0b00 }
+ };
+ static const struct bwn_smpair v3[] = {
+ { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0001 },
+ { BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0400 },
+ { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0001 },
+ { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0500 },
+ { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
+ { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0800 },
+ { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
+ { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0a00 }
+ };
+ static const struct bwn_smpair v4[] = {
+ { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x0004 },
+ { BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0800 },
+ { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x0004 },
+ { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0c00 },
+ { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0002 },
+ { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0100 },
+ { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0002 },
+ { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0300 }
+ };
+ static const struct bwn_smpair v5[] = {
+ { BWN_PHY_TR_LOOKUP_1, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_1, 0xc0ff, 0x0900 },
+ { BWN_PHY_TR_LOOKUP_2, 0xffc0, 0x000a },
+ { BWN_PHY_TR_LOOKUP_2, 0xc0ff, 0x0b00 },
+ { BWN_PHY_TR_LOOKUP_3, 0xffc0, 0x0006 },
+ { BWN_PHY_TR_LOOKUP_3, 0xc0ff, 0x0500 },
+ { BWN_PHY_TR_LOOKUP_4, 0xffc0, 0x0006 },
+ { BWN_PHY_TR_LOOKUP_4, 0xc0ff, 0x0700 }
+ };
+ int i;
+ uint16_t tmp, tmp2;
+
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf7ff);
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0);
+ BWN_PHY_SET(mac, BWN_PHY_AFE_DAC_CTL, 0x0004);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDMSYNCTHRESH0, 0xff00, 0x0078);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CLIPCTRTHRESH, 0x83ff, 0x5800);
+ BWN_PHY_WRITE(mac, BWN_PHY_ADC_COMPENSATION_CTL, 0x0016);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_ADC_CTL_0, 0xfff8, 0x0004);
+ BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0x00ff, 0x5400);
+ BWN_PHY_SETMASK(mac, BWN_PHY_HIGAINDB, 0x00ff, 0x2400);
+ BWN_PHY_SETMASK(mac, BWN_PHY_LOWGAINDB, 0x00ff, 0x2100);
+ BWN_PHY_SETMASK(mac, BWN_PHY_VERYLOWGAINDB, 0xff00, 0x0006);
+ BWN_PHY_MASK(mac, BWN_PHY_RX_RADIO_CTL, 0xfffe);
+ for (i = 0; i < N(v1); i++)
+ BWN_PHY_SETMASK(mac, v1[i].offset, v1[i].mask, v1[i].set);
+ BWN_PHY_SETMASK(mac, BWN_PHY_INPUT_PWRDB,
+ 0xff00, plp->plp_rxpwroffset);
+ if ((siba->siba_sprom.bf_lo & BWN_BFL_FEM) &&
+ ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ||
+ (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF))) {
+ siba_cc_pmu_set_ldovolt(&siba->siba_cc, SIBA_LDO_PAREF, 0x28);
+ siba_cc_pmu_set_ldoparef(&siba->siba_cc, 1);
+ if (mac->mac_phy.rev == 0)
+ BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT,
+ 0xffcf, 0x0010);
+ bwn_tab_write(mac, BWN_TAB_2(11, 7), 60);
+ } else {
+ siba_cc_pmu_set_ldoparef(&siba->siba_cc, 0);
+ BWN_PHY_SETMASK(mac, BWN_PHY_LP_RF_SIGNAL_LUT, 0xffcf, 0x0020);
+ bwn_tab_write(mac, BWN_TAB_2(11, 7), 100);
+ }
+ tmp = plp->plp_rssivf | plp->plp_rssivc << 4 | 0xa000;
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_RSSI_CTL_0, tmp);
+ if (siba->siba_sprom.bf_hi & BWN_BFH_RSSIINV)
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x0aaa);
+ else
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_RSSI_CTL_1, 0xf000, 0x02aa);
+ bwn_tab_write(mac, BWN_TAB_2(11, 1), 24);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RX_RADIO_CTL,
+ 0xfff9, (plp->plp_bxarch << 1));
+ if (mac->mac_phy.rev == 1 &&
+ (siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT)) {
+ for (i = 0; i < N(v2); i++)
+ BWN_PHY_SETMASK(mac, v2[i].offset, v2[i].mask,
+ v2[i].set);
+ } else if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan) ||
+ (siba->siba_board_type == 0x048a) || ((mac->mac_phy.rev == 0) &&
+ (siba->siba_sprom.bf_lo & BWN_BFL_FEM))) {
+ for (i = 0; i < N(v3); i++)
+ BWN_PHY_SETMASK(mac, v3[i].offset, v3[i].mask,
+ v3[i].set);
+ } else if (mac->mac_phy.rev == 1 ||
+ (siba->siba_sprom.bf_lo & BWN_BFL_FEM)) {
+ for (i = 0; i < N(v4); i++)
+ BWN_PHY_SETMASK(mac, v4[i].offset, v4[i].mask,
+ v4[i].set);
+ } else {
+ for (i = 0; i < N(v5); i++)
+ BWN_PHY_SETMASK(mac, v5[i].offset, v5[i].mask,
+ v5[i].set);
+ }
+ if (mac->mac_phy.rev == 1 &&
+ (siba->siba_sprom.bf_hi & BWN_BFH_LDO_PAREF)) {
+ BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_5, BWN_PHY_TR_LOOKUP_1);
+ BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_6, BWN_PHY_TR_LOOKUP_2);
+ BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_7, BWN_PHY_TR_LOOKUP_3);
+ BWN_PHY_COPY(mac, BWN_PHY_TR_LOOKUP_8, BWN_PHY_TR_LOOKUP_4);
+ }
+ if ((siba->siba_sprom.bf_hi & BWN_BFH_FEM_BT) &&
+ (siba->siba_chipid == 0x5354) &&
+ (siba->siba_chippkg == SIBA_CHIPPACK_BCM4712S)) {
+ BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0006);
+ BWN_PHY_WRITE(mac, BWN_PHY_GPIO_SELECT, 0x0005);
+ BWN_PHY_WRITE(mac, BWN_PHY_GPIO_OUTEN, 0xffff);
+ bwn_hf_write(mac, bwn_hf_read(mac) | BWN_HF_PR45960W);
+ }
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x8000);
+ BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x0040);
+ BWN_PHY_SETMASK(mac, BWN_PHY_MINPWR_LEVEL, 0x00ff, 0xa400);
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xf0ff, 0x0b00);
+ BWN_PHY_SETMASK(mac, BWN_PHY_SYNCPEAKCNT, 0xfff8, 0x0007);
+ BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xfff8, 0x0003);
+ BWN_PHY_SETMASK(mac, BWN_PHY_DSSS_CONFIRM_CNT, 0xffc7, 0x0020);
+ BWN_PHY_MASK(mac, BWN_PHY_IDLEAFTERPKTRXTO, 0x00ff);
+ } else {
+ BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0x7fff);
+ BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xffbf);
+ }
+ if (mac->mac_phy.rev == 1) {
+ tmp = BWN_PHY_READ(mac, BWN_PHY_CLIPCTRTHRESH);
+ tmp2 = (tmp & 0x03e0) >> 5;
+ tmp2 |= tmp2 << 5;
+ BWN_PHY_WRITE(mac, BWN_PHY_4C3, tmp2);
+ tmp = BWN_PHY_READ(mac, BWN_PHY_GAINDIRECTMISMATCH);
+ tmp2 = (tmp & 0x1f00) >> 8;
+ tmp2 |= tmp2 << 5;
+ BWN_PHY_WRITE(mac, BWN_PHY_4C4, tmp2);
+ tmp = BWN_PHY_READ(mac, BWN_PHY_VERYLOWGAINDB);
+ tmp2 = tmp & 0x00ff;
+ tmp2 |= tmp << 8;
+ BWN_PHY_WRITE(mac, BWN_PHY_4C5, tmp2);
+ }
+}
+
+struct bwn_b2062_freq {
+ uint16_t freq;
+ uint8_t value[6];
+};
+
+static void
+bwn_phy_lp_b2062_init(struct bwn_mac *mac)
+{
+#define CALC_CTL7(freq, div) \
+ (((800000000 * (div) + (freq)) / (2 * (freq)) - 8) & 0xff)
+#define CALC_CTL18(freq, div) \
+ ((((100 * (freq) + 16000000 * (div)) / (32000000 * (div))) - 1) & 0xff)
+#define CALC_CTL19(freq, div) \
+ ((((2 * (freq) + 1000000 * (div)) / (2000000 * (div))) - 1) & 0xff)
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ static const struct bwn_b2062_freq freqdata_tab[] = {
+ { 12000, { 6, 6, 6, 6, 10, 6 } },
+ { 13000, { 4, 4, 4, 4, 11, 7 } },
+ { 14400, { 3, 3, 3, 3, 12, 7 } },
+ { 16200, { 3, 3, 3, 3, 13, 8 } },
+ { 18000, { 2, 2, 2, 2, 14, 8 } },
+ { 19200, { 1, 1, 1, 1, 14, 9 } }
+ };
+ static const struct bwn_wpair v1[] = {
+ { BWN_B2062_N_TXCTL3, 0 },
+ { BWN_B2062_N_TXCTL4, 0 },
+ { BWN_B2062_N_TXCTL5, 0 },
+ { BWN_B2062_N_TXCTL6, 0 },
+ { BWN_B2062_N_PDNCTL0, 0x40 },
+ { BWN_B2062_N_PDNCTL0, 0 },
+ { BWN_B2062_N_CALIB_TS, 0x10 },
+ { BWN_B2062_N_CALIB_TS, 0 }
+ };
+ const struct bwn_b2062_freq *f = NULL;
+ uint32_t xtalfreq, ref;
+ unsigned int i;
+
+ bwn_phy_lp_b2062_tblinit(mac);
+
+ for (i = 0; i < N(v1); i++)
+ BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
+ if (mac->mac_phy.rev > 0)
+ BWN_RF_WRITE(mac, BWN_B2062_S_BG_CTL1,
+ (BWN_RF_READ(mac, BWN_B2062_N_COM2) >> 1) | 0x80);
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ BWN_RF_SET(mac, BWN_B2062_N_TSSI_CTL0, 0x1);
+ else
+ BWN_RF_MASK(mac, BWN_B2062_N_TSSI_CTL0, ~0x1);
+
+ KASSERT(siba->siba_cc.scc_caps & SIBA_CC_CAPS_PMU,
+ ("%s:%d: fail", __func__, __LINE__));
+ xtalfreq = siba->siba_cc.scc_pmu.freq * 1000;
+ KASSERT(xtalfreq != 0, ("%s:%d: fail", __func__, __LINE__));
+
+ if (xtalfreq <= 30000000) {
+ plp->plp_div = 1;
+ BWN_RF_MASK(mac, BWN_B2062_S_RFPLLCTL1, 0xfffb);
+ } else {
+ plp->plp_div = 2;
+ BWN_RF_SET(mac, BWN_B2062_S_RFPLLCTL1, 0x4);
+ }
+
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL7,
+ CALC_CTL7(xtalfreq, plp->plp_div));
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL18,
+ CALC_CTL18(xtalfreq, plp->plp_div));
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL19,
+ CALC_CTL19(xtalfreq, plp->plp_div));
+
+ ref = (1000 * plp->plp_div + 2 * xtalfreq) / (2000 * plp->plp_div);
+ ref &= 0xffff;
+ for (i = 0; i < N(freqdata_tab); i++) {
+ if (ref < freqdata_tab[i].freq) {
+ f = &freqdata_tab[i];
+ break;
+ }
+ }
+ if (f == NULL)
+ f = &freqdata_tab[N(freqdata_tab) - 1];
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL8,
+ ((uint16_t)(f->value[1]) << 4) | f->value[0]);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL9,
+ ((uint16_t)(f->value[3]) << 4) | f->value[2]);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL10, f->value[4]);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL11, f->value[5]);
+#undef CALC_CTL7
+#undef CALC_CTL18
+#undef CALC_CTL19
+}
+
+static void
+bwn_phy_lp_b2063_init(struct bwn_mac *mac)
+{
+
+ bwn_phy_lp_b2063_tblinit(mac);
+ BWN_RF_WRITE(mac, BWN_B2063_LOGEN_SP5, 0);
+ BWN_RF_SET(mac, BWN_B2063_COM8, 0x38);
+ BWN_RF_WRITE(mac, BWN_B2063_REG_SP1, 0x56);
+ BWN_RF_MASK(mac, BWN_B2063_RX_BB_CTL2, ~0x2);
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0);
+ BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP6, 0x20);
+ BWN_RF_WRITE(mac, BWN_B2063_TX_RF_SP9, 0x40);
+ if (mac->mac_phy.rev == 2) {
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0xa0);
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP4, 0xa0);
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x18);
+ } else {
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP3, 0x20);
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP2, 0x20);
+ }
+}
+
+static void
+bwn_phy_lp_rxcal_r2(struct bwn_mac *mac)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ static const struct bwn_wpair v1[] = {
+ { BWN_B2063_RX_BB_SP8, 0x0 },
+ { BWN_B2063_RC_CALIB_CTL1, 0x7e },
+ { BWN_B2063_RC_CALIB_CTL1, 0x7c },
+ { BWN_B2063_RC_CALIB_CTL2, 0x15 },
+ { BWN_B2063_RC_CALIB_CTL3, 0x70 },
+ { BWN_B2063_RC_CALIB_CTL4, 0x52 },
+ { BWN_B2063_RC_CALIB_CTL5, 0x1 },
+ { BWN_B2063_RC_CALIB_CTL1, 0x7d }
+ };
+ static const struct bwn_wpair v2[] = {
+ { BWN_B2063_TX_BB_SP3, 0x0 },
+ { BWN_B2063_RC_CALIB_CTL1, 0x7e },
+ { BWN_B2063_RC_CALIB_CTL1, 0x7c },
+ { BWN_B2063_RC_CALIB_CTL2, 0x55 },
+ { BWN_B2063_RC_CALIB_CTL3, 0x76 }
+ };
+ uint32_t freqxtal = siba->siba_cc.scc_pmu.freq * 1000;
+ int i;
+ uint8_t tmp;
+
+ tmp = BWN_RF_READ(mac, BWN_B2063_RX_BB_SP8) & 0xff;
+
+ for (i = 0; i < 2; i++)
+ BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
+ BWN_RF_MASK(mac, BWN_B2063_PLL_SP1, 0xf7);
+ for (i = 2; i < N(v1); i++)
+ BWN_RF_WRITE(mac, v1[i].reg, v1[i].value);
+ for (i = 0; i < 10000; i++) {
+ if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
+ break;
+ DELAY(1000);
+ }
+
+ if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
+ BWN_RF_WRITE(mac, BWN_B2063_RX_BB_SP8, tmp);
+
+ tmp = BWN_RF_READ(mac, BWN_B2063_TX_BB_SP3) & 0xff;
+
+ for (i = 0; i < N(v2); i++)
+ BWN_RF_WRITE(mac, v2[i].reg, v2[i].value);
+ if (freqxtal == 24000000) {
+ BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0xfc);
+ BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x0);
+ } else {
+ BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL4, 0x13);
+ BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL5, 0x1);
+ }
+ BWN_RF_WRITE(mac, BWN_B2063_PA_SP7, 0x7d);
+ for (i = 0; i < 10000; i++) {
+ if (BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2)
+ break;
+ DELAY(1000);
+ }
+ if (!(BWN_RF_READ(mac, BWN_B2063_RC_CALIB_CTL6) & 0x2))
+ BWN_RF_WRITE(mac, BWN_B2063_TX_BB_SP3, tmp);
+ BWN_RF_WRITE(mac, BWN_B2063_RC_CALIB_CTL1, 0x7e);
+}
+
+static void
+bwn_phy_lp_rccal_r12(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct bwn_phy_lp_iq_est ie;
+ struct bwn_txgain tx_gains;
+ static const uint32_t pwrtbl[21] = {
+ 0x10000, 0x10557, 0x10e2d, 0x113e0, 0x10f22, 0x0ff64,
+ 0x0eda2, 0x0e5d4, 0x0efd1, 0x0fbe8, 0x0b7b8, 0x04b35,
+ 0x01a5e, 0x00a0b, 0x00444, 0x001fd, 0x000ff, 0x00088,
+ 0x0004c, 0x0002c, 0x0001a,
+ };
+ uint32_t npwr, ipwr, sqpwr, tmp;
+ int loopback, i, j, sum, error;
+ uint16_t save[7];
+ uint8_t txo, bbmult, txpctlmode;
+
+ error = bwn_phy_lp_switch_channel(mac, 7);
+ if (error)
+ device_printf(sc->sc_dev,
+ "failed to change channel to 7 (%d)\n", error);
+ txo = (BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR) & 0x40) ? 1 : 0;
+ bbmult = bwn_phy_lp_get_bbmult(mac);
+ if (txo)
+ tx_gains = bwn_phy_lp_get_txgain(mac);
+
+ save[0] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_0);
+ save[1] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_VAL_0);
+ save[2] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVR);
+ save[3] = BWN_PHY_READ(mac, BWN_PHY_AFE_CTL_OVRVAL);
+ save[4] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2);
+ save[5] = BWN_PHY_READ(mac, BWN_PHY_RF_OVERRIDE_2_VAL);
+ save[6] = BWN_PHY_READ(mac, BWN_PHY_LP_PHY_CTL);
+
+ bwn_phy_lp_get_txpctlmode(mac);
+ txpctlmode = plp->plp_txpctlmode;
+ bwn_phy_lp_set_txpctlmode(mac, BWN_PHYLP_TXPCTL_OFF);
+
+ /* disable CRS */
+ bwn_phy_lp_set_deaf(mac, 1);
+ bwn_phy_lp_set_trsw_over(mac, 0, 1);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffb);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x4);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfff7);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x10);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffdf);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x20);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xffbf);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x7);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x38);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0x100);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfdff);
+ BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL0, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL1, 1);
+ BWN_PHY_WRITE(mac, BWN_PHY_PS_CTL_OVERRIDE_VAL2, 0x20);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfbff);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xf7ff);
+ BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0);
+ BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, 0x45af);
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, 0x3ff);
+
+ loopback = bwn_phy_lp_loopback(mac);
+ if (loopback == -1)
+ goto done;
+ bwn_phy_lp_set_rxgain_idx(mac, loopback);
+ BWN_PHY_SETMASK(mac, BWN_PHY_LP_PHY_CTL, 0xffbf, 0x40);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xfff8, 0x1);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xffc7, 0x8);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL, 0xff3f, 0xc0);
+
+ tmp = 0;
+ memset(&ie, 0, sizeof(ie));
+ for (i = 128; i <= 159; i++) {
+ BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2, i);
+ sum = 0;
+ for (j = 5; j <= 25; j++) {
+ bwn_phy_lp_ddfs_turnon(mac, 1, 1, j, j, 0);
+ if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
+ goto done;
+ sqpwr = ie.ie_ipwr + ie.ie_qpwr;
+ ipwr = ((pwrtbl[j - 5] >> 3) + 1) >> 1;
+ npwr = bwn_phy_lp_roundup(sqpwr, (j == 5) ? sqpwr : 0,
+ 12);
+ sum += ((ipwr - npwr) * (ipwr - npwr));
+ if ((i == 128) || (sum < tmp)) {
+ plp->plp_rccap = i;
+ tmp = sum;
+ }
+ }
+ }
+ bwn_phy_lp_ddfs_turnoff(mac);
+done:
+ /* restore CRS */
+ bwn_phy_lp_clear_deaf(mac, 1);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_0, 0xff80);
+ BWN_PHY_MASK(mac, BWN_PHY_RF_OVERRIDE_2, 0xfc00);
+
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_VAL_0, save[1]);
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_0, save[0]);
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVRVAL, save[3]);
+ BWN_PHY_WRITE(mac, BWN_PHY_AFE_CTL_OVR, save[2]);
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2_VAL, save[5]);
+ BWN_PHY_WRITE(mac, BWN_PHY_RF_OVERRIDE_2, save[4]);
+ BWN_PHY_WRITE(mac, BWN_PHY_LP_PHY_CTL, save[6]);
+
+ bwn_phy_lp_set_bbmult(mac, bbmult);
+ if (txo)
+ bwn_phy_lp_set_txgain(mac, &tx_gains);
+ bwn_phy_lp_set_txpctlmode(mac, txpctlmode);
+ if (plp->plp_rccap)
+ bwn_phy_lp_set_rccap(mac);
+}
+
+static void
+bwn_phy_lp_set_rccap(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ uint8_t rc_cap = (plp->plp_rccap & 0x1f) >> 1;
+
+ if (mac->mac_phy.rev == 1)
+ rc_cap = MIN(rc_cap + 5, 15);
+
+ BWN_RF_WRITE(mac, BWN_B2062_N_RXBB_CALIB2,
+ MAX(plp->plp_rccap - 4, 0x80));
+ BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, rc_cap | 0x80);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RXG_CNT16,
+ ((plp->plp_rccap & 0x1f) >> 2) | 0x80);
+}
+
+static uint32_t
+bwn_phy_lp_roundup(uint32_t value, uint32_t div, uint8_t pre)
+{
+ uint32_t i, q, r;
+
+ if (div == 0)
+ return (0);
+
+ for (i = 0, q = value / div, r = value % div; i < pre; i++) {
+ q <<= 1;
+ if (r << 1 >= div) {
+ q++;
+ r = (r << 1) - div;
+ }
+ }
+ if (r << 1 >= div)
+ q++;
+ return (q);
+}
+
+static void
+bwn_phy_lp_b2062_reset_pllbias(struct bwn_mac *mac)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0xff);
+ DELAY(20);
+ if (siba->siba_chipid == 0x5354) {
+ BWN_RF_WRITE(mac, BWN_B2062_N_COM1, 4);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 4);
+ } else {
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL2, 0);
+ }
+ DELAY(5);
+}
+
+static void
+bwn_phy_lp_b2062_vco_calib(struct bwn_mac *mac)
+{
+
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x42);
+ BWN_RF_WRITE(mac, BWN_B2062_S_RFPLLCTL21, 0x62);
+ DELAY(200);
+}
+
+static void
+bwn_phy_lp_b2062_tblinit(struct bwn_mac *mac)
+{
+#define FLAG_A 0x01
+#define FLAG_G 0x02
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ static const struct bwn_b206x_rfinit_entry bwn_b2062_init_tab[] = {
+ { BWN_B2062_N_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_PDNCTL1, 0x0, 0xca, FLAG_G, },
+ { BWN_B2062_N_PDNCTL3, 0x0, 0x0, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_PDNCTL4, 0x15, 0x2a, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_LGENC, 0xDB, 0xff, FLAG_A, },
+ { BWN_B2062_N_LGENATUNE0, 0xdd, 0x0, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_LGENATUNE2, 0xdd, 0x0, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_LGENATUNE3, 0x77, 0xB5, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_LGENACTL3, 0x0, 0xff, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_LGENACTL7, 0x33, 0x33, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_RXA_CTL1, 0x0, 0x0, FLAG_G, },
+ { BWN_B2062_N_RXBB_CTL0, 0x82, 0x80, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_RXBB_GAIN1, 0x4, 0x4, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_RXBB_GAIN2, 0x0, 0x0, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_TXCTL4, 0x3, 0x3, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_TXCTL5, 0x2, 0x2, FLAG_A | FLAG_G, },
+ { BWN_B2062_N_TX_TUNE, 0x88, 0x1b, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_COM4, 0x1, 0x0, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_PDS_CTL0, 0xff, 0xff, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_LGENG_CTL0, 0xf8, 0xd8, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_LGENG_CTL1, 0x3c, 0x24, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_LGENG_CTL8, 0x88, 0x80, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_LGENG_CTL10, 0x88, 0x80, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL0, 0x98, 0x98, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL1, 0x10, 0x10, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL5, 0x43, 0x43, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL6, 0x47, 0x47, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL7, 0xc, 0xc, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL8, 0x11, 0x11, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL9, 0x11, 0x11, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL10, 0xe, 0xe, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL11, 0x8, 0x8, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL12, 0x33, 0x33, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL13, 0xa, 0xa, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL14, 0x6, 0x6, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL18, 0x3e, 0x3e, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL19, 0x13, 0x13, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL21, 0x62, 0x62, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL22, 0x7, 0x7, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL23, 0x16, 0x16, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL24, 0x5c, 0x5c, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL25, 0x95, 0x95, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL30, 0xa0, 0xa0, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL31, 0x4, 0x4, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL33, 0xcc, 0xcc, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RFPLLCTL34, 0x7, 0x7, FLAG_A | FLAG_G, },
+ { BWN_B2062_S_RXG_CNT8, 0xf, 0xf, FLAG_A, },
+ };
+ const struct bwn_b206x_rfinit_entry *br;
+ unsigned int i;
+
+ for (i = 0; i < N(bwn_b2062_init_tab); i++) {
+ br = &bwn_b2062_init_tab[i];
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ if (br->br_flags & FLAG_G)
+ BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
+ } else {
+ if (br->br_flags & FLAG_A)
+ BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
+ }
+ }
+#undef FLAG_A
+#undef FLAG_B
+}
+
+static void
+bwn_phy_lp_b2063_tblinit(struct bwn_mac *mac)
+{
+#define FLAG_A 0x01
+#define FLAG_G 0x02
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ static const struct bwn_b206x_rfinit_entry bwn_b2063_init_tab[] = {
+ { BWN_B2063_COM1, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM10, 0x1, 0x0, FLAG_A, },
+ { BWN_B2063_COM16, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM17, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM18, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM19, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM20, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM21, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM22, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM23, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_COM24, 0x0, 0x0, FLAG_G, },
+ { BWN_B2063_LOGEN_SP1, 0xe8, 0xd4, FLAG_A | FLAG_G, },
+ { BWN_B2063_LOGEN_SP2, 0xa7, 0x53, FLAG_A | FLAG_G, },
+ { BWN_B2063_LOGEN_SP4, 0xf0, 0xf, FLAG_A | FLAG_G, },
+ { BWN_B2063_G_RX_SP1, 0x1f, 0x5e, FLAG_G, },
+ { BWN_B2063_G_RX_SP2, 0x7f, 0x7e, FLAG_G, },
+ { BWN_B2063_G_RX_SP3, 0x30, 0xf0, FLAG_G, },
+ { BWN_B2063_G_RX_SP7, 0x7f, 0x7f, FLAG_A | FLAG_G, },
+ { BWN_B2063_G_RX_SP10, 0xc, 0xc, FLAG_A | FLAG_G, },
+ { BWN_B2063_A_RX_SP1, 0x3c, 0x3f, FLAG_A, },
+ { BWN_B2063_A_RX_SP2, 0xfc, 0xfe, FLAG_A, },
+ { BWN_B2063_A_RX_SP7, 0x8, 0x8, FLAG_A | FLAG_G, },
+ { BWN_B2063_RX_BB_SP4, 0x60, 0x60, FLAG_A | FLAG_G, },
+ { BWN_B2063_RX_BB_SP8, 0x30, 0x30, FLAG_A | FLAG_G, },
+ { BWN_B2063_TX_RF_SP3, 0xc, 0xb, FLAG_A | FLAG_G, },
+ { BWN_B2063_TX_RF_SP4, 0x10, 0xf, FLAG_A | FLAG_G, },
+ { BWN_B2063_PA_SP1, 0x3d, 0xfd, FLAG_A | FLAG_G, },
+ { BWN_B2063_TX_BB_SP1, 0x2, 0x2, FLAG_A | FLAG_G, },
+ { BWN_B2063_BANDGAP_CTL1, 0x56, 0x56, FLAG_A | FLAG_G, },
+ { BWN_B2063_JTAG_VCO2, 0xF7, 0xF7, FLAG_A | FLAG_G, },
+ { BWN_B2063_G_RX_MIX3, 0x71, 0x71, FLAG_A | FLAG_G, },
+ { BWN_B2063_G_RX_MIX4, 0x71, 0x71, FLAG_A | FLAG_G, },
+ { BWN_B2063_A_RX_1ST2, 0xf0, 0x30, FLAG_A, },
+ { BWN_B2063_A_RX_PS6, 0x77, 0x77, FLAG_A | FLAG_G, },
+ { BWN_B2063_A_RX_MIX4, 0x3, 0x3, FLAG_A | FLAG_G, },
+ { BWN_B2063_A_RX_MIX5, 0xf, 0xf, FLAG_A | FLAG_G, },
+ { BWN_B2063_A_RX_MIX6, 0xf, 0xf, FLAG_A | FLAG_G, },
+ { BWN_B2063_RX_TIA_CTL1, 0x77, 0x77, FLAG_A | FLAG_G, },
+ { BWN_B2063_RX_TIA_CTL3, 0x77, 0x77, FLAG_A | FLAG_G, },
+ { BWN_B2063_RX_BB_CTL2, 0x4, 0x4, FLAG_A | FLAG_G, },
+ { BWN_B2063_PA_CTL1, 0x0, 0x4, FLAG_A, },
+ { BWN_B2063_VREG_CTL1, 0x3, 0x3, FLAG_A | FLAG_G, },
+ };
+ const struct bwn_b206x_rfinit_entry *br;
+ unsigned int i;
+
+ for (i = 0; i < N(bwn_b2063_init_tab); i++) {
+ br = &bwn_b2063_init_tab[i];
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ if (br->br_flags & FLAG_G)
+ BWN_RF_WRITE(mac, br->br_offset, br->br_valueg);
+ } else {
+ if (br->br_flags & FLAG_A)
+ BWN_RF_WRITE(mac, br->br_offset, br->br_valuea);
+ }
+ }
+#undef FLAG_A
+#undef FLAG_B
+}
+
+static void
+bwn_tab_read_multi(struct bwn_mac *mac, uint32_t typenoffset,
+ int count, void *_data)
+{
+ unsigned int i;
+ uint32_t offset, type;
+ uint8_t *data = _data;
+
+ type = BWN_TAB_GETTYPE(typenoffset);
+ offset = BWN_TAB_GETOFFSET(typenoffset);
+ KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
+
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+
+ for (i = 0; i < count; i++) {
+ switch (type) {
+ case BWN_TAB_8BIT:
+ *data = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
+ data++;
+ break;
+ case BWN_TAB_16BIT:
+ *((uint16_t *)data) = BWN_PHY_READ(mac,
+ BWN_PHY_TABLEDATALO);
+ data += 2;
+ break;
+ case BWN_TAB_32BIT:
+ *((uint32_t *)data) = BWN_PHY_READ(mac,
+ BWN_PHY_TABLEDATAHI);
+ *((uint32_t *)data) <<= 16;
+ *((uint32_t *)data) |= BWN_PHY_READ(mac,
+ BWN_PHY_TABLEDATALO);
+ data += 4;
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+ }
+}
+
+static void
+bwn_tab_write_multi(struct bwn_mac *mac, uint32_t typenoffset,
+ int count, const void *_data)
+{
+ uint32_t offset, type, value;
+ const uint8_t *data = _data;
+ unsigned int i;
+
+ type = BWN_TAB_GETTYPE(typenoffset);
+ offset = BWN_TAB_GETOFFSET(typenoffset);
+ KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
+
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+
+ for (i = 0; i < count; i++) {
+ switch (type) {
+ case BWN_TAB_8BIT:
+ value = *data;
+ data++;
+ KASSERT(!(value & ~0xff),
+ ("%s:%d: fail", __func__, __LINE__));
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
+ break;
+ case BWN_TAB_16BIT:
+ value = *((const uint16_t *)data);
+ data += 2;
+ KASSERT(!(value & ~0xffff),
+ ("%s:%d: fail", __func__, __LINE__));
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
+ break;
+ case BWN_TAB_32BIT:
+ value = *((const uint32_t *)data);
+ data += 4;
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+ }
+}
+
+static struct bwn_txgain
+bwn_phy_lp_get_txgain(struct bwn_mac *mac)
+{
+ struct bwn_txgain tg;
+ uint16_t tmp;
+
+ tg.tg_dac = (BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0x380) >> 7;
+ if (mac->mac_phy.rev < 2) {
+ tmp = BWN_PHY_READ(mac,
+ BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL) & 0x7ff;
+ tg.tg_gm = tmp & 0x0007;
+ tg.tg_pga = (tmp & 0x0078) >> 3;
+ tg.tg_pad = (tmp & 0x780) >> 7;
+ return (tg);
+ }
+
+ tmp = BWN_PHY_READ(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL);
+ tg.tg_pad = BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0xff;
+ tg.tg_gm = tmp & 0xff;
+ tg.tg_pga = (tmp >> 8) & 0xff;
+ return (tg);
+}
+
+static uint8_t
+bwn_phy_lp_get_bbmult(struct bwn_mac *mac)
+{
+
+ return (bwn_tab_read(mac, BWN_TAB_2(0, 87)) & 0xff00) >> 8;
+}
+
+static void
+bwn_phy_lp_set_txgain(struct bwn_mac *mac, struct bwn_txgain *tg)
+{
+ uint16_t pa;
+
+ if (mac->mac_phy.rev < 2) {
+ BWN_PHY_SETMASK(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL, 0xf800,
+ (tg->tg_pad << 7) | (tg->tg_pga << 3) | tg->tg_gm);
+ bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
+ bwn_phy_lp_set_txgain_override(mac);
+ return;
+ }
+
+ pa = bwn_phy_lp_get_pa_gain(mac);
+ BWN_PHY_WRITE(mac, BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL,
+ (tg->tg_pga << 8) | tg->tg_gm);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0x8000,
+ tg->tg_pad | (pa << 6));
+ BWN_PHY_WRITE(mac, BWN_PHY_OFDM(0xfc), (tg->tg_pga << 8) | tg->tg_gm);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x8000,
+ tg->tg_pad | (pa << 8));
+ bwn_phy_lp_set_txgain_dac(mac, tg->tg_dac);
+ bwn_phy_lp_set_txgain_override(mac);
+}
+
+static void
+bwn_phy_lp_set_bbmult(struct bwn_mac *mac, uint8_t bbmult)
+{
+
+ bwn_tab_write(mac, BWN_TAB_2(0, 87), (uint16_t)bbmult << 8);
+}
+
+static void
+bwn_phy_lp_set_trsw_over(struct bwn_mac *mac, uint8_t tx, uint8_t rx)
+{
+ uint16_t trsw = (tx << 1) | rx;
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffc, trsw);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x3);
+}
+
+static void
+bwn_phy_lp_set_rxgain(struct bwn_mac *mac, uint32_t gain)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint16_t ext_lna, high_gain, lna, low_gain, trsw, tmp;
+
+ if (mac->mac_phy.rev < 2) {
+ trsw = gain & 0x1;
+ lna = (gain & 0xfffc) | ((gain & 0xc) >> 2);
+ ext_lna = (gain & 2) >> 1;
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
+ 0xfbff, ext_lna << 10);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
+ 0xf7ff, ext_lna << 11);
+ BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, lna);
+ } else {
+ low_gain = gain & 0xffff;
+ high_gain = (gain >> 16) & 0xf;
+ ext_lna = (gain >> 21) & 0x1;
+ trsw = ~(gain >> 20) & 0x1;
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0xfffe, trsw);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
+ 0xfdff, ext_lna << 9);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
+ 0xfbff, ext_lna << 10);
+ BWN_PHY_WRITE(mac, BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL, low_gain);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff0, high_gain);
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ tmp = (gain >> 2) & 0x3;
+ BWN_PHY_SETMASK(mac, BWN_PHY_RF_OVERRIDE_2_VAL,
+ 0xe7ff, tmp<<11);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xe6), 0xffe7,
+ tmp << 3);
+ }
+ }
+
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x1);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x10);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x40);
+ if (mac->mac_phy.rev >= 2) {
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x400);
+ BWN_PHY_SET(mac, BWN_PHY_OFDM(0xe5), 0x8);
+ }
+ return;
+ }
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x200);
+}
+
+static void
+bwn_phy_lp_set_deaf(struct bwn_mac *mac, uint8_t user)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+
+ if (user)
+ plp->plp_crsusr_off = 1;
+ else
+ plp->plp_crssys_off = 1;
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x80);
+}
+
+static void
+bwn_phy_lp_clear_deaf(struct bwn_mac *mac, uint8_t user)
+{
+ struct bwn_phy_lp *plp = &mac->mac_phy.phy_lp;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ if (user)
+ plp->plp_crsusr_off = 0;
+ else
+ plp->plp_crssys_off = 0;
+
+ if (plp->plp_crsusr_off || plp->plp_crssys_off)
+ return;
+
+ if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x60);
+ else
+ BWN_PHY_SETMASK(mac, BWN_PHY_CRSGAIN_CTL, 0xff1f, 0x20);
+}
+
+static unsigned int
+bwn_sqrt(struct bwn_mac *mac, unsigned int x)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ /* Table holding (10 * sqrt(x)) for x between 1 and 256. */
+ static uint8_t sqrt_table[256] = {
+ 10, 14, 17, 20, 22, 24, 26, 28,
+ 30, 31, 33, 34, 36, 37, 38, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 50, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 60, 61, 62, 63,
+ 64, 64, 65, 66, 67, 67, 68, 69,
+ 70, 70, 71, 72, 72, 73, 74, 74,
+ 75, 76, 76, 77, 78, 78, 79, 80,
+ 80, 81, 81, 82, 83, 83, 84, 84,
+ 85, 86, 86, 87, 87, 88, 88, 89,
+ 90, 90, 91, 91, 92, 92, 93, 93,
+ 94, 94, 95, 95, 96, 96, 97, 97,
+ 98, 98, 99, 100, 100, 100, 101, 101,
+ 102, 102, 103, 103, 104, 104, 105, 105,
+ 106, 106, 107, 107, 108, 108, 109, 109,
+ 110, 110, 110, 111, 111, 112, 112, 113,
+ 113, 114, 114, 114, 115, 115, 116, 116,
+ 117, 117, 117, 118, 118, 119, 119, 120,
+ 120, 120, 121, 121, 122, 122, 122, 123,
+ 123, 124, 124, 124, 125, 125, 126, 126,
+ 126, 127, 127, 128, 128, 128, 129, 129,
+ 130, 130, 130, 131, 131, 131, 132, 132,
+ 133, 133, 133, 134, 134, 134, 135, 135,
+ 136, 136, 136, 137, 137, 137, 138, 138,
+ 138, 139, 139, 140, 140, 140, 141, 141,
+ 141, 142, 142, 142, 143, 143, 143, 144,
+ 144, 144, 145, 145, 145, 146, 146, 146,
+ 147, 147, 147, 148, 148, 148, 149, 149,
+ 150, 150, 150, 150, 151, 151, 151, 152,
+ 152, 152, 153, 153, 153, 154, 154, 154,
+ 155, 155, 155, 156, 156, 156, 157, 157,
+ 157, 158, 158, 158, 159, 159, 159, 160
+ };
+
+ if (x == 0)
+ return (0);
+ if (x >= 256) {
+ device_printf(sc->sc_dev,
+ "out of bounds of the square-root table (%d)\n", x);
+ return (16);
+ }
+ return (sqrt_table[x - 1] / 10);
+}
+
+static int
+bwn_phy_lp_calc_rx_iq_comp(struct bwn_mac *mac, uint16_t sample)
+{
+#define CALC_COEFF(_v, _x, _y, _z) do { \
+ int _t; \
+ _t = _x - 20; \
+ if (_t >= 0) { \
+ _v = ((_y << (30 - _x)) + (_z >> (1 + _t))) / (_z >> _t); \
+ } else { \
+ _v = ((_y << (30 - _x)) + (_z << (-1 - _t))) / (_z << -_t); \
+ } \
+} while (0)
+#define CALC_COEFF2(_v, _x, _y, _z) do { \
+ int _t; \
+ _t = _x - 11; \
+ if (_t >= 0) \
+ tmp[3] = (_y << (31 - _x)) / (_z >> _t); \
+ else \
+ tmp[3] = (_y << (31 - _x)) / (_z << -_t); \
+} while (0)
+ struct bwn_phy_lp_iq_est ie;
+ uint16_t v0, v1;
+ int tmp[2], ret;
+
+ v1 = BWN_PHY_READ(mac, BWN_PHY_RX_COMP_COEFF_S);
+ v0 = v1 >> 8;
+ v1 |= 0xff;
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, 0x00c0);
+ BWN_PHY_MASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff);
+
+ ret = bwn_phy_lp_rx_iq_est(mac, sample, 32, &ie);
+ if (ret == 0)
+ goto done;
+
+ if (ie.ie_ipwr + ie.ie_qpwr < 2) {
+ ret = 0;
+ goto done;
+ }
+
+ CALC_COEFF(tmp[0], bwn_nbits(ie.ie_iqprod), ie.ie_iqprod, ie.ie_ipwr);
+ CALC_COEFF2(tmp[1], bwn_nbits(ie.ie_qpwr), ie.ie_qpwr, ie.ie_ipwr);
+
+ tmp[1] = -bwn_sqrt(mac, tmp[1] - (tmp[0] * tmp[0]));
+ v0 = tmp[0] >> 3;
+ v1 = tmp[1] >> 4;
+done:
+ BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0xff00, v1);
+ BWN_PHY_SETMASK(mac, BWN_PHY_RX_COMP_COEFF_S, 0x00ff, v0 << 8);
+ return ret;
+#undef CALC_COEFF
+#undef CALC_COEFF2
+}
+
+static void
+bwn_phy_lp_tblinit_r01(struct bwn_mac *mac)
+{
+ static const uint16_t noisescale[] = {
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4,
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4,
+ 0xa4a4, 0xa4a4, 0x00a4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x4c00, 0x2d36, 0x0000, 0x0000, 0x4c00, 0x2d36,
+ };
+ static const uint16_t crsgainnft[] = {
+ 0x0366, 0x036a, 0x036f, 0x0364, 0x0367, 0x036d, 0x0374, 0x037f,
+ 0x036f, 0x037b, 0x038a, 0x0378, 0x0367, 0x036d, 0x0375, 0x0381,
+ 0x0374, 0x0381, 0x0392, 0x03a9, 0x03c4, 0x03e1, 0x0001, 0x001f,
+ 0x0040, 0x005e, 0x007f, 0x009e, 0x00bd, 0x00dd, 0x00fd, 0x011d,
+ 0x013d,
+ };
+ static const uint16_t filterctl[] = {
+ 0xa0fc, 0x10fc, 0x10db, 0x20b7, 0xff93, 0x10bf, 0x109b, 0x2077,
+ 0xff53, 0x0127,
+ };
+ static const uint32_t psctl[] = {
+ 0x00010000, 0x000000a0, 0x00040000, 0x00000048, 0x08080101,
+ 0x00000080, 0x08080101, 0x00000040, 0x08080101, 0x000000c0,
+ 0x08a81501, 0x000000c0, 0x0fe8fd01, 0x000000c0, 0x08300105,
+ 0x000000c0, 0x08080201, 0x000000c0, 0x08280205, 0x000000c0,
+ 0xe80802fe, 0x000000c7, 0x28080206, 0x000000c0, 0x08080202,
+ 0x000000c0, 0x0ba87602, 0x000000c0, 0x1068013d, 0x000000c0,
+ 0x10280105, 0x000000c0, 0x08880102, 0x000000c0, 0x08280106,
+ 0x000000c0, 0xe80801fd, 0x000000c7, 0xa8080115, 0x000000c0,
+ };
+ static const uint16_t ofdmcckgain_r0[] = {
+ 0x0001, 0x0001, 0x0001, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
+ 0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
+ 0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
+ 0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
+ 0x755d,
+ };
+ static const uint16_t ofdmcckgain_r1[] = {
+ 0x5000, 0x6000, 0x7000, 0x0001, 0x1001, 0x2001, 0x3001, 0x4001,
+ 0x5001, 0x6001, 0x7001, 0x7011, 0x7021, 0x2035, 0x2045, 0x2055,
+ 0x2065, 0x2075, 0x006d, 0x007d, 0x014d, 0x015d, 0x115d, 0x035d,
+ 0x135d, 0x055d, 0x155d, 0x0d5d, 0x1d5d, 0x2d5d, 0x555d, 0x655d,
+ 0x755d,
+ };
+ static const uint16_t gaindelta[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000,
+ };
+ static const uint32_t txpwrctl[] = {
+ 0x00000050, 0x0000004f, 0x0000004e, 0x0000004d, 0x0000004c,
+ 0x0000004b, 0x0000004a, 0x00000049, 0x00000048, 0x00000047,
+ 0x00000046, 0x00000045, 0x00000044, 0x00000043, 0x00000042,
+ 0x00000041, 0x00000040, 0x0000003f, 0x0000003e, 0x0000003d,
+ 0x0000003c, 0x0000003b, 0x0000003a, 0x00000039, 0x00000038,
+ 0x00000037, 0x00000036, 0x00000035, 0x00000034, 0x00000033,
+ 0x00000032, 0x00000031, 0x00000030, 0x0000002f, 0x0000002e,
+ 0x0000002d, 0x0000002c, 0x0000002b, 0x0000002a, 0x00000029,
+ 0x00000028, 0x00000027, 0x00000026, 0x00000025, 0x00000024,
+ 0x00000023, 0x00000022, 0x00000021, 0x00000020, 0x0000001f,
+ 0x0000001e, 0x0000001d, 0x0000001c, 0x0000001b, 0x0000001a,
+ 0x00000019, 0x00000018, 0x00000017, 0x00000016, 0x00000015,
+ 0x00000014, 0x00000013, 0x00000012, 0x00000011, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x000075a0, 0x000075a0, 0x000075a1,
+ 0x000075a1, 0x000075a2, 0x000075a2, 0x000075a3, 0x000075a3,
+ 0x000074b0, 0x000074b0, 0x000074b1, 0x000074b1, 0x000074b2,
+ 0x000074b2, 0x000074b3, 0x000074b3, 0x00006d20, 0x00006d20,
+ 0x00006d21, 0x00006d21, 0x00006d22, 0x00006d22, 0x00006d23,
+ 0x00006d23, 0x00004660, 0x00004660, 0x00004661, 0x00004661,
+ 0x00004662, 0x00004662, 0x00004663, 0x00004663, 0x00003e60,
+ 0x00003e60, 0x00003e61, 0x00003e61, 0x00003e62, 0x00003e62,
+ 0x00003e63, 0x00003e63, 0x00003660, 0x00003660, 0x00003661,
+ 0x00003661, 0x00003662, 0x00003662, 0x00003663, 0x00003663,
+ 0x00002e60, 0x00002e60, 0x00002e61, 0x00002e61, 0x00002e62,
+ 0x00002e62, 0x00002e63, 0x00002e63, 0x00002660, 0x00002660,
+ 0x00002661, 0x00002661, 0x00002662, 0x00002662, 0x00002663,
+ 0x00002663, 0x000025e0, 0x000025e0, 0x000025e1, 0x000025e1,
+ 0x000025e2, 0x000025e2, 0x000025e3, 0x000025e3, 0x00001de0,
+ 0x00001de0, 0x00001de1, 0x00001de1, 0x00001de2, 0x00001de2,
+ 0x00001de3, 0x00001de3, 0x00001d60, 0x00001d60, 0x00001d61,
+ 0x00001d61, 0x00001d62, 0x00001d62, 0x00001d63, 0x00001d63,
+ 0x00001560, 0x00001560, 0x00001561, 0x00001561, 0x00001562,
+ 0x00001562, 0x00001563, 0x00001563, 0x00000d60, 0x00000d60,
+ 0x00000d61, 0x00000d61, 0x00000d62, 0x00000d62, 0x00000d63,
+ 0x00000d63, 0x00000ce0, 0x00000ce0, 0x00000ce1, 0x00000ce1,
+ 0x00000ce2, 0x00000ce2, 0x00000ce3, 0x00000ce3, 0x00000e10,
+ 0x00000e10, 0x00000e11, 0x00000e11, 0x00000e12, 0x00000e12,
+ 0x00000e13, 0x00000e13, 0x00000bf0, 0x00000bf0, 0x00000bf1,
+ 0x00000bf1, 0x00000bf2, 0x00000bf2, 0x00000bf3, 0x00000bf3,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x04200000, 0x04000000,
+ 0x04200000, 0x04000000, 0x04200000, 0x04000000, 0x04200000,
+ 0x04000000, 0x04200000, 0x04000000, 0x000000ff, 0x000002fc,
+ 0x0000fa08, 0x00000305, 0x00000206, 0x00000304, 0x0000fb04,
+ 0x0000fcff, 0x000005fb, 0x0000fd01, 0x00000401, 0x00000006,
+ 0x0000ff03, 0x000007fc, 0x0000fc08, 0x00000203, 0x0000fffb,
+ 0x00000600, 0x0000fa01, 0x0000fc03, 0x0000fe06, 0x0000fe00,
+ 0x00000102, 0x000007fd, 0x000004fb, 0x000006ff, 0x000004fd,
+ 0x0000fdfa, 0x000007fb, 0x0000fdfa, 0x0000fa06, 0x00000500,
+ 0x0000f902, 0x000007fa, 0x0000fafa, 0x00000500, 0x000007fa,
+ 0x00000700, 0x00000305, 0x000004ff, 0x00000801, 0x00000503,
+ 0x000005f9, 0x00000404, 0x0000fb08, 0x000005fd, 0x00000501,
+ 0x00000405, 0x0000fb03, 0x000007fc, 0x00000403, 0x00000303,
+ 0x00000402, 0x0000faff, 0x0000fe05, 0x000005fd, 0x0000fe01,
+ 0x000007fa, 0x00000202, 0x00000504, 0x00000102, 0x000008fe,
+ 0x0000fa04, 0x0000fafc, 0x0000fe08, 0x000000f9, 0x000002fa,
+ 0x000003fe, 0x00000304, 0x000004f9, 0x00000100, 0x0000fd06,
+ 0x000008fc, 0x00000701, 0x00000504, 0x0000fdfe, 0x0000fdfc,
+ 0x000003fe, 0x00000704, 0x000002fc, 0x000004f9, 0x0000fdfd,
+ 0x0000fa07, 0x00000205, 0x000003fd, 0x000005fb, 0x000004f9,
+ 0x00000804, 0x0000fc06, 0x0000fcf9, 0x00000100, 0x0000fe05,
+ 0x00000408, 0x0000fb02, 0x00000304, 0x000006fe, 0x000004fa,
+ 0x00000305, 0x000008fc, 0x00000102, 0x000001fd, 0x000004fc,
+ 0x0000fe03, 0x00000701, 0x000001fb, 0x000001f9, 0x00000206,
+ 0x000006fd, 0x00000508, 0x00000700, 0x00000304, 0x000005fe,
+ 0x000005ff, 0x0000fa04, 0x00000303, 0x0000fefb, 0x000007f9,
+ 0x0000fefc, 0x000004fd, 0x000005fc, 0x0000fffd, 0x0000fc08,
+ 0x0000fbf9, 0x0000fd07, 0x000008fb, 0x0000fe02, 0x000006fb,
+ 0x00000702,
+ };
+
+ KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
+
+ bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
+ bwn_tab_sigsq_tbl);
+ bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
+ bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(crsgainnft), crsgainnft);
+ bwn_tab_write_multi(mac, BWN_TAB_2(8, 0), N(filterctl), filterctl);
+ bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(psctl), psctl);
+ bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
+ bwn_tab_pllfrac_tbl);
+ bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
+ bwn_tabl_iqlocal_tbl);
+ if (mac->mac_phy.rev == 0) {
+ bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r0),
+ ofdmcckgain_r0);
+ bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r0),
+ ofdmcckgain_r0);
+ } else {
+ bwn_tab_write_multi(mac, BWN_TAB_2(13, 0), N(ofdmcckgain_r1),
+ ofdmcckgain_r1);
+ bwn_tab_write_multi(mac, BWN_TAB_2(12, 0), N(ofdmcckgain_r1),
+ ofdmcckgain_r1);
+ }
+ bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(gaindelta), gaindelta);
+ bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(txpwrctl), txpwrctl);
+}
+
+static void
+bwn_phy_lp_tblinit_r2(struct bwn_mac *mac)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ int i;
+ static const uint16_t noisescale[] = {
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x0000, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4,
+ 0x00a4, 0x00a4, 0x00a4, 0x00a4, 0x00a4
+ };
+ static const uint32_t filterctl[] = {
+ 0x000141fc, 0x000021fc, 0x000021b7, 0x0000416f, 0x0001ff27,
+ 0x0000217f, 0x00002137, 0x000040ef, 0x0001fea7, 0x0000024f
+ };
+ static const uint32_t psctl[] = {
+ 0x00e38e08, 0x00e08e38, 0x00000000, 0x00000000, 0x00000000,
+ 0x00002080, 0x00006180, 0x00003002, 0x00000040, 0x00002042,
+ 0x00180047, 0x00080043, 0x00000041, 0x000020c1, 0x00046006,
+ 0x00042002, 0x00040000, 0x00002003, 0x00180006, 0x00080002
+ };
+ static const uint32_t gainidx[] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x10000001, 0x00000000,
+ 0x20000082, 0x00000000, 0x40000104, 0x00000000, 0x60004207,
+ 0x00000001, 0x7000838a, 0x00000001, 0xd021050d, 0x00000001,
+ 0xe041c683, 0x00000001, 0x50828805, 0x00000000, 0x80e34288,
+ 0x00000000, 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000,
+ 0x12064711, 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794,
+ 0x00000010, 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011,
+ 0xc1848a9c, 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21,
+ 0x00000019, 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019,
+ 0xb36811a6, 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329,
+ 0x0000001a, 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a,
+ 0x54aa152c, 0x0000001a, 0x64ca55ad, 0x0000001a, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x10000001, 0x00000000, 0x20000082,
+ 0x00000000, 0x40000104, 0x00000000, 0x60004207, 0x00000001,
+ 0x7000838a, 0x00000001, 0xd021050d, 0x00000001, 0xe041c683,
+ 0x00000001, 0x50828805, 0x00000000, 0x80e34288, 0x00000000,
+ 0xb144040b, 0x00000000, 0xe1a6058e, 0x00000000, 0x12064711,
+ 0x00000001, 0xb0a18612, 0x00000010, 0xe1024794, 0x00000010,
+ 0x11630915, 0x00000011, 0x31c3ca1b, 0x00000011, 0xc1848a9c,
+ 0x00000018, 0xf1e50da0, 0x00000018, 0x22468e21, 0x00000019,
+ 0x4286d023, 0x00000019, 0xa347d0a4, 0x00000019, 0xb36811a6,
+ 0x00000019, 0xf3e89227, 0x00000019, 0x0408d329, 0x0000001a,
+ 0x244953aa, 0x0000001a, 0x346994ab, 0x0000001a, 0x54aa152c,
+ 0x0000001a, 0x64ca55ad, 0x0000001a
+ };
+ static const uint16_t auxgainidx[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0001, 0x0002, 0x0004, 0x0016, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002,
+ 0x0004, 0x0016
+ };
+ static const uint16_t swctl[] = {
+ 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
+ 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
+ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018,
+ 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
+ 0x0128, 0x0128, 0x0009, 0x0009, 0x0028, 0x0028, 0x0028, 0x0028,
+ 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009,
+ 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018, 0x0018
+ };
+ static const uint8_t hf[] = {
+ 0x4b, 0x36, 0x24, 0x18, 0x49, 0x34, 0x23, 0x17, 0x48,
+ 0x33, 0x23, 0x17, 0x48, 0x33, 0x23, 0x17
+ };
+ static const uint32_t gainval[] = {
+ 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
+ 0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
+ 0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
+ 0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+ 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
+ 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000009,
+ 0x000000f1, 0x00000000, 0x00000000
+ };
+ static const uint16_t gain[] = {
+ 0x0000, 0x0400, 0x0800, 0x0802, 0x0804, 0x0806, 0x0807, 0x0808,
+ 0x080a, 0x080b, 0x080c, 0x080e, 0x080f, 0x0810, 0x0812, 0x0813,
+ 0x0814, 0x0816, 0x0817, 0x081a, 0x081b, 0x081f, 0x0820, 0x0824,
+ 0x0830, 0x0834, 0x0837, 0x083b, 0x083f, 0x0840, 0x0844, 0x0857,
+ 0x085b, 0x085f, 0x08d7, 0x08db, 0x08df, 0x0957, 0x095b, 0x095f,
+ 0x0b57, 0x0b5b, 0x0b5f, 0x0f5f, 0x135f, 0x175f, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+ };
+ static const uint32_t papdeps[] = {
+ 0x00000000, 0x00013ffc, 0x0001dff3, 0x0001bff0, 0x00023fe9,
+ 0x00021fdf, 0x00028fdf, 0x00033fd2, 0x00039fcb, 0x00043fc7,
+ 0x0004efc2, 0x00055fb5, 0x0005cfb0, 0x00063fa8, 0x00068fa3,
+ 0x00071f98, 0x0007ef92, 0x00084f8b, 0x0008df82, 0x00097f77,
+ 0x0009df69, 0x000a3f62, 0x000adf57, 0x000b6f4c, 0x000bff41,
+ 0x000c9f39, 0x000cff30, 0x000dbf27, 0x000e4f1e, 0x000edf16,
+ 0x000f7f13, 0x00102f11, 0x00110f10, 0x0011df11, 0x0012ef15,
+ 0x00143f1c, 0x00158f27, 0x00172f35, 0x00193f47, 0x001baf5f,
+ 0x001e6f7e, 0x0021cfa4, 0x0025bfd2, 0x002a2008, 0x002fb047,
+ 0x00360090, 0x003d40e0, 0x0045c135, 0x004fb189, 0x005ae1d7,
+ 0x0067221d, 0x0075025a, 0x007ff291, 0x007ff2bf, 0x007ff2e3,
+ 0x007ff2ff, 0x007ff315, 0x007ff329, 0x007ff33f, 0x007ff356,
+ 0x007ff36e, 0x007ff39c, 0x007ff441, 0x007ff506
+ };
+ static const uint32_t papdmult[] = {
+ 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
+ 0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
+ 0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
+ 0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
+ 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
+ 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
+ 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
+ 0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
+ 0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
+ 0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
+ 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
+ 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
+ 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
+ };
+ static const uint32_t gainidx_a0[] = {
+ 0x001111e0, 0x00652051, 0x00606055, 0x005b005a, 0x00555060,
+ 0x00511065, 0x004c806b, 0x0047d072, 0x00444078, 0x00400080,
+ 0x003ca087, 0x0039408f, 0x0035e098, 0x0032e0a1, 0x003030aa,
+ 0x002d80b4, 0x002ae0bf, 0x002880ca, 0x002640d6, 0x002410e3,
+ 0x002220f0, 0x002020ff, 0x001e510e, 0x001ca11e, 0x001b012f,
+ 0x00199140, 0x00182153, 0x0016c168, 0x0015817d, 0x00145193,
+ 0x001321ab, 0x001211c5, 0x001111e0, 0x001021fc, 0x000f321a,
+ 0x000e523a, 0x000d925c, 0x000cd27f, 0x000c12a5, 0x000b62cd,
+ 0x000ac2f8, 0x000a2325, 0x00099355, 0x00091387, 0x000883bd,
+ 0x000813f5, 0x0007a432, 0x00073471, 0x0006c4b5, 0x000664fc,
+ 0x00061547, 0x0005b598, 0x000565ec, 0x00051646, 0x0004d6a5,
+ 0x0004870a, 0x00044775, 0x000407e6, 0x0003d85e, 0x000398dd,
+ 0x00036963, 0x000339f2, 0x00030a89, 0x0002db28
+ };
+ static const uint16_t auxgainidx_a0[] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0002, 0x0014, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0002, 0x0014
+ };
+ static const uint32_t gainval_a0[] = {
+ 0x00000008, 0x0000000e, 0x00000014, 0x0000001a, 0x000000fb,
+ 0x00000004, 0x00000008, 0x0000000d, 0x00000001, 0x00000004,
+ 0x00000007, 0x0000000a, 0x0000000d, 0x00000010, 0x00000012,
+ 0x00000015, 0x00000000, 0x00000006, 0x0000000c, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000012, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000018, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x0000001e, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003,
+ 0x00000006, 0x00000009, 0x0000000c, 0x0000000f, 0x00000012,
+ 0x00000015, 0x00000018, 0x0000001b, 0x0000001e, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x0000000f,
+ 0x000000f7, 0x00000000, 0x00000000
+ };
+ static const uint16_t gain_a0[] = {
+ 0x0000, 0x0002, 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b,
+ 0x000c, 0x000e, 0x000f, 0x0010, 0x0012, 0x0013, 0x0014, 0x0016,
+ 0x0017, 0x001a, 0x001b, 0x001f, 0x0020, 0x0024, 0x0030, 0x0034,
+ 0x0037, 0x003b, 0x003f, 0x0040, 0x0044, 0x0057, 0x005b, 0x005f,
+ 0x00d7, 0x00db, 0x00df, 0x0157, 0x015b, 0x015f, 0x0357, 0x035b,
+ 0x035f, 0x075f, 0x0b5f, 0x0f5f, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+ };
+
+ KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
+
+ for (i = 0; i < 704; i++)
+ bwn_tab_write(mac, BWN_TAB_4(7, i), 0);
+
+ bwn_tab_write_multi(mac, BWN_TAB_1(2, 0), N(bwn_tab_sigsq_tbl),
+ bwn_tab_sigsq_tbl);
+ bwn_tab_write_multi(mac, BWN_TAB_2(1, 0), N(noisescale), noisescale);
+ bwn_tab_write_multi(mac, BWN_TAB_4(11, 0), N(filterctl), filterctl);
+ bwn_tab_write_multi(mac, BWN_TAB_4(12, 0), N(psctl), psctl);
+ bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx), gainidx);
+ bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx), auxgainidx);
+ bwn_tab_write_multi(mac, BWN_TAB_2(15, 0), N(swctl), swctl);
+ bwn_tab_write_multi(mac, BWN_TAB_1(16, 0), N(hf), hf);
+ bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval), gainval);
+ bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain), gain);
+ bwn_tab_write_multi(mac, BWN_TAB_1(6, 0), N(bwn_tab_pllfrac_tbl),
+ bwn_tab_pllfrac_tbl);
+ bwn_tab_write_multi(mac, BWN_TAB_2(0, 0), N(bwn_tabl_iqlocal_tbl),
+ bwn_tabl_iqlocal_tbl);
+ bwn_tab_write_multi(mac, BWN_TAB_4(9, 0), N(papdeps), papdeps);
+ bwn_tab_write_multi(mac, BWN_TAB_4(10, 0), N(papdmult), papdmult);
+
+ if ((siba->siba_chipid == 0x4325) && (siba->siba_chiprev == 0)) {
+ bwn_tab_write_multi(mac, BWN_TAB_4(13, 0), N(gainidx_a0),
+ gainidx_a0);
+ bwn_tab_write_multi(mac, BWN_TAB_2(14, 0), N(auxgainidx_a0),
+ auxgainidx_a0);
+ bwn_tab_write_multi(mac, BWN_TAB_4(17, 0), N(gainval_a0),
+ gainval_a0);
+ bwn_tab_write_multi(mac, BWN_TAB_2(18, 0), N(gain_a0), gain_a0);
+ }
+}
+
+static void
+bwn_phy_lp_tblinit_txgain(struct bwn_mac *mac)
+{
+ struct siba_dev_softc *sd = mac->mac_sd;
+ struct siba_softc *siba = sd->sd_bus;
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ static struct bwn_txgain_entry txgain_r2[] = {
+ { 255, 255, 203, 0, 152 }, { 255, 255, 203, 0, 147 },
+ { 255, 255, 203, 0, 143 }, { 255, 255, 203, 0, 139 },
+ { 255, 255, 203, 0, 135 }, { 255, 255, 203, 0, 131 },
+ { 255, 255, 203, 0, 128 }, { 255, 255, 203, 0, 124 },
+ { 255, 255, 203, 0, 121 }, { 255, 255, 203, 0, 117 },
+ { 255, 255, 203, 0, 114 }, { 255, 255, 203, 0, 111 },
+ { 255, 255, 203, 0, 107 }, { 255, 255, 203, 0, 104 },
+ { 255, 255, 203, 0, 101 }, { 255, 255, 203, 0, 99 },
+ { 255, 255, 203, 0, 96 }, { 255, 255, 203, 0, 93 },
+ { 255, 255, 203, 0, 90 }, { 255, 255, 203, 0, 88 },
+ { 255, 255, 203, 0, 85 }, { 255, 255, 203, 0, 83 },
+ { 255, 255, 203, 0, 81 }, { 255, 255, 203, 0, 78 },
+ { 255, 255, 203, 0, 76 }, { 255, 255, 203, 0, 74 },
+ { 255, 255, 203, 0, 72 }, { 255, 255, 203, 0, 70 },
+ { 255, 255, 203, 0, 68 }, { 255, 255, 203, 0, 66 },
+ { 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
+ { 255, 255, 192, 0, 64 }, { 255, 255, 186, 0, 64 },
+ { 255, 255, 181, 0, 64 }, { 255, 255, 176, 0, 64 },
+ { 255, 255, 171, 0, 64 }, { 255, 255, 166, 0, 64 },
+ { 255, 255, 161, 0, 64 }, { 255, 255, 157, 0, 64 },
+ { 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
+ { 255, 255, 144, 0, 64 }, { 255, 255, 140, 0, 64 },
+ { 255, 255, 136, 0, 64 }, { 255, 255, 132, 0, 64 },
+ { 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
+ { 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
+ { 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
+ { 255, 255, 108, 0, 64 }, { 255, 255, 105, 0, 64 },
+ { 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
+ { 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
+ { 255, 255, 91, 0, 64 }, { 255, 255, 88, 0, 64 },
+ { 255, 255, 86, 0, 64 }, { 255, 255, 83, 0, 64 },
+ { 255, 255, 81, 0, 64 }, { 255, 255, 79, 0, 64 },
+ { 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
+ { 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
+ { 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
+ { 255, 255, 64, 0, 64 }, { 255, 248, 64, 0, 64 },
+ { 255, 248, 62, 0, 64 }, { 255, 241, 62, 0, 64 },
+ { 255, 241, 60, 0, 64 }, { 255, 234, 60, 0, 64 },
+ { 255, 234, 59, 0, 64 }, { 255, 227, 59, 0, 64 },
+ { 255, 227, 57, 0, 64 }, { 255, 221, 57, 0, 64 },
+ { 255, 221, 55, 0, 64 }, { 255, 215, 55, 0, 64 },
+ { 255, 215, 54, 0, 64 }, { 255, 208, 54, 0, 64 },
+ { 255, 208, 52, 0, 64 }, { 255, 203, 52, 0, 64 },
+ { 255, 203, 51, 0, 64 }, { 255, 197, 51, 0, 64 },
+ { 255, 197, 49, 0, 64 }, { 255, 191, 49, 0, 64 },
+ { 255, 191, 48, 0, 64 }, { 255, 186, 48, 0, 64 },
+ { 255, 186, 47, 0, 64 }, { 255, 181, 47, 0, 64 },
+ { 255, 181, 45, 0, 64 }, { 255, 175, 45, 0, 64 },
+ { 255, 175, 44, 0, 64 }, { 255, 170, 44, 0, 64 },
+ { 255, 170, 43, 0, 64 }, { 255, 166, 43, 0, 64 },
+ { 255, 166, 42, 0, 64 }, { 255, 161, 42, 0, 64 },
+ { 255, 161, 40, 0, 64 }, { 255, 156, 40, 0, 64 },
+ { 255, 156, 39, 0, 64 }, { 255, 152, 39, 0, 64 },
+ { 255, 152, 38, 0, 64 }, { 255, 148, 38, 0, 64 },
+ { 255, 148, 37, 0, 64 }, { 255, 143, 37, 0, 64 },
+ { 255, 143, 36, 0, 64 }, { 255, 139, 36, 0, 64 },
+ { 255, 139, 35, 0, 64 }, { 255, 135, 35, 0, 64 },
+ { 255, 135, 34, 0, 64 }, { 255, 132, 34, 0, 64 },
+ { 255, 132, 33, 0, 64 }, { 255, 128, 33, 0, 64 },
+ { 255, 128, 32, 0, 64 }, { 255, 124, 32, 0, 64 },
+ { 255, 124, 31, 0, 64 }, { 255, 121, 31, 0, 64 },
+ { 255, 121, 30, 0, 64 }, { 255, 117, 30, 0, 64 },
+ { 255, 117, 29, 0, 64 }, { 255, 114, 29, 0, 64 },
+ { 255, 114, 29, 0, 64 }, { 255, 111, 29, 0, 64 },
+ };
+ static struct bwn_txgain_entry txgain_2ghz_r2[] = {
+ { 7, 99, 255, 0, 64 }, { 7, 96, 255, 0, 64 },
+ { 7, 93, 255, 0, 64 }, { 7, 90, 255, 0, 64 },
+ { 7, 88, 255, 0, 64 }, { 7, 85, 255, 0, 64 },
+ { 7, 83, 255, 0, 64 }, { 7, 81, 255, 0, 64 },
+ { 7, 78, 255, 0, 64 }, { 7, 76, 255, 0, 64 },
+ { 7, 74, 255, 0, 64 }, { 7, 72, 255, 0, 64 },
+ { 7, 70, 255, 0, 64 }, { 7, 68, 255, 0, 64 },
+ { 7, 66, 255, 0, 64 }, { 7, 64, 255, 0, 64 },
+ { 7, 64, 255, 0, 64 }, { 7, 62, 255, 0, 64 },
+ { 7, 62, 248, 0, 64 }, { 7, 60, 248, 0, 64 },
+ { 7, 60, 241, 0, 64 }, { 7, 59, 241, 0, 64 },
+ { 7, 59, 234, 0, 64 }, { 7, 57, 234, 0, 64 },
+ { 7, 57, 227, 0, 64 }, { 7, 55, 227, 0, 64 },
+ { 7, 55, 221, 0, 64 }, { 7, 54, 221, 0, 64 },
+ { 7, 54, 215, 0, 64 }, { 7, 52, 215, 0, 64 },
+ { 7, 52, 208, 0, 64 }, { 7, 51, 208, 0, 64 },
+ { 7, 51, 203, 0, 64 }, { 7, 49, 203, 0, 64 },
+ { 7, 49, 197, 0, 64 }, { 7, 48, 197, 0, 64 },
+ { 7, 48, 191, 0, 64 }, { 7, 47, 191, 0, 64 },
+ { 7, 47, 186, 0, 64 }, { 7, 45, 186, 0, 64 },
+ { 7, 45, 181, 0, 64 }, { 7, 44, 181, 0, 64 },
+ { 7, 44, 175, 0, 64 }, { 7, 43, 175, 0, 64 },
+ { 7, 43, 170, 0, 64 }, { 7, 42, 170, 0, 64 },
+ { 7, 42, 166, 0, 64 }, { 7, 40, 166, 0, 64 },
+ { 7, 40, 161, 0, 64 }, { 7, 39, 161, 0, 64 },
+ { 7, 39, 156, 0, 64 }, { 7, 38, 156, 0, 64 },
+ { 7, 38, 152, 0, 64 }, { 7, 37, 152, 0, 64 },
+ { 7, 37, 148, 0, 64 }, { 7, 36, 148, 0, 64 },
+ { 7, 36, 143, 0, 64 }, { 7, 35, 143, 0, 64 },
+ { 7, 35, 139, 0, 64 }, { 7, 34, 139, 0, 64 },
+ { 7, 34, 135, 0, 64 }, { 7, 33, 135, 0, 64 },
+ { 7, 33, 132, 0, 64 }, { 7, 32, 132, 0, 64 },
+ { 7, 32, 128, 0, 64 }, { 7, 31, 128, 0, 64 },
+ { 7, 31, 124, 0, 64 }, { 7, 30, 124, 0, 64 },
+ { 7, 30, 121, 0, 64 }, { 7, 29, 121, 0, 64 },
+ { 7, 29, 117, 0, 64 }, { 7, 29, 117, 0, 64 },
+ { 7, 29, 114, 0, 64 }, { 7, 28, 114, 0, 64 },
+ { 7, 28, 111, 0, 64 }, { 7, 27, 111, 0, 64 },
+ { 7, 27, 108, 0, 64 }, { 7, 26, 108, 0, 64 },
+ { 7, 26, 104, 0, 64 }, { 7, 25, 104, 0, 64 },
+ { 7, 25, 102, 0, 64 }, { 7, 25, 102, 0, 64 },
+ { 7, 25, 99, 0, 64 }, { 7, 24, 99, 0, 64 },
+ { 7, 24, 96, 0, 64 }, { 7, 23, 96, 0, 64 },
+ { 7, 23, 93, 0, 64 }, { 7, 23, 93, 0, 64 },
+ { 7, 23, 90, 0, 64 }, { 7, 22, 90, 0, 64 },
+ { 7, 22, 88, 0, 64 }, { 7, 21, 88, 0, 64 },
+ { 7, 21, 85, 0, 64 }, { 7, 21, 85, 0, 64 },
+ { 7, 21, 83, 0, 64 }, { 7, 20, 83, 0, 64 },
+ { 7, 20, 81, 0, 64 }, { 7, 20, 81, 0, 64 },
+ { 7, 20, 78, 0, 64 }, { 7, 19, 78, 0, 64 },
+ { 7, 19, 76, 0, 64 }, { 7, 19, 76, 0, 64 },
+ { 7, 19, 74, 0, 64 }, { 7, 18, 74, 0, 64 },
+ { 7, 18, 72, 0, 64 }, { 7, 18, 72, 0, 64 },
+ { 7, 18, 70, 0, 64 }, { 7, 17, 70, 0, 64 },
+ { 7, 17, 68, 0, 64 }, { 7, 17, 68, 0, 64 },
+ { 7, 17, 66, 0, 64 }, { 7, 16, 66, 0, 64 },
+ { 7, 16, 64, 0, 64 }, { 7, 16, 64, 0, 64 },
+ { 7, 16, 62, 0, 64 }, { 7, 15, 62, 0, 64 },
+ { 7, 15, 60, 0, 64 }, { 7, 15, 60, 0, 64 },
+ { 7, 15, 59, 0, 64 }, { 7, 14, 59, 0, 64 },
+ { 7, 14, 57, 0, 64 }, { 7, 14, 57, 0, 64 },
+ { 7, 14, 55, 0, 64 }, { 7, 14, 55, 0, 64 },
+ { 7, 14, 54, 0, 64 }, { 7, 13, 54, 0, 64 },
+ { 7, 13, 52, 0, 64 }, { 7, 13, 52, 0, 64 },
+ };
+ static struct bwn_txgain_entry txgain_5ghz_r2[] = {
+ { 255, 255, 255, 0, 152 }, { 255, 255, 255, 0, 147 },
+ { 255, 255, 255, 0, 143 }, { 255, 255, 255, 0, 139 },
+ { 255, 255, 255, 0, 135 }, { 255, 255, 255, 0, 131 },
+ { 255, 255, 255, 0, 128 }, { 255, 255, 255, 0, 124 },
+ { 255, 255, 255, 0, 121 }, { 255, 255, 255, 0, 117 },
+ { 255, 255, 255, 0, 114 }, { 255, 255, 255, 0, 111 },
+ { 255, 255, 255, 0, 107 }, { 255, 255, 255, 0, 104 },
+ { 255, 255, 255, 0, 101 }, { 255, 255, 255, 0, 99 },
+ { 255, 255, 255, 0, 96 }, { 255, 255, 255, 0, 93 },
+ { 255, 255, 255, 0, 90 }, { 255, 255, 255, 0, 88 },
+ { 255, 255, 255, 0, 85 }, { 255, 255, 255, 0, 83 },
+ { 255, 255, 255, 0, 81 }, { 255, 255, 255, 0, 78 },
+ { 255, 255, 255, 0, 76 }, { 255, 255, 255, 0, 74 },
+ { 255, 255, 255, 0, 72 }, { 255, 255, 255, 0, 70 },
+ { 255, 255, 255, 0, 68 }, { 255, 255, 255, 0, 66 },
+ { 255, 255, 255, 0, 64 }, { 255, 255, 248, 0, 64 },
+ { 255, 255, 241, 0, 64 }, { 255, 255, 234, 0, 64 },
+ { 255, 255, 227, 0, 64 }, { 255, 255, 221, 0, 64 },
+ { 255, 255, 215, 0, 64 }, { 255, 255, 208, 0, 64 },
+ { 255, 255, 203, 0, 64 }, { 255, 255, 197, 0, 64 },
+ { 255, 255, 191, 0, 64 }, { 255, 255, 186, 0, 64 },
+ { 255, 255, 181, 0, 64 }, { 255, 255, 175, 0, 64 },
+ { 255, 255, 170, 0, 64 }, { 255, 255, 166, 0, 64 },
+ { 255, 255, 161, 0, 64 }, { 255, 255, 156, 0, 64 },
+ { 255, 255, 152, 0, 64 }, { 255, 255, 148, 0, 64 },
+ { 255, 255, 143, 0, 64 }, { 255, 255, 139, 0, 64 },
+ { 255, 255, 135, 0, 64 }, { 255, 255, 132, 0, 64 },
+ { 255, 255, 128, 0, 64 }, { 255, 255, 124, 0, 64 },
+ { 255, 255, 121, 0, 64 }, { 255, 255, 117, 0, 64 },
+ { 255, 255, 114, 0, 64 }, { 255, 255, 111, 0, 64 },
+ { 255, 255, 108, 0, 64 }, { 255, 255, 104, 0, 64 },
+ { 255, 255, 102, 0, 64 }, { 255, 255, 99, 0, 64 },
+ { 255, 255, 96, 0, 64 }, { 255, 255, 93, 0, 64 },
+ { 255, 255, 90, 0, 64 }, { 255, 255, 88, 0, 64 },
+ { 255, 255, 85, 0, 64 }, { 255, 255, 83, 0, 64 },
+ { 255, 255, 81, 0, 64 }, { 255, 255, 78, 0, 64 },
+ { 255, 255, 76, 0, 64 }, { 255, 255, 74, 0, 64 },
+ { 255, 255, 72, 0, 64 }, { 255, 255, 70, 0, 64 },
+ { 255, 255, 68, 0, 64 }, { 255, 255, 66, 0, 64 },
+ { 255, 255, 64, 0, 64 }, { 255, 255, 64, 0, 64 },
+ { 255, 255, 62, 0, 64 }, { 255, 248, 62, 0, 64 },
+ { 255, 248, 60, 0, 64 }, { 255, 241, 60, 0, 64 },
+ { 255, 241, 59, 0, 64 }, { 255, 234, 59, 0, 64 },
+ { 255, 234, 57, 0, 64 }, { 255, 227, 57, 0, 64 },
+ { 255, 227, 55, 0, 64 }, { 255, 221, 55, 0, 64 },
+ { 255, 221, 54, 0, 64 }, { 255, 215, 54, 0, 64 },
+ { 255, 215, 52, 0, 64 }, { 255, 208, 52, 0, 64 },
+ { 255, 208, 51, 0, 64 }, { 255, 203, 51, 0, 64 },
+ { 255, 203, 49, 0, 64 }, { 255, 197, 49, 0, 64 },
+ { 255, 197, 48, 0, 64 }, { 255, 191, 48, 0, 64 },
+ { 255, 191, 47, 0, 64 }, { 255, 186, 47, 0, 64 },
+ { 255, 186, 45, 0, 64 }, { 255, 181, 45, 0, 64 },
+ { 255, 181, 44, 0, 64 }, { 255, 175, 44, 0, 64 },
+ { 255, 175, 43, 0, 64 }, { 255, 170, 43, 0, 64 },
+ { 255, 170, 42, 0, 64 }, { 255, 166, 42, 0, 64 },
+ { 255, 166, 40, 0, 64 }, { 255, 161, 40, 0, 64 },
+ { 255, 161, 39, 0, 64 }, { 255, 156, 39, 0, 64 },
+ { 255, 156, 38, 0, 64 }, { 255, 152, 38, 0, 64 },
+ { 255, 152, 37, 0, 64 }, { 255, 148, 37, 0, 64 },
+ { 255, 148, 36, 0, 64 }, { 255, 143, 36, 0, 64 },
+ { 255, 143, 35, 0, 64 }, { 255, 139, 35, 0, 64 },
+ { 255, 139, 34, 0, 64 }, { 255, 135, 34, 0, 64 },
+ { 255, 135, 33, 0, 64 }, { 255, 132, 33, 0, 64 },
+ { 255, 132, 32, 0, 64 }, { 255, 128, 32, 0, 64 }
+ };
+ static struct bwn_txgain_entry txgain_r0[] = {
+ { 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
+ { 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
+ { 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
+ { 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
+ { 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
+ { 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
+ { 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
+ { 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
+ { 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
+ { 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
+ { 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
+ { 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
+ { 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
+ { 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
+ { 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
+ { 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
+ { 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
+ { 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
+ { 7, 15, 13, 0, 70 }, { 7, 15, 13, 0, 68 },
+ { 7, 15, 13, 0, 66 }, { 7, 15, 13, 0, 64 },
+ { 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
+ { 7, 15, 13, 0, 59 }, { 7, 15, 13, 0, 57 },
+ { 7, 15, 12, 0, 71 }, { 7, 15, 12, 0, 69 },
+ { 7, 15, 12, 0, 67 }, { 7, 15, 12, 0, 65 },
+ { 7, 15, 12, 0, 63 }, { 7, 15, 12, 0, 62 },
+ { 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 58 },
+ { 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 70 },
+ { 7, 15, 11, 0, 68 }, { 7, 15, 11, 0, 66 },
+ { 7, 15, 11, 0, 65 }, { 7, 15, 11, 0, 63 },
+ { 7, 15, 11, 0, 61 }, { 7, 15, 11, 0, 59 },
+ { 7, 15, 11, 0, 58 }, { 7, 15, 10, 0, 71 },
+ { 7, 15, 10, 0, 69 }, { 7, 15, 10, 0, 67 },
+ { 7, 15, 10, 0, 65 }, { 7, 15, 10, 0, 63 },
+ { 7, 15, 10, 0, 61 }, { 7, 15, 10, 0, 60 },
+ { 7, 15, 10, 0, 58 }, { 7, 15, 10, 0, 56 },
+ { 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
+ { 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
+ { 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 60 },
+ { 7, 15, 9, 0, 59 }, { 7, 14, 9, 0, 72 },
+ { 7, 14, 9, 0, 70 }, { 7, 14, 9, 0, 68 },
+ { 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 64 },
+ { 7, 14, 9, 0, 62 }, { 7, 14, 9, 0, 60 },
+ { 7, 14, 9, 0, 59 }, { 7, 13, 9, 0, 72 },
+ { 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
+ { 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
+ { 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
+ { 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
+ { 7, 13, 8, 0, 72 }, { 7, 13, 8, 0, 70 },
+ { 7, 13, 8, 0, 68 }, { 7, 13, 8, 0, 66 },
+ { 7, 13, 8, 0, 64 }, { 7, 13, 8, 0, 62 },
+ { 7, 13, 8, 0, 60 }, { 7, 13, 8, 0, 59 },
+ { 7, 12, 8, 0, 72 }, { 7, 12, 8, 0, 70 },
+ { 7, 12, 8, 0, 68 }, { 7, 12, 8, 0, 66 },
+ { 7, 12, 8, 0, 64 }, { 7, 12, 8, 0, 62 },
+ { 7, 12, 8, 0, 61 }, { 7, 12, 8, 0, 59 },
+ { 7, 12, 7, 0, 73 }, { 7, 12, 7, 0, 71 },
+ { 7, 12, 7, 0, 69 }, { 7, 12, 7, 0, 67 },
+ { 7, 12, 7, 0, 65 }, { 7, 12, 7, 0, 63 },
+ { 7, 12, 7, 0, 61 }, { 7, 12, 7, 0, 59 },
+ { 7, 11, 7, 0, 72 }, { 7, 11, 7, 0, 70 },
+ { 7, 11, 7, 0, 68 }, { 7, 11, 7, 0, 66 },
+ { 7, 11, 7, 0, 65 }, { 7, 11, 7, 0, 63 },
+ { 7, 11, 7, 0, 61 }, { 7, 11, 7, 0, 59 },
+ { 7, 11, 6, 0, 73 }, { 7, 11, 6, 0, 71 }
+ };
+ static struct bwn_txgain_entry txgain_2ghz_r0[] = {
+ { 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
+ { 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
+ { 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
+ { 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
+ { 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
+ { 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
+ { 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
+ { 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
+ { 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
+ { 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
+ { 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
+ { 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
+ { 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
+ { 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
+ { 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
+ { 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
+ { 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
+ { 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
+ { 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
+ { 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
+ { 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
+ { 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
+ { 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
+ { 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
+ { 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
+ { 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
+ { 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
+ { 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
+ { 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
+ { 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
+ { 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
+ { 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
+ { 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
+ { 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 },
+ { 4, 10, 6, 0, 59 }, { 4, 10, 5, 0, 72 },
+ { 4, 10, 5, 0, 70 }, { 4, 10, 5, 0, 68 },
+ { 4, 10, 5, 0, 66 }, { 4, 10, 5, 0, 64 },
+ { 4, 10, 5, 0, 62 }, { 4, 10, 5, 0, 60 },
+ { 4, 10, 5, 0, 59 }, { 4, 9, 5, 0, 70 },
+ { 4, 9, 5, 0, 68 }, { 4, 9, 5, 0, 66 },
+ { 4, 9, 5, 0, 64 }, { 4, 9, 5, 0, 63 },
+ { 4, 9, 5, 0, 61 }, { 4, 9, 5, 0, 59 },
+ { 4, 9, 4, 0, 71 }, { 4, 9, 4, 0, 69 },
+ { 4, 9, 4, 0, 67 }, { 4, 9, 4, 0, 65 },
+ { 4, 9, 4, 0, 63 }, { 4, 9, 4, 0, 62 },
+ { 4, 9, 4, 0, 60 }, { 4, 9, 4, 0, 58 },
+ { 4, 8, 4, 0, 70 }, { 4, 8, 4, 0, 68 },
+ { 4, 8, 4, 0, 66 }, { 4, 8, 4, 0, 65 },
+ { 4, 8, 4, 0, 63 }, { 4, 8, 4, 0, 61 },
+ { 4, 8, 4, 0, 59 }, { 4, 7, 4, 0, 68 },
+ { 4, 7, 4, 0, 66 }, { 4, 7, 4, 0, 64 },
+ { 4, 7, 4, 0, 62 }, { 4, 7, 4, 0, 61 },
+ { 4, 7, 4, 0, 59 }, { 4, 7, 3, 0, 67 },
+ { 4, 7, 3, 0, 65 }, { 4, 7, 3, 0, 63 },
+ { 4, 7, 3, 0, 62 }, { 4, 7, 3, 0, 60 },
+ { 4, 6, 3, 0, 65 }, { 4, 6, 3, 0, 63 },
+ { 4, 6, 3, 0, 61 }, { 4, 6, 3, 0, 60 },
+ { 4, 6, 3, 0, 58 }, { 4, 5, 3, 0, 68 },
+ { 4, 5, 3, 0, 66 }, { 4, 5, 3, 0, 64 },
+ { 4, 5, 3, 0, 62 }, { 4, 5, 3, 0, 60 },
+ { 4, 5, 3, 0, 59 }, { 4, 5, 3, 0, 57 },
+ { 4, 4, 2, 0, 83 }, { 4, 4, 2, 0, 81 },
+ { 4, 4, 2, 0, 78 }, { 4, 4, 2, 0, 76 },
+ { 4, 4, 2, 0, 74 }, { 4, 4, 2, 0, 72 }
+ };
+ static struct bwn_txgain_entry txgain_5ghz_r0[] = {
+ { 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
+ { 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
+ { 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
+ { 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
+ { 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
+ { 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
+ { 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
+ { 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
+ { 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
+ { 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
+ { 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
+ { 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
+ { 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
+ { 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
+ { 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
+ { 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
+ { 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
+ { 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
+ { 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
+ { 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
+ { 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
+ { 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
+ { 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
+ { 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
+ { 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
+ { 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
+ { 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
+ { 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
+ { 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
+ { 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
+ { 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
+ { 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
+ { 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
+ { 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
+ { 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
+ { 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
+ { 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
+ { 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
+ { 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
+ { 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
+ { 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
+ { 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
+ { 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
+ { 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
+ { 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
+ { 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
+ { 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
+ { 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
+ { 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
+ { 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
+ { 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
+ { 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
+ { 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
+ { 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
+ { 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
+ { 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
+ { 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
+ { 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
+ { 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
+ { 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
+ { 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
+ { 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
+ { 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
+ { 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
+ };
+ static struct bwn_txgain_entry txgain_r1[] = {
+ { 7, 15, 14, 0, 152 }, { 7, 15, 14, 0, 147 },
+ { 7, 15, 14, 0, 143 }, { 7, 15, 14, 0, 139 },
+ { 7, 15, 14, 0, 135 }, { 7, 15, 14, 0, 131 },
+ { 7, 15, 14, 0, 128 }, { 7, 15, 14, 0, 124 },
+ { 7, 15, 14, 0, 121 }, { 7, 15, 14, 0, 117 },
+ { 7, 15, 14, 0, 114 }, { 7, 15, 14, 0, 111 },
+ { 7, 15, 14, 0, 107 }, { 7, 15, 14, 0, 104 },
+ { 7, 15, 14, 0, 101 }, { 7, 15, 14, 0, 99 },
+ { 7, 15, 14, 0, 96 }, { 7, 15, 14, 0, 93 },
+ { 7, 15, 14, 0, 90 }, { 7, 15, 14, 0, 88 },
+ { 7, 15, 14, 0, 85 }, { 7, 15, 14, 0, 83 },
+ { 7, 15, 14, 0, 81 }, { 7, 15, 14, 0, 78 },
+ { 7, 15, 14, 0, 76 }, { 7, 15, 14, 0, 74 },
+ { 7, 15, 14, 0, 72 }, { 7, 15, 14, 0, 70 },
+ { 7, 15, 14, 0, 68 }, { 7, 15, 14, 0, 66 },
+ { 7, 15, 14, 0, 64 }, { 7, 15, 14, 0, 62 },
+ { 7, 15, 14, 0, 60 }, { 7, 15, 14, 0, 59 },
+ { 7, 15, 14, 0, 57 }, { 7, 15, 13, 0, 72 },
+ { 7, 15, 13, 0, 70 }, { 7, 15, 14, 0, 68 },
+ { 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
+ { 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
+ { 7, 15, 14, 0, 59 }, { 7, 15, 14, 0, 57 },
+ { 7, 15, 13, 0, 72 }, { 7, 15, 13, 0, 70 },
+ { 7, 15, 13, 0, 68 }, { 7, 15, 13, 0, 66 },
+ { 7, 15, 13, 0, 64 }, { 7, 15, 13, 0, 62 },
+ { 7, 15, 13, 0, 60 }, { 7, 15, 13, 0, 59 },
+ { 7, 15, 13, 0, 57 }, { 7, 15, 12, 0, 71 },
+ { 7, 15, 12, 0, 69 }, { 7, 15, 12, 0, 67 },
+ { 7, 15, 12, 0, 65 }, { 7, 15, 12, 0, 63 },
+ { 7, 15, 12, 0, 62 }, { 7, 15, 12, 0, 60 },
+ { 7, 15, 12, 0, 58 }, { 7, 15, 12, 0, 57 },
+ { 7, 15, 11, 0, 70 }, { 7, 15, 11, 0, 68 },
+ { 7, 15, 11, 0, 66 }, { 7, 15, 11, 0, 65 },
+ { 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
+ { 7, 15, 11, 0, 59 }, { 7, 15, 11, 0, 58 },
+ { 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
+ { 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
+ { 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
+ { 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
+ { 7, 15, 10, 0, 56 }, { 7, 15, 9, 0, 70 },
+ { 7, 15, 9, 0, 68 }, { 7, 15, 9, 0, 66 },
+ { 7, 15, 9, 0, 64 }, { 7, 15, 9, 0, 62 },
+ { 7, 15, 9, 0, 60 }, { 7, 15, 9, 0, 59 },
+ { 7, 14, 9, 0, 72 }, { 7, 14, 9, 0, 70 },
+ { 7, 14, 9, 0, 68 }, { 7, 14, 9, 0, 66 },
+ { 7, 14, 9, 0, 64 }, { 7, 14, 9, 0, 62 },
+ { 7, 14, 9, 0, 60 }, { 7, 14, 9, 0, 59 },
+ { 7, 13, 9, 0, 72 }, { 7, 13, 9, 0, 70 },
+ { 7, 13, 9, 0, 68 }, { 7, 13, 9, 0, 66 },
+ { 7, 13, 9, 0, 64 }, { 7, 13, 9, 0, 63 },
+ { 7, 13, 9, 0, 61 }, { 7, 13, 9, 0, 59 },
+ { 7, 13, 9, 0, 57 }, { 7, 13, 8, 0, 72 },
+ { 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
+ { 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
+ { 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
+ { 7, 13, 8, 0, 59 }, { 7, 12, 8, 0, 72 },
+ { 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
+ { 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
+ { 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
+ { 7, 12, 8, 0, 59 }, { 7, 12, 7, 0, 73 },
+ { 7, 12, 7, 0, 71 }, { 7, 12, 7, 0, 69 },
+ { 7, 12, 7, 0, 67 }, { 7, 12, 7, 0, 65 },
+ { 7, 12, 7, 0, 63 }, { 7, 12, 7, 0, 61 },
+ { 7, 12, 7, 0, 59 }, { 7, 11, 7, 0, 72 },
+ { 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
+ { 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 65 },
+ { 7, 11, 7, 0, 63 }, { 7, 11, 7, 0, 61 },
+ { 7, 11, 7, 0, 59 }, { 7, 11, 6, 0, 73 },
+ { 7, 11, 6, 0, 71 }
+ };
+ static struct bwn_txgain_entry txgain_2ghz_r1[] = {
+ { 4, 15, 15, 0, 90 }, { 4, 15, 15, 0, 88 },
+ { 4, 15, 15, 0, 85 }, { 4, 15, 15, 0, 83 },
+ { 4, 15, 15, 0, 81 }, { 4, 15, 15, 0, 78 },
+ { 4, 15, 15, 0, 76 }, { 4, 15, 15, 0, 74 },
+ { 4, 15, 15, 0, 72 }, { 4, 15, 15, 0, 70 },
+ { 4, 15, 15, 0, 68 }, { 4, 15, 15, 0, 66 },
+ { 4, 15, 15, 0, 64 }, { 4, 15, 15, 0, 62 },
+ { 4, 15, 15, 0, 60 }, { 4, 15, 15, 0, 59 },
+ { 4, 15, 14, 0, 72 }, { 4, 15, 14, 0, 70 },
+ { 4, 15, 14, 0, 68 }, { 4, 15, 14, 0, 66 },
+ { 4, 15, 14, 0, 64 }, { 4, 15, 14, 0, 62 },
+ { 4, 15, 14, 0, 60 }, { 4, 15, 14, 0, 59 },
+ { 4, 15, 13, 0, 72 }, { 4, 15, 13, 0, 70 },
+ { 4, 15, 13, 0, 68 }, { 4, 15, 13, 0, 66 },
+ { 4, 15, 13, 0, 64 }, { 4, 15, 13, 0, 62 },
+ { 4, 15, 13, 0, 60 }, { 4, 15, 13, 0, 59 },
+ { 4, 15, 12, 0, 72 }, { 4, 15, 12, 0, 70 },
+ { 4, 15, 12, 0, 68 }, { 4, 15, 12, 0, 66 },
+ { 4, 15, 12, 0, 64 }, { 4, 15, 12, 0, 62 },
+ { 4, 15, 12, 0, 60 }, { 4, 15, 12, 0, 59 },
+ { 4, 15, 11, 0, 72 }, { 4, 15, 11, 0, 70 },
+ { 4, 15, 11, 0, 68 }, { 4, 15, 11, 0, 66 },
+ { 4, 15, 11, 0, 64 }, { 4, 15, 11, 0, 62 },
+ { 4, 15, 11, 0, 60 }, { 4, 15, 11, 0, 59 },
+ { 4, 15, 10, 0, 72 }, { 4, 15, 10, 0, 70 },
+ { 4, 15, 10, 0, 68 }, { 4, 15, 10, 0, 66 },
+ { 4, 15, 10, 0, 64 }, { 4, 15, 10, 0, 62 },
+ { 4, 15, 10, 0, 60 }, { 4, 15, 10, 0, 59 },
+ { 4, 15, 9, 0, 72 }, { 4, 15, 9, 0, 70 },
+ { 4, 15, 9, 0, 68 }, { 4, 15, 9, 0, 66 },
+ { 4, 15, 9, 0, 64 }, { 4, 15, 9, 0, 62 },
+ { 4, 15, 9, 0, 60 }, { 4, 15, 9, 0, 59 },
+ { 4, 14, 9, 0, 72 }, { 4, 14, 9, 0, 70 },
+ { 4, 14, 9, 0, 68 }, { 4, 14, 9, 0, 66 },
+ { 4, 14, 9, 0, 64 }, { 4, 14, 9, 0, 62 },
+ { 4, 14, 9, 0, 60 }, { 4, 14, 9, 0, 59 },
+ { 4, 13, 9, 0, 72 }, { 4, 13, 9, 0, 70 },
+ { 4, 13, 9, 0, 68 }, { 4, 13, 9, 0, 66 },
+ { 4, 13, 9, 0, 64 }, { 4, 13, 9, 0, 63 },
+ { 4, 13, 9, 0, 61 }, { 4, 13, 9, 0, 59 },
+ { 4, 13, 9, 0, 57 }, { 4, 13, 8, 0, 72 },
+ { 4, 13, 8, 0, 70 }, { 4, 13, 8, 0, 68 },
+ { 4, 13, 8, 0, 66 }, { 4, 13, 8, 0, 64 },
+ { 4, 13, 8, 0, 62 }, { 4, 13, 8, 0, 60 },
+ { 4, 13, 8, 0, 59 }, { 4, 12, 8, 0, 72 },
+ { 4, 12, 8, 0, 70 }, { 4, 12, 8, 0, 68 },
+ { 4, 12, 8, 0, 66 }, { 4, 12, 8, 0, 64 },
+ { 4, 12, 8, 0, 62 }, { 4, 12, 8, 0, 61 },
+ { 4, 12, 8, 0, 59 }, { 4, 12, 7, 0, 73 },
+ { 4, 12, 7, 0, 71 }, { 4, 12, 7, 0, 69 },
+ { 4, 12, 7, 0, 67 }, { 4, 12, 7, 0, 65 },
+ { 4, 12, 7, 0, 63 }, { 4, 12, 7, 0, 61 },
+ { 4, 12, 7, 0, 59 }, { 4, 11, 7, 0, 72 },
+ { 4, 11, 7, 0, 70 }, { 4, 11, 7, 0, 68 },
+ { 4, 11, 7, 0, 66 }, { 4, 11, 7, 0, 65 },
+ { 4, 11, 7, 0, 63 }, { 4, 11, 7, 0, 61 },
+ { 4, 11, 7, 0, 59 }, { 4, 11, 6, 0, 73 },
+ { 4, 11, 6, 0, 71 }, { 4, 11, 6, 0, 69 },
+ { 4, 11, 6, 0, 67 }, { 4, 11, 6, 0, 65 },
+ { 4, 11, 6, 0, 63 }, { 4, 11, 6, 0, 61 },
+ { 4, 11, 6, 0, 60 }, { 4, 10, 6, 0, 72 },
+ { 4, 10, 6, 0, 70 }, { 4, 10, 6, 0, 68 },
+ { 4, 10, 6, 0, 66 }, { 4, 10, 6, 0, 64 },
+ { 4, 10, 6, 0, 62 }, { 4, 10, 6, 0, 60 }
+ };
+ static struct bwn_txgain_entry txgain_5ghz_r1[] = {
+ { 7, 15, 15, 0, 99 }, { 7, 15, 15, 0, 96 },
+ { 7, 15, 15, 0, 93 }, { 7, 15, 15, 0, 90 },
+ { 7, 15, 15, 0, 88 }, { 7, 15, 15, 0, 85 },
+ { 7, 15, 15, 0, 83 }, { 7, 15, 15, 0, 81 },
+ { 7, 15, 15, 0, 78 }, { 7, 15, 15, 0, 76 },
+ { 7, 15, 15, 0, 74 }, { 7, 15, 15, 0, 72 },
+ { 7, 15, 15, 0, 70 }, { 7, 15, 15, 0, 68 },
+ { 7, 15, 15, 0, 66 }, { 7, 15, 15, 0, 64 },
+ { 7, 15, 15, 0, 62 }, { 7, 15, 15, 0, 60 },
+ { 7, 15, 15, 0, 59 }, { 7, 15, 15, 0, 57 },
+ { 7, 15, 15, 0, 55 }, { 7, 15, 14, 0, 72 },
+ { 7, 15, 14, 0, 70 }, { 7, 15, 14, 0, 68 },
+ { 7, 15, 14, 0, 66 }, { 7, 15, 14, 0, 64 },
+ { 7, 15, 14, 0, 62 }, { 7, 15, 14, 0, 60 },
+ { 7, 15, 14, 0, 58 }, { 7, 15, 14, 0, 56 },
+ { 7, 15, 14, 0, 55 }, { 7, 15, 13, 0, 71 },
+ { 7, 15, 13, 0, 69 }, { 7, 15, 13, 0, 67 },
+ { 7, 15, 13, 0, 65 }, { 7, 15, 13, 0, 63 },
+ { 7, 15, 13, 0, 62 }, { 7, 15, 13, 0, 60 },
+ { 7, 15, 13, 0, 58 }, { 7, 15, 13, 0, 56 },
+ { 7, 15, 12, 0, 72 }, { 7, 15, 12, 0, 70 },
+ { 7, 15, 12, 0, 68 }, { 7, 15, 12, 0, 66 },
+ { 7, 15, 12, 0, 64 }, { 7, 15, 12, 0, 62 },
+ { 7, 15, 12, 0, 60 }, { 7, 15, 12, 0, 59 },
+ { 7, 15, 12, 0, 57 }, { 7, 15, 11, 0, 73 },
+ { 7, 15, 11, 0, 71 }, { 7, 15, 11, 0, 69 },
+ { 7, 15, 11, 0, 67 }, { 7, 15, 11, 0, 65 },
+ { 7, 15, 11, 0, 63 }, { 7, 15, 11, 0, 61 },
+ { 7, 15, 11, 0, 60 }, { 7, 15, 11, 0, 58 },
+ { 7, 15, 10, 0, 71 }, { 7, 15, 10, 0, 69 },
+ { 7, 15, 10, 0, 67 }, { 7, 15, 10, 0, 65 },
+ { 7, 15, 10, 0, 63 }, { 7, 15, 10, 0, 61 },
+ { 7, 15, 10, 0, 60 }, { 7, 15, 10, 0, 58 },
+ { 7, 15, 9, 0, 70 }, { 7, 15, 9, 0, 68 },
+ { 7, 15, 9, 0, 66 }, { 7, 15, 9, 0, 64 },
+ { 7, 15, 9, 0, 62 }, { 7, 15, 9, 0, 61 },
+ { 7, 15, 9, 0, 59 }, { 7, 15, 9, 0, 57 },
+ { 7, 15, 9, 0, 56 }, { 7, 14, 9, 0, 68 },
+ { 7, 14, 9, 0, 66 }, { 7, 14, 9, 0, 65 },
+ { 7, 14, 9, 0, 63 }, { 7, 14, 9, 0, 61 },
+ { 7, 14, 9, 0, 59 }, { 7, 14, 9, 0, 58 },
+ { 7, 13, 9, 0, 70 }, { 7, 13, 9, 0, 68 },
+ { 7, 13, 9, 0, 66 }, { 7, 13, 9, 0, 64 },
+ { 7, 13, 9, 0, 63 }, { 7, 13, 9, 0, 61 },
+ { 7, 13, 9, 0, 59 }, { 7, 13, 9, 0, 57 },
+ { 7, 13, 8, 0, 70 }, { 7, 13, 8, 0, 68 },
+ { 7, 13, 8, 0, 66 }, { 7, 13, 8, 0, 64 },
+ { 7, 13, 8, 0, 62 }, { 7, 13, 8, 0, 60 },
+ { 7, 13, 8, 0, 59 }, { 7, 13, 8, 0, 57 },
+ { 7, 12, 8, 0, 70 }, { 7, 12, 8, 0, 68 },
+ { 7, 12, 8, 0, 66 }, { 7, 12, 8, 0, 64 },
+ { 7, 12, 8, 0, 62 }, { 7, 12, 8, 0, 61 },
+ { 7, 12, 8, 0, 59 }, { 7, 12, 8, 0, 57 },
+ { 7, 12, 7, 0, 70 }, { 7, 12, 7, 0, 68 },
+ { 7, 12, 7, 0, 66 }, { 7, 12, 7, 0, 64 },
+ { 7, 12, 7, 0, 62 }, { 7, 12, 7, 0, 61 },
+ { 7, 12, 7, 0, 59 }, { 7, 12, 7, 0, 57 },
+ { 7, 11, 7, 0, 70 }, { 7, 11, 7, 0, 68 },
+ { 7, 11, 7, 0, 66 }, { 7, 11, 7, 0, 64 },
+ { 7, 11, 7, 0, 62 }, { 7, 11, 7, 0, 61 },
+ { 7, 11, 7, 0, 59 }, { 7, 11, 7, 0, 57 },
+ { 7, 11, 6, 0, 69 }, { 7, 11, 6, 0, 67 },
+ { 7, 11, 6, 0, 65 }, { 7, 11, 6, 0, 63 },
+ { 7, 11, 6, 0, 62 }, { 7, 11, 6, 0, 60 }
+ };
+
+ if (mac->mac_phy.rev != 0 && mac->mac_phy.rev != 1) {
+ if (siba->siba_sprom.bf_hi & BWN_BFH_NOPA)
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r2);
+ else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
+ txgain_2ghz_r2);
+ else
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
+ txgain_5ghz_r2);
+ return;
+ }
+
+ if (mac->mac_phy.rev == 0) {
+ if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
+ (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r0);
+ else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
+ txgain_2ghz_r0);
+ else
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128,
+ txgain_5ghz_r0);
+ return;
+ }
+
+ if ((siba->siba_sprom.bf_hi & BWN_BFH_NOPA) ||
+ (siba->siba_sprom.bf_lo & BWN_BFL_HGPA))
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_r1);
+ else if (IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_2ghz_r1);
+ else
+ bwn_phy_lp_gaintbl_write_multi(mac, 0, 128, txgain_5ghz_r1);
+}
+
+static void
+bwn_tab_write(struct bwn_mac *mac, uint32_t typeoffset, uint32_t value)
+{
+ uint32_t offset, type;
+
+ type = BWN_TAB_GETTYPE(typeoffset);
+ offset = BWN_TAB_GETOFFSET(typeoffset);
+ KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
+
+ switch (type) {
+ case BWN_TAB_8BIT:
+ KASSERT(!(value & ~0xff), ("%s:%d: fail", __func__, __LINE__));
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
+ break;
+ case BWN_TAB_16BIT:
+ KASSERT(!(value & ~0xffff),
+ ("%s:%d: fail", __func__, __LINE__));
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
+ break;
+ case BWN_TAB_32BIT:
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATAHI, value >> 16);
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLEDATALO, value);
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ }
+}
+
+static int
+bwn_phy_lp_loopback(struct bwn_mac *mac)
+{
+ struct bwn_phy_lp_iq_est ie;
+ int i, index = -1;
+ uint32_t tmp;
+
+ memset(&ie, 0, sizeof(ie));
+
+ bwn_phy_lp_set_trsw_over(mac, 1, 1);
+ BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 1);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_CTL_OVRVAL, 0xfffe);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x800);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x800);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x8);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x8);
+ BWN_RF_WRITE(mac, BWN_B2062_N_TXCTL_A, 0x80);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_0, 0x80);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_VAL_0, 0x80);
+ for (i = 0; i < 32; i++) {
+ bwn_phy_lp_set_rxgain_idx(mac, i);
+ bwn_phy_lp_ddfs_turnon(mac, 1, 1, 5, 5, 0);
+ if (!(bwn_phy_lp_rx_iq_est(mac, 1000, 32, &ie)))
+ continue;
+ tmp = (ie.ie_ipwr + ie.ie_qpwr) / 1000;
+ if ((tmp > 4000) && (tmp < 10000)) {
+ index = i;
+ break;
+ }
+ }
+ bwn_phy_lp_ddfs_turnoff(mac);
+ return (index);
+}
+
+static void
+bwn_phy_lp_set_rxgain_idx(struct bwn_mac *mac, uint16_t idx)
+{
+
+ bwn_phy_lp_set_rxgain(mac, bwn_tab_read(mac, BWN_TAB_2(12, idx)));
+}
+
+static void
+bwn_phy_lp_ddfs_turnon(struct bwn_mac *mac, int i_on, int q_on,
+ int incr1, int incr2, int scale_idx)
+{
+
+ bwn_phy_lp_ddfs_turnoff(mac);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0xff80);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS_POINTER_INIT, 0x80ff);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0xff80, incr1);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS_INCR_INIT, 0x80ff, incr2 << 8);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xfff7, i_on << 3);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xffef, q_on << 4);
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DDFS, 0xff9f, scale_idx << 5);
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffb);
+ BWN_PHY_SET(mac, BWN_PHY_AFE_DDFS, 0x2);
+ BWN_PHY_SET(mac, BWN_PHY_LP_PHY_CTL, 0x20);
+}
+
+static uint8_t
+bwn_phy_lp_rx_iq_est(struct bwn_mac *mac, uint16_t sample, uint8_t time,
+ struct bwn_phy_lp_iq_est *ie)
+{
+ int i;
+
+ BWN_PHY_MASK(mac, BWN_PHY_CRSGAIN_CTL, 0xfff7);
+ BWN_PHY_WRITE(mac, BWN_PHY_IQ_NUM_SMPLS_ADDR, sample);
+ BWN_PHY_SETMASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xff00, time);
+ BWN_PHY_MASK(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0xfeff);
+ BWN_PHY_SET(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR, 0x200);
+
+ for (i = 0; i < 500; i++) {
+ if (!(BWN_PHY_READ(mac,
+ BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200))
+ break;
+ DELAY(1000);
+ }
+ if ((BWN_PHY_READ(mac, BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR) & 0x200)) {
+ BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
+ return 0;
+ }
+
+ ie->ie_iqprod = BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_HI_ADDR);
+ ie->ie_iqprod <<= 16;
+ ie->ie_iqprod |= BWN_PHY_READ(mac, BWN_PHY_IQ_ACC_LO_ADDR);
+ ie->ie_ipwr = BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_HI_ADDR);
+ ie->ie_ipwr <<= 16;
+ ie->ie_ipwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_I_PWR_ACC_LO_ADDR);
+ ie->ie_qpwr = BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR);
+ ie->ie_qpwr <<= 16;
+ ie->ie_qpwr |= BWN_PHY_READ(mac, BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR);
+
+ BWN_PHY_SET(mac, BWN_PHY_CRSGAIN_CTL, 0x8);
+ return 1;
+}
+
+static uint32_t
+bwn_tab_read(struct bwn_mac *mac, uint32_t typeoffset)
+{
+ uint32_t offset, type, value;
+
+ type = BWN_TAB_GETTYPE(typeoffset);
+ offset = BWN_TAB_GETOFFSET(typeoffset);
+ KASSERT(offset <= 0xffff, ("%s:%d: fail", __func__, __LINE__));
+
+ switch (type) {
+ case BWN_TAB_8BIT:
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+ value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO) & 0xff;
+ break;
+ case BWN_TAB_16BIT:
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+ value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
+ break;
+ case BWN_TAB_32BIT:
+ BWN_PHY_WRITE(mac, BWN_PHY_TABLE_ADDR, offset);
+ value = BWN_PHY_READ(mac, BWN_PHY_TABLEDATAHI);
+ value <<= 16;
+ value |= BWN_PHY_READ(mac, BWN_PHY_TABLEDATALO);
+ break;
+ default:
+ KASSERT(0 == 1, ("%s:%d: fail", __func__, __LINE__));
+ value = 0;
+ }
+
+ return (value);
+}
+
+static void
+bwn_phy_lp_ddfs_turnoff(struct bwn_mac *mac)
+{
+
+ BWN_PHY_MASK(mac, BWN_PHY_AFE_DDFS, 0xfffd);
+ BWN_PHY_MASK(mac, BWN_PHY_LP_PHY_CTL, 0xffdf);
+}
+
+static void
+bwn_phy_lp_set_txgain_dac(struct bwn_mac *mac, uint16_t dac)
+{
+ uint16_t ctl;
+
+ ctl = BWN_PHY_READ(mac, BWN_PHY_AFE_DAC_CTL) & 0xc7f;
+ ctl |= dac << 7;
+ BWN_PHY_SETMASK(mac, BWN_PHY_AFE_DAC_CTL, 0xf000, ctl);
+}
+
+static void
+bwn_phy_lp_set_txgain_pa(struct bwn_mac *mac, uint16_t gain)
+{
+
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfb), 0xe03f, gain << 6);
+ BWN_PHY_SETMASK(mac, BWN_PHY_OFDM(0xfd), 0x80ff, gain << 8);
+}
+
+static void
+bwn_phy_lp_set_txgain_override(struct bwn_mac *mac)
+{
+
+ if (mac->mac_phy.rev < 2)
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x100);
+ else {
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x80);
+ BWN_PHY_SET(mac, BWN_PHY_RF_OVERRIDE_2, 0x4000);
+ }
+ BWN_PHY_SET(mac, BWN_PHY_AFE_CTL_OVR, 0x40);
+}
+
+static uint16_t
+bwn_phy_lp_get_pa_gain(struct bwn_mac *mac)
+{
+
+ return BWN_PHY_READ(mac, BWN_PHY_OFDM(0xfb)) & 0x7f;
+}
+
+static uint8_t
+bwn_nbits(int32_t val)
+{
+ uint32_t tmp;
+ uint8_t nbits = 0;
+
+ for (tmp = abs(val); tmp != 0; tmp >>= 1)
+ nbits++;
+ return (nbits);
+}
+
+static void
+bwn_phy_lp_gaintbl_write_multi(struct bwn_mac *mac, int offset, int count,
+ struct bwn_txgain_entry *table)
+{
+ int i;
+
+ for (i = offset; i < count; i++)
+ bwn_phy_lp_gaintbl_write(mac, i, table[i]);
+}
+
+static void
+bwn_phy_lp_gaintbl_write(struct bwn_mac *mac, int offset,
+ struct bwn_txgain_entry data)
+{
+
+ if (mac->mac_phy.rev >= 2)
+ bwn_phy_lp_gaintbl_write_r2(mac, offset, data);
+ else
+ bwn_phy_lp_gaintbl_write_r01(mac, offset, data);
+}
+
+static void
+bwn_phy_lp_gaintbl_write_r2(struct bwn_mac *mac, int offset,
+ struct bwn_txgain_entry te)
+{
+ struct bwn_softc *sc = mac->mac_sc;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ uint32_t tmp;
+
+ KASSERT(mac->mac_phy.rev >= 2, ("%s:%d: fail", __func__, __LINE__));
+
+ tmp = (te.te_pad << 16) | (te.te_pga << 8) | te.te_gm;
+ if (mac->mac_phy.rev >= 3) {
+ tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
+ (0x10 << 24) : (0x70 << 24));
+ } else {
+ tmp |= ((IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) ?
+ (0x14 << 24) : (0x7f << 24));
+ }
+ bwn_tab_write(mac, BWN_TAB_4(7, 0xc0 + offset), tmp);
+ bwn_tab_write(mac, BWN_TAB_4(7, 0x140 + offset),
+ te.te_bbmult << 20 | te.te_dac << 28);
+}
+
+static void
+bwn_phy_lp_gaintbl_write_r01(struct bwn_mac *mac, int offset,
+ struct bwn_txgain_entry te)
+{
+
+ KASSERT(mac->mac_phy.rev < 2, ("%s:%d: fail", __func__, __LINE__));
+
+ bwn_tab_write(mac, BWN_TAB_4(10, 0xc0 + offset),
+ (te.te_pad << 11) | (te.te_pga << 7) | (te.te_gm << 4) |
+ te.te_dac);
+ bwn_tab_write(mac, BWN_TAB_4(10, 0x140 + offset), te.te_bbmult << 20);
+}
+
+static void
+bwn_identify(driver_t *driver, device_t parent)
+{
+
+ BUS_ADD_CHILD(parent, 0, "bwn", -1);
+}
+
+static device_method_t bwn_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, bwn_identify),
+ DEVMETHOD(device_probe, bwn_probe),
+ DEVMETHOD(device_attach, bwn_attach),
+ DEVMETHOD(device_detach, bwn_detach),
+ DEVMETHOD(device_suspend, bwn_suspend),
+ DEVMETHOD(device_resume, bwn_resume),
+ { 0,0 }
+};
+static driver_t bwn_driver = {
+ "bwn",
+ bwn_methods,
+ sizeof(struct bwn_softc)
+};
+static devclass_t bwn_devclass;
+DRIVER_MODULE(bwn, siba_bwn, bwn_driver, bwn_devclass, 0, 0);
+MODULE_DEPEND(bwn, siba_bwn, 1, 1, 1);
+MODULE_DEPEND(bwn, wlan, 1, 1, 1); /* 802.11 media layer */
+MODULE_DEPEND(bwn, firmware, 1, 1, 1); /* firmware support */
+MODULE_DEPEND(bwn, wlan_amrr, 1, 1, 1);
diff --git a/sys/dev/bwn/if_bwnreg.h b/sys/dev/bwn/if_bwnreg.h
new file mode 100644
index 0000000..71f56f4
--- /dev/null
+++ b/sys/dev/bwn/if_bwnreg.h
@@ -0,0 +1,998 @@
+/*-
+ * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_BWNREG_H
+#define _IF_BWNREG_H
+
+#define PCI_VENDOR_COMPAQ 0x0e11
+#define PCI_VENDOR_DELL 0x1028
+#define PCI_VENDOR_HP 0x103c
+#define PCI_VENDOR_ASUSTEK 0x1043
+#define PCI_VENDOR_MOTOROLA 0x1057
+#define PCI_VENDOR_APPLE 0x106b
+#define PCI_VENDOR_BROADCOM 0x14e4
+#define PCI_VENDOR_LINKSYS 0x1737
+
+#define BWN_BFL_BTCOEXIST 0x0001
+#define BWN_BFL_PACTRL 0x0002
+#define BWN_BFL_RSSI 0x0008
+#define BWN_BFL_CRYSTAL_NOSLOW 0x0020
+#define BWN_BFL_FEM 0x0800
+#define BWN_BFL_EXTLNA 0x1000
+#define BWN_BFL_HGPA 0x2000 /* had high gain PA */
+#define BWN_BFL_BTCMOD 0x4000
+#define BWN_BFL_ALTIQ 0x8000
+
+#define BWN_BFH_NOPA 0x0001
+#define BWN_BFH_RSSIINV 0x0002
+#define BWN_BFH_LDO_PAREF 0x0004
+#define BWN_BFH_FEM_BT 0x0040
+
+#define BWN_TGSLOW_SUPPORT_G 0x20000000
+#define BWN_TGSLOW_PHYRESET 0x00080000
+#define BWN_TGSLOW_PHYCLOCK_ENABLE 0x00040000
+#define BWN_TGSHIGH_HAVE_2GHZ 0x00010000
+#define BWN_TGSHIGH_HAVE_5GHZ 0x00020000
+
+#define BWN_PHYTYPE_A 0x00
+#define BWN_PHYTYPE_B 0x01
+#define BWN_PHYTYPE_G 0x02
+#define BWN_PHYTYPE_N 0x04
+#define BWN_PHYTYPE_LP 0x05
+
+#define BWN_DMA0_REASON 0x20
+#define BWN_DMA0_INTR_MASK 0x24
+#define BWN_DMA1_REASON 0x28
+#define BWN_DMA1_INTR_MASK 0x2c
+#define BWN_DMA2_REASON 0x30
+#define BWN_DMA2_INTR_MASK 0x34
+#define BWN_DMA3_REASON 0x38
+#define BWN_DMA3_INTR_MASK 0x3c
+#define BWN_DMA4_REASON 0x40
+#define BWN_DMA4_INTR_MASK 0x44
+#define BWN_DMA5_INTR_MASK 0x4c
+#define BWN_MACCTL 0x120
+#define BWN_MACCTL_ON 0x00000001
+#define BWN_MACCTL_MCODE_RUN 0x00000002
+#define BWN_MACCTL_MCODE_JMP0 0x00000004
+#define BWN_MACCTL_SHM_ON 0x00000100
+#define BWN_MACCTL_IHR_ON 0x00000400
+#define BWN_MACCTL_GPOUT_MASK 0x0000c000
+#define BWN_MACCTL_BIGENDIAN 0x00010000
+#define BWN_MACCTL_STA 0x00020000
+#define BWN_MACCTL_HOSTAP 0x00040000
+#define BWN_MACCTL_RADIO_LOCK 0x00080000
+#define BWN_MACCTL_BEACON_PROMISC 0x00100000
+#define BWN_MACCTL_PASS_BADPLCP 0x00200000
+#define BWN_MACCTL_PASS_CTL 0x00400000
+#define BWN_MACCTL_PASS_BADFCS 0x00800000
+#define BWN_MACCTL_PROMISC 0x01000000
+#define BWN_MACCTL_HWPS 0x02000000
+#define BWN_MACCTL_AWAKE 0x04000000
+#define BWN_MACCTL_GMODE 0x80000000
+#define BWN_MACCMD 0x124 /* MAC command */
+#define BWN_MACCMD_BEACON0_VALID 0x00000001
+#define BWN_MACCMD_BEACON1_VALID 0x00000002
+#define BWN_MACCMD_DFQ_VALID 0x00000004
+#define BWN_MACCMD_BGNOISE 0x00000010
+#define BWN_INTR_REASON 0x128
+#define BWN_INTR_MASK 0x12c
+#define BWN_RAM_CONTROL 0x130
+#define BWN_RAM_DATA 0x134
+#define BWN_PS_STATUS 0x140
+#define BWN_RF_HWENABLED_HI 0x158
+#define BWN_RF_HWENABLED_HI_MASK (1 << 16)
+#define BWN_SHM_CONTROL 0x160
+#define BWN_SHM_DATA 0x164
+#define BWN_SHM_DATA_UNALIGNED 0x166
+#define BWN_XMITSTAT_0 0x170
+#define BWN_XMITSTAT_1 0x174
+#define BWN_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
+#define BWN_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
+#define BWN_TSF_CFP_START 0x18c
+
+/* 32-bit DMA */
+#define BWN_DMA32_BASE0 0x200
+#define BWN_DMA32_BASE1 0x220
+#define BWN_DMA32_BASE2 0x240
+#define BWN_DMA32_BASE3 0x260
+#define BWN_DMA32_BASE4 0x280
+#define BWN_DMA32_BASE5 0x2a0
+/* 64-bit DMA */
+#define BWN_DMA64_BASE0 0x200
+#define BWN_DMA64_BASE1 0x240
+#define BWN_DMA64_BASE2 0x280
+#define BWN_DMA64_BASE3 0x2c0
+#define BWN_DMA64_BASE4 0x300
+#define BWN_DMA64_BASE5 0x340
+
+/* PIO on core rev < 11 */
+#define BWN_PIO_BASE0 0x300
+#define BWN_PIO_BASE1 0x310
+#define BWN_PIO_BASE2 0x320
+#define BWN_PIO_BASE3 0x330
+#define BWN_PIO_BASE4 0x340
+#define BWN_PIO_BASE5 0x350
+#define BWN_PIO_BASE6 0x360
+#define BWN_PIO_BASE7 0x370
+/* PIO on core rev >= 11 */
+#define BWN_PIO11_BASE0 0x200
+#define BWN_PIO11_BASE1 0x240
+#define BWN_PIO11_BASE2 0x280
+#define BWN_PIO11_BASE3 0x2c0
+#define BWN_PIO11_BASE4 0x300
+#define BWN_PIO11_BASE5 0x340
+
+#define BWN_GPIOCTL 0x06c
+#define BWN_PHYVER 0x3e0
+#define BWN_PHYVER_ANALOG 0xf000
+#define BWN_PHYVER_TYPE 0x0f00
+#define BWN_PHYVER_VERSION 0x00ff
+#define BWN_PHY_RADIO 0x3e2
+#define BWN_PHY0 0x3e6
+#define BWN_CHANNEL 0x3f0
+#define BWN_CHANNEL_EXT 0x3f4
+#define BWN_RFCTL 0x3f6
+#define BWN_RFCTL_ID 0x01
+#define BWN_RFDATAHI 0x3f8
+#define BWN_RFDATALO 0x3fa
+#define BWN_PHYCTL 0x3fc
+#define BWN_PHYDATA 0x3fe
+#define BWN_MACFILTER_CONTROL 0x420
+#define BWN_MACFILTER_DATA 0x422
+#define BWN_RCMTA_COUNT 0x43c
+#define BWN_RF_HWENABLED_LO 0x49a
+#define BWN_RF_HWENABLED_LO_MASK (1 << 4)
+#define BWN_GPIO_CONTROL 0x49c
+#define BWN_GPIO_MASK 0x49e
+#define BWN_TSF_CFP_START_LOW 0x604
+#define BWN_TSF_CFP_START_HIGH 0x606
+#define BWN_TSF_CFP_PRETBTT 0x612
+#define BWN_RNG 0x65a
+#define BWN_IFSCTL 0x688 /* Interframe space control */
+#define BWN_IFSCTL_USE_EDCF 0x0004
+#define BWN_POWERUP_DELAY 0x6a8
+#define BWN_BTCOEX_CTL 0x6b4
+#define BWN_BTCOEX_TXCTL 0x6b8
+
+#define BWN_UCODE 0x0
+#define BWN_HW 0x3
+#define BWN_RCMTA 0x4
+
+#define BWN_TSSI_MAX 0x7f
+#define BWN_SHARED 0x1
+#define BWN_SHARED_UCODE_REV 0x0000
+#define BWN_SHARED_UCODE_PATCH 0x0002
+#define BWN_SHARED_UCODE_DATE 0x0004
+#define BWN_SHARED_UCODE_TIME 0x0006
+#define BWN_SHARED_COREREV 0x0016
+#define BWN_SHARED_ACKCTS_PHYCTL 0x0022
+#define BWN_SHARED_RX_PADOFFSET 0x0034
+#define BWN_SHARED_UCODESTAT 0x0040
+#define BWN_SHARED_UCODESTAT_SUSPEND 3
+#define BWN_SHARED_UCODESTAT_SLEEP 4
+#define BWN_SHARED_FWCAPS 0x0042
+#define BWN_SHARED_SHORT_RETRY_FALLBACK 0x0044
+#define BWN_SHARED_LONG_RETRY_FALLBACK 0x0046
+#define BWN_SHARED_BEACON_PHYCTL 0x0054
+#define BWN_SHARED_KEY_TABLEP 0x0056
+#define BWN_SHARED_TSSI_CCK 0x0058
+#define BWN_SHARED_HFLO 0x005e /* low hostflag */
+#define BWN_SHARED_HFMI 0x0060 /* middle hostflag */
+#define BWN_SHARED_HFHI 0x0062 /* high hostflag */
+#define BWN_SHARED_RADIO_ATT 0x0064
+#define BWN_SHARED_TSSI_OFDM_G 0x0070
+#define BWN_SHARED_PROBE_RESP_MAXTIME 0x0074
+#define BWN_SHARED_SPU_WAKEUP 0x0094
+#define BWN_SHARED_PRETBTT 0x0096
+#define BWN_SHARED_CHAN 0x00a0
+#define BWN_SHARED_AUTOINC 0x0100
+#define BWN_SHARED_PROBE_RESP_PHYCTL 0x0188
+#define BWN_SHARED_EDCFQ 0x0240
+#define BWN_SHARED_KEYIDX_BLOCK 0x05d4
+#define BWN_SHARED_PSM 0x05f4
+
+/* SHM_SCRATCH offsets */
+#define BWN_SCRATCH 0x2
+#define BWN_SCRATCH_CONT_MIN 0x0003
+#define BWN_SCRATCH_CONT_MAX 0x0004
+#define BWN_SCRATCH_SHORT_RETRY 0x0006
+#define BWN_SCRATCH_LONG_RETRY 0x0007
+
+/* Generic-Interrupt reasons. */
+#define BWN_INTR_MAC_SUSPENDED 0x00000001
+#define BWN_INTR_BEACON 0x00000002
+#define BWN_INTR_TBTT_INDI 0x00000004
+#define BWN_INTR_ATIM_END 0x00000020
+#define BWN_INTR_PMQ 0x00000040
+#define BWN_INTR_MAC_TXERR 0x00000200
+#define BWN_INTR_PHY_TXERR 0x00000800
+#define BWN_INTR_DMA 0x00008000
+#define BWN_INTR_TXFIFO_FLUSH_OK 0x00010000
+#define BWN_INTR_NOISESAMPLE_OK 0x00040000
+#define BWN_INTR_UCODE_DEBUG 0x08000000
+#define BWN_INTR_RFKILL 0x10000000
+#define BWN_INTR_TX_OK 0x20000000
+#define BWN_INTR_ALL 0xffffffff
+#define BWN_INTR_MASKTEMPLATE \
+ (BWN_INTR_TBTT_INDI | BWN_INTR_ATIM_END | BWN_INTR_PMQ | \
+ BWN_INTR_MAC_TXERR | BWN_INTR_PHY_TXERR | BWN_INTR_DMA | \
+ BWN_INTR_TXFIFO_FLUSH_OK | BWN_INTR_NOISESAMPLE_OK | \
+ BWN_INTR_UCODE_DEBUG | BWN_INTR_RFKILL | BWN_INTR_TX_OK)
+
+#define BWN_HF_UCODE_ANTDIV_HELPER 0x000000000001ull
+#define BWN_HF_GPHY_SYM_WORKAROUND 0x000000000002ull
+#define BWN_HF_4DB_CCK_POWERBOOST 0x000000000008ull
+#define BWN_HF_BT_COEXIST 0x000000000010ull
+#define BWN_HF_GPHY_DC_CANCELFILTER 0x000000000020ull
+#define BWN_HF_PAGAINBOOST_OFDM_ON 0x000000000040ull
+#define BWN_HF_JAPAN_CHAN14_OFF 0x000000000080ull
+#define BWN_HF_EDCF 0x000000000100ull
+#define BWN_HF_TSSI_RESET_PSM_WORKAROUN 0x000000000200ull
+#define BWN_HF_SLOWCLOCK_REQ_OFF 0x000000000400ull
+#define BWN_HF_ACI_WORKAROUND 0x000000000800ull
+#define BWN_HF_2060_RADIO_WORKAROUND 0x000000001000ull
+#define BWN_HF_FORCE_VCO_RECALC 0x000000040000ull
+#define BWN_HF_PCI_SLOWCLOCK_WORKAROUND 0x000000080000ull
+#define BWN_HF_4318_TSSI 0x000000200000ull
+#define BWN_HF_HW_POWERCTL 0x000000800000ull
+#define BWN_HF_BT_COEXISTALT 0x000001000000ull
+#define BWN_HF_SKIP_CFP_UPDATE 0x000004000000ull
+#define BWN_HF_PR45960W 0x080000000000ULL
+
+#define BWN_TX_PHY_ENC_CCK 0x0000
+#define BWN_TX_PHY_ENC_OFDM 0x0001
+#define BWN_TX_PHY_SHORTPRMBL 0x0010
+#define BWN_TX_PHY_ANT 0x03c0
+#define BWN_TX_PHY_ANT0 0x0000
+#define BWN_TX_PHY_ANT1 0x0040
+#define BWN_TX_PHY_ANT01AUTO 0x00c0
+#define BWN_TX_PHY_ANT2 0x0100
+#define BWN_TX_PHY_ANT3 0x0200
+#define BWN_TX_PHY_TXPWR 0xfc00
+#define BWN_TX_MAC_ACK 0x00000001 /* immediate ACK */
+#define BWN_TX_MAC_LONGFRAME 0x00000002
+#define BWN_TX_MAC_SEND_RTSCTS 0x00000004
+#define BWN_TX_MAC_START_MSDU 0x00000008
+#define BWN_TX_MAC_HWSEQ 0x00000010
+#define BWN_TX_MAC_5GHZ 0x00000080
+#define BWN_TX_MAC_SEND_CTSTOSELF 0x00000800
+#define BWN_TX_EFT_FB_CCK 0x00
+#define BWN_TX_EFT_FB_OFDM 0x01
+#define BWN_TX_EFT_RTS_CCK 0x00
+#define BWN_TX_EFT_RTS_OFDM 0x04
+#define BWN_TX_EFT_RTS_FBCCK 0x00
+#define BWN_TX_EFT_RTS_FBOFDM 0x10
+
+#define BWN_PIO_TXCTL 0x00
+#define BWN_PIO_TXCTL_WRITELO 0x0001
+#define BWN_PIO_TXCTL_WRITEHI 0x0002
+#define BWN_PIO_TXCTL_EOF 0x0004
+#define BWN_PIO_TXCTL_FRAMEREADY 0x0008
+#define BWN_PIO_TXDATA 0x02
+#define BWN_PIO_TXQBUFSIZE 0x04
+#define BWN_PIO_RXCTL 0x00
+#define BWN_PIO_RXCTL_FRAMEREADY 0x0001
+#define BWN_PIO_RXCTL_DATAREADY 0x0002
+#define BWN_PIO_RXDATA 0x02
+#define BWN_PIO8_TXCTL 0x00
+#define BWN_PIO8_TXCTL_0_7 0x00000001
+#define BWN_PIO8_TXCTL_8_15 0x00000002
+#define BWN_PIO8_TXCTL_16_23 0x00000004
+#define BWN_PIO8_TXCTL_24_31 0x00000008
+#define BWN_PIO8_TXCTL_EOF 0x00000010
+#define BWN_PIO8_TXCTL_FRAMEREADY 0x00000080
+#define BWN_PIO8_TXDATA 0x04
+#define BWN_PIO8_RXCTL 0x00
+#define BWN_PIO8_RXCTL_FRAMEREADY 0x00000001
+#define BWN_PIO8_RXCTL_DATAREADY 0x00000002
+#define BWN_PIO8_RXDATA 0x04
+
+#define BWN_DMA32_TXCTL 0x00
+#define BWN_DMA32_TXENABLE 0x00000001
+#define BWN_DMA32_TXSUSPEND 0x00000002
+#define BWN_DMA32_TXADDREXT_MASK 0x00030000
+#define BWN_DMA32_TXADDREXT_SHIFT 16
+#define BWN_DMA32_TXRING 0x04
+#define BWN_DMA32_TXINDEX 0x08
+#define BWN_DMA32_TXSTATUS 0x0c
+#define BWN_DMA32_TXSTATE 0x0000f000
+#define BWN_DMA32_TXSTAT_DISABLED 0x00000000
+#define BWN_DMA32_TXSTAT_IDLEWAIT 0x00002000
+#define BWN_DMA32_TXSTAT_STOPPED 0x00003000
+#define BWN_DMA32_RXCTL 0x10
+#define BWN_DMA32_RXENABLE 0x00000001
+#define BWN_DMA32_RXFROFF_SHIFT 1
+#define BWN_DMA32_RXDIRECTFIFO 0x00000100
+#define BWN_DMA32_RXADDREXT_MASK 0x00030000
+#define BWN_DMA32_RXADDREXT_SHIFT 16
+#define BWN_DMA32_RXRING 0x14
+#define BWN_DMA32_RXINDEX 0x18
+#define BWN_DMA32_RXSTATUS 0x1c
+#define BWN_DMA32_RXDPTR 0x00000fff
+#define BWN_DMA32_RXSTATE 0x0000f000
+#define BWN_DMA32_RXSTAT_DISABLED 0x00000000
+#define BWN_DMA64_TXCTL 0x00
+#define BWN_DMA64_TXENABLE 0x00000001
+#define BWN_DMA64_TXSUSPEND 0x00000002
+#define BWN_DMA64_TXADDREXT_MASK 0x00030000
+#define BWN_DMA64_TXADDREXT_SHIFT 16
+#define BWN_DMA64_TXINDEX 0x04
+#define BWN_DMA64_TXRINGLO 0x08
+#define BWN_DMA64_TXRINGHI 0x0c
+#define BWN_DMA64_TXSTATUS 0x10
+#define BWN_DMA64_TXSTAT 0xf0000000
+#define BWN_DMA64_TXSTAT_DISABLED 0x00000000
+#define BWN_DMA64_TXSTAT_IDLEWAIT 0x20000000
+#define BWN_DMA64_TXSTAT_STOPPED 0x30000000
+#define BWN_DMA64_RXCTL 0x20
+#define BWN_DMA64_RXENABLE 0x00000001
+#define BWN_DMA64_RXFROFF_SHIFT 1
+#define BWN_DMA64_RXDIRECTFIFO 0x00000100
+#define BWN_DMA64_RXADDREXT_MASK 0x00030000
+#define BWN_DMA64_RXADDREXT_SHIFT 16
+#define BWN_DMA64_RXINDEX 0x24
+#define BWN_DMA64_RXRINGLO 0x28
+#define BWN_DMA64_RXRINGHI 0x2c
+#define BWN_DMA64_RXSTATUS 0x30
+#define BWN_DMA64_RXSTATDPTR 0x00001fff
+#define BWN_DMA64_RXSTAT 0xf0000000
+#define BWN_DMA64_RXSTAT_DISABLED 0x00000000
+#define BWN_DMA_RINGMEMSIZE PAGE_SIZE
+#define BWN_DMA0_RX_FRAMEOFFSET 30
+
+#define BWN_TXRING_SLOTS 64
+#define BWN_RXRING_SLOTS 64
+#define BWN_DMA0_RX_BUFFERSIZE IEEE80211_MAX_LEN
+
+#define BWN_PHYROUTE_BASE 0x0000
+#define BWN_PHYROUTE_OFDM_GPHY 0x0400
+#define BWN_PHYROUTE_EXT_GPHY 0x0800
+#define BWN_PHY_CCK(reg) ((reg) | BWN_PHYROUTE_BASE)
+#define BWN_PHY_N_BMODE(reg) ((reg) | BWN_PHYROUTE_N_BMODE)
+#define BWN_PHY_OFDM(reg) ((reg) | BWN_PHYROUTE_OFDM_GPHY)
+#define BWN_PHY_EXTG(reg) ((reg) | BWN_PHYROUTE_EXT_GPHY)
+
+#define BWN_PHY_VERSION_OFDM BWN_PHY_OFDM(0x00)
+#define BWN_PHY_BBANDCFG BWN_PHY_OFDM(0x01)
+#define BWN_PHY_BBANDCFG_RXANT 0x180
+#define BWN_PHY_BBANDCFG_RXANT_SHIFT 7
+#define BWN_PHY_PWRDOWN BWN_PHY_OFDM(0x03)
+#define BWN_PHY_CRSTHRES1_R1 BWN_PHY_OFDM(0x06)
+#define BWN_PHY_CRSGAIN_CTL BWN_PHY_OFDM(0x10)
+#define BWN_PHY_MINPWR_LEVEL BWN_PHY_OFDM(0x16)
+#define BWN_PHY_OFDMSYNCTHRESH0 BWN_PHY_OFDM(0x17)
+#define BWN_PHY_IDLEAFTERPKTRXTO BWN_PHY_OFDM(0x1a)
+#define BWN_PHY_LNAHPFCTL BWN_PHY_OFDM(0x1c)
+#define BWN_PHY_DCOFFSETTRANSIENT BWN_PHY_OFDM(0x1c) /* for LP */
+#define BWN_PHY_PREAMBLECONFIRMTO BWN_PHY_OFDM(0x1e)
+#define BWN_PHY_CLIPTHRESH BWN_PHY_OFDM(0x1f)
+#define BWN_PHY_LPFGAINCTL BWN_PHY_OFDM(0x20)
+#define BWN_PHY_CLIPCTRTHRESH BWN_PHY_OFDM(0x20) /* for LP */
+#define BWN_PHY_HIGAINDB BWN_PHY_OFDM(0x23)
+#define BWN_PHY_LOWGAINDB BWN_PHY_OFDM(0x24)
+#define BWN_PHY_VERYLOWGAINDB BWN_PHY_OFDM(0x25)
+#define BWN_PHY_GAINMISMATCH BWN_PHY_OFDM(0x26)
+#define BWN_PHY_ADIVRELATED BWN_PHY_OFDM(0x27)
+#define BWN_PHY_GAINDIRECTMISMATCH BWN_PHY_OFDM(0x27) /* for LP */
+#define BWN_PHY_CRS0 BWN_PHY_OFDM(0x29)
+#define BWN_PHY_CRS0_EN 0x4000
+#define BWN_PHY_PWR_THRESH1 BWN_PHY_OFDM(0x29) /* for LP */
+#define BWN_PHY_ANTDWELL BWN_PHY_OFDM(0x2b)
+#define BWN_PHY_ANTDWELL_AUTODIV1 0x0100
+#define BWN_PHY_DSSS_CONFIRM_CNT BWN_PHY_OFDM(0x2f) /* DSSS Confirm Cnt */
+#define BWN_PHY_PEAK_COUNT BWN_PHY_OFDM(0x30)
+#define BWN_PHY_GAIN_MISMATCH_LIMIT BWN_PHY_OFDM(0x31)
+#define BWN_PHY_CRS_ED_THRESH BWN_PHY_OFDM(0x32)
+#define BWN_PHY_INPUT_PWRDB BWN_PHY_OFDM(0x34)
+#define BWN_PHY_AFE_ADC_CTL_0 BWN_PHY_OFDM(0x36)
+#define BWN_PHY_AFE_ADC_CTL_1 BWN_PHY_OFDM(0x37)
+#define BWN_PHY_AFE_DAC_CTL BWN_PHY_OFDM(0x39)
+#define BWN_PHY_AFE_CTL BWN_PHY_OFDM(0x3a)
+#define BWN_PHY_AFE_CTL_OVR BWN_PHY_OFDM(0x3b)
+#define BWN_PHY_AFE_CTL_OVRVAL BWN_PHY_OFDM(0x3c)
+#define BWN_PHY_AFE_RSSI_CTL_0 BWN_PHY_OFDM(0x3d)
+#define BWN_PHY_AFE_RSSI_CTL_1 BWN_PHY_OFDM(0x3e)
+#define BWN_PHY_LP_PHY_CTL BWN_PHY_OFDM(0x48)
+#define BWN_PHY_ENCORE BWN_PHY_OFDM(0x49)
+#define BWN_PHY_ENCORE_EN 0x0200
+#define BWN_PHY_RESET_CTL BWN_PHY_OFDM(0x4a)
+#define BWN_PHY_RF_OVERRIDE_0 BWN_PHY_OFDM(0x4c)
+#define BWN_PHY_RF_OVERRIDE_VAL_0 BWN_PHY_OFDM(0x4d)
+#define BWN_PHY_TR_LOOKUP_1 BWN_PHY_OFDM(0x4e)
+#define BWN_PHY_TR_LOOKUP_2 BWN_PHY_OFDM(0x4F)
+#define BWN_PHY_LMS BWN_PHY_OFDM(0x55)
+#define BWN_PHY_TABLE_ADDR BWN_PHY_OFDM(0x55) /* for LP */
+#define BWN_PHY_TABLEDATALO BWN_PHY_OFDM(0x56)
+#define BWN_PHY_TABLEDATAHI BWN_PHY_OFDM(0x57)
+#define BWN_PHY_OFDM61 BWN_PHY_OFDM(0x61)
+#define BWN_PHY_OFDM61_10 0x0010
+#define BWN_PHY_ADC_COMPENSATION_CTL BWN_PHY_OFDM(0x70)
+#define BWN_PHY_OTABLECTL BWN_PHY_OFDM(0x72)
+#define BWN_PHY_OTABLENR_SHIFT 10
+#define BWN_PHY_OTABLEI BWN_PHY_OFDM(0x73)
+#define BWN_PHY_OTABLEQ BWN_PHY_OFDM(0x74)
+#define BWN_PHY_HPWR_TSSICTL BWN_PHY_OFDM(0x78)
+#define BWN_PHY_IQ_ENABLE_WAIT_TIME_ADDR BWN_PHY_OFDM(0x81)
+#define BWN_PHY_IQ_NUM_SMPLS_ADDR BWN_PHY_OFDM(0x82)
+#define BWN_PHY_IQ_ACC_HI_ADDR BWN_PHY_OFDM(0x83)
+#define BWN_PHY_IQ_ACC_LO_ADDR BWN_PHY_OFDM(0x84)
+#define BWN_PHY_IQ_I_PWR_ACC_HI_ADDR BWN_PHY_OFDM(0x85)
+#define BWN_PHY_IQ_I_PWR_ACC_LO_ADDR BWN_PHY_OFDM(0x86)
+#define BWN_PHY_IQ_Q_PWR_ACC_HI_ADDR BWN_PHY_OFDM(0x87)
+#define BWN_PHY_IQ_Q_PWR_ACC_LO_ADDR BWN_PHY_OFDM(0x88)
+#define BWN_PHY_ANTWRSETT BWN_PHY_OFDM(0x8c)
+#define BWN_PHY_ANTWRSETT_ARXDIV 0x2000
+#define BWN_PHY_OFDM9B BWN_PHY_OFDM(0x9b)
+#define BWN_PHY_A_PHY_CTL_ADDR BWN_PHY_OFDM(0x9c)
+#define BWN_PHY_RX_COMP_COEFF_S BWN_PHY_OFDM(0x9e)
+#define BWN_PHY_N1P1GAIN BWN_PHY_OFDM(0xa0)
+#define BWN_PHY_SMPL_PLAY_COUNT BWN_PHY_OFDM(0xa0) /* for LP */
+#define BWN_PHY_P1P2GAIN BWN_PHY_OFDM(0xa1)
+#define BWN_PHY_SMPL_PLAY_BUFFER_CTL BWN_PHY_OFDM(0xA1) /* for LP */
+#define BWN_PHY_N1N2GAIN BWN_PHY_OFDM(0xa2)
+#define BWN_PHY_4WIRECTL BWN_PHY_OFDM(0xa2) /* for LP */
+#define BWN_PHY_TX_PWR_CTL_CMD BWN_PHY_OFDM(0xa4)
+#define BWN_PHY_TX_PWR_CTL_CMD_MODE 0xe000
+#define BWN_PHY_TX_PWR_CTL_CMD_MODE_OFF 0x0000
+#define BWN_PHY_TX_PWR_CTL_CMD_MODE_SW 0x8000
+#define BWN_PHY_TX_PWR_CTL_CMD_MODE_HW 0xe000
+#define BWN_PHY_CCKSHIFTBITS_WA BWN_PHY_OFDM(0xa5)
+#define BWN_PHY_TX_PWR_CTL_NNUM BWN_PHY_OFDM(0xa5) /* for LP */
+#define BWN_PHY_CCKSHIFTBITS BWN_PHY_OFDM(0xa7)
+#define BWN_PHY_DIVSRCHIDX BWN_PHY_OFDM(0xa8)
+#define BWN_PHY_DIVP1P2GAIN BWN_PHY_OFDM(0xab)
+#define BWN_PHY_LP_RF_SIGNAL_LUT BWN_PHY_OFDM(0xac)
+#define BWN_PHY_DIVSRCHGAINBACK BWN_PHY_OFDM(0xad)
+#define BWN_PHY_RX_RADIO_CTL BWN_PHY_OFDM(0xae)
+#define BWN_PHY_RF_OVERRIDE_2 BWN_PHY_OFDM(0xb0)
+#define BWN_PHY_RF_OVERRIDE_2_VAL BWN_PHY_OFDM(0xb1)
+#define BWN_PHY_PS_CTL_OVERRIDE_VAL0 BWN_PHY_OFDM(0xB2)
+#define BWN_PHY_PS_CTL_OVERRIDE_VAL1 BWN_PHY_OFDM(0xB3)
+#define BWN_PHY_PS_CTL_OVERRIDE_VAL2 BWN_PHY_OFDM(0xB4)
+#define BWN_PHY_TX_GAIN_CTL_OVERRIDE_VAL BWN_PHY_OFDM(0xB5)
+#define BWN_PHY_RX_GAIN_CTL_OVERRIDE_VAL BWN_PHY_OFDM(0xB6)
+#define BWN_PHY_AFE_DDFS BWN_PHY_OFDM(0xb7)
+#define BWN_PHY_AFE_DDFS_POINTER_INIT BWN_PHY_OFDM(0xB8)
+#define BWN_PHY_AFE_DDFS_INCR_INIT BWN_PHY_OFDM(0xB9)
+#define BWN_PHY_TR_LOOKUP_3 BWN_PHY_OFDM(0xbb)
+#define BWN_PHY_TR_LOOKUP_4 BWN_PHY_OFDM(0xbc)
+#define BWN_PHY_GPIO_OUTEN BWN_PHY_OFDM(0xbe)
+#define BWN_PHY_GPIO_SELECT BWN_PHY_OFDM(0xbf)
+#define BWN_PHY_CRSTHRES1 BWN_PHY_OFDM(0xc0)
+#define BWN_PHY_CRSTHRES2 BWN_PHY_OFDM(0xc1)
+#define BWN_PHY_4C3 BWN_PHY_OFDM(0xC3)
+#define BWN_PHY_4C4 BWN_PHY_OFDM(0xC4)
+#define BWN_PHY_4C5 BWN_PHY_OFDM(0xC5)
+#define BWN_PHY_TR_LOOKUP_5 BWN_PHY_OFDM(0xC7)
+#define BWN_PHY_TR_LOOKUP_6 BWN_PHY_OFDM(0xC8)
+#define BWN_PHY_TR_LOOKUP_7 BWN_PHY_OFDM(0xC9)
+#define BWN_PHY_TR_LOOKUP_8 BWN_PHY_OFDM(0xCA)
+#define BWN_PHY_RF_PWR_OVERRIDE BWN_PHY_OFDM(0xd3)
+
+#define BWN_OFDMTAB(number, offset) \
+ (((number) << BWN_PHY_OTABLENR_SHIFT) | (offset))
+#define BWN_OFDMTAB_AGC1 BWN_OFDMTAB(0x00, 0)
+#define BWN_OFDMTAB_GAIN0 BWN_OFDMTAB(0x00, 0)
+#define BWN_OFDMTAB_GAINX BWN_OFDMTAB(0x01, 0)
+#define BWN_OFDMTAB_GAIN1 BWN_OFDMTAB(0x01, 4)
+#define BWN_OFDMTAB_AGC3 BWN_OFDMTAB(0x02, 0)
+#define BWN_OFDMTAB_GAIN2 BWN_OFDMTAB(0x02, 3)
+#define BWN_OFDMTAB_LNAHPFGAIN1 BWN_OFDMTAB(0x03, 0)
+#define BWN_OFDMTAB_WRSSI BWN_OFDMTAB(0x04, 0)
+#define BWN_OFDMTAB_NOISESCALE BWN_OFDMTAB(0x05, 0)
+#define BWN_OFDMTAB_AGC2 BWN_OFDMTAB(0x06, 0)
+#define BWN_OFDMTAB_ROTOR BWN_OFDMTAB(0x08, 0)
+#define BWN_OFDMTAB_ADVRETARD BWN_OFDMTAB(0x09, 0)
+#define BWN_OFDMTAB_DAC BWN_OFDMTAB(0x0c, 0)
+#define BWN_OFDMTAB_DC BWN_OFDMTAB(0x0e, 7)
+#define BWN_OFDMTAB_PWRDYN2 BWN_OFDMTAB(0x0e, 12)
+#define BWN_OFDMTAB_UNKNOWN_0F BWN_OFDMTAB(0x0f, 0)
+#define BWN_OFDMTAB_UNKNOWN_APHY BWN_OFDMTAB(0x0f, 7)
+#define BWN_OFDMTAB_LPFGAIN BWN_OFDMTAB(0x0f, 12)
+#define BWN_OFDMTAB_RSSI BWN_OFDMTAB(0x10, 0)
+#define BWN_OFDMTAB_UNKNOWN_11 BWN_OFDMTAB(0x11, 4)
+#define BWN_OFDMTAB_AGC1_R1 BWN_OFDMTAB(0x13, 0)
+#define BWN_OFDMTAB_GAINX_R1 BWN_OFDMTAB(0x14, 0)
+#define BWN_OFDMTAB_MINSIGSQ BWN_OFDMTAB(0x14, 0)
+#define BWN_OFDMTAB_AGC3_R1 BWN_OFDMTAB(0x15, 0)
+#define BWN_OFDMTAB_WRSSI_R1 BWN_OFDMTAB(0x15, 4)
+#define BWN_OFDMTAB_DACRFPABB BWN_OFDMTAB(0x16, 0)
+
+#define BWN_PHY_CCKBBANDCFG BWN_PHY_CCK(0x01)
+#define BWN_PHY_PGACTL BWN_PHY_CCK(0x15)
+#define BWN_PHY_PGACTL_LPF 0x1000
+#define BWN_PHY_PGACTL_LOWBANDW 0x0040
+#define BWN_PHY_PGACTL_UNKNOWN 0xefa0
+#define BWN_PHY_TSSI BWN_PHY_CCK(0x29)
+#define BWN_PHY_LO_LEAKAGE BWN_PHY_CCK(0x2d)
+#define BWN_PHY_SYNCPEAKCNT BWN_PHY_CCK(0x30)
+#define BWN_PHY_SYNCCTL BWN_PHY_CCK(0x35)
+#define BWN_PHY_DACCTL BWN_PHY_CCK(0x60)
+
+#define BWN_PHY_CLASSCTL BWN_PHY_EXTG(0x02)
+#define BWN_PHY_GTABCTL BWN_PHY_EXTG(0x03)
+#define BWN_PHY_GTABNR_SHIFT 10
+#define BWN_PHY_GTABDATA BWN_PHY_EXTG(0x04)
+#define BWN_PHY_LO_MASK BWN_PHY_EXTG(0x0f)
+#define BWN_PHY_LO_CTL BWN_PHY_EXTG(0x10)
+#define BWN_PHY_RFOVER BWN_PHY_EXTG(0x11)
+#define BWN_PHY_RFOVERVAL BWN_PHY_EXTG(0x12)
+#define BWN_PHY_RFOVERVAL_EXTLNA 0x8000
+#define BWN_PHY_RFOVERVAL_LNA 0x7000
+#define BWN_PHY_RFOVERVAL_LNA_SHIFT 12
+#define BWN_PHY_RFOVERVAL_PGA 0x0f00
+#define BWN_PHY_RFOVERVAL_PGA_SHIFT 8
+#define BWN_PHY_RFOVERVAL_UNK 0x0010
+#define BWN_PHY_RFOVERVAL_TRSWRX 0x00e0
+#define BWN_PHY_RFOVERVAL_BW 0x0003
+#define BWN_PHY_RFOVERVAL_BW_LPF 0x0001
+#define BWN_PHY_RFOVERVAL_BW_LBW 0x0002
+#define BWN_PHY_ANALOGOVER BWN_PHY_EXTG(0x14)
+#define BWN_PHY_ANALOGOVERVAL BWN_PHY_EXTG(0x15)
+
+#define BWN_GTAB(number, offset) \
+ (((number) << BWN_PHY_GTABNR_SHIFT) | (offset))
+#define BWN_GTAB_ORIGTR BWN_GTAB(0x2e, 0x298)
+
+#define BWN_PHY_G_LOCTL 0x0810
+#define BWN_PHY_RADIO_BITFIELD 0x0401
+#define BWN_PHY_G_CRS 0x0429
+#define BWN_PHY_NRSSI_CTRL 0x0803
+#define BWN_PHY_NRSSI_DATA 0x0804
+#define BWN_FWCAPS_HWCRYPTO 0x0001
+#define BWN_FWCAPS_WME 0x0002
+#define BWN_MACFILTER_SELF 0x0000
+#define BWN_MACFILTER_BSSID 0x0003
+#define BWN_SEC_KEYSIZE 16
+#define BWN_SEC_ALGO_NONE 0
+#define BWN_LED_BEHAVIOUR 0x7f
+#define BWN_LED_ACTIVELOW 0x80
+
+#define BWN_DEBUGINTR_REASON_REG 63
+#define BWN_DEBUGINTR_PANIC 0
+#define BWN_DEBUGINTR_DUMP_SHM 1
+#define BWN_DEBUGINTR_DUMP_REGS 2
+#define BWN_DEBUGINTR_MARKER 3
+#define BWN_DEBUGINTR_ACK 0xffff
+
+#define BWN_FWPANIC_REASON_REG 3
+#define BWN_FWPANIC_DIE 0
+#define BWN_FWPANIC_RESTART 1
+#define BWN_WATCHDOG_REG 1
+
+#define BWN_CCK_RATE_1MB 0x02
+#define BWN_CCK_RATE_2MB 0x04
+#define BWN_CCK_RATE_5MB 0x0b
+#define BWN_CCK_RATE_11MB 0x16
+#define BWN_OFDM_RATE_6MB 0x0c
+#define BWN_OFDM_RATE_9MB 0x12
+#define BWN_OFDM_RATE_12MB 0x18
+#define BWN_OFDM_RATE_18MB 0x24
+#define BWN_OFDM_RATE_24MB 0x30
+#define BWN_OFDM_RATE_36MB 0x48
+#define BWN_OFDM_RATE_48MB 0x60
+#define BWN_OFDM_RATE_54MB 0x6c
+
+#define BWN_RX_CHAN_PHYTYPE 0x0007
+#define BWN_RX_PHYST0_GAINCTL 0x4000
+#define BWN_RX_PHYST0_PLCPHCF 0x0200
+#define BWN_RX_PHYST0_PLCPFV 0x0100
+#define BWN_RX_PHYST0_SHORTPRMBL 0x0080
+#define BWN_RX_PHYST0_OFDM 0x0001
+#define BWN_RX_PHYST3_TRSTATE 0x0400
+#define BWN_RX_MAC_KEYIDX 0x000007e0
+#define BWN_RX_MAC_KEYIDX_SHIFT 5
+#define BWN_RX_MAC_DECERR 0x00000010
+#define BWN_RX_MAC_DEC 0x00000008
+#define BWN_RX_MAC_PADDING 0x00000004
+#define BWN_RX_MAC_FCSERR 0x00000001
+
+#define BWN_PS_ON (1 << 0)
+#define BWN_PS_OFF (1 << 1)
+#define BWN_PS_AWAKE (1 << 2)
+#define BWN_PS_ASLEEP (1 << 3)
+
+#define BWN_TAB_NOISESCALE_SIZE 27
+
+/*
+ * SPROM GPIO
+ */
+#define BWN_LED_ACT_LOW 0x80
+#define BWN_LED_ACT_MASK 0x7f
+#define BWN_LED_ACT_OFF 0
+#define BWN_LED_ACT_ON 1
+#define BWN_LED_ACT_BLINK 2
+#define BWN_LED_ACT_RF_ENABLED 3
+#define BWN_LED_ACT_5GHZ 4
+#define BWN_LED_ACT_2GHZ 5
+#define BWN_LED_ACT_11G 6
+#define BWN_LED_ACT_BLINK_SLOW 7
+#define BWN_LED_ACT_BLINK_POLL 8
+#define BWN_LED_ACT_UNKN 9
+#define BWN_LED_ACT_ASSOC 10
+#define BWN_LED_ACT_NULL 11
+
+#define BWN_VENDOR_LED_ACT_COMPAQ \
+ BWN_LED_ACT_RF_ENABLED, \
+ BWN_LED_ACT_2GHZ, \
+ BWN_LED_ACT_5GHZ, \
+ BWN_LED_ACT_OFF
+
+#define BWN_VENDOR_LED_ACT_ASUSTEK \
+ BWN_LED_ACT_ASSOC, \
+ BWN_LED_ACT_2GHZ, \
+ BWN_LED_ACT_5GHZ, \
+ BWN_LED_ACT_OFF
+
+#define BWN_VENDOR_LED_ACT_DEFAULT \
+ BWN_LED_ACT_BLINK, \
+ BWN_LED_ACT_2GHZ, \
+ BWN_LED_ACT_5GHZ, \
+ BWN_LED_ACT_OFF
+
+#define BWN_TAB_ROTOR \
+{ \
+ 0xfeb93ffd, 0xfec63ffd, 0xfed23ffd, 0xfedf3ffd, 0xfeec3ffe, \
+ 0xfef83ffe, 0xff053ffe, 0xff113ffe, 0xff1e3ffe, 0xff2a3fff, \
+ 0xff373fff, 0xff443fff, 0xff503fff, 0xff5d3fff, 0xff693fff, \
+ 0xff763fff, 0xff824000, 0xff8f4000, 0xff9b4000, 0xffa84000, \
+ 0xffb54000, 0xffc14000, 0xffce4000, 0xffda4000, 0xffe74000, \
+ 0xfff34000, 0x00004000, 0x000d4000, 0x00194000, 0x00264000, \
+ 0x00324000, 0x003f4000, 0x004b4000, 0x00584000, 0x00654000, \
+ 0x00714000, 0x007e4000, 0x008a3fff, 0x00973fff, 0x00a33fff, \
+ 0x00b03fff, 0x00bc3fff, 0x00c93fff, 0x00d63fff, 0x00e23ffe, \
+ 0x00ef3ffe, 0x00fb3ffe, 0x01083ffe, 0x01143ffe, 0x01213ffd, \
+ 0x012e3ffd, 0x013a3ffd, 0x01473ffd \
+}
+
+#define BWN_TAB_RETARD \
+{ \
+ 0xdb93cb87, 0xd666cf64, 0xd1fdd358, 0xcda6d826, 0xca38dd9f, \
+ 0xc729e2b4, 0xc469e88e, 0xc26aee2b, 0xc0def46c, 0xc073fa62, \
+ 0xc01d00d5, 0xc0760743, 0xc1560d1e, 0xc2e51369, 0xc4ed18ff, \
+ 0xc7ac1ed7, 0xcb2823b2, 0xcefa28d9, 0xd2f62d3f, 0xd7bb3197, \
+ 0xdce53568, 0xe1fe3875, 0xe7d13b35, 0xed663d35, 0xf39b3ec4, \
+ 0xf98e3fa7, 0x00004000, 0x06723fa7, 0x0c653ec4, 0x129a3d35, \
+ 0x182f3b35, 0x1e023875, 0x231b3568, 0x28453197, 0x2d0a2d3f, \
+ 0x310628d9, 0x34d823b2, 0x38541ed7, 0x3b1318ff, 0x3d1b1369, \
+ 0x3eaa0d1e, 0x3f8a0743, 0x3fe300d5, 0x3f8dfa62, 0x3f22f46c, \
+ 0x3d96ee2b, 0x3b97e88e, 0x38d7e2b4, 0x35c8dd9f, 0x325ad826, \
+ 0x2e03d358, 0x299acf64, 0x246dcb87, \
+}
+
+#define BWN_TAB_FINEFREQ_G \
+{ \
+ 0x0089, 0x02e9, 0x0409, 0x04e9, 0x05a9, 0x0669, 0x0709, 0x0789, \
+ 0x0829, 0x08a9, 0x0929, 0x0989, 0x0a09, 0x0a69, 0x0ac9, 0x0b29, \
+ 0x0ba9, 0x0be9, 0x0c49, 0x0ca9, 0x0d09, 0x0d69, 0x0da9, 0x0e09, \
+ 0x0e69, 0x0ea9, 0x0f09, 0x0f49, 0x0fa9, 0x0fe9, 0x1029, 0x1089, \
+ 0x10c9, 0x1109, 0x1169, 0x11a9, 0x11e9, 0x1229, 0x1289, 0x12c9, \
+ 0x1309, 0x1349, 0x1389, 0x13c9, 0x1409, 0x1449, 0x14a9, 0x14e9, \
+ 0x1529, 0x1569, 0x15a9, 0x15e9, 0x1629, 0x1669, 0x16a9, 0x16e8, \
+ 0x1728, 0x1768, 0x17a8, 0x17e8, 0x1828, 0x1868, 0x18a8, 0x18e8, \
+ 0x1928, 0x1968, 0x19a8, 0x19e8, 0x1a28, 0x1a68, 0x1aa8, 0x1ae8, \
+ 0x1b28, 0x1b68, 0x1ba8, 0x1be8, 0x1c28, 0x1c68, 0x1ca8, 0x1ce8, \
+ 0x1d28, 0x1d68, 0x1dc8, 0x1e08, 0x1e48, 0x1e88, 0x1ec8, 0x1f08, \
+ 0x1f48, 0x1f88, 0x1fe8, 0x2028, 0x2068, 0x20a8, 0x2108, 0x2148, \
+ 0x2188, 0x21c8, 0x2228, 0x2268, 0x22c8, 0x2308, 0x2348, 0x23a8, \
+ 0x23e8, 0x2448, 0x24a8, 0x24e8, 0x2548, 0x25a8, 0x2608, 0x2668, \
+ 0x26c8, 0x2728, 0x2787, 0x27e7, 0x2847, 0x28c7, 0x2947, 0x29a7, \
+ 0x2a27, 0x2ac7, 0x2b47, 0x2be7, 0x2ca7, 0x2d67, 0x2e47, 0x2f67, \
+ 0x3247, 0x3526, 0x3646, 0x3726, 0x3806, 0x38a6, 0x3946, 0x39e6, \
+ 0x3a66, 0x3ae6, 0x3b66, 0x3bc6, 0x3c45, 0x3ca5, 0x3d05, 0x3d85, \
+ 0x3de5, 0x3e45, 0x3ea5, 0x3ee5, 0x3f45, 0x3fa5, 0x4005, 0x4045, \
+ 0x40a5, 0x40e5, 0x4145, 0x4185, 0x41e5, 0x4225, 0x4265, 0x42c5, \
+ 0x4305, 0x4345, 0x43a5, 0x43e5, 0x4424, 0x4464, 0x44c4, 0x4504, \
+ 0x4544, 0x4584, 0x45c4, 0x4604, 0x4644, 0x46a4, 0x46e4, 0x4724, \
+ 0x4764, 0x47a4, 0x47e4, 0x4824, 0x4864, 0x48a4, 0x48e4, 0x4924, \
+ 0x4964, 0x49a4, 0x49e4, 0x4a24, 0x4a64, 0x4aa4, 0x4ae4, 0x4b23, \
+ 0x4b63, 0x4ba3, 0x4be3, 0x4c23, 0x4c63, 0x4ca3, 0x4ce3, 0x4d23, \
+ 0x4d63, 0x4da3, 0x4de3, 0x4e23, 0x4e63, 0x4ea3, 0x4ee3, 0x4f23, \
+ 0x4f63, 0x4fc3, 0x5003, 0x5043, 0x5083, 0x50c3, 0x5103, 0x5143, \
+ 0x5183, 0x51e2, 0x5222, 0x5262, 0x52a2, 0x52e2, 0x5342, 0x5382, \
+ 0x53c2, 0x5402, 0x5462, 0x54a2, 0x5502, 0x5542, 0x55a2, 0x55e2, \
+ 0x5642, 0x5682, 0x56e2, 0x5722, 0x5782, 0x57e1, 0x5841, 0x58a1, \
+ 0x5901, 0x5961, 0x59c1, 0x5a21, 0x5aa1, 0x5b01, 0x5b81, 0x5be1, \
+ 0x5c61, 0x5d01, 0x5d80, 0x5e20, 0x5ee0, 0x5fa0, 0x6080, 0x61c0, \
+}
+
+#define BWN_TAB_NOISE_G1 \
+{ \
+ 0x013c, 0x01f5, 0x031a, 0x0631, 0x0001, 0x0001, 0x0001, 0x0001, \
+}
+
+#define BWN_TAB_NOISE_G2 \
+{ \
+ 0x5484, 0x3c40, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, \
+}
+
+#define BWN_TAB_NOISESCALE_G1 \
+{ \
+ 0x6c77, 0x5162, 0x3b40, 0x3335, 0x2f2d, 0x2a2a, 0x2527, 0x1f21, \
+ 0x1a1d, 0x1719, 0x1616, 0x1414, 0x1414, 0x1400, 0x1414, 0x1614, \
+ 0x1716, 0x1a19, 0x1f1d, 0x2521, 0x2a27, 0x2f2a, 0x332d, 0x3b35, \
+ 0x5140, 0x6c62, 0x0077, \
+}
+
+#define BWN_TAB_NOISESCALE_G2 \
+{ \
+ 0xd8dd, 0xcbd4, 0xbcc0, 0xb6b7, 0xb2b0, 0xadad, 0xa7a9, 0x9fa1, \
+ 0x969b, 0x9195, 0x8f8f, 0x8a8a, 0x8a8a, 0x8a00, 0x8a8a, 0x8f8a, \
+ 0x918f, 0x9695, 0x9f9b, 0xa7a1, 0xada9, 0xb2ad, 0xb6b0, 0xbcb7, \
+ 0xcbc0, 0xd8d4, 0x00dd, \
+}
+
+#define BWN_TAB_NOISESCALE_G3 \
+{ \
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, \
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa400, 0xa4a4, 0xa4a4, \
+ 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, 0xa4a4, \
+ 0xa4a4, 0xa4a4, 0x00a4, \
+}
+
+#define BWN_TAB_SIGMASQR2 \
+{ \
+ 0x00de, 0x00dc, 0x00da, 0x00d8, 0x00d6, 0x00d4, 0x00d2, 0x00cf, \
+ 0x00cd, 0x00ca, 0x00c7, 0x00c4, 0x00c1, 0x00be, 0x00be, 0x00be, \
+ 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, \
+ 0x00be, 0x00be, 0x0000, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, \
+ 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, 0x00be, \
+ 0x00c1, 0x00c4, 0x00c7, 0x00ca, 0x00cd, 0x00cf, 0x00d2, 0x00d4, \
+ 0x00d6, 0x00d8, 0x00da, 0x00dc, 0x00de, \
+}
+
+#define BWN_PHY_G_TSSI2DBM_TABLE \
+{ \
+ 77, 77, 77, 76, 76, 76, 75, 75, 74, 74, 73, 73, 73, 72, 72, 71, \
+ 71, 70, 70, 69, 68, 68, 67, 67, 66, 65, 65, 64, 63, 63, 62, 61, \
+ 60, 59, 58, 57, 56, 55, 54, 53, 52, 50, 49, 47, 45, 43, 40, 37, \
+ 33, 28, 22, 14, 5, -7, -20, -20, -20, -20, -20, -20, -20, -20, \
+ -20, -20 \
+}
+
+#define BWN_PHY_G_RF_CHANNELS \
+{ \
+ 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, 72, 84, \
+}
+
+#define BWN_BITREV_TABLE \
+{ \
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, \
+ 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, \
+ 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, \
+ 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, \
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, \
+ 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, \
+ 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, \
+ 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, \
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, \
+ 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, \
+ 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, \
+ 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, \
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, \
+ 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, \
+ 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, \
+ 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, \
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, \
+ 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, \
+ 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, \
+ 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, \
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, \
+ 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, \
+ 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, \
+ 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, \
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, \
+ 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff \
+}
+
+/*
+ * LP PHY
+ */
+
+#define BWN_TAB_TYPEMASK 0xf0000000
+#define BWN_TAB_GETTYPE(v) ((v) & BWN_TAB_TYPEMASK)
+#define BWN_TAB_GETOFFSET(v) ((v) & ~BWN_TAB_TYPEMASK)
+#define BWN_TAB_8BIT 0x10000000
+#define BWN_TAB_16BIT 0x20000000
+#define BWN_TAB_32BIT 0x30000000
+#define BWN_TAB_1(table, offset) \
+ (((table) << 10) | (offset) | BWN_TAB_8BIT)
+#define BWN_TAB_2(table, offset) \
+ (((table) << 10) | (offset) | BWN_TAB_16BIT)
+#define BWN_TAB_4(table, offset) \
+ (((table) << 10) | (offset) | BWN_TAB_32BIT)
+
+#define BWN_LP_RADIO(radio_reg) (radio_reg)
+#define BWN_LP_NORTH(radio_reg) BWN_LP_RADIO(radio_reg)
+#define BWN_LP_SOUTH(radio_reg) BWN_LP_RADIO((radio_reg) | 0x4000)
+
+#define BWN_B2062_N_COM1 BWN_LP_NORTH(0x000)
+#define BWN_B2062_N_COM2 BWN_LP_NORTH(0x002)
+#define BWN_B2062_N_COM4 BWN_LP_NORTH(0x004)
+#define BWN_B2062_N_PDNCTL0 BWN_LP_NORTH(0x010)
+#define BWN_B2062_N_PDNCTL1 BWN_LP_NORTH(0x011)
+#define BWN_B2062_N_PDNCTL3 BWN_LP_NORTH(0x013)
+#define BWN_B2062_N_PDNCTL4 BWN_LP_NORTH(0x014)
+#define BWN_B2062_N_LGENC BWN_LP_NORTH(0x017)
+#define BWN_B2062_N_LGENATUNE0 BWN_LP_NORTH(0x01E)
+#define BWN_B2062_N_LGENATUNE2 BWN_LP_NORTH(0x020)
+#define BWN_B2062_N_LGENATUNE3 BWN_LP_NORTH(0x021)
+#define BWN_B2062_N_LGENACTL3 BWN_LP_NORTH(0x022)
+#define BWN_B2062_N_LGENACTL5 BWN_LP_NORTH(0x024)
+#define BWN_B2062_N_LGENACTL6 BWN_LP_NORTH(0x025)
+#define BWN_B2062_N_LGENACTL7 BWN_LP_NORTH(0x026)
+#define BWN_B2062_N_RXA_CTL1 BWN_LP_NORTH(0x028)
+#define BWN_B2062_N_RXBB_CTL0 BWN_LP_NORTH(0x02F)
+#define BWN_B2062_N_RXBB_GAIN1 BWN_LP_NORTH(0x033)
+#define BWN_B2062_N_RXBB_GAIN2 BWN_LP_NORTH(0x034)
+#define BWN_B2062_N_RXBB_CALIB2 BWN_LP_NORTH(0x03A)
+#define BWN_B2062_N_TXCTL3 BWN_LP_NORTH(0x048)
+#define BWN_B2062_N_TXCTL4 BWN_LP_NORTH(0x049)
+#define BWN_B2062_N_TXCTL5 BWN_LP_NORTH(0x04A)
+#define BWN_B2062_N_TXCTL6 BWN_LP_NORTH(0x04B)
+#define BWN_B2062_N_TXCTL_A BWN_LP_NORTH(0x04F)
+#define BWN_B2062_N_TX_TUNE BWN_LP_NORTH(0x052)
+#define BWN_B2062_N_TX_PAD BWN_LP_NORTH(0x053)
+#define BWN_B2062_N_TX_PGA BWN_LP_NORTH(0x054)
+#define BWN_B2062_N_TSSI_CTL0 BWN_LP_NORTH(0x057)
+#define BWN_B2062_N_CALIB_TS BWN_LP_NORTH(0x05D)
+#define BWN_B2062_S_COM4 BWN_LP_SOUTH(0x004)
+#define BWN_B2062_S_PDS_CTL0 BWN_LP_SOUTH(0x010)
+#define BWN_B2062_S_BG_CTL1 BWN_LP_SOUTH(0x015)
+#define BWN_B2062_S_LGENG_CTL0 BWN_LP_SOUTH(0x017)
+#define BWN_B2062_S_LGENG_CTL1 BWN_LP_SOUTH(0x018)
+#define BWN_B2062_S_LGENG_CTL8 BWN_LP_SOUTH(0x01F)
+#define BWN_B2062_S_LGENG_CTL10 BWN_LP_SOUTH(0x021)
+#define BWN_B2062_S_RFPLLCTL0 BWN_LP_SOUTH(0x034)
+#define BWN_B2062_S_RFPLLCTL1 BWN_LP_SOUTH(0x035)
+#define BWN_B2062_S_RFPLLCTL2 BWN_LP_SOUTH(0x036)
+#define BWN_B2062_S_RFPLLCTL3 BWN_LP_SOUTH(0x037)
+#define BWN_B2062_S_RFPLLCTL5 BWN_LP_SOUTH(0x039)
+#define BWN_B2062_S_RFPLLCTL6 BWN_LP_SOUTH(0x03A)
+#define BWN_B2062_S_RFPLLCTL7 BWN_LP_SOUTH(0x03B)
+#define BWN_B2062_S_RFPLLCTL8 BWN_LP_SOUTH(0x03C)
+#define BWN_B2062_S_RFPLLCTL9 BWN_LP_SOUTH(0x03D)
+#define BWN_B2062_S_RFPLLCTL10 BWN_LP_SOUTH(0x03E)
+#define BWN_B2062_S_RFPLLCTL11 BWN_LP_SOUTH(0x03F)
+#define BWN_B2062_S_RFPLLCTL12 BWN_LP_SOUTH(0x040)
+#define BWN_B2062_S_RFPLLCTL13 BWN_LP_SOUTH(0x041)
+#define BWN_B2062_S_RFPLLCTL14 BWN_LP_SOUTH(0x042)
+#define BWN_B2062_S_RFPLLCTL18 BWN_LP_SOUTH(0x046)
+#define BWN_B2062_S_RFPLLCTL19 BWN_LP_SOUTH(0x047)
+#define BWN_B2062_S_RFPLLCTL21 BWN_LP_SOUTH(0x049)
+#define BWN_B2062_S_RFPLLCTL22 BWN_LP_SOUTH(0x04A)
+#define BWN_B2062_S_RFPLLCTL23 BWN_LP_SOUTH(0x04B)
+#define BWN_B2062_S_RFPLLCTL24 BWN_LP_SOUTH(0x04C)
+#define BWN_B2062_S_RFPLLCTL25 BWN_LP_SOUTH(0x04D)
+#define BWN_B2062_S_RFPLLCTL26 BWN_LP_SOUTH(0x04E)
+#define BWN_B2062_S_RFPLLCTL27 BWN_LP_SOUTH(0x04F)
+#define BWN_B2062_S_RFPLLCTL28 BWN_LP_SOUTH(0x050)
+#define BWN_B2062_S_RFPLLCTL29 BWN_LP_SOUTH(0x051)
+#define BWN_B2062_S_RFPLLCTL30 BWN_LP_SOUTH(0x052)
+#define BWN_B2062_S_RFPLLCTL31 BWN_LP_SOUTH(0x053)
+#define BWN_B2062_S_RFPLLCTL33 BWN_LP_SOUTH(0x055)
+#define BWN_B2062_S_RFPLLCTL34 BWN_LP_SOUTH(0x056)
+#define BWN_B2062_S_RXG_CNT8 BWN_LP_SOUTH(0x05F)
+#define BWN_B2062_S_RXG_CNT16 BWN_LP_SOUTH(0x067)
+#define BWN_B2063_COM1 BWN_LP_RADIO(0x000)
+#define BWN_B2063_COM8 BWN_LP_RADIO(0x008)
+#define BWN_B2063_COM10 BWN_LP_RADIO(0x00A)
+#define BWN_B2063_COM15 BWN_LP_RADIO(0x00F)
+#define BWN_B2063_COM16 BWN_LP_RADIO(0x010)
+#define BWN_B2063_COM17 BWN_LP_RADIO(0x011)
+#define BWN_B2063_COM18 BWN_LP_RADIO(0x012)
+#define BWN_B2063_COM19 BWN_LP_RADIO(0x013)
+#define BWN_B2063_COM20 BWN_LP_RADIO(0x014)
+#define BWN_B2063_COM21 BWN_LP_RADIO(0x015)
+#define BWN_B2063_COM22 BWN_LP_RADIO(0x016)
+#define BWN_B2063_COM23 BWN_LP_RADIO(0x017)
+#define BWN_B2063_COM24 BWN_LP_RADIO(0x018)
+#define BWN_B2063_PLL_SP1 BWN_LP_RADIO(0x01A)
+#define BWN_B2063_PLL_SP2 BWN_LP_RADIO(0x01B)
+#define BWN_B2063_LOGEN_SP1 BWN_LP_RADIO(0x01C)
+#define BWN_B2063_LOGEN_SP2 BWN_LP_RADIO(0x01D)
+#define BWN_B2063_LOGEN_SP4 BWN_LP_RADIO(0x01F)
+#define BWN_B2063_LOGEN_SP5 BWN_LP_RADIO(0x020)
+#define BWN_B2063_G_RX_SP1 BWN_LP_RADIO(0x021)
+#define BWN_B2063_G_RX_SP2 BWN_LP_RADIO(0x022)
+#define BWN_B2063_G_RX_SP3 BWN_LP_RADIO(0x023)
+#define BWN_B2063_G_RX_SP7 BWN_LP_RADIO(0x027)
+#define BWN_B2063_G_RX_SP10 BWN_LP_RADIO(0x02A)
+#define BWN_B2063_A_RX_SP1 BWN_LP_RADIO(0x02C)
+#define BWN_B2063_A_RX_SP2 BWN_LP_RADIO(0x02D)
+#define BWN_B2063_A_RX_SP7 BWN_LP_RADIO(0x032)
+#define BWN_B2063_RX_BB_SP3 BWN_LP_RADIO(0x035)
+#define BWN_B2063_RX_BB_SP4 BWN_LP_RADIO(0x036)
+#define BWN_B2063_RX_BB_SP8 BWN_LP_RADIO(0x03A)
+#define BWN_B2063_TX_RF_SP3 BWN_LP_RADIO(0x03D)
+#define BWN_B2063_TX_RF_SP4 BWN_LP_RADIO(0x03E)
+#define BWN_B2063_TX_RF_SP6 BWN_LP_RADIO(0x040)
+#define BWN_B2063_TX_RF_SP9 BWN_LP_RADIO(0x043)
+#define BWN_B2063_PA_SP1 BWN_LP_RADIO(0x04C)
+#define BWN_B2063_PA_SP2 BWN_LP_RADIO(0x04D)
+#define BWN_B2063_PA_SP3 BWN_LP_RADIO(0x04E)
+#define BWN_B2063_PA_SP4 BWN_LP_RADIO(0x04F)
+#define BWN_B2063_PA_SP7 BWN_LP_RADIO(0x052)
+#define BWN_B2063_TX_BB_SP1 BWN_LP_RADIO(0x053)
+#define BWN_B2063_TX_BB_SP3 BWN_LP_RADIO(0x055)
+#define BWN_B2063_REG_SP1 BWN_LP_RADIO(0x056)
+#define BWN_B2063_BANDGAP_CTL1 BWN_LP_RADIO(0x057)
+#define BWN_B2063_RC_CALIB_CTL1 BWN_LP_RADIO(0x05A)
+#define BWN_B2063_RC_CALIB_CTL2 BWN_LP_RADIO(0x05B)
+#define BWN_B2063_RC_CALIB_CTL3 BWN_LP_RADIO(0x05C)
+#define BWN_B2063_RC_CALIB_CTL4 BWN_LP_RADIO(0x05D)
+#define BWN_B2063_RC_CALIB_CTL5 BWN_LP_RADIO(0x05E)
+#define BWN_B2063_RC_CALIB_CTL6 BWN_LP_RADIO(0x05F)
+#define BWN_B2063_JTAG_CALNRST BWN_LP_RADIO(0x064)
+#define BWN_B2063_JTAG_CP2 BWN_LP_RADIO(0x068)
+#define BWN_B2063_JTAG_CP3 BWN_LP_RADIO(0x069)
+#define BWN_B2063_JTAG_LF1 BWN_LP_RADIO(0x06C)
+#define BWN_B2063_JTAG_LF2 BWN_LP_RADIO(0x06D)
+#define BWN_B2063_JTAG_LF3 BWN_LP_RADIO(0x06E)
+#define BWN_B2063_JTAG_LF4 BWN_LP_RADIO(0x06F)
+#define BWN_B2063_JTAG_SG1 BWN_LP_RADIO(0x070)
+#define BWN_B2063_JTAG_SG2 BWN_LP_RADIO(0x071)
+#define BWN_B2063_JTAG_SG3 BWN_LP_RADIO(0x072)
+#define BWN_B2063_JTAG_SG4 BWN_LP_RADIO(0x073)
+#define BWN_B2063_JTAG_VCO1 BWN_LP_RADIO(0x075)
+#define BWN_B2063_JTAG_VCO2 BWN_LP_RADIO(0x076)
+#define BWN_B2063_JTAG_VCO_CALIB3 BWN_LP_RADIO(0x079)
+#define BWN_B2063_JTAG_VCO_CALIB5 BWN_LP_RADIO(0x07B)
+#define BWN_B2063_JTAG_VCO_CALIB6 BWN_LP_RADIO(0x07C)
+#define BWN_B2063_JTAG_VCO_CALIB7 BWN_LP_RADIO(0x07D)
+#define BWN_B2063_JTAG_VCO_CALIB8 BWN_LP_RADIO(0x07E)
+#define BWN_B2063_JTAG_XTAL_12 BWN_LP_RADIO(0x081)
+#define BWN_B2063_LOGEN_RCCR1 BWN_LP_RADIO(0x0A1)
+#define BWN_B2063_LOGEN_VCOBUF1 BWN_LP_RADIO(0x0A2)
+#define BWN_B2063_LOGEN_MIXER2 BWN_LP_RADIO(0x0A4)
+#define BWN_B2063_LOGEN_BUF2 BWN_LP_RADIO(0x0A6)
+#define BWN_B2063_G_RX_MIX3 BWN_LP_RADIO(0x0C4)
+#define BWN_B2063_G_RX_MIX4 BWN_LP_RADIO(0x0C5)
+#define BWN_B2063_A_RX_1ST2 BWN_LP_RADIO(0x0CF)
+#define BWN_B2063_A_RX_1ST3 BWN_LP_RADIO(0x0D0)
+#define BWN_B2063_A_RX_2ND1 BWN_LP_RADIO(0x0D3)
+#define BWN_B2063_A_RX_2ND4 BWN_LP_RADIO(0x0D6)
+#define BWN_B2063_A_RX_2ND7 BWN_LP_RADIO(0x0D9)
+#define BWN_B2063_A_RX_PS6 BWN_LP_RADIO(0x0DF)
+#define BWN_B2063_A_RX_MIX4 BWN_LP_RADIO(0x0E3)
+#define BWN_B2063_A_RX_MIX5 BWN_LP_RADIO(0x0E4)
+#define BWN_B2063_A_RX_MIX6 BWN_LP_RADIO(0x0E5)
+#define BWN_B2063_RX_TIA_CTL1 BWN_LP_RADIO(0x0EC)
+#define BWN_B2063_RX_TIA_CTL3 BWN_LP_RADIO(0x0EE)
+#define BWN_B2063_RX_BB_CTL2 BWN_LP_RADIO(0x0F3)
+#define BWN_B2063_TX_RF_CTL2 BWN_LP_RADIO(0x100)
+#define BWN_B2063_TX_RF_CTL5 BWN_LP_RADIO(0x103)
+#define BWN_B2063_PA_CTL1 BWN_LP_RADIO(0x10B)
+#define BWN_B2063_PA_CTL11 BWN_LP_RADIO(0x115)
+#define BWN_B2063_VREG_CTL1 BWN_LP_RADIO(0x11D)
+
+#endif /* !_IF_BWNREG_H */
diff --git a/sys/dev/bwn/if_bwnvar.h b/sys/dev/bwn/if_bwnvar.h
new file mode 100644
index 0000000..40b759e
--- /dev/null
+++ b/sys/dev/bwn/if_bwnvar.h
@@ -0,0 +1,957 @@
+/*-
+ * Copyright (c) 2009-2010 Weongyo Jeong <weongyo@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ * redistribution must be conditioned upon including a substantially
+ * similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _IF_BWNVAR_H
+#define _IF_BWNVAR_H
+
+struct siba_dev_softc;
+struct bwn_softc;
+struct bwn_mac;
+
+#define N(a) (sizeof(a) / sizeof(a[0]))
+#define BWN_ALIGN 0x1000
+#define BWN_BUS_SPACE_MAXADDR_30BIT 0x3fffffff
+#define BWN_RETRY_SHORT 7
+#define BWN_RETRY_LONG 4
+#define BWN_STAID_MAX 64
+#define BWN_TXPWR_IGNORE_TIME (1 << 0)
+#define BWN_TXPWR_IGNORE_TSSI (1 << 1)
+#define BWN_HAS_TXMAG(phy) \
+ (((phy)->rev >= 2) && ((phy)->rf_ver == 0x2050) && \
+ ((phy)->rf_rev == 8))
+#define BWN_HAS_LOOPBACK(phy) \
+ (((phy)->rev > 1) || ((phy)->gmode))
+#define BWN_TXERROR_MAX 1000
+#define BWN_GETTIME(v) do { \
+ struct timespec ts; \
+ nanouptime(&ts); \
+ (v) = ts.tv_nsec / 1000000 + ts.tv_sec * 1000; \
+} while (0)
+#define BWN_ISOLDFMT(mac) ((mac)->mac_fw.rev <= 351)
+#define BWN_TSSI2DBM(num, den) \
+ ((int32_t)((num < 0) ? num / den : (num + den / 2) / den))
+#define BWN_HDRSIZE(mac) \
+ ((BWN_ISOLDFMT(mac)) ? (100 + sizeof(struct bwn_plcp6)) : \
+ (104 + sizeof(struct bwn_plcp6)))
+#define BWN_PIO_COOKIE(tq, tp) \
+ ((uint16_t)((((uint16_t)tq->tq_index + 1) << 12) | tp->tp_index))
+#define BWN_DMA_COOKIE(dr, slot) \
+ ((uint16_t)(((uint16_t)dr->dr_index + 1) << 12) | (uint16_t)slot)
+#define BWN_READ_2(mac, o) (siba_read_2(mac->mac_sd, o))
+#define BWN_READ_4(mac, o) (siba_read_4(mac->mac_sd, o))
+#define BWN_WRITE_2(mac, o, v) (siba_write_2(mac->mac_sd, o, v))
+#define BWN_WRITE_4(mac, o, v) (siba_write_4(mac->mac_sd, o, v))
+#define BWN_PIO_TXQOFFSET(mac) \
+ ((mac->mac_sd->sd_id.sd_rev >= 11) ? 0x18 : 0)
+#define BWN_PIO_RXQOFFSET(mac) \
+ ((mac->mac_sd->sd_id.sd_rev >= 11) ? 0x38 : 8)
+#define BWN_SEC_NEWAPI(mac) (mac->mac_fw.rev >= 351)
+#define BWN_SEC_KEY2FW(mac, idx) \
+ (BWN_SEC_NEWAPI(mac) ? idx : ((idx >= 4) ? idx - 4 : idx))
+#define BWN_RF_READ(mac, r) (mac->mac_phy.rf_read(mac, r))
+#define BWN_RF_WRITE(mac, r, v) (mac->mac_phy.rf_write(mac, r, v))
+#define BWN_RF_MASK(mac, o, m) \
+ BWN_RF_WRITE(mac, o, BWN_RF_READ(mac, o) & m)
+#define BWN_RF_SETMASK(mac, offset, mask, set) \
+ BWN_RF_WRITE(mac, offset, (BWN_RF_READ(mac, offset) & mask) | set)
+#define BWN_RF_SET(mac, offset, set) \
+ BWN_RF_WRITE(mac, offset, BWN_RF_READ(mac, offset) | set)
+#define BWN_PHY_READ(mac, r) (mac->mac_phy.phy_read(mac, r))
+#define BWN_PHY_WRITE(mac, r, v) \
+ (mac->mac_phy.phy_write(mac, r, v))
+#define BWN_PHY_SET(mac, offset, set) do { \
+ if (mac->mac_phy.phy_maskset != NULL) { \
+ KASSERT(mac->mac_status < BWN_MAC_STATUS_INITED || \
+ mac->mac_suspended > 0, \
+ ("dont access PHY or RF registers after turning on MAC")); \
+ mac->mac_phy.phy_maskset(mac, offset, 0xffff, set); \
+ } else \
+ BWN_PHY_WRITE(mac, offset, \
+ BWN_PHY_READ(mac, offset) | (set)); \
+} while (0)
+#define BWN_PHY_SETMASK(mac, offset, mask, set) do { \
+ if (mac->mac_phy.phy_maskset != NULL) { \
+ KASSERT(mac->mac_status < BWN_MAC_STATUS_INITED || \
+ mac->mac_suspended > 0, \
+ ("dont access PHY or RF registers after turning on MAC")); \
+ mac->mac_phy.phy_maskset(mac, offset, mask, set); \
+ } else \
+ BWN_PHY_WRITE(mac, offset, \
+ (BWN_PHY_READ(mac, offset) & (mask)) | (set)); \
+} while (0)
+#define BWN_PHY_MASK(mac, offset, mask) do { \
+ if (mac->mac_phy.phy_maskset != NULL) { \
+ KASSERT(mac->mac_status < BWN_MAC_STATUS_INITED || \
+ mac->mac_suspended > 0, \
+ ("dont access PHY or RF registers after turning on MAC")); \
+ mac->mac_phy.phy_maskset(mac, offset, mask, 0); \
+ } else \
+ BWN_PHY_WRITE(mac, offset, \
+ BWN_PHY_READ(mac, offset) & mask); \
+} while (0)
+#define BWN_PHY_COPY(mac, dst, src) do { \
+ KASSERT(mac->mac_status < BWN_MAC_STATUS_INITED || \
+ mac->mac_suspended > 0, \
+ ("dont access PHY or RF registers after turning on MAC")); \
+ BWN_PHY_WRITE(mac, dst, BWN_PHY_READ(mac, src)); \
+} while (0)
+#define BWN_LO_CALIB_EXPIRE (1000 * (30 - 2))
+#define BWN_LO_PWRVEC_EXPIRE (1000 * (30 - 2))
+#define BWN_LO_TXCTL_EXPIRE (1000 * (180 - 4))
+#define BWN_DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
+#define BWN_LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0))
+#define BWN_BITREV4(tmp) (BWN_BITREV8(tmp) >> 4)
+#define BWN_BITREV8(byte) (bwn_bitrev_table[byte])
+#define BWN_BBATTCMP(a, b) ((a)->att == (b)->att)
+#define BWN_RFATTCMP(a, b) \
+ (((a)->att == (b)->att) && ((a)->padmix == (b)->padmix))
+#define BWN_PIO_WRITE_2(mac, tq, offset, value) \
+ BWN_WRITE_2(mac, (tq)->tq_base + offset, value)
+#define BWN_PIO_READ_4(mac, tq, offset) \
+ BWN_READ_4(mac, tq->tq_base + offset)
+#define BWN_ISCCKRATE(rate) \
+ (rate == BWN_CCK_RATE_1MB || rate == BWN_CCK_RATE_2MB || \
+ rate == BWN_CCK_RATE_5MB || rate == BWN_CCK_RATE_11MB)
+#define BWN_ISOFDMRATE(rate) (!BWN_ISCCKRATE(rate))
+#define BWN_BARRIER(mac, flags) siba_barrier(mac->mac_sd, flags)
+#define BWN_DMA_READ(dr, offset) \
+ (BWN_READ_4(dr->dr_mac, dr->dr_base + offset))
+#define BWN_DMA_WRITE(dr, offset, value) \
+ (BWN_WRITE_4(dr->dr_mac, dr->dr_base + offset, value))
+
+struct bwn_rate {
+ uint16_t rateid;
+ uint32_t flags;
+};
+
+#define BWN_ANT0 0
+#define BWN_ANT1 1
+#define BWN_ANTAUTO0 2
+#define BWN_ANTAUTO1 3
+#define BWN_ANT2 4
+#define BWN_ANT3 8
+#define BWN_ANTAUTO BWN_ANTAUTO0
+#define BWN_ANT_DEFAULT BWN_ANTAUTO
+#define BWN_TX_SLOTS_PER_FRAME 2
+
+struct bwn_channel {
+ unsigned freq;
+ unsigned ieee;
+ unsigned maxTxPow;
+};
+
+struct bwn_channelinfo {
+ struct bwn_channel channels[IEEE80211_CHAN_MAX];
+ unsigned nchannels;
+};
+
+struct bwn_bbatt {
+ uint8_t att;
+};
+
+struct bwn_bbatt_list {
+ const struct bwn_bbatt *array;
+ uint8_t len;
+ uint8_t min;
+ uint8_t max;
+};
+
+struct bwn_rfatt {
+ uint8_t att;
+ int padmix;
+};
+
+struct bwn_rfatt_list {
+ const struct bwn_rfatt *array;
+ uint8_t len;
+ uint8_t min;
+ uint8_t max;
+};
+
+#define BWN_DC_LT_SIZE 32
+
+struct bwn_loctl {
+ int8_t i;
+ int8_t q;
+};
+
+struct bwn_lo_calib {
+ struct bwn_bbatt bbatt;
+ struct bwn_rfatt rfatt;
+ struct bwn_loctl ctl;
+ unsigned long calib_time;
+ TAILQ_ENTRY(bwn_lo_calib) list;
+};
+
+struct bwn_rxhdr4 {
+ uint16_t frame_len;
+ uint8_t pad1[2];
+ uint16_t phy_status0;
+ union {
+ struct {
+ uint8_t rssi;
+ uint8_t sig_qual;
+ } __packed abg;
+ struct {
+ int8_t power0;
+ int8_t power1;
+ } __packed n;
+ } __packed phy;
+ uint16_t phy_status2;
+ uint16_t phy_status3;
+ uint32_t mac_status;
+ uint16_t mac_time;
+ uint16_t channel;
+} __packed;
+
+struct bwn_txstatus {
+ uint16_t cookie;
+ uint16_t seq;
+ uint8_t phy_stat;
+ uint8_t framecnt;
+ uint8_t rtscnt;
+ uint8_t sreason;
+ uint8_t pm;
+ uint8_t im;
+ uint8_t ampdu;
+ uint8_t ack;
+};
+
+#define BWN_TXCTL_PA3DB 0x40
+#define BWN_TXCTL_PA2DB 0x20
+#define BWN_TXCTL_TXMIX 0x10
+
+struct bwn_txpwr_loctl {
+ struct bwn_rfatt_list rfatt;
+ struct bwn_bbatt_list bbatt;
+ uint16_t dc_lt[BWN_DC_LT_SIZE];
+ TAILQ_HEAD(, bwn_lo_calib) calib_list;
+ unsigned long pwr_vec_read_time;
+ unsigned long txctl_measured_time;
+ uint8_t tx_bias;
+ uint8_t tx_magn;
+ uint64_t power_vector;
+};
+
+#define BWN_OFDMTAB_DIR_UNKNOWN 0
+#define BWN_OFDMTAB_DIR_READ 1
+#define BWN_OFDMTAB_DIR_WRITE 2
+
+struct bwn_phy_g {
+ unsigned pg_flags;
+#define BWN_PHY_G_FLAG_TSSITABLE_ALLOC (1 << 0)
+#define BWN_PHY_G_FLAG_RADIOCTX_VALID (1 << 1)
+ int pg_aci_enable;
+ int pg_aci_wlan_automatic;
+ int pg_aci_hw_rssi;
+ int pg_rf_on;
+ uint16_t pg_radioctx_over;
+ uint16_t pg_radioctx_overval;
+ uint16_t pg_minlowsig[2];
+ uint16_t pg_minlowsigpos[2];
+ int8_t *pg_tssi2dbm;
+ int pg_idletssi;
+ int pg_curtssi;
+ uint8_t pg_avgtssi;
+ struct bwn_bbatt pg_bbatt;
+ struct bwn_rfatt pg_rfatt;
+ uint8_t pg_txctl;
+ int pg_bbatt_delta;
+ int pg_rfatt_delta;
+
+ struct bwn_txpwr_loctl pg_loctl;
+ int16_t pg_max_lb_gain;
+ int16_t pg_trsw_rx_gain;
+ int16_t pg_lna_lod_gain;
+ int16_t pg_lna_gain;
+ int16_t pg_pga_gain;
+ int pg_immode;
+#define BWN_INTERFSTACK_SIZE 26
+ uint32_t pg_interfstack[BWN_INTERFSTACK_SIZE];
+
+ int16_t pg_nrssi[2];
+ int32_t pg_nrssi_slope;
+ int8_t pg_nrssi_lt[64];
+
+ uint16_t pg_lofcal;
+
+ uint16_t pg_initval;
+ uint16_t pg_ofdmtab_addr;
+ unsigned pg_ofdmtab_dir;
+};
+
+#define BWN_IMMODE_NONE 0
+#define BWN_IMMODE_NONWLAN 1
+#define BWN_IMMODE_MANUAL 2
+#define BWN_IMMODE_AUTO 3
+#define BWN_TXPWR_RES_NEED_ADJUST 0
+#define BWN_TXPWR_RES_DONE 1
+
+#define BWN_PHYLP_TXPCTL_UNKNOWN 0
+#define BWN_PHYLP_TXPCTL_OFF 1
+#define BWN_PHYLP_TXPCTL_ON_SW 2
+#define BWN_PHYLP_TXPCTL_ON_HW 3
+
+struct bwn_phy_lp {
+ uint8_t plp_chan;
+ uint8_t plp_chanfullcal;
+ int32_t plp_antenna;
+ uint8_t plp_txpctlmode;
+ uint8_t plp_txisoband_h;
+ uint8_t plp_txisoband_m;
+ uint8_t plp_txisoband_l;
+ uint8_t plp_rxpwroffset;
+ int8_t plp_txpwridx;
+ uint16_t plp_tssiidx;
+ uint16_t plp_tssinpt;
+ uint8_t plp_rssivf;
+ uint8_t plp_rssivc;
+ uint8_t plp_rssigs;
+ uint8_t plp_rccap;
+ uint8_t plp_bxarch;
+ uint8_t plp_crsusr_off;
+ uint8_t plp_crssys_off;
+ uint32_t plp_div;
+ int32_t plp_tonefreq;
+ uint16_t plp_digfilt[9];
+};
+
+/* for LP */
+struct bwn_txgain {
+ uint16_t tg_gm;
+ uint16_t tg_pga;
+ uint16_t tg_pad;
+ uint16_t tg_dac;
+};
+
+struct bwn_rxcompco {
+ uint8_t rc_chan;
+ int8_t rc_c1;
+ int8_t rc_c0;
+};
+
+struct bwn_phy_lp_iq_est {
+ uint32_t ie_iqprod;
+ uint32_t ie_ipwr;
+ uint32_t ie_qpwr;
+};
+
+struct bwn_txgain_entry {
+ uint8_t te_gm;
+ uint8_t te_pga;
+ uint8_t te_pad;
+ uint8_t te_dac;
+ uint8_t te_bbmult;
+};
+
+/* only for LP PHY */
+struct bwn_stxtable {
+ uint16_t st_phyoffset;
+ uint16_t st_physhift;
+ uint16_t st_rfaddr;
+ uint16_t st_rfshift;
+ uint16_t st_mask;
+};
+
+struct bwn_b206x_chan {
+ uint8_t bc_chan;
+ uint16_t bc_freq;
+ const uint8_t *bc_data;
+};
+
+struct bwn_b206x_rfinit_entry {
+ uint16_t br_offset;
+ uint16_t br_valuea;
+ uint16_t br_valueg;
+ uint8_t br_flags;
+};
+
+struct bwn_phy {
+ uint8_t type;
+ uint8_t rev;
+ uint8_t analog;
+
+ int supports_2ghz;
+ int supports_5ghz;
+
+ int gmode;
+ struct bwn_phy_g phy_g;
+ struct bwn_phy_lp phy_lp;
+
+ uint16_t rf_manuf;
+ uint16_t rf_ver;
+ uint8_t rf_rev;
+ int rf_on;
+
+ int txpower;
+ int hwpctl;
+ unsigned long nexttime;
+ unsigned int chan;
+ int txerrors;
+
+ int (*attach)(struct bwn_mac *);
+ void (*detach)(struct bwn_mac *);
+ int (*prepare_hw)(struct bwn_mac *);
+ void (*init_pre)(struct bwn_mac *);
+ int (*init)(struct bwn_mac *);
+ void (*exit)(struct bwn_mac *);
+ uint16_t (*phy_read)(struct bwn_mac *, uint16_t);
+ void (*phy_write)(struct bwn_mac *, uint16_t,
+ uint16_t);
+ void (*phy_maskset)(struct bwn_mac *,
+ uint16_t, uint16_t, uint16_t);
+ uint16_t (*rf_read)(struct bwn_mac *, uint16_t);
+ void (*rf_write)(struct bwn_mac *, uint16_t,
+ uint16_t);
+ int (*use_hwpctl)(struct bwn_mac *);
+ void (*rf_onoff)(struct bwn_mac *, int);
+ void (*switch_analog)(struct bwn_mac *, int);
+ int (*switch_channel)(struct bwn_mac *,
+ unsigned int);
+ uint32_t (*get_default_chan)(struct bwn_mac *);
+ void (*set_antenna)(struct bwn_mac *, int);
+ int (*set_im)(struct bwn_mac *, int);
+ int (*recalc_txpwr)(struct bwn_mac *, int);
+ void (*set_txpwr)(struct bwn_mac *);
+ void (*task_15s)(struct bwn_mac *);
+ void (*task_60s)(struct bwn_mac *);
+};
+
+struct bwn_chan_band {
+ uint32_t flags;
+ uint8_t nchan;
+#define BWN_MAX_CHAN_PER_BAND 14
+ uint8_t chan[BWN_MAX_CHAN_PER_BAND];
+};
+
+#define BWN_NR_WMEPARAMS 16
+enum {
+ BWN_WMEPARAM_TXOP = 0,
+ BWN_WMEPARAM_CWMIN,
+ BWN_WMEPARAM_CWMAX,
+ BWN_WMEPARAM_CWCUR,
+ BWN_WMEPARAM_AIFS,
+ BWN_WMEPARAM_BSLOTS,
+ BWN_WMEPARAM_REGGAP,
+ BWN_WMEPARAM_STATUS,
+};
+
+#define BWN_WME_PARAMS(queue) \
+ (BWN_SHARED_EDCFQ + (BWN_NR_WMEPARAMS * sizeof(uint16_t) * (queue)))
+#define BWN_WME_BACKGROUND BWN_WME_PARAMS(0)
+#define BWN_WME_BESTEFFORT BWN_WME_PARAMS(1)
+#define BWN_WME_VIDEO BWN_WME_PARAMS(2)
+#define BWN_WME_VOICE BWN_WME_PARAMS(3)
+
+/*
+ * Radio capture format.
+ */
+#define BWN_RX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_TSFT) | \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | \
+ 0)
+
+struct bwn_rx_radiotap_header {
+ struct ieee80211_radiotap_header wr_ihdr;
+ uint64_t wr_tsf;
+ u_int8_t wr_flags;
+ u_int8_t wr_rate;
+ u_int16_t wr_chan_freq;
+ u_int16_t wr_chan_flags;
+ int8_t wr_antsignal;
+ int8_t wr_antnoise;
+ u_int8_t wr_antenna;
+};
+
+#define BWN_TX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_CHANNEL) | \
+ (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
+ (1 << IEEE80211_RADIOTAP_ANTENNA) | \
+ 0)
+
+struct bwn_tx_radiotap_header {
+ struct ieee80211_radiotap_header wt_ihdr;
+ u_int8_t wt_flags;
+ u_int8_t wt_rate;
+ u_int16_t wt_chan_freq;
+ u_int16_t wt_chan_flags;
+ u_int8_t wt_txpower;
+ u_int8_t wt_antenna;
+};
+
+struct bwn_stats {
+ int32_t link_noise;
+};
+
+/* Noise Calculation (Link Quality) */
+struct bwn_noise {
+ uint8_t noi_running;
+ uint8_t noi_nsamples;
+ int8_t noi_samples[8][4];
+};
+
+#define BWN_DMA_30BIT 30
+#define BWN_DMA_32BIT 32
+#define BWN_DMA_64BIT 64
+
+struct bwn_dmadesc_meta {
+ bus_dmamap_t mt_dmap;
+ bus_addr_t mt_paddr;
+ struct mbuf *mt_m;
+ struct ieee80211_node *mt_ni;
+ uint8_t mt_txtype;
+#define BWN_DMADESC_METATYPE_HEADER 0
+#define BWN_DMADESC_METATYPE_BODY 1
+ uint8_t mt_islast;
+};
+
+#define BWN_DMAINTR_FATALMASK \
+ ((1 << 10) | (1 << 11) | (1 << 12) | (1 << 14) | (1 << 15))
+#define BWN_DMAINTR_NONFATALMASK (1 << 13)
+#define BWN_DMAINTR_RX_DONE (1 << 16)
+
+#define BWN_DMA32_DCTL_BYTECNT 0x00001fff
+#define BWN_DMA32_DCTL_ADDREXT_MASK 0x00030000
+#define BWN_DMA32_DCTL_ADDREXT_SHIFT 16
+#define BWN_DMA32_DCTL_DTABLEEND 0x10000000
+#define BWN_DMA32_DCTL_IRQ 0x20000000
+#define BWN_DMA32_DCTL_FRAMEEND 0x40000000
+#define BWN_DMA32_DCTL_FRAMESTART 0x80000000
+struct bwn_dmadesc32 {
+ uint32_t control;
+ uint32_t address;
+} __packed;
+
+#define BWN_DMA64_DCTL0_DTABLEEND 0x10000000
+#define BWN_DMA64_DCTL0_IRQ 0x20000000
+#define BWN_DMA64_DCTL0_FRAMEEND 0x40000000
+#define BWN_DMA64_DCTL0_FRAMESTART 0x80000000
+#define BWN_DMA64_DCTL1_BYTECNT 0x00001fff
+#define BWN_DMA64_DCTL1_ADDREXT_MASK 0x00030000
+#define BWN_DMA64_DCTL1_ADDREXT_SHIFT 16
+struct bwn_dmadesc64 {
+ uint32_t control0;
+ uint32_t control1;
+ uint32_t address_low;
+ uint32_t address_high;
+} __packed;
+
+struct bwn_dmadesc_generic {
+ union {
+ struct bwn_dmadesc32 dma32;
+ struct bwn_dmadesc64 dma64;
+ } __packed dma;
+} __packed;
+
+struct bwn_dma_ring;
+
+struct bwn_dma_ring {
+ struct bwn_mac *dr_mac;
+ const struct bwn_dma_ops *dr_ops;
+ struct bwn_dmadesc_meta *dr_meta;
+ void *dr_txhdr_cache;
+ bus_dma_tag_t dr_ring_dtag;
+ bus_dma_tag_t dr_txring_dtag;
+ bus_dmamap_t dr_spare_dmap; /* only for RX */
+ bus_dmamap_t dr_ring_dmap;
+ bus_addr_t dr_txring_paddr;
+ void *dr_ring_descbase;
+ bus_addr_t dr_ring_dmabase;
+ int dr_numslots;
+ int dr_usedslot;
+ int dr_curslot;
+ uint32_t dr_frameoffset;
+ uint16_t dr_rx_bufsize;
+ uint16_t dr_base;
+ int dr_index;
+ uint8_t dr_tx;
+ uint8_t dr_stop;
+ int dr_type;
+
+ void (*getdesc)(struct bwn_dma_ring *,
+ int, struct bwn_dmadesc_generic **,
+ struct bwn_dmadesc_meta **);
+ void (*setdesc)(struct bwn_dma_ring *,
+ struct bwn_dmadesc_generic *,
+ bus_addr_t, uint16_t, int, int,
+ int);
+ void (*start_transfer)(struct bwn_dma_ring *,
+ int);
+ void (*suspend)(struct bwn_dma_ring *);
+ void (*resume)(struct bwn_dma_ring *);
+ int (*get_curslot)(struct bwn_dma_ring *);
+ void (*set_curslot)(struct bwn_dma_ring *,
+ int);
+};
+
+struct bwn_dma {
+ int dmatype;
+ bus_dma_tag_t parent_dtag;
+ bus_dma_tag_t rxbuf_dtag;
+ bus_dma_tag_t txbuf_dtag;
+
+ struct bwn_dma_ring *wme[5];
+ struct bwn_dma_ring *mcast;
+ struct bwn_dma_ring *rx;
+ uint64_t lastseq; /* XXX FIXME */
+};
+
+struct bwn_pio_rxqueue {
+ struct bwn_mac *prq_mac;
+ uint16_t prq_base;
+ uint8_t prq_rev;
+};
+
+struct bwn_pio_txqueue;
+struct bwn_pio_txpkt {
+ struct bwn_pio_txqueue *tp_queue;
+ struct ieee80211_node *tp_ni;
+ struct mbuf *tp_m;
+ uint8_t tp_index;
+ TAILQ_ENTRY(bwn_pio_txpkt) tp_list;
+};
+
+#define BWN_PIO_MAX_TXPACKETS 32
+struct bwn_pio_txqueue {
+ uint16_t tq_base;
+ uint16_t tq_size;
+ uint16_t tq_used;
+ uint16_t tq_free;
+ uint8_t tq_stop;
+ uint8_t tq_index;
+ struct bwn_pio_txpkt tq_pkts[BWN_PIO_MAX_TXPACKETS];
+ TAILQ_HEAD(, bwn_pio_txpkt) tq_pktlist;
+};
+
+struct bwn_pio {
+ struct bwn_pio_txqueue wme[5];
+ struct bwn_pio_txqueue mcast;
+ struct bwn_pio_rxqueue rx;
+};
+
+struct bwn_plcp4 {
+ union {
+ uint32_t data;
+ uint8_t raw[4];
+ } __packed o;
+} __packed;
+
+struct bwn_plcp6 {
+ union {
+ uint32_t data;
+ uint8_t raw[6];
+ } __packed o;
+} __packed;
+
+struct bwn_txhdr {
+ uint32_t macctl;
+ uint8_t macfc[2];
+ uint16_t tx_festime;
+ uint16_t phyctl;
+ uint16_t phyctl_1;
+ uint16_t phyctl_1fb;
+ uint16_t phyctl_1rts;
+ uint16_t phyctl_1rtsfb;
+ uint8_t phyrate;
+ uint8_t phyrate_rts;
+ uint8_t eftypes; /* extra frame types */
+ uint8_t chan;
+ uint8_t iv[16];
+ uint8_t addr1[IEEE80211_ADDR_LEN];
+ uint16_t tx_festime_fb;
+ struct bwn_plcp6 rts_plcp_fb;
+ uint16_t rts_dur_fb;
+ struct bwn_plcp6 plcp_fb;
+ uint16_t dur_fb;
+ uint16_t mimo_modelen;
+ uint16_t mimo_ratelen_fb;
+ uint32_t timeout;
+
+ union {
+ /* format <= r351 */
+ struct {
+ uint8_t pad0[2];
+ uint16_t cookie;
+ uint16_t tx_status;
+ struct bwn_plcp6 rts_plcp;
+ uint8_t rts_frame[16];
+ uint8_t pad1[2];;
+ struct bwn_plcp6 plcp;
+ } __packed old;
+ /* format > r410 */
+ struct {
+ uint16_t mimo_antenna;
+ uint16_t preload_size;
+ uint8_t pad0[2];
+ uint16_t cookie;
+ uint16_t tx_status;
+ struct bwn_plcp6 rts_plcp;
+ uint8_t rts_frame[16];
+ uint8_t pad1[2];
+ struct bwn_plcp6 plcp;
+ } __packed new;
+ } __packed body;
+} __packed;
+
+#define BWN_FWTYPE_UCODE 'u'
+#define BWN_FWTYPE_PCM 'p'
+#define BWN_FWTYPE_IV 'i'
+struct bwn_fwhdr {
+ uint8_t type;
+ uint8_t ver;
+ uint8_t pad[2];
+ uint32_t size;
+} __packed;
+
+#define BWN_FWINITVALS_OFFSET_MASK 0x7fff
+#define BWN_FWINITVALS_32BIT 0x8000
+struct bwn_fwinitvals {
+ uint16_t offset_size;
+ union {
+ uint16_t d16;
+ uint32_t d32;
+ } __packed data;
+} __packed;
+
+enum bwn_fwtype {
+ BWN_FWTYPE_DEFAULT,
+ BWN_FWTYPE_OPENSOURCE,
+ BWN_NR_FWTYPES,
+};
+
+struct bwn_fwfile {
+ const char *filename;
+ const struct firmware *fw;
+ enum bwn_fwtype type;
+};
+
+struct bwn_key {
+ void *keyconf;
+ uint8_t algorithm;
+};
+
+struct bwn_fw {
+ struct bwn_fwfile ucode;
+ struct bwn_fwfile pcm;
+ struct bwn_fwfile initvals;
+ struct bwn_fwfile initvals_band;
+
+ uint16_t rev;
+ uint16_t patch;
+ uint8_t opensource;
+ uint8_t no_pcmfile;
+};
+
+struct bwn_lo_g_sm {
+ int curstate;
+ int nmeasure;
+ int multipler;
+ uint16_t feedth;
+ struct bwn_loctl loctl;
+};
+
+struct bwn_lo_g_value {
+ uint8_t old_channel;
+ uint16_t phy_lomask;
+ uint16_t phy_extg;
+ uint16_t phy_dacctl_hwpctl;
+ uint16_t phy_dacctl;
+ uint16_t phy_hpwr_tssictl;
+ uint16_t phy_analogover;
+ uint16_t phy_analogoverval;
+ uint16_t phy_rfover;
+ uint16_t phy_rfoverval;
+ uint16_t phy_classctl;
+ uint16_t phy_crs0;
+ uint16_t phy_pgactl;
+ uint16_t phy_syncctl;
+ uint16_t phy_cck0;
+ uint16_t phy_cck1;
+ uint16_t phy_cck2;
+ uint16_t phy_cck3;
+ uint16_t phy_cck4;
+ uint16_t reg0;
+ uint16_t reg1;
+ uint16_t rf0;
+ uint16_t rf1;
+ uint16_t rf2;
+};
+
+#define BWN_LED_MAX 4
+
+#define BWN_LED_EVENT_NONE -1
+#define BWN_LED_EVENT_POLL 0
+#define BWN_LED_EVENT_TX 1
+#define BWN_LED_EVENT_RX 2
+#define BWN_LED_SLOWDOWN(dur) (dur) = (((dur) * 3) / 2)
+
+struct bwn_led {
+ uint8_t led_flags; /* BWN_LED_F_ */
+ uint8_t led_act; /* BWN_LED_ACT_ */
+ uint8_t led_mask;
+};
+
+#define BWN_LED_F_ACTLOW 0x1
+#define BWN_LED_F_BLINK 0x2
+#define BWN_LED_F_POLLABLE 0x4
+#define BWN_LED_F_SLOW 0x8
+
+struct bwn_mac {
+ struct bwn_softc *mac_sc;
+ struct siba_dev_softc *mac_sd;
+ unsigned mac_status;
+#define BWN_MAC_STATUS_UNINIT 0
+#define BWN_MAC_STATUS_INITED 1
+#define BWN_MAC_STATUS_STARTED 2
+ unsigned mac_flags;
+ /* use "Bad Frames Preemption" */
+#define BWN_MAC_FLAG_BADFRAME_PREEMP (1 << 0)
+#define BWN_MAC_FLAG_DFQVALID (1 << 1)
+#define BWN_MAC_FLAG_RADIO_ON (1 << 2)
+#define BWN_MAC_FLAG_DMA (1 << 3)
+#define BWN_MAC_FLAG_WME (1 << 4)
+#define BWN_MAC_FLAG_HWCRYPTO (1 << 5)
+
+ struct resource_spec *mac_intr_spec;
+#define BWN_MSI_MESSAGES 1
+ struct resource *mac_res_irq[BWN_MSI_MESSAGES];
+ void *mac_intrhand[BWN_MSI_MESSAGES];
+ int mac_msi;
+
+ struct bwn_noise mac_noise;
+ struct bwn_phy mac_phy;
+ struct bwn_stats mac_stats;
+ uint32_t mac_reason_intr;
+ uint32_t mac_reason[6];
+ uint32_t mac_intr_mask;
+ int mac_suspended;
+
+ struct bwn_fw mac_fw;
+
+ union {
+ struct bwn_dma dma;
+ struct bwn_pio pio;
+ } mac_method;
+
+ uint16_t mac_ktp; /* Key table pointer */
+ uint8_t mac_max_nr_keys;
+ struct bwn_key mac_key[58];
+
+ unsigned int mac_task_state;
+ struct task mac_intrtask;
+ struct task mac_hwreset;
+ struct task mac_txpower;
+
+ TAILQ_ENTRY(bwn_mac) mac_list;
+};
+
+struct bwn_node {
+ struct ieee80211_node bn_node; /* must be the first */
+ struct ieee80211_amrr_node bn_amn;
+};
+#define BWN_NODE(ni) ((struct bwn_node *)(ni))
+
+/*
+ * Driver-specific vap state.
+ */
+struct bwn_vap {
+ struct ieee80211vap bv_vap; /* base class */
+ struct ieee80211_amrr bv_amrr;
+ int (*bv_newstate)(struct ieee80211vap *,
+ enum ieee80211_state, int);
+};
+#define BWN_VAP(vap) ((struct bwn_vap *)(vap))
+#define BWN_VAP_CONST(vap) ((const struct mwl_vap *)(vap))
+
+struct bwn_softc {
+ device_t sc_dev;
+ struct siba_dev_softc *sc_sd;
+ struct mtx sc_mtx;
+ struct ifnet *sc_ifp;
+ unsigned sc_flags;
+#define BWN_FLAG_ATTACHED (1 << 0)
+#define BWN_FLAG_INVALID (1 << 1)
+#define BWN_FLAG_NEED_BEACON_TP (1 << 2)
+ unsigned sc_debug;
+
+ struct bwn_mac *sc_curmac;
+ TAILQ_HEAD(, bwn_mac) sc_maclist;
+
+ uint8_t sc_macaddr[IEEE80211_ADDR_LEN];
+ uint8_t sc_bssid[IEEE80211_ADDR_LEN];
+ unsigned int sc_filters;
+ uint8_t sc_beacons[2];
+ uint8_t sc_rf_enabled;
+
+ struct wmeParams sc_wmeParams[4];
+
+ struct callout sc_rfswitch_ch; /* for laptop */
+ struct callout sc_task_ch;
+ struct callout sc_watchdog_ch;
+ int sc_watchdog_timer;
+ struct taskqueue *sc_tq; /* private task queue */
+ int (*sc_newstate)(struct ieee80211com *,
+ enum ieee80211_state, int);
+ void (*sc_node_cleanup)(
+ struct ieee80211_node *);
+
+ int sc_rx_rate;
+ int sc_tx_rate;
+
+ int sc_led_blinking;
+ int sc_led_ticks;
+ struct bwn_led *sc_blink_led;
+ struct callout sc_led_blink_ch;
+ int sc_led_blink_offdur;
+ struct bwn_led sc_leds[BWN_LED_MAX];
+ int sc_led_idle;
+ int sc_led_blink;
+
+ struct bwn_tx_radiotap_header sc_tx_th;
+ struct bwn_rx_radiotap_header sc_rx_th;
+};
+
+#define BWN_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->sc_dev), \
+ MTX_NETWORK_LOCK, MTX_DEF)
+#define BWN_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
+#define BWN_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define BWN_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define BWN_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED)
+
+#endif /* !_IF_BWNVAR_H */
diff --git a/sys/modules/bwn/Makefile b/sys/modules/bwn/Makefile
new file mode 100644
index 0000000..a5b18aa
--- /dev/null
+++ b/sys/modules/bwn/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../dev/bwn
+
+KMOD= if_bwn
+SRCS= if_bwn.c if_bwnreg.h if_bwnvar.h
+SRCS+= device_if.h bus_if.h pci_if.h
+
+.include <bsd.kmod.mk>
OpenPOWER on IntegriCloud