summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorstsp <stsp@openbsd.org>2016-03-09 18:18:28 +0000
committerstsp <stsp@openbsd.org>2016-03-09 18:18:28 +0000
commit8b9da0f5386cb6178df1bd53d1a731eeac657848 (patch)
treee30e6a261711802493567d0b1916f3ee83ae45dc /sys
parentdelete dangling vax reference (diff)
downloadwireguard-openbsd-8b9da0f5386cb6178df1bd53d1a731eeac657848.tar.xz
wireguard-openbsd-8b9da0f5386cb6178df1bd53d1a731eeac657848.zip
Split the rtwn(4) driver into two layers:
One layer which handles PCI support and low-level packet processing. And another layer which handles ioctls, net80211 state transitions, and all communication with the chip. The plan is to eventually merge corresponding code from urtwn(4) in here. ok mpi@
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ic/rtwn.c2696
-rw-r--r--sys/dev/ic/rtwnvar.h83
-rw-r--r--sys/dev/pci/files.pci7
-rw-r--r--sys/dev/pci/if_rtwn.c2880
4 files changed, 2960 insertions, 2706 deletions
diff --git a/sys/dev/ic/rtwn.c b/sys/dev/ic/rtwn.c
new file mode 100644
index 00000000000..a98a37bbb59
--- /dev/null
+++ b/sys/dev/ic/rtwn.c
@@ -0,0 +1,2696 @@
+/* $OpenBSD: rtwn.c,v 1.1 2016/03/09 18:18:28 stsp Exp $ */
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Driver for Realtek RTL8188CE
+ */
+
+#include "bpfilter.h"
+
+#include <sys/param.h>
+#include <sys/sockio.h>
+#include <sys/mbuf.h>
+#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/task.h>
+#include <sys/timeout.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/endian.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+
+#include <netinet/in.h>
+#include <netinet/if_ether.h>
+
+#include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_radiotap.h>
+
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcidevs.h>
+
+#include <dev/ic/r92creg.h>
+#include <dev/ic/rtwnvar.h>
+
+#define R92C_PUBQ_NPAGES 176
+#define R92C_HPQ_NPAGES 41
+#define R92C_LPQ_NPAGES 28
+#define R92C_TXPKTBUF_COUNT 256
+#define R92C_TX_PAGE_COUNT \
+ (R92C_PUBQ_NPAGES + R92C_HPQ_NPAGES + R92C_LPQ_NPAGES)
+#define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1)
+
+#define RTWN_RIDX_COUNT 28
+
+#define RTWN_LED_LINK 0
+#define RTWN_LED_DATA 1
+
+#ifdef RTWN_DEBUG
+#define DPRINTF(x) do { if (rtwn_debug) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (rtwn_debug >= (n)) printf x; } while (0)
+int rtwn_debug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n, x)
+#endif
+
+void rtwn_write_1(struct rtwn_softc *, uint16_t, uint8_t);
+void rtwn_write_2(struct rtwn_softc *, uint16_t, uint16_t);
+void rtwn_write_4(struct rtwn_softc *, uint16_t, uint32_t);
+uint8_t rtwn_read_1(struct rtwn_softc *, uint16_t);
+uint16_t rtwn_read_2(struct rtwn_softc *, uint16_t);
+uint32_t rtwn_read_4(struct rtwn_softc *, uint16_t);
+int rtwn_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int);
+void rtwn_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
+uint32_t rtwn_rf_read(struct rtwn_softc *, int, uint8_t);
+void rtwn_cam_write(struct rtwn_softc *, uint32_t, uint32_t);
+int rtwn_llt_write(struct rtwn_softc *, uint32_t, uint32_t);
+uint8_t rtwn_efuse_read_1(struct rtwn_softc *, uint16_t);
+void rtwn_efuse_read(struct rtwn_softc *);
+int rtwn_read_chipid(struct rtwn_softc *);
+void rtwn_read_rom(struct rtwn_softc *);
+int rtwn_media_change(struct ifnet *);
+int rtwn_ra_init(struct rtwn_softc *);
+void rtwn_tsf_sync_enable(struct rtwn_softc *);
+void rtwn_set_led(struct rtwn_softc *, int, int);
+void rtwn_calib_to(void *);
+void rtwn_next_scan(void *);
+int rtwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
+void rtwn_updateedca(struct ieee80211com *);
+int rtwn_set_key(struct ieee80211com *, struct ieee80211_node *,
+ struct ieee80211_key *);
+void rtwn_delete_key(struct ieee80211com *,
+ struct ieee80211_node *, struct ieee80211_key *);
+void rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t);
+int8_t rtwn_get_rssi(struct rtwn_softc *, int, void *);
+void rtwn_start(struct ifnet *);
+void rtwn_watchdog(struct ifnet *);
+int rtwn_ioctl(struct ifnet *, u_long, caddr_t);
+int rtwn_power_on(struct rtwn_softc *);
+int rtwn_llt_init(struct rtwn_softc *);
+void rtwn_fw_reset(struct rtwn_softc *);
+int rtwn_fw_loadpage(struct rtwn_softc *, int, uint8_t *, int);
+int rtwn_load_firmware(struct rtwn_softc *);
+int rtwn_dma_init(struct rtwn_softc *);
+void rtwn_mac_init(struct rtwn_softc *);
+void rtwn_bb_init(struct rtwn_softc *);
+void rtwn_rf_init(struct rtwn_softc *);
+void rtwn_cam_init(struct rtwn_softc *);
+void rtwn_pa_bias_init(struct rtwn_softc *);
+void rtwn_rxfilter_init(struct rtwn_softc *);
+void rtwn_edca_init(struct rtwn_softc *);
+void rtwn_write_txpower(struct rtwn_softc *, int, uint16_t[]);
+void rtwn_get_txpower(struct rtwn_softc *, int,
+ struct ieee80211_channel *, struct ieee80211_channel *,
+ uint16_t[]);
+void rtwn_set_txpower(struct rtwn_softc *,
+ struct ieee80211_channel *, struct ieee80211_channel *);
+void rtwn_set_chan(struct rtwn_softc *,
+ struct ieee80211_channel *, struct ieee80211_channel *);
+int rtwn_iq_calib_chain(struct rtwn_softc *, int, uint16_t[2],
+ uint16_t[2]);
+void rtwn_iq_calib_run(struct rtwn_softc *, int, uint16_t[2][2],
+ uint16_t[2][2]);
+int rtwn_iq_calib_compare_results(uint16_t[2][2], uint16_t[2][2],
+ uint16_t[2][2], uint16_t[2][2], int);
+void rtwn_iq_calib_write_results(struct rtwn_softc *, uint16_t[2],
+ uint16_t[2], int);
+void rtwn_iq_calib(struct rtwn_softc *);
+void rtwn_lc_calib(struct rtwn_softc *);
+void rtwn_temp_calib(struct rtwn_softc *);
+int rtwn_init(struct ifnet *);
+void rtwn_init_task(void *);
+void rtwn_stop(struct ifnet *);
+
+/* Aliases. */
+#define rtwn_bb_write rtwn_write_4
+#define rtwn_bb_read rtwn_read_4
+
+void
+rtwn_attach(struct device *pdev, struct rtwn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ int i, error;
+
+ sc->sc_pdev = pdev;
+
+ timeout_set(&sc->calib_to, rtwn_calib_to, sc);
+ timeout_set(&sc->scan_to, rtwn_next_scan, sc);
+
+ task_set(&sc->init_task, rtwn_init_task, sc);
+
+ error = rtwn_read_chipid(sc);
+ if (error != 0) {
+ printf("%s: unsupported test chip\n", sc->sc_pdev->dv_xname);
+ return;
+ }
+
+ /* Determine number of Tx/Rx chains. */
+ if (sc->chip & RTWN_CHIP_92C) {
+ sc->ntxchains = (sc->chip & RTWN_CHIP_92C_1T2R) ? 1 : 2;
+ sc->nrxchains = 2;
+ } else {
+ sc->ntxchains = 1;
+ sc->nrxchains = 1;
+ }
+ rtwn_read_rom(sc);
+
+ printf("%s: MAC/BB RTL%s, RF 6052 %dT%dR, address %s\n",
+ sc->sc_pdev->dv_xname,
+ (sc->chip & RTWN_CHIP_92C) ? "8192CE" : "8188CE",
+ sc->ntxchains, sc->nrxchains,
+ ether_sprintf(ic->ic_myaddr));
+
+ ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */
+ ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */
+ ic->ic_state = IEEE80211_S_INIT;
+
+ /* Set device capabilities. */
+ ic->ic_caps =
+ IEEE80211_C_MONITOR | /* Monitor mode supported. */
+ IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
+ IEEE80211_C_SHSLOT | /* Short slot time supported. */
+ IEEE80211_C_WEP | /* WEP. */
+ IEEE80211_C_RSN; /* WPA/RSN. */
+
+ /* Set HT capabilities. */
+ ic->ic_htcaps =
+ IEEE80211_HTCAP_CBW20_40 |
+ IEEE80211_HTCAP_DSSSCCK40;
+ /* Set supported HT rates. */
+ for (i = 0; i < sc->nrxchains; i++)
+ ic->ic_sup_mcs[i] = 0xff;
+
+ /* Set supported .11b and .11g rates. */
+ ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
+ ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
+
+ /* Set supported .11b and .11g channels (1 through 14). */
+ for (i = 1; i <= 14; i++) {
+ ic->ic_channels[i].ic_freq =
+ ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
+ ic->ic_channels[i].ic_flags =
+ IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
+ }
+
+#ifdef notyet
+ /*
+ * The number of STAs that we can support is limited by the number
+ * of CAM entries used for hardware crypto.
+ */
+ ic->ic_max_nnodes = R92C_CAM_ENTRY_COUNT - 4;
+ if (ic->ic_max_nnodes > IEEE80211_CACHE_SIZE)
+ ic->ic_max_nnodes = IEEE80211_CACHE_SIZE;
+#endif
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = rtwn_ioctl;
+ ifp->if_start = rtwn_start;
+ ifp->if_watchdog = rtwn_watchdog;
+ IFQ_SET_READY(&ifp->if_snd);
+ memcpy(ifp->if_xname, sc->sc_pdev->dv_xname, IFNAMSIZ);
+
+ if_attach(ifp);
+ ieee80211_ifattach(ifp);
+ ic->ic_updateedca = rtwn_updateedca;
+#ifdef notyet
+ ic->ic_set_key = rtwn_set_key;
+ ic->ic_delete_key = rtwn_delete_key;
+#endif
+ /* Override state transition machine. */
+ sc->sc_newstate = ic->ic_newstate;
+ ic->ic_newstate = rtwn_newstate;
+ ieee80211_media_init(ifp, rtwn_media_change, ieee80211_media_status);
+}
+
+int
+rtwn_detach(struct rtwn_softc *sc, int flags)
+{
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ int s;
+
+ s = splnet();
+
+ if (timeout_initialized(&sc->scan_to))
+ timeout_del(&sc->scan_to);
+ if (timeout_initialized(&sc->calib_to))
+ timeout_del(&sc->calib_to);
+
+ task_del(systq, &sc->init_task);
+
+ if (ifp->if_softc != NULL) {
+ ieee80211_ifdetach(ifp);
+ if_detach(ifp);
+ }
+
+ splx(s);
+
+ return (0);
+}
+
+int
+rtwn_activate(struct rtwn_softc *sc, int act)
+{
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+
+ switch (act) {
+ case DVACT_SUSPEND:
+ if (ifp->if_flags & IFF_RUNNING)
+ rtwn_stop(ifp);
+ break;
+ case DVACT_WAKEUP:
+ rtwn_init_task(sc);
+ break;
+ }
+ return (0);
+}
+
+void
+rtwn_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val)
+{
+ sc->sc_ops.write_1(sc->sc_ops.cookie, addr, val);
+}
+
+void
+rtwn_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val)
+{
+ val = htole16(val);
+ sc->sc_ops.write_2(sc->sc_ops.cookie, addr, val);
+}
+
+void
+rtwn_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val)
+{
+ val = htole32(val);
+ sc->sc_ops.write_4(sc->sc_ops.cookie, addr, val);
+}
+
+uint8_t
+rtwn_read_1(struct rtwn_softc *sc, uint16_t addr)
+{
+ return sc->sc_ops.read_1(sc->sc_ops.cookie, addr);
+}
+
+uint16_t
+rtwn_read_2(struct rtwn_softc *sc, uint16_t addr)
+{
+ return sc->sc_ops.read_2(sc->sc_ops.cookie, addr);
+}
+
+uint32_t
+rtwn_read_4(struct rtwn_softc *sc, uint16_t addr)
+{
+ return sc->sc_ops.read_4(sc->sc_ops.cookie, addr);
+}
+
+int
+rtwn_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
+{
+ struct r92c_fw_cmd cmd;
+ int ntries;
+
+ /* Wait for current FW box to be empty. */
+ for (ntries = 0; ntries < 100; ntries++) {
+ if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
+ break;
+ DELAY(1);
+ }
+ if (ntries == 100) {
+ printf("%s: could not send firmware command %d\n",
+ sc->sc_pdev->dv_xname, id);
+ return (ETIMEDOUT);
+ }
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.id = id;
+ if (len > 3)
+ cmd.id |= R92C_CMD_FLAG_EXT;
+ KASSERT(len <= sizeof(cmd.msg));
+ memcpy(cmd.msg, buf, len);
+
+ /* Write the first word last since that will trigger the FW. */
+ rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), *((uint8_t *)&cmd + 4));
+ rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *((uint8_t *)&cmd + 0));
+
+ sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
+
+ /* Give firmware some time for processing. */
+ DELAY(2000);
+
+ return (0);
+}
+
+void
+rtwn_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
+{
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
+ SM(R92C_LSSI_PARAM_ADDR, addr) |
+ SM(R92C_LSSI_PARAM_DATA, val));
+}
+
+uint32_t
+rtwn_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr)
+{
+ uint32_t reg[R92C_MAX_CHAINS], val;
+
+ reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0));
+ if (chain != 0)
+ reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain));
+
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
+ reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE);
+ DELAY(1000);
+
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain),
+ RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) |
+ R92C_HSSI_PARAM2_READ_EDGE);
+ DELAY(1000);
+
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
+ reg[0] | R92C_HSSI_PARAM2_READ_EDGE);
+ DELAY(1000);
+
+ if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI)
+ val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain));
+ else
+ val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain));
+ return (MS(val, R92C_LSSI_READBACK_DATA));
+}
+
+void
+rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
+{
+ rtwn_write_4(sc, R92C_CAMWRITE, data);
+ rtwn_write_4(sc, R92C_CAMCMD,
+ R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
+ SM(R92C_CAMCMD_ADDR, addr));
+}
+
+int
+rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
+{
+ int ntries;
+
+ rtwn_write_4(sc, R92C_LLT_INIT,
+ SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) |
+ SM(R92C_LLT_INIT_ADDR, addr) |
+ SM(R92C_LLT_INIT_DATA, data));
+ /* Wait for write operation to complete. */
+ for (ntries = 0; ntries < 20; ntries++) {
+ if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) ==
+ R92C_LLT_INIT_OP_NO_ACTIVE)
+ return (0);
+ DELAY(5);
+ }
+ return (ETIMEDOUT);
+}
+
+uint8_t
+rtwn_efuse_read_1(struct rtwn_softc *sc, uint16_t addr)
+{
+ uint32_t reg;
+ int ntries;
+
+ reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
+ reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr);
+ reg &= ~R92C_EFUSE_CTRL_VALID;
+ rtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
+ /* Wait for read operation to complete. */
+ for (ntries = 0; ntries < 100; ntries++) {
+ reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
+ if (reg & R92C_EFUSE_CTRL_VALID)
+ return (MS(reg, R92C_EFUSE_CTRL_DATA));
+ DELAY(5);
+ }
+ printf("%s: could not read efuse byte at address 0x%x\n",
+ sc->sc_pdev->dv_xname, addr);
+ return (0xff);
+}
+
+void
+rtwn_efuse_read(struct rtwn_softc *sc)
+{
+ uint8_t *rom = (uint8_t *)&sc->rom;
+ uint16_t addr = 0;
+ uint32_t reg;
+ uint8_t off, msk;
+ int i;
+
+ reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL);
+ if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
+ rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+ reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
+ }
+ reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+ if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+ reg | R92C_SYS_FUNC_EN_ELDR);
+ }
+ reg = rtwn_read_2(sc, R92C_SYS_CLKR);
+ if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
+ (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
+ rtwn_write_2(sc, R92C_SYS_CLKR,
+ reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
+ }
+ memset(&sc->rom, 0xff, sizeof(sc->rom));
+ while (addr < 512) {
+ reg = rtwn_efuse_read_1(sc, addr);
+ if (reg == 0xff)
+ break;
+ addr++;
+ off = reg >> 4;
+ msk = reg & 0xf;
+ for (i = 0; i < 4; i++) {
+ if (msk & (1 << i))
+ continue;
+ rom[off * 8 + i * 2 + 0] =
+ rtwn_efuse_read_1(sc, addr);
+ addr++;
+ rom[off * 8 + i * 2 + 1] =
+ rtwn_efuse_read_1(sc, addr);
+ addr++;
+ }
+ }
+#ifdef RTWN_DEBUG
+ if (rtwn_debug >= 2) {
+ /* Dump ROM content. */
+ printf("\n");
+ for (i = 0; i < sizeof(sc->rom); i++)
+ printf("%02x:", rom[i]);
+ printf("\n");
+ }
+#endif
+}
+
+/* rtwn_read_chipid: reg=0x40073b chipid=0x0 */
+int
+rtwn_read_chipid(struct rtwn_softc *sc)
+{
+ uint32_t reg;
+
+ reg = rtwn_read_4(sc, R92C_SYS_CFG);
+ if (reg & R92C_SYS_CFG_TRP_VAUX_EN)
+ /* Unsupported test chip. */
+ return (EIO);
+
+ if (reg & R92C_SYS_CFG_TYPE_92C) {
+ sc->chip |= RTWN_CHIP_92C;
+ /* Check if it is a castrated 8192C. */
+ if (MS(rtwn_read_4(sc, R92C_HPON_FSM),
+ R92C_HPON_FSM_CHIP_BONDING_ID) ==
+ R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R)
+ sc->chip |= RTWN_CHIP_92C_1T2R;
+ }
+ if (reg & R92C_SYS_CFG_VENDOR_UMC) {
+ sc->chip |= RTWN_CHIP_UMC;
+ if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0)
+ sc->chip |= RTWN_CHIP_UMC_A_CUT;
+ }
+ return (0);
+}
+
+void
+rtwn_read_rom(struct rtwn_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct r92c_rom *rom = &sc->rom;
+
+ /* Read full ROM image. */
+ rtwn_efuse_read(sc);
+
+ if (rom->id != 0x8129) {
+ printf("%s: invalid EEPROM ID 0x%x\n",
+ sc->sc_pdev->dv_xname, rom->id);
+ }
+
+ /* XXX Weird but this is what the vendor driver does. */
+ sc->pa_setting = rtwn_efuse_read_1(sc, 0x1fa);
+ DPRINTF(("PA setting=0x%x\n", sc->pa_setting));
+
+ sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
+
+ sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
+ DPRINTF(("regulatory type=%d\n", sc->regulatory));
+
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr);
+}
+
+int
+rtwn_media_change(struct ifnet *ifp)
+{
+ int error;
+
+ error = ieee80211_media_change(ifp);
+ if (error != ENETRESET)
+ return (error);
+
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
+ (IFF_UP | IFF_RUNNING)) {
+ rtwn_stop(ifp);
+ rtwn_init(ifp);
+ }
+ return (0);
+}
+
+/*
+ * Initialize rate adaptation in firmware.
+ */
+int
+rtwn_ra_init(struct rtwn_softc *sc)
+{
+ static const uint8_t map[] =
+ { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni = ic->ic_bss;
+ struct ieee80211_rateset *rs = &ni->ni_rates;
+ struct r92c_fw_cmd_macid_cfg cmd;
+ uint32_t rates, basicrates;
+ uint8_t mode;
+ int maxrate, maxbasicrate, error, i, j;
+
+ /* Get normal and basic rates mask. */
+ rates = basicrates = 0;
+ maxrate = maxbasicrate = 0;
+ for (i = 0; i < rs->rs_nrates; i++) {
+ /* Convert 802.11 rate to HW rate index. */
+ for (j = 0; j < nitems(map); j++)
+ if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j])
+ break;
+ if (j == nitems(map)) /* Unknown rate, skip. */
+ continue;
+ rates |= 1 << j;
+ if (j > maxrate)
+ maxrate = j;
+ if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) {
+ basicrates |= 1 << j;
+ if (j > maxbasicrate)
+ maxbasicrate = j;
+ }
+ }
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ mode = R92C_RAID_11B;
+ else
+ mode = R92C_RAID_11BG;
+ DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n",
+ mode, rates, basicrates));
+
+ /* Set rates mask for group addressed frames. */
+ cmd.macid = R92C_MACID_BC | R92C_MACID_VALID;
+ cmd.mask = htole32(mode << 28 | basicrates);
+ error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
+ if (error != 0) {
+ printf("%s: could not add broadcast station\n",
+ sc->sc_pdev->dv_xname);
+ return (error);
+ }
+ /* Set initial MRR rate. */
+ DPRINTF(("maxbasicrate=%d\n", maxbasicrate));
+ rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(R92C_MACID_BC),
+ maxbasicrate);
+
+ /* Set rates mask for unicast frames. */
+ cmd.macid = R92C_MACID_BSS | R92C_MACID_VALID;
+ cmd.mask = htole32(mode << 28 | rates);
+ error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
+ if (error != 0) {
+ printf("%s: could not add BSS station\n",
+ sc->sc_pdev->dv_xname);
+ return (error);
+ }
+ /* Set initial MRR rate. */
+ DPRINTF(("maxrate=%d\n", maxrate));
+ rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(R92C_MACID_BSS),
+ maxrate);
+
+ /* Configure Automatic Rate Fallback Register. */
+ if (ic->ic_curmode == IEEE80211_MODE_11B) {
+ if (rates & 0x0c)
+ rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d));
+ else
+ rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f));
+ } else
+ rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5));
+
+ /* Indicate highest supported rate. */
+ ni->ni_txrate = rs->rs_nrates - 1;
+ return (0);
+}
+
+void
+rtwn_tsf_sync_enable(struct rtwn_softc *sc)
+{
+ struct ieee80211_node *ni = sc->sc_ic.ic_bss;
+ uint64_t tsf;
+
+ /* Enable TSF synchronization. */
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN);
+
+ /* Set initial TSF. */
+ memcpy(&tsf, ni->ni_tstamp, 8);
+ tsf = letoh64(tsf);
+ tsf = tsf - (tsf % (ni->ni_intval * IEEE80211_DUR_TU));
+ tsf -= IEEE80211_DUR_TU;
+ rtwn_write_4(sc, R92C_TSFTR + 0, tsf);
+ rtwn_write_4(sc, R92C_TSFTR + 4, tsf >> 32);
+
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN);
+}
+
+void
+rtwn_set_led(struct rtwn_softc *sc, int led, int on)
+{
+ uint8_t reg;
+
+ if (led == RTWN_LED_LINK) {
+ reg = rtwn_read_1(sc, R92C_LEDCFG2) & 0xf0;
+ if (!on)
+ reg |= R92C_LEDCFG2_DIS;
+ else
+ reg |= R92C_LEDCFG2_EN;
+ rtwn_write_1(sc, R92C_LEDCFG2, reg);
+ sc->ledlink = on; /* Save LED state. */
+ }
+}
+
+void
+rtwn_calib_to(void *arg)
+{
+ struct rtwn_softc *sc = arg;
+ struct r92c_fw_cmd_rssi cmd;
+
+ if (sc->avg_pwdb != -1) {
+ /* Indicate Rx signal strength to FW for rate adaptation. */
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.macid = 0; /* BSS. */
+ cmd.pwdb = sc->avg_pwdb;
+ DPRINTFN(3, ("sending RSSI command avg=%d\n", sc->avg_pwdb));
+ rtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
+ }
+
+ /* Do temperature compensation. */
+ rtwn_temp_calib(sc);
+
+ timeout_add_sec(&sc->calib_to, 2);
+}
+
+void
+rtwn_next_scan(void *arg)
+{
+ struct rtwn_softc *sc = arg;
+
+ sc->sc_ops.next_scan(sc->sc_ops.cookie);
+}
+
+int
+rtwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ struct ieee80211_node *ni;
+ enum ieee80211_state ostate;
+ uint32_t reg;
+ int s;
+
+ s = splnet();
+ ostate = ic->ic_state;
+
+ if (nstate != ostate)
+ DPRINTF(("newstate %s -> %s\n",
+ ieee80211_state_name[ostate],
+ ieee80211_state_name[nstate]));
+
+ if (ostate == IEEE80211_S_RUN) {
+ /* Stop calibration. */
+ timeout_del(&sc->calib_to);
+
+ /* Turn link LED off. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 0);
+
+ /* Set media status to 'No Link'. */
+ reg = rtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_NOLINK);
+ rtwn_write_4(sc, R92C_CR, reg);
+
+ /* Stop Rx of data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0);
+
+ /* Rest TSF. */
+ rtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03);
+
+ /* Disable TSF synchronization. */
+ rtwn_write_1(sc, R92C_BCN_CTRL,
+ rtwn_read_1(sc, R92C_BCN_CTRL) |
+ R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+ /* Reset EDCA parameters. */
+ rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
+ rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
+ rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
+ rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
+ }
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ /* Turn link LED off. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 0);
+ break;
+ case IEEE80211_S_SCAN:
+ if (ostate != IEEE80211_S_SCAN) {
+ /* Allow Rx from any BSSID. */
+ rtwn_write_4(sc, R92C_RCR,
+ rtwn_read_4(sc, R92C_RCR) &
+ ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN));
+
+ /* Set gain for scanning. */
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
+ }
+
+ /* Make link LED blink during scan. */
+ rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink);
+
+ /* Pause AC Tx queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE,
+ rtwn_read_1(sc, R92C_TXPAUSE) | 0x0f);
+ rtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL);
+ timeout_add_msec(&sc->scan_to, 200);
+ break;
+
+ case IEEE80211_S_AUTH:
+ /* Set initial gain under link. */
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
+ reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
+
+ rtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL);
+ break;
+ case IEEE80211_S_ASSOC:
+ break;
+ case IEEE80211_S_RUN:
+ if (ic->ic_opmode == IEEE80211_M_MONITOR) {
+ rtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
+
+ /* Enable Rx of data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+
+ /* Turn link LED on. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 1);
+ break;
+ }
+ ni = ic->ic_bss;
+
+ /* Set media status to 'Associated'. */
+ reg = rtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
+ rtwn_write_4(sc, R92C_CR, reg);
+
+ /* Set BSSID. */
+ rtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0]));
+ rtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4]));
+
+ if (ic->ic_curmode == IEEE80211_MODE_11B)
+ rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
+ else /* 802.11b/g */
+ rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
+
+ /* Enable Rx of data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+
+ /* Flush all AC queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0);
+
+ /* Set beacon interval. */
+ rtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
+
+ /* Allow Rx from our BSSID only. */
+ rtwn_write_4(sc, R92C_RCR,
+ rtwn_read_4(sc, R92C_RCR) |
+ R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
+
+ /* Enable TSF synchronization. */
+ rtwn_tsf_sync_enable(sc);
+
+ rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10);
+ rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10);
+ rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10);
+ rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10);
+ rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10);
+ rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10);
+
+ /* Intialize rate adaptation. */
+ rtwn_ra_init(sc);
+ /* Turn link LED on. */
+ rtwn_set_led(sc, RTWN_LED_LINK, 1);
+
+ sc->avg_pwdb = -1; /* Reset average RSSI. */
+ /* Reset temperature calibration state machine. */
+ sc->thcal_state = 0;
+ sc->thcal_lctemp = 0;
+ /* Start periodic calibration. */
+ timeout_add_sec(&sc->calib_to, 2);
+ break;
+ }
+ (void)sc->sc_newstate(ic, nstate, arg);
+ splx(s);
+
+ return (0);
+}
+
+void
+rtwn_updateedca(struct ieee80211com *ic)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ const uint16_t aci2reg[EDCA_NUM_AC] = {
+ R92C_EDCA_BE_PARAM,
+ R92C_EDCA_BK_PARAM,
+ R92C_EDCA_VI_PARAM,
+ R92C_EDCA_VO_PARAM
+ };
+ struct ieee80211_edca_ac_params *ac;
+ int s, aci, aifs, slottime;
+
+ s = splnet();
+ slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
+ for (aci = 0; aci < EDCA_NUM_AC; aci++) {
+ ac = &ic->ic_edca_ac[aci];
+ /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
+ aifs = ac->ac_aifsn * slottime + 10;
+ rtwn_write_4(sc, aci2reg[aci],
+ SM(R92C_EDCA_PARAM_TXOP, ac->ac_txoplimit) |
+ SM(R92C_EDCA_PARAM_ECWMIN, ac->ac_ecwmin) |
+ SM(R92C_EDCA_PARAM_ECWMAX, ac->ac_ecwmax) |
+ SM(R92C_EDCA_PARAM_AIFS, aifs));
+ }
+ splx(s);
+}
+
+int
+rtwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ static const uint8_t etherzeroaddr[6] = { 0 };
+ const uint8_t *macaddr;
+ uint8_t keybuf[16], algo;
+ int i, entry;
+
+ /* Defer setting of WEP keys until interface is brought up. */
+ if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
+ (IFF_UP | IFF_RUNNING))
+ return (0);
+
+ /* Map net80211 cipher to HW crypto algorithm. */
+ switch (k->k_cipher) {
+ case IEEE80211_CIPHER_WEP40:
+ algo = R92C_CAM_ALGO_WEP40;
+ break;
+ case IEEE80211_CIPHER_WEP104:
+ algo = R92C_CAM_ALGO_WEP104;
+ break;
+ case IEEE80211_CIPHER_TKIP:
+ algo = R92C_CAM_ALGO_TKIP;
+ break;
+ case IEEE80211_CIPHER_CCMP:
+ algo = R92C_CAM_ALGO_AES;
+ break;
+ default:
+ /* Fallback to software crypto for other ciphers. */
+ return (ieee80211_set_key(ic, ni, k));
+ }
+ if (k->k_flags & IEEE80211_KEY_GROUP) {
+ macaddr = etherzeroaddr;
+ entry = k->k_id;
+ } else {
+ macaddr = ic->ic_bss->ni_macaddr;
+ entry = 4;
+ }
+ /* Write key. */
+ memset(keybuf, 0, sizeof(keybuf));
+ memcpy(keybuf, k->k_key, MIN(k->k_len, sizeof(keybuf)));
+ for (i = 0; i < 4; i++) {
+ rtwn_cam_write(sc, R92C_CAM_KEY(entry, i),
+ LE_READ_4(&keybuf[i * 4]));
+ }
+ /* Write CTL0 last since that will validate the CAM entry. */
+ rtwn_cam_write(sc, R92C_CAM_CTL1(entry),
+ LE_READ_4(&macaddr[2]));
+ rtwn_cam_write(sc, R92C_CAM_CTL0(entry),
+ SM(R92C_CAM_ALGO, algo) |
+ SM(R92C_CAM_KEYID, k->k_id) |
+ SM(R92C_CAM_MACLO, LE_READ_2(&macaddr[0])) |
+ R92C_CAM_VALID);
+
+ return (0);
+}
+
+void
+rtwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
+ struct ieee80211_key *k)
+{
+ struct rtwn_softc *sc = ic->ic_softc;
+ int i, entry;
+
+ if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
+ ic->ic_state != IEEE80211_S_RUN)
+ return; /* Nothing to do. */
+
+ if (k->k_flags & IEEE80211_KEY_GROUP)
+ entry = k->k_id;
+ else
+ entry = 4;
+ rtwn_cam_write(sc, R92C_CAM_CTL0(entry), 0);
+ rtwn_cam_write(sc, R92C_CAM_CTL1(entry), 0);
+ /* Clear key. */
+ for (i = 0; i < 4; i++)
+ rtwn_cam_write(sc, R92C_CAM_KEY(entry, i), 0);
+}
+
+void
+rtwn_update_avgrssi(struct rtwn_softc *sc, int rate, int8_t rssi)
+{
+ int pwdb;
+
+ /* Convert antenna signal to percentage. */
+ if (rssi <= -100 || rssi >= 20)
+ pwdb = 0;
+ else if (rssi >= 0)
+ pwdb = 100;
+ else
+ pwdb = 100 + rssi;
+ if (rate <= 3) {
+ /* CCK gain is smaller than OFDM/MCS gain. */
+ pwdb += 6;
+ if (pwdb > 100)
+ pwdb = 100;
+ if (pwdb <= 14)
+ pwdb -= 4;
+ else if (pwdb <= 26)
+ pwdb -= 8;
+ else if (pwdb <= 34)
+ pwdb -= 6;
+ else if (pwdb <= 42)
+ pwdb -= 2;
+ }
+ if (sc->avg_pwdb == -1) /* Init. */
+ sc->avg_pwdb = pwdb;
+ else if (sc->avg_pwdb < pwdb)
+ sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
+ else
+ sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
+ DPRINTFN(4, ("PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb));
+}
+
+int8_t
+rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt)
+{
+ static const int8_t cckoff[] = { 16, -12, -26, -46 };
+ struct r92c_rx_phystat *phy;
+ struct r92c_rx_cck *cck;
+ uint8_t rpt;
+ int8_t rssi;
+
+ if (rate <= 3) {
+ cck = (struct r92c_rx_cck *)physt;
+ if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) {
+ rpt = (cck->agc_rpt >> 5) & 0x3;
+ rssi = (cck->agc_rpt & 0x1f) << 1;
+ } else {
+ rpt = (cck->agc_rpt >> 6) & 0x3;
+ rssi = cck->agc_rpt & 0x3e;
+ }
+ rssi = cckoff[rpt] - rssi;
+ } else { /* OFDM/HT. */
+ phy = (struct r92c_rx_phystat *)physt;
+ rssi = ((letoh32(phy->phydw1) >> 1) & 0x7f) - 110;
+ }
+ return (rssi);
+}
+
+void
+rtwn_start(struct ifnet *ifp)
+{
+ struct rtwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211_node *ni;
+ struct mbuf *m;
+
+ if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
+ return;
+
+ for (;;) {
+ if (sc->sc_ops.is_oactive(sc->sc_ops.cookie)) {
+ ifq_set_oactive(&ifp->if_snd);
+ break;
+ }
+ /* Send pending management frames first. */
+ m = mq_dequeue(&ic->ic_mgtq);
+ if (m != NULL) {
+ ni = m->m_pkthdr.ph_cookie;
+ goto sendit;
+ }
+ if (ic->ic_state != IEEE80211_S_RUN)
+ break;
+
+ /* Encapsulate and send data frames. */
+ IFQ_DEQUEUE(&ifp->if_snd, m);
+ if (m == NULL)
+ break;
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
+#endif
+ if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
+ continue;
+sendit:
+#if NBPFILTER > 0
+ if (ic->ic_rawbpf != NULL)
+ bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
+#endif
+ if (sc->sc_ops.tx(sc->sc_ops.cookie, m, ni) != 0) {
+ ieee80211_release_node(ic, ni);
+ ifp->if_oerrors++;
+ continue;
+ }
+
+ sc->sc_tx_timer = 5;
+ ifp->if_timer = 1;
+ }
+}
+
+void
+rtwn_watchdog(struct ifnet *ifp)
+{
+ struct rtwn_softc *sc = ifp->if_softc;
+
+ ifp->if_timer = 0;
+
+ if (sc->sc_tx_timer > 0) {
+ if (--sc->sc_tx_timer == 0) {
+ printf("%s: device timeout\n", sc->sc_pdev->dv_xname);
+ task_add(systq, &sc->init_task);
+ ifp->if_oerrors++;
+ return;
+ }
+ ifp->if_timer = 1;
+ }
+ ieee80211_watchdog(ifp);
+}
+
+int
+rtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct rtwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifreq *ifr;
+ int s, error = 0;
+
+ s = splnet();
+ /*
+ * Prevent processes from entering this function while another
+ * process is tsleep'ing in it.
+ */
+ while ((sc->sc_flags & RTWN_FLAG_BUSY) && error == 0)
+ error = tsleep(&sc->sc_flags, PCATCH, "rtwnioc", 0);
+ if (error != 0) {
+ splx(s);
+ return error;
+ }
+ sc->sc_flags |= RTWN_FLAG_BUSY;
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ /* FALLTHROUGH */
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (!(ifp->if_flags & IFF_RUNNING))
+ rtwn_init(ifp);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ rtwn_stop(ifp);
+ }
+ break;
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ ifr = (struct ifreq *)data;
+ error = (cmd == SIOCADDMULTI) ?
+ ether_addmulti(ifr, &ic->ic_ac) :
+ ether_delmulti(ifr, &ic->ic_ac);
+ if (error == ENETRESET)
+ error = 0;
+ break;
+ case SIOCS80211CHANNEL:
+ error = ieee80211_ioctl(ifp, cmd, data);
+ if (error == ENETRESET &&
+ ic->ic_opmode == IEEE80211_M_MONITOR) {
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
+ (IFF_UP | IFF_RUNNING))
+ rtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
+ error = 0;
+ }
+ break;
+ default:
+ error = ieee80211_ioctl(ifp, cmd, data);
+ }
+
+ if (error == ENETRESET) {
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
+ (IFF_UP | IFF_RUNNING)) {
+ rtwn_stop(ifp);
+ rtwn_init(ifp);
+ }
+ error = 0;
+ }
+ sc->sc_flags &= ~RTWN_FLAG_BUSY;
+ wakeup(&sc->sc_flags);
+ splx(s);
+
+ return (error);
+}
+
+int
+rtwn_power_on(struct rtwn_softc *sc)
+{
+ uint32_t reg;
+ int ntries;
+
+ /* Wait for autoload done bit. */
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ printf("%s: timeout waiting for chip autoload\n",
+ sc->sc_pdev->dv_xname);
+ return (ETIMEDOUT);
+ }
+
+ /* Unlock ISO/CLK/Power control register. */
+ rtwn_write_1(sc, R92C_RSV_CTRL, 0);
+
+ /* TODO: check if we need this for 8188CE */
+ if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
+ /* bt coex */
+ reg = rtwn_read_4(sc, R92C_APS_FSMCO);
+ reg |= (R92C_APS_FSMCO_SOP_ABG |
+ R92C_APS_FSMCO_SOP_AMB |
+ R92C_APS_FSMCO_XOP_BTCK);
+ rtwn_write_4(sc, R92C_APS_FSMCO, reg);
+ }
+
+ /* Move SPS into PWM mode. */
+ rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
+
+ /* Set low byte to 0x0f, leave others unchanged. */
+ rtwn_write_4(sc, R92C_AFE_XTAL_CTRL,
+ (rtwn_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f);
+
+ /* TODO: check if we need this for 8188CE */
+ if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
+ /* bt coex */
+ reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL);
+ reg &= (~0x00024800); /* XXX magic from linux */
+ rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, reg);
+ }
+
+ rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+ (rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) |
+ R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR);
+ DELAY(200);
+
+ /* TODO: linux does additional btcoex stuff here */
+
+ /* Auto enable WLAN. */
+ rtwn_write_2(sc, R92C_APS_FSMCO,
+ rtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
+ R92C_APS_FSMCO_APFM_ONMAC))
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ printf("%s: timeout waiting for MAC auto ON\n",
+ sc->sc_pdev->dv_xname);
+ return (ETIMEDOUT);
+ }
+
+ /* Enable radio, GPIO and LED functions. */
+ rtwn_write_2(sc, R92C_APS_FSMCO,
+ R92C_APS_FSMCO_AFSM_PCIE |
+ R92C_APS_FSMCO_PDN_EN |
+ R92C_APS_FSMCO_PFM_ALDN);
+ /* Release RF digital isolation. */
+ rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
+ rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
+
+ if (sc->chip & RTWN_CHIP_92C)
+ rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77);
+ else
+ rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22);
+
+ rtwn_write_4(sc, R92C_INT_MIG, 0);
+
+ if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
+ /* bt coex */
+ reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL + 2);
+ reg &= 0xfd; /* XXX magic from linux */
+ rtwn_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg);
+ }
+
+ rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+ rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL);
+
+ reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL);
+ if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) {
+ printf("%s: radio is disabled by hardware switch\n",
+ sc->sc_pdev->dv_xname);
+ return (EPERM); /* :-) */
+ }
+
+ /* Initialize MAC. */
+ reg = rtwn_read_1(sc, R92C_APSD_CTRL);
+ rtwn_write_1(sc, R92C_APSD_CTRL,
+ rtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
+ for (ntries = 0; ntries < 200; ntries++) {
+ if (!(rtwn_read_1(sc, R92C_APSD_CTRL) &
+ R92C_APSD_CTRL_OFF_STATUS))
+ break;
+ DELAY(500);
+ }
+ if (ntries == 200) {
+ printf("%s: timeout waiting for MAC initialization\n",
+ sc->sc_pdev->dv_xname);
+ return (ETIMEDOUT);
+ }
+
+ /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
+ reg = rtwn_read_2(sc, R92C_CR);
+ reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+ R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
+ R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
+ R92C_CR_ENSEC;
+ rtwn_write_2(sc, R92C_CR, reg);
+
+ rtwn_write_1(sc, 0xfe10, 0x19);
+
+ return (0);
+}
+
+int
+rtwn_llt_init(struct rtwn_softc *sc)
+{
+ int i, error;
+
+ /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */
+ for (i = 0; i < R92C_TX_PAGE_COUNT; i++) {
+ if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
+ return (error);
+ }
+ /* NB: 0xff indicates end-of-list. */
+ if ((error = rtwn_llt_write(sc, i, 0xff)) != 0)
+ return (error);
+ /*
+ * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1]
+ * as ring buffer.
+ */
+ for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) {
+ if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
+ return (error);
+ }
+ /* Make the last page point to the beginning of the ring buffer. */
+ error = rtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1);
+ return (error);
+}
+
+void
+rtwn_fw_reset(struct rtwn_softc *sc)
+{
+ uint16_t reg;
+ int ntries;
+
+ /* Tell 8051 to reset itself. */
+ rtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
+
+ /* Wait until 8051 resets by itself. */
+ for (ntries = 0; ntries < 100; ntries++) {
+ reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
+ if (!(reg & R92C_SYS_FUNC_EN_CPUEN))
+ goto sleep;
+ DELAY(50);
+ }
+ /* Force 8051 reset. */
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
+sleep:
+ /*
+ * We must sleep for one second to let the firmware settle.
+ * Accessing registers too early will hang the whole system.
+ */
+ tsleep(&reg, 0, "rtwnrst", hz);
+}
+
+int
+rtwn_fw_loadpage(struct rtwn_softc *sc, int page, uint8_t *buf, int len)
+{
+ uint32_t reg;
+ int off, mlen, error = 0, i;
+
+ reg = rtwn_read_4(sc, R92C_MCUFWDL);
+ reg = RW(reg, R92C_MCUFWDL_PAGE, page);
+ rtwn_write_4(sc, R92C_MCUFWDL, reg);
+
+ DELAY(5);
+
+ off = R92C_FW_START_ADDR;
+ while (len > 0) {
+ if (len > 196)
+ mlen = 196;
+ else if (len > 4)
+ mlen = 4;
+ else
+ mlen = 1;
+ for (i = 0; i < mlen; i++)
+ rtwn_write_1(sc, off++, buf[i]);
+ buf += mlen;
+ len -= mlen;
+ }
+
+ return (error);
+}
+
+int
+rtwn_load_firmware(struct rtwn_softc *sc)
+{
+ const struct r92c_fw_hdr *hdr;
+ const char *name;
+ u_char *fw, *ptr;
+ size_t len;
+ uint32_t reg;
+ int mlen, ntries, page, error;
+
+ /* Read firmware image from the filesystem. */
+ if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
+ RTWN_CHIP_UMC_A_CUT)
+ name = "rtwn-rtl8192cfwU";
+ else
+ name = "rtwn-rtl8192cfwU_B";
+ if ((error = loadfirmware(name, &fw, &len)) != 0) {
+ printf("%s: could not read firmware %s (error %d)\n",
+ sc->sc_pdev->dv_xname, name, error);
+ return (error);
+ }
+ if (len < sizeof(*hdr)) {
+ printf("%s: firmware too short\n", sc->sc_pdev->dv_xname);
+ error = EINVAL;
+ goto fail;
+ }
+ ptr = fw;
+ hdr = (const struct r92c_fw_hdr *)ptr;
+ /* Check if there is a valid FW header and skip it. */
+ if ((letoh16(hdr->signature) >> 4) == 0x88c ||
+ (letoh16(hdr->signature) >> 4) == 0x92c) {
+ DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n",
+ letoh16(hdr->version), letoh16(hdr->subversion),
+ hdr->month, hdr->date, hdr->hour, hdr->minute));
+ ptr += sizeof(*hdr);
+ len -= sizeof(*hdr);
+ }
+
+ if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+ rtwn_fw_reset(sc);
+
+ /* Enable FW download. */
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+ rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
+ R92C_SYS_FUNC_EN_CPUEN);
+ rtwn_write_1(sc, R92C_MCUFWDL,
+ rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN);
+ rtwn_write_1(sc, R92C_MCUFWDL + 2,
+ rtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08);
+
+ /* Reset the FWDL checksum. */
+ rtwn_write_1(sc, R92C_MCUFWDL,
+ rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT);
+
+ for (page = 0; len > 0; page++) {
+ mlen = MIN(len, R92C_FW_PAGE_SIZE);
+ error = rtwn_fw_loadpage(sc, page, ptr, mlen);
+ if (error != 0) {
+ printf("%s: could not load firmware page %d\n",
+ sc->sc_pdev->dv_xname, page);
+ goto fail;
+ }
+ ptr += mlen;
+ len -= mlen;
+ }
+
+ /* Disable FW download. */
+ rtwn_write_1(sc, R92C_MCUFWDL,
+ rtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN);
+ rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
+
+ /* Wait for checksum report. */
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT)
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ printf("%s: timeout waiting for checksum report\n",
+ sc->sc_pdev->dv_xname);
+ error = ETIMEDOUT;
+ goto fail;
+ }
+
+ reg = rtwn_read_4(sc, R92C_MCUFWDL);
+ reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY;
+ rtwn_write_4(sc, R92C_MCUFWDL, reg);
+ /* Wait for firmware readiness. */
+ for (ntries = 0; ntries < 1000; ntries++) {
+ if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
+ break;
+ DELAY(5);
+ }
+ if (ntries == 1000) {
+ printf("%s: timeout waiting for firmware readiness\n",
+ sc->sc_pdev->dv_xname);
+ error = ETIMEDOUT;
+ goto fail;
+ }
+ fail:
+ free(fw, M_DEVBUF, len);
+ return (error);
+}
+
+int
+rtwn_dma_init(struct rtwn_softc *sc)
+{
+ uint32_t reg;
+ int error;
+
+ /* Initialize LLT table. */
+ error = rtwn_llt_init(sc);
+ if (error != 0)
+ return error;
+
+ /* Set number of pages for normal priority queue. */
+ rtwn_write_2(sc, R92C_RQPN_NPQ, 0);
+ rtwn_write_4(sc, R92C_RQPN,
+ /* Set number of pages for public queue. */
+ SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) |
+ /* Set number of pages for high priority queue. */
+ SM(R92C_RQPN_HPQ, R92C_HPQ_NPAGES) |
+ /* Set number of pages for low priority queue. */
+ SM(R92C_RQPN_LPQ, R92C_LPQ_NPAGES) |
+ /* Load values. */
+ R92C_RQPN_LD);
+
+ rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY);
+ rtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY);
+
+ reg = rtwn_read_2(sc, R92C_TRXDMA_CTRL);
+ reg &= ~R92C_TRXDMA_CTRL_QMAP_M;
+ reg |= 0xF771;
+ rtwn_write_2(sc, R92C_TRXDMA_CTRL, reg);
+
+ rtwn_write_4(sc, R92C_TCR, R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13));
+
+ sc->sc_ops.configure_dma(sc->sc_ops.cookie);
+
+ /* Set Tx/Rx transfer page boundary. */
+ rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff);
+
+ /* Set Tx/Rx transfer page size. */
+ rtwn_write_1(sc, R92C_PBP,
+ SM(R92C_PBP_PSRX, R92C_PBP_128) |
+ SM(R92C_PBP_PSTX, R92C_PBP_128));
+ return (0);
+}
+
+void
+rtwn_mac_init(struct rtwn_softc *sc)
+{
+ int i;
+
+ /* Write MAC initialization values. */
+ for (i = 0; i < nitems(rtl8192ce_mac); i++)
+ rtwn_write_1(sc, rtl8192ce_mac[i].reg, rtl8192ce_mac[i].val);
+}
+
+void
+rtwn_bb_init(struct rtwn_softc *sc)
+{
+ const struct r92c_bb_prog *prog;
+ uint32_t reg;
+ int i;
+
+ /* Enable BB and RF. */
+ rtwn_write_2(sc, R92C_SYS_FUNC_EN,
+ rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
+ R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
+ R92C_SYS_FUNC_EN_DIO_RF);
+
+ rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
+
+ rtwn_write_1(sc, R92C_RF_CTRL,
+ R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
+
+ rtwn_write_1(sc, R92C_SYS_FUNC_EN,
+ R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA |
+ R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST |
+ R92C_SYS_FUNC_EN_BBRSTB);
+
+ rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
+
+ rtwn_write_4(sc, R92C_LEDCFG0,
+ rtwn_read_4(sc, R92C_LEDCFG0) | 0x00800000);
+
+ /* Select BB programming. */
+ prog = (sc->chip & RTWN_CHIP_92C) ?
+ &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t;
+
+ /* Write BB initialization values. */
+ for (i = 0; i < prog->count; i++) {
+ rtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
+ DELAY(1);
+ }
+
+ if (sc->chip & RTWN_CHIP_92C_1T2R) {
+ /* 8192C 1T only configuration. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO);
+ reg = (reg & ~0x00000003) | 0x2;
+ rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
+
+ reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO);
+ reg = (reg & ~0x00300033) | 0x00200022;
+ rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
+
+ reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING);
+ reg = (reg & ~0xff000000) | 0x45 << 24;
+ rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
+ reg = (reg & ~0x000000ff) | 0x23;
+ rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
+ reg = (reg & ~0x00000030) | 1 << 4;
+ rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
+
+ reg = rtwn_bb_read(sc, 0xe74);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe74, reg);
+ reg = rtwn_bb_read(sc, 0xe78);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe78, reg);
+ reg = rtwn_bb_read(sc, 0xe7c);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe7c, reg);
+ reg = rtwn_bb_read(sc, 0xe80);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe80, reg);
+ reg = rtwn_bb_read(sc, 0xe88);
+ reg = (reg & ~0x0c000000) | 2 << 26;
+ rtwn_bb_write(sc, 0xe88, reg);
+ }
+
+ /* Write AGC values. */
+ for (i = 0; i < prog->agccount; i++) {
+ rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
+ prog->agcvals[i]);
+ DELAY(1);
+ }
+
+ if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
+ R92C_HSSI_PARAM2_CCK_HIPWR)
+ sc->sc_flags |= RTWN_FLAG_CCK_HIPWR;
+}
+
+void
+rtwn_rf_init(struct rtwn_softc *sc)
+{
+ const struct r92c_rf_prog *prog;
+ uint32_t reg, type;
+ int i, j, idx, off;
+
+ /* Select RF programming based on board type. */
+ if (!(sc->chip & RTWN_CHIP_92C)) {
+ if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
+ prog = rtl8188ce_rf_prog;
+ else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
+ prog = rtl8188ru_rf_prog;
+ else
+ prog = rtl8188cu_rf_prog;
+ } else
+ prog = rtl8192ce_rf_prog;
+
+ for (i = 0; i < sc->nrxchains; i++) {
+ /* Save RF_ENV control type. */
+ idx = i / 2;
+ off = (i % 2) * 16;
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
+ type = (reg >> off) & 0x10;
+
+ /* Set RF_ENV enable. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
+ reg |= 0x100000;
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
+ DELAY(1);
+ /* Set RF_ENV output high. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
+ reg |= 0x10;
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
+ DELAY(1);
+ /* Set address and data lengths of RF registers. */
+ reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
+ reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH;
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
+ DELAY(1);
+ reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
+ reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH;
+ rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
+ DELAY(1);
+
+ /* Write RF initialization values for this chain. */
+ for (j = 0; j < prog[i].count; j++) {
+ if (prog[i].regs[j] >= 0xf9 &&
+ prog[i].regs[j] <= 0xfe) {
+ /*
+ * These are fake RF registers offsets that
+ * indicate a delay is required.
+ */
+ DELAY(50);
+ continue;
+ }
+ rtwn_rf_write(sc, i, prog[i].regs[j],
+ prog[i].vals[j]);
+ DELAY(1);
+ }
+
+ /* Restore RF_ENV control type. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
+ reg &= ~(0x10 << off) | (type << off);
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg);
+
+ /* Cache RF register CHNLBW. */
+ sc->rf_chnlbw[i] = rtwn_rf_read(sc, i, R92C_RF_CHNLBW);
+ }
+
+ if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
+ RTWN_CHIP_UMC_A_CUT) {
+ rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255);
+ rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00);
+ }
+}
+
+void
+rtwn_cam_init(struct rtwn_softc *sc)
+{
+ /* Invalidate all CAM entries. */
+ rtwn_write_4(sc, R92C_CAMCMD,
+ R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
+}
+
+void
+rtwn_pa_bias_init(struct rtwn_softc *sc)
+{
+ uint8_t reg;
+ int i;
+
+ for (i = 0; i < sc->nrxchains; i++) {
+ if (sc->pa_setting & (1 << i))
+ continue;
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406);
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406);
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406);
+ rtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406);
+ }
+ if (!(sc->pa_setting & 0x10)) {
+ reg = rtwn_read_1(sc, 0x16);
+ reg = (reg & ~0xf0) | 0x90;
+ rtwn_write_1(sc, 0x16, reg);
+ }
+}
+
+void
+rtwn_rxfilter_init(struct rtwn_softc *sc)
+{
+ /* Initialize Rx filter. */
+ /* TODO: use better filter for monitor mode. */
+ rtwn_write_4(sc, R92C_RCR,
+ R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB |
+ R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL |
+ R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS);
+ /* Accept all multicast frames. */
+ rtwn_write_4(sc, R92C_MAR + 0, 0xffffffff);
+ rtwn_write_4(sc, R92C_MAR + 4, 0xffffffff);
+ /* Accept all management frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff);
+ /* Reject all control frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
+ /* Accept all data frames. */
+ rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
+}
+
+void
+rtwn_edca_init(struct rtwn_softc *sc)
+{
+ rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010);
+ rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010);
+ rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010);
+ rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e);
+ rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
+ rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
+ rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322);
+ rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222);
+}
+
+void
+rtwn_write_txpower(struct rtwn_softc *sc, int chain,
+ uint16_t power[RTWN_RIDX_COUNT])
+{
+ uint32_t reg;
+
+ /* Write per-CCK rate Tx power. */
+ if (chain == 0) {
+ reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
+ reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]);
+ rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
+ reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
+ reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]);
+ reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]);
+ reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]);
+ rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
+ } else {
+ reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
+ reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]);
+ reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]);
+ reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]);
+ rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
+ reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
+ reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]);
+ rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
+ }
+ /* Write per-OFDM rate Tx power. */
+ rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
+ SM(R92C_TXAGC_RATE06, power[ 4]) |
+ SM(R92C_TXAGC_RATE09, power[ 5]) |
+ SM(R92C_TXAGC_RATE12, power[ 6]) |
+ SM(R92C_TXAGC_RATE18, power[ 7]));
+ rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
+ SM(R92C_TXAGC_RATE24, power[ 8]) |
+ SM(R92C_TXAGC_RATE36, power[ 9]) |
+ SM(R92C_TXAGC_RATE48, power[10]) |
+ SM(R92C_TXAGC_RATE54, power[11]));
+ /* Write per-MCS Tx power. */
+ rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
+ SM(R92C_TXAGC_MCS00, power[12]) |
+ SM(R92C_TXAGC_MCS01, power[13]) |
+ SM(R92C_TXAGC_MCS02, power[14]) |
+ SM(R92C_TXAGC_MCS03, power[15]));
+ rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
+ SM(R92C_TXAGC_MCS04, power[16]) |
+ SM(R92C_TXAGC_MCS05, power[17]) |
+ SM(R92C_TXAGC_MCS06, power[18]) |
+ SM(R92C_TXAGC_MCS07, power[19]));
+ rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
+ SM(R92C_TXAGC_MCS08, power[20]) |
+ SM(R92C_TXAGC_MCS09, power[21]) |
+ SM(R92C_TXAGC_MCS10, power[22]) |
+ SM(R92C_TXAGC_MCS11, power[23]));
+ rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
+ SM(R92C_TXAGC_MCS12, power[24]) |
+ SM(R92C_TXAGC_MCS13, power[25]) |
+ SM(R92C_TXAGC_MCS14, power[26]) |
+ SM(R92C_TXAGC_MCS15, power[27]));
+}
+
+void
+rtwn_get_txpower(struct rtwn_softc *sc, int chain,
+ struct ieee80211_channel *c, struct ieee80211_channel *extc,
+ uint16_t power[RTWN_RIDX_COUNT])
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct r92c_rom *rom = &sc->rom;
+ uint16_t cckpow, ofdmpow, htpow, diff, max;
+ const struct r92c_txpwr *base;
+ int ridx, chan, group;
+
+ /* Determine channel group. */
+ chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
+ if (chan <= 3)
+ group = 0;
+ else if (chan <= 9)
+ group = 1;
+ else
+ group = 2;
+
+ /* Get original Tx power based on board type and RF chain. */
+ if (!(sc->chip & RTWN_CHIP_92C)) {
+ if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
+ base = &rtl8188ru_txagc[chain];
+ else
+ base = &rtl8192cu_txagc[chain];
+ } else
+ base = &rtl8192cu_txagc[chain];
+
+ memset(power, 0, RTWN_RIDX_COUNT * sizeof(power[0]));
+ if (sc->regulatory == 0) {
+ for (ridx = 0; ridx <= 3; ridx++)
+ power[ridx] = base->pwr[0][ridx];
+ }
+ for (ridx = 4; ridx < RTWN_RIDX_COUNT; ridx++) {
+ if (sc->regulatory == 3) {
+ power[ridx] = base->pwr[0][ridx];
+ /* Apply vendor limits. */
+ if (extc != NULL)
+ max = rom->ht40_max_pwr[group];
+ else
+ max = rom->ht20_max_pwr[group];
+ max = (max >> (chain * 4)) & 0xf;
+ if (power[ridx] > max)
+ power[ridx] = max;
+ } else if (sc->regulatory == 1) {
+ if (extc == NULL)
+ power[ridx] = base->pwr[group][ridx];
+ } else if (sc->regulatory != 2)
+ power[ridx] = base->pwr[0][ridx];
+ }
+
+ /* Compute per-CCK rate Tx power. */
+ cckpow = rom->cck_tx_pwr[chain][group];
+ for (ridx = 0; ridx <= 3; ridx++) {
+ power[ridx] += cckpow;
+ if (power[ridx] > R92C_MAX_TX_PWR)
+ power[ridx] = R92C_MAX_TX_PWR;
+ }
+
+ htpow = rom->ht40_1s_tx_pwr[chain][group];
+ if (sc->ntxchains > 1) {
+ /* Apply reduction for 2 spatial streams. */
+ diff = rom->ht40_2s_tx_pwr_diff[group];
+ diff = (diff >> (chain * 4)) & 0xf;
+ htpow = (htpow > diff) ? htpow - diff : 0;
+ }
+
+ /* Compute per-OFDM rate Tx power. */
+ diff = rom->ofdm_tx_pwr_diff[group];
+ diff = (diff >> (chain * 4)) & 0xf;
+ ofdmpow = htpow + diff; /* HT->OFDM correction. */
+ for (ridx = 4; ridx <= 11; ridx++) {
+ power[ridx] += ofdmpow;
+ if (power[ridx] > R92C_MAX_TX_PWR)
+ power[ridx] = R92C_MAX_TX_PWR;
+ }
+
+ /* Compute per-MCS Tx power. */
+ if (extc == NULL) {
+ diff = rom->ht20_tx_pwr_diff[group];
+ diff = (diff >> (chain * 4)) & 0xf;
+ htpow += diff; /* HT40->HT20 correction. */
+ }
+ for (ridx = 12; ridx <= 27; ridx++) {
+ power[ridx] += htpow;
+ if (power[ridx] > R92C_MAX_TX_PWR)
+ power[ridx] = R92C_MAX_TX_PWR;
+ }
+#ifdef RTWN_DEBUG
+ if (rtwn_debug >= 4) {
+ /* Dump per-rate Tx power values. */
+ printf("Tx power for chain %d:\n", chain);
+ for (ridx = 0; ridx < RTWN_RIDX_COUNT; ridx++)
+ printf("Rate %d = %u\n", ridx, power[ridx]);
+ }
+#endif
+}
+
+void
+rtwn_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c,
+ struct ieee80211_channel *extc)
+{
+ uint16_t power[RTWN_RIDX_COUNT];
+ int i;
+
+ for (i = 0; i < sc->ntxchains; i++) {
+ /* Compute per-rate Tx power values. */
+ rtwn_get_txpower(sc, i, c, extc, power);
+ /* Write per-rate Tx power values to hardware. */
+ rtwn_write_txpower(sc, i, power);
+ }
+}
+
+void
+rtwn_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c,
+ struct ieee80211_channel *extc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ u_int chan;
+ int i;
+
+ chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
+
+ /* Set Tx power for this new channel. */
+ rtwn_set_txpower(sc, c, extc);
+
+ for (i = 0; i < sc->nrxchains; i++) {
+ rtwn_rf_write(sc, i, R92C_RF_CHNLBW,
+ RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
+ }
+ if (extc != NULL) {
+ uint32_t reg;
+
+ /* Is secondary channel below or above primary? */
+ int prichlo = c->ic_freq < extc->ic_freq;
+
+ rtwn_write_1(sc, R92C_BWOPMODE,
+ rtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ);
+
+ reg = rtwn_read_1(sc, R92C_RRSR + 2);
+ reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5;
+ rtwn_write_1(sc, R92C_RRSR + 2, reg);
+
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ);
+ rtwn_bb_write(sc, R92C_FPGA1_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ);
+
+ /* Set CCK side band. */
+ reg = rtwn_bb_read(sc, R92C_CCK0_SYSTEM);
+ reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4;
+ rtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM1_LSTF);
+ reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10;
+ rtwn_bb_write(sc, R92C_OFDM1_LSTF, reg);
+
+ rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
+ rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) &
+ ~R92C_FPGA0_ANAPARAM2_CBW20);
+
+ reg = rtwn_bb_read(sc, 0x818);
+ reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26;
+ rtwn_bb_write(sc, 0x818, reg);
+
+ /* Select 40MHz bandwidth. */
+ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+ (sc->rf_chnlbw[0] & ~0xfff) | chan);
+ } else {
+ rtwn_write_1(sc, R92C_BWOPMODE,
+ rtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ);
+
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ);
+ rtwn_bb_write(sc, R92C_FPGA1_RFMOD,
+ rtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ);
+
+ rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
+ rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) |
+ R92C_FPGA0_ANAPARAM2_CBW20);
+
+ /* Select 20MHz bandwidth. */
+ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+ (sc->rf_chnlbw[0] & ~0xfff) | R92C_RF_CHNLBW_BW20 | chan);
+ }
+}
+
+int
+rtwn_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2],
+ uint16_t rx[2])
+{
+ uint32_t status;
+ int offset = chain * 0x20;
+
+ if (chain == 0) { /* IQ calibration for chain 0. */
+ /* IQ calibration settings for chain 0. */
+ rtwn_bb_write(sc, 0xe30, 0x10008c1f);
+ rtwn_bb_write(sc, 0xe34, 0x10008c1f);
+ rtwn_bb_write(sc, 0xe38, 0x82140102);
+
+ if (sc->ntxchains > 1) {
+ rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */
+ /* IQ calibration settings for chain 1. */
+ rtwn_bb_write(sc, 0xe50, 0x10008c22);
+ rtwn_bb_write(sc, 0xe54, 0x10008c22);
+ rtwn_bb_write(sc, 0xe58, 0x82140102);
+ rtwn_bb_write(sc, 0xe5c, 0x28160202);
+ } else
+ rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */
+
+ /* LO calibration settings. */
+ rtwn_bb_write(sc, 0xe4c, 0x001028d1);
+ /* We're doing LO and IQ calibration in one shot. */
+ rtwn_bb_write(sc, 0xe48, 0xf9000000);
+ rtwn_bb_write(sc, 0xe48, 0xf8000000);
+
+ } else { /* IQ calibration for chain 1. */
+ /* We're doing LO and IQ calibration in one shot. */
+ rtwn_bb_write(sc, 0xe60, 0x00000002);
+ rtwn_bb_write(sc, 0xe60, 0x00000000);
+ }
+
+ /* Give LO and IQ calibrations the time to complete. */
+ DELAY(1000);
+
+ /* Read IQ calibration status. */
+ status = rtwn_bb_read(sc, 0xeac);
+
+ if (status & (1 << (28 + chain * 3)))
+ return (0); /* Tx failed. */
+ /* Read Tx IQ calibration results. */
+ tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff;
+ tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff;
+ if (tx[0] == 0x142 || tx[1] == 0x042)
+ return (0); /* Tx failed. */
+
+ if (status & (1 << (27 + chain * 3)))
+ return (1); /* Rx failed. */
+ /* Read Rx IQ calibration results. */
+ rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff;
+ rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff;
+ if (rx[0] == 0x132 || rx[1] == 0x036)
+ return (1); /* Rx failed. */
+
+ return (3); /* Both Tx and Rx succeeded. */
+}
+
+void
+rtwn_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2],
+ uint16_t rx[2][2])
+{
+ /* Registers to save and restore during IQ calibration. */
+ struct iq_cal_regs {
+ uint32_t adda[16];
+ uint8_t txpause;
+ uint8_t bcn_ctrl;
+ uint8_t ustime_tsf;
+ uint32_t gpio_muxcfg;
+ uint32_t ofdm0_trxpathena;
+ uint32_t ofdm0_trmuxpar;
+ uint32_t fpga0_rfifacesw1;
+ } iq_cal_regs;
+ static const uint16_t reg_adda[16] = {
+ 0x85c, 0xe6c, 0xe70, 0xe74,
+ 0xe78, 0xe7c, 0xe80, 0xe84,
+ 0xe88, 0xe8c, 0xed0, 0xed4,
+ 0xed8, 0xedc, 0xee0, 0xeec
+ };
+ int i, chain;
+ uint32_t hssi_param1;
+
+ if (n == 0) {
+ for (i = 0; i < nitems(reg_adda); i++)
+ iq_cal_regs.adda[i] = rtwn_bb_read(sc, reg_adda[i]);
+
+ iq_cal_regs.txpause = rtwn_read_1(sc, R92C_TXPAUSE);
+ iq_cal_regs.bcn_ctrl = rtwn_read_1(sc, R92C_BCN_CTRL);
+ iq_cal_regs.ustime_tsf = rtwn_read_1(sc, R92C_USTIME_TSF);
+ iq_cal_regs.gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
+ }
+
+ if (sc->ntxchains == 1) {
+ rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0);
+ for (i = 1; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0);
+ } else {
+ for (i = 0; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], 0x04db25a4);
+ }
+
+ hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0));
+ if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(0),
+ hssi_param1 | R92C_HSSI_PARAM1_PI);
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(1),
+ hssi_param1 | R92C_HSSI_PARAM1_PI);
+ }
+
+ if (n == 0) {
+ iq_cal_regs.ofdm0_trxpathena =
+ rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
+ iq_cal_regs.ofdm0_trmuxpar =
+ rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR);
+ iq_cal_regs.fpga0_rfifacesw1 =
+ rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1));
+ }
+
+ rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
+ rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
+ if (sc->ntxchains > 1) {
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000);
+ }
+
+ rtwn_write_1(sc, R92C_TXPAUSE, 0x3f);
+ rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl & ~(0x08));
+ rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf & ~(0x08));
+ rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+ iq_cal_regs.gpio_muxcfg & ~(0x20));
+
+ rtwn_bb_write(sc, 0x0b68, 0x00080000);
+ if (sc->ntxchains > 1)
+ rtwn_bb_write(sc, 0x0b6c, 0x00080000);
+
+ rtwn_bb_write(sc, 0x0e28, 0x80800000);
+ rtwn_bb_write(sc, 0x0e40, 0x01007c00);
+ rtwn_bb_write(sc, 0x0e44, 0x01004800);
+
+ rtwn_bb_write(sc, 0x0b68, 0x00080000);
+
+ for (chain = 0; chain < sc->ntxchains; chain++) {
+ if (chain > 0) {
+ /* Put chain 0 on standby. */
+ rtwn_bb_write(sc, 0x0e28, 0x00);
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
+ rtwn_bb_write(sc, 0x0e28, 0x80800000);
+
+ /* Enable chain 1. */
+ for (i = 0; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4);
+ }
+
+ /* Run IQ calibration twice. */
+ for (i = 0; i < 2; i++) {
+ int ret;
+
+ ret = rtwn_iq_calib_chain(sc, chain,
+ tx[chain], rx[chain]);
+ if (ret == 0) {
+ DPRINTF(("%s: chain %d: Tx failed.\n",
+ __func__, chain));
+ tx[chain][0] = 0xff;
+ tx[chain][1] = 0xff;
+ rx[chain][0] = 0xff;
+ rx[chain][1] = 0xff;
+ } else if (ret == 1) {
+ DPRINTF(("%s: chain %d: Rx failed.\n",
+ __func__, chain));
+ rx[chain][0] = 0xff;
+ rx[chain][1] = 0xff;
+ } else if (ret == 3) {
+ DPRINTF(("%s: chain %d: Both Tx and Rx "
+ "succeeded.\n", __func__, chain));
+ }
+ }
+
+ DPRINTF(("%s: results for run %d chain %d: tx[0]=0x%x, "
+ "tx[1]=0x%x rx[0]=0x%x rx[1]=0x%x\n", __func__, n, chain,
+ tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]));
+ }
+
+ rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA,
+ iq_cal_regs.ofdm0_trxpathena);
+ rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1),
+ iq_cal_regs.fpga0_rfifacesw1);
+ rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, iq_cal_regs.ofdm0_trmuxpar);
+
+ rtwn_bb_write(sc, 0x0e28, 0x00);
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3);
+ if (sc->ntxchains > 1)
+ rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3);
+
+ if (n != 0) {
+ if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1);
+ rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1);
+ }
+
+ for (i = 0; i < nitems(reg_adda); i++)
+ rtwn_bb_write(sc, reg_adda[i], iq_cal_regs.adda[i]);
+
+ rtwn_write_1(sc, R92C_TXPAUSE, iq_cal_regs.txpause);
+ rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl);
+ rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf);
+ rtwn_write_4(sc, R92C_GPIO_MUXCFG, iq_cal_regs.gpio_muxcfg);
+ }
+}
+
+#define RTWN_IQ_CAL_MAX_TOLERANCE 5
+int
+rtwn_iq_calib_compare_results(uint16_t tx1[2][2], uint16_t rx1[2][2],
+ uint16_t tx2[2][2], uint16_t rx2[2][2], int ntxchains)
+{
+ int chain, i, tx_ok[2], rx_ok[2];
+
+ tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0;
+ for (chain = 0; chain < ntxchains; chain++) {
+ for (i = 0; i < 2; i++) {
+ if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff ||
+ rx1[chain][i] == 0xff || rx2[chain][i] == 0xff)
+ continue;
+
+ tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <=
+ RTWN_IQ_CAL_MAX_TOLERANCE);
+
+ rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <=
+ RTWN_IQ_CAL_MAX_TOLERANCE);
+ }
+ }
+
+ if (ntxchains > 1)
+ return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]);
+ else
+ return (tx_ok[0] && rx_ok[0]);
+}
+#undef RTWN_IQ_CAL_MAX_TOLERANCE
+
+void
+rtwn_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2],
+ uint16_t rx[2], int chain)
+{
+ uint32_t reg, val, x;
+ long y, tx_c;
+
+ if (tx[0] == 0xff || tx[1] == 0xff)
+ return;
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
+ val = ((reg >> 22) & 0x3ff);
+ x = tx[0];
+ if (x & 0x0200)
+ x |= 0xfc00;
+ reg = (((x * val) >> 8) & 0x3ff);
+ rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD);
+ if (((x * val) >> 7) & 0x01)
+ reg |= 0x80000000;
+ else
+ reg &= ~0x80000000;
+ rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg);
+
+ y = tx[1];
+ if (y & 0x00000200)
+ y |= 0xfffffc00;
+ tx_c = (y * val) >> 8;
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TXAFE(chain));
+ reg |= ((((tx_c & 0x3c0) >> 6) << 24) & 0xf0000000);
+ rtwn_bb_write(sc, R92C_OFDM0_TXAFE(chain), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
+ reg |= (((tx_c & 0x3f) << 16) & 0x003F0000);
+ rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg);
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD);
+ if (((y * val) >> 7) & 0x01)
+ reg |= 0x20000000;
+ else
+ reg &= ~0x20000000;
+ rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg);
+
+ if (rx[0] == 0xff || rx[1] == 0xff)
+ return;
+
+ reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQIMBALANCE(chain));
+ reg |= (rx[0] & 0x3ff);
+ rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg);
+ reg |= (((rx[1] & 0x03f) << 8) & 0xFC00);
+ rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg);
+
+ if (chain == 0) {
+ reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQEXTANTA);
+ reg |= (((rx[1] & 0xf) >> 6) & 0x000f);
+ rtwn_bb_write(sc, R92C_OFDM0_RXIQEXTANTA, reg);
+ } else {
+ reg = rtwn_bb_read(sc, R92C_OFDM0_AGCRSSITABLE);
+ reg |= ((((rx[1] & 0xf) >> 6) << 12) & 0xf000);
+ rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, reg);
+ }
+}
+
+#define RTWN_IQ_CAL_NRUN 3
+void
+rtwn_iq_calib(struct rtwn_softc *sc)
+{
+ uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2];
+ int n, valid;
+
+ valid = 0;
+ for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) {
+ rtwn_iq_calib_run(sc, n, tx[n], rx[n]);
+
+ if (n == 0)
+ continue;
+
+ /* Valid results remain stable after consecutive runs. */
+ valid = rtwn_iq_calib_compare_results(tx[n - 1], rx[n - 1],
+ tx[n], rx[n], sc->ntxchains);
+ if (valid)
+ break;
+ }
+
+ if (valid) {
+ rtwn_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0);
+ if (sc->ntxchains > 1)
+ rtwn_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1);
+ }
+}
+#undef RTWN_IQ_CAL_NRUN
+
+void
+rtwn_lc_calib(struct rtwn_softc *sc)
+{
+ uint32_t rf_ac[2];
+ uint8_t txmode;
+ int i;
+
+ txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
+ if ((txmode & 0x70) != 0) {
+ /* Disable all continuous Tx. */
+ rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
+
+ /* Set RF mode to standby mode. */
+ for (i = 0; i < sc->nrxchains; i++) {
+ rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC);
+ rtwn_rf_write(sc, i, R92C_RF_AC,
+ RW(rf_ac[i], R92C_RF_AC_MODE,
+ R92C_RF_AC_MODE_STANDBY));
+ }
+ } else {
+ /* Block all Tx queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0xff);
+ }
+ /* Start calibration. */
+ rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
+ rtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART);
+
+ /* Give calibration the time to complete. */
+ DELAY(100);
+
+ /* Restore configuration. */
+ if ((txmode & 0x70) != 0) {
+ /* Restore Tx mode. */
+ rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
+ /* Restore RF mode. */
+ for (i = 0; i < sc->nrxchains; i++)
+ rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
+ } else {
+ /* Unblock all Tx queues. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0x00);
+ }
+}
+
+void
+rtwn_temp_calib(struct rtwn_softc *sc)
+{
+ int temp;
+
+ if (sc->thcal_state == 0) {
+ /* Start measuring temperature. */
+ rtwn_rf_write(sc, 0, R92C_RF_T_METER, 0x60);
+ sc->thcal_state = 1;
+ return;
+ }
+ sc->thcal_state = 0;
+
+ /* Read measured temperature. */
+ temp = rtwn_rf_read(sc, 0, R92C_RF_T_METER) & 0x1f;
+ if (temp == 0) /* Read failed, skip. */
+ return;
+ DPRINTFN(2, ("temperature=%d\n", temp));
+
+ /*
+ * Redo IQ and LC calibration if temperature changed significantly
+ * since last calibration.
+ */
+ if (sc->thcal_lctemp == 0) {
+ /* First calibration is performed in rtwn_init(). */
+ sc->thcal_lctemp = temp;
+ } else if (abs(temp - sc->thcal_lctemp) > 1) {
+ DPRINTF(("IQ/LC calib triggered by temp: %d -> %d\n",
+ sc->thcal_lctemp, temp));
+ rtwn_iq_calib(sc);
+ rtwn_lc_calib(sc);
+ /* Record temperature of last calibration. */
+ sc->thcal_lctemp = temp;
+ }
+}
+
+int
+rtwn_init(struct ifnet *ifp)
+{
+ struct rtwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ uint32_t reg;
+ int i, error;
+
+ /* Init firmware commands ring. */
+ sc->fwcur = 0;
+
+ /* Power on adapter. */
+ error = rtwn_power_on(sc);
+ if (error != 0) {
+ printf("%s: could not power on adapter\n",
+ sc->sc_pdev->dv_xname);
+ goto fail;
+ }
+
+ /* Initialize DMA. */
+ error = rtwn_dma_init(sc);
+ if (error != 0) {
+ printf("%s: could not initialize DMA\n",
+ sc->sc_pdev->dv_xname);
+ goto fail;
+ }
+
+ /* Set info size in Rx descriptors (in 64-bit words). */
+ rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4);
+
+ /* Disable interrupts. */
+ rtwn_write_4(sc, R92C_HISR, 0x00000000);
+ rtwn_write_4(sc, R92C_HIMR, 0x00000000);
+
+ /* Set MAC address. */
+ IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
+ for (i = 0; i < IEEE80211_ADDR_LEN; i++)
+ rtwn_write_1(sc, R92C_MACID + i, ic->ic_myaddr[i]);
+
+ /* Set initial network type. */
+ reg = rtwn_read_4(sc, R92C_CR);
+ reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
+ rtwn_write_4(sc, R92C_CR, reg);
+
+ rtwn_rxfilter_init(sc);
+
+ reg = rtwn_read_4(sc, R92C_RRSR);
+ reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_ALL);
+ rtwn_write_4(sc, R92C_RRSR, reg);
+
+ /* Set short/long retry limits. */
+ rtwn_write_2(sc, R92C_RL,
+ SM(R92C_RL_SRL, 0x07) | SM(R92C_RL_LRL, 0x07));
+
+ /* Initialize EDCA parameters. */
+ rtwn_edca_init(sc);
+
+ /* Set data and response automatic rate fallback retry counts. */
+ rtwn_write_4(sc, R92C_DARFRC + 0, 0x01000000);
+ rtwn_write_4(sc, R92C_DARFRC + 4, 0x07060504);
+ rtwn_write_4(sc, R92C_RARFRC + 0, 0x01000000);
+ rtwn_write_4(sc, R92C_RARFRC + 4, 0x07060504);
+
+ rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, 0x1f80);
+
+ /* Set ACK timeout. */
+ rtwn_write_1(sc, R92C_ACKTO, 0x40);
+
+ /* Initialize beacon parameters. */
+ rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404);
+ rtwn_write_1(sc, R92C_DRVERLYINT, 0x05);
+ rtwn_write_1(sc, R92C_BCNDMATIM, 0x02);
+ rtwn_write_2(sc, R92C_BCNTCFG, 0x660f);
+
+ /* Setup AMPDU aggregation. */
+ rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */
+ rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
+
+ rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff);
+ rtwn_write_1(sc, R92C_BCN_CTRL, R92C_BCN_CTRL_DIS_TSF_UDT0);
+
+ rtwn_write_4(sc, R92C_PIFS, 0x1c);
+ rtwn_write_4(sc, R92C_MCUTST_1, 0x0);
+
+ /* Load 8051 microcode. */
+ error = rtwn_load_firmware(sc);
+ if (error != 0)
+ goto fail;
+
+ /* Initialize MAC/BB/RF blocks. */
+ rtwn_mac_init(sc);
+ rtwn_bb_init(sc);
+ rtwn_rf_init(sc);
+
+ /* Turn CCK and OFDM blocks on. */
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD);
+ reg |= R92C_RFMOD_CCK_EN;
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
+ reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD);
+ reg |= R92C_RFMOD_OFDM_EN;
+ rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
+
+ /* Clear per-station keys table. */
+ rtwn_cam_init(sc);
+
+ /* Enable hardware sequence numbering. */
+ rtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff);
+
+ /* Perform LO and IQ calibrations. */
+ rtwn_iq_calib(sc);
+ /* Perform LC calibration. */
+ rtwn_lc_calib(sc);
+
+ rtwn_pa_bias_init(sc);
+
+ /* Initialize GPIO setting. */
+ rtwn_write_1(sc, R92C_GPIO_MUXCFG,
+ rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT);
+
+ /* Fix for lower temperature. */
+ rtwn_write_1(sc, 0x15, 0xe9);
+
+ /* Set default channel. */
+ ic->ic_bss->ni_chan = ic->ic_ibss_chan;
+ rtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
+
+ /* Enable interrupts. */
+ sc->sc_ops.enable_intr(sc->sc_ops.cookie);
+
+ /* We're ready to go. */
+ ifq_clr_oactive(&ifp->if_snd);
+ ifp->if_flags |= IFF_RUNNING;
+
+#ifdef notyet
+ if (ic->ic_flags & IEEE80211_F_WEPON) {
+ /* Install WEP keys. */
+ for (i = 0; i < IEEE80211_WEP_NKID; i++)
+ rtwn_set_key(ic, NULL, &ic->ic_nw_keys[i]);
+ }
+#endif
+ if (ic->ic_opmode == IEEE80211_M_MONITOR)
+ ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
+ else
+ ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+ return (0);
+ fail:
+ rtwn_stop(ifp);
+ return (error);
+}
+
+void
+rtwn_init_task(void *arg1)
+{
+ struct rtwn_softc *sc = arg1;
+ struct ifnet *ifp = &sc->sc_ic.ic_if;
+ int s;
+
+ s = splnet();
+ while (sc->sc_flags & RTWN_FLAG_BUSY)
+ tsleep(&sc->sc_flags, 0, "rtwnpwr", 0);
+ sc->sc_flags |= RTWN_FLAG_BUSY;
+
+ rtwn_stop(ifp);
+
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
+ rtwn_init(ifp);
+
+ sc->sc_flags &= ~RTWN_FLAG_BUSY;
+ wakeup(&sc->sc_flags);
+ splx(s);
+}
+
+void
+rtwn_stop(struct ifnet *ifp)
+{
+ struct rtwn_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ int s;
+ u_int16_t reg;
+
+ sc->sc_tx_timer = 0;
+ ifp->if_timer = 0;
+ ifp->if_flags &= ~IFF_RUNNING;
+ ifq_clr_oactive(&ifp->if_snd);
+
+ s = splnet();
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
+ timeout_del(&sc->scan_to);
+ timeout_del(&sc->calib_to);
+
+ task_del(systq, &sc->init_task);
+
+ /* Disable interrupts. */
+ sc->sc_ops.disable_intr(sc->sc_ops.cookie);
+
+ /* Stop hardware. */
+ rtwn_write_1(sc, R92C_TXPAUSE, 0xff);
+ rtwn_write_1(sc, R92C_RF_CTRL, 0x00);
+ reg = rtwn_read_1(sc, R92C_SYS_FUNC_EN);
+ reg |= R92C_SYS_FUNC_EN_BB_GLB_RST;
+ rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg);
+ reg &= ~R92C_SYS_FUNC_EN_BB_GLB_RST;
+ rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg);
+ reg = rtwn_read_2(sc, R92C_CR);
+ reg &= ~(R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
+ R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
+ R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
+ R92C_CR_ENSEC);
+ rtwn_write_2(sc, R92C_CR, reg);
+ if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
+ rtwn_fw_reset(sc);
+ /* TODO: linux does additional btcoex stuff here */
+ rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */
+ rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */
+ rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */
+ rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e);
+ rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN);
+
+ sc->sc_ops.stop(sc->sc_ops.cookie);
+
+ splx(s);
+
+}
diff --git a/sys/dev/ic/rtwnvar.h b/sys/dev/ic/rtwnvar.h
new file mode 100644
index 00000000000..07b8e1c04f5
--- /dev/null
+++ b/sys/dev/ic/rtwnvar.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: rtwnvar.h,v 1.1 2016/03/09 18:18:28 stsp Exp $ */
+
+/*-
+ * Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2015 Stefan Sperling <stsp@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Operations provided by bus-specific attachment drivers. */
+struct rtwn_ops {
+ void *cookie; /* Attachment driver's private data. */
+
+ uint8_t (*read_1)(void *, uint16_t);
+ uint16_t (*read_2)(void *, uint16_t);
+ uint32_t (*read_4)(void *, uint16_t);
+ void (*write_1)(void *, uint16_t, uint8_t);
+ void (*write_2)(void *, uint16_t, uint16_t);
+ void (*write_4)(void *, uint16_t, uint32_t);
+ void (*next_scan)(void *);
+ int (*tx)(void *, struct mbuf *, struct ieee80211_node *);
+ int (*configure_dma)(void *);
+ void (*enable_intr)(void *);
+ void (*disable_intr)(void *);
+ void (*stop)(void *);
+ int (*is_oactive)(void *);
+};
+
+struct rtwn_softc {
+ /* sc_ops must be initialized by the attachment driver! */
+ struct rtwn_ops sc_ops;
+
+ struct device *sc_pdev;
+ struct ieee80211com sc_ic;
+ int (*sc_newstate)(struct ieee80211com *,
+ enum ieee80211_state, int);
+ struct timeout scan_to;
+ struct timeout calib_to;
+ struct task init_task;
+ int ac2idx[EDCA_NUM_AC];
+ u_int sc_flags;
+#define RTWN_FLAG_CCK_HIPWR 0x01
+#define RTWN_FLAG_BUSY 0x02
+
+ u_int chip;
+#define RTWN_CHIP_88C 0x00
+#define RTWN_CHIP_92C 0x01
+#define RTWN_CHIP_92C_1T2R 0x02
+#define RTWN_CHIP_UMC 0x04
+#define RTWN_CHIP_UMC_A_CUT 0x08
+
+ uint8_t board_type;
+ uint8_t regulatory;
+ uint8_t pa_setting;
+ int avg_pwdb;
+ int thcal_state;
+ int thcal_lctemp;
+ int ntxchains;
+ int nrxchains;
+ int ledlink;
+
+ int sc_tx_timer;
+ int fwcur;
+ struct r92c_rom rom;
+
+ uint32_t rf_chnlbw[R92C_MAX_CHAINS];
+};
+
+void rtwn_attach(struct device *, struct rtwn_softc *);
+int rtwn_detach(struct rtwn_softc *, int);
+int rtwn_activate(struct rtwn_softc *, int);
+int8_t rtwn_get_rssi(struct rtwn_softc *, int, void *);
+void rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t);
diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci
index 0614e568d71..cae5a3aae6f 100644
--- a/sys/dev/pci/files.pci
+++ b/sys/dev/pci/files.pci
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pci,v 1.322 2015/12/31 13:06:49 kettenis Exp $
+# $OpenBSD: files.pci,v 1.323 2016/03/09 18:18:28 stsp Exp $
# $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $
#
# Config file and device description for machine-independent PCI code.
@@ -677,9 +677,8 @@ attach rtw at pci with rtw_pci
file dev/pci/if_rtw_pci.c rtw_pci
# Realtek RTL8188CE Mini-PCI
-device rtwn: ifnet, wlan, firmload
-attach rtwn at pci
-file dev/pci/if_rtwn.c rtwn
+attach rtwn at pci with rtwn_pci
+file dev/pci/if_rtwn.c rtwn_pci
# Ralink RT2500 PCI/Mini-PCI
attach ral at pci with ral_pci
diff --git a/sys/dev/pci/if_rtwn.c b/sys/dev/pci/if_rtwn.c
index b575193f7dd..fa84bbcbb70 100644
--- a/sys/dev/pci/if_rtwn.c
+++ b/sys/dev/pci/if_rtwn.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_rtwn.c,v 1.15 2016/03/07 19:41:49 stsp Exp $ */
+/* $OpenBSD: if_rtwn.c,v 1.16 2016/03/09 18:18:28 stsp Exp $ */
/*-
* Copyright (c) 2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -18,7 +18,7 @@
*/
/*
- * Driver for Realtek RTL8188CE
+ * PCI front-end for Realtek RTL8188CE driver.
*/
#include "bpfilter.h"
@@ -56,14 +56,7 @@
#include <dev/pci/pcidevs.h>
#include <dev/ic/r92creg.h>
-
-#define R92C_PUBQ_NPAGES 176
-#define R92C_HPQ_NPAGES 41
-#define R92C_LPQ_NPAGES 28
-#define R92C_TXPKTBUF_COUNT 256
-#define R92C_TX_PAGE_COUNT \
- (R92C_PUBQ_NPAGES + R92C_HPQ_NPAGES + R92C_LPQ_NPAGES)
-#define R92C_TX_PAGE_BOUNDARY (R92C_TX_PAGE_COUNT + 1)
+#include <dev/ic/rtwnvar.h>
/*
* Driver definitions.
@@ -71,7 +64,6 @@
#define RTWN_NTXQUEUES 9
#define RTWN_RX_LIST_COUNT 256
#define RTWN_TX_LIST_COUNT 256
-#define RTWN_HOST_CMD_RING_COUNT 32
/* TX queue indices. */
#define RTWN_BK_QUEUE 0
@@ -84,19 +76,6 @@
#define RTWN_HIGH_QUEUE 7
#define RTWN_HCCA_QUEUE 8
-/* RX queue indices. */
-#define RTWN_RX_QUEUE 0
-
-#define RTWN_RXBUFSZ (16 * 1024)
-#define RTWN_TXBUFSZ (sizeof(struct r92c_tx_desc_pci) + IEEE80211_MAX_LEN)
-
-#define RTWN_RIDX_COUNT 28
-
-#define RTWN_TX_TIMEOUT 5000 /* ms */
-
-#define RTWN_LED_LINK 0
-#define RTWN_LED_DATA 1
-
struct rtwn_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
uint8_t wr_flags;
@@ -123,8 +102,6 @@ struct rtwn_tx_radiotap_header {
(1 << IEEE80211_RADIOTAP_FLAGS | \
1 << IEEE80211_RADIOTAP_CHANNEL)
-struct rtwn_softc;
-
struct rtwn_rx_data {
bus_dmamap_t map;
struct mbuf *m;
@@ -154,28 +131,13 @@ struct rtwn_tx_ring {
int cur;
};
-struct rtwn_host_cmd {
- void (*cb)(struct rtwn_softc *, void *);
- uint8_t data[256];
-};
+struct rtwn_pci_softc {
+ struct device sc_dev;
+ struct rtwn_softc sc_sc;
-struct rtwn_cmd_key {
- struct ieee80211_key key;
- uint16_t associd;
-};
-
-struct rtwn_host_cmd_ring {
- struct rtwn_host_cmd cmd[RTWN_HOST_CMD_RING_COUNT];
- int cur;
- int next;
- int queued;
-};
-
-struct rtwn_softc {
- struct device sc_dev;
- struct ieee80211com sc_ic;
- int (*sc_newstate)(struct ieee80211com *,
- enum ieee80211_state, int);
+ struct rtwn_rx_ring rx_ring;
+ struct rtwn_tx_ring tx_ring[RTWN_NTXQUEUES];
+ uint32_t qfullmsk;
/* PCI specific goo. */
bus_dma_tag_t sc_dmat;
@@ -187,40 +149,6 @@ struct rtwn_softc {
bus_size_t sc_mapsize;
int sc_cap_off;
-
- struct timeout scan_to;
- struct timeout calib_to;
- struct task init_task;
- int ac2idx[EDCA_NUM_AC];
- u_int sc_flags;
-#define RTWN_FLAG_CCK_HIPWR 0x01
-#define RTWN_FLAG_BUSY 0x02
-
- u_int chip;
-#define RTWN_CHIP_88C 0x00
-#define RTWN_CHIP_92C 0x01
-#define RTWN_CHIP_92C_1T2R 0x02
-#define RTWN_CHIP_UMC 0x04
-#define RTWN_CHIP_UMC_A_CUT 0x08
-
- uint8_t board_type;
- uint8_t regulatory;
- uint8_t pa_setting;
- int avg_pwdb;
- int thcal_state;
- int thcal_lctemp;
- int ntxchains;
- int nrxchains;
- int ledlink;
-
- int sc_tx_timer;
- int fwcur;
- struct rtwn_rx_ring rx_ring;
- struct rtwn_tx_ring tx_ring[RTWN_NTXQUEUES];
- uint32_t qfullmsk;
- struct r92c_rom rom;
-
- uint32_t rf_chnlbw[R92C_MAX_CHAINS];
#if NBPFILTER > 0
caddr_t sc_drvbpf;
@@ -240,11 +168,10 @@ struct rtwn_softc {
#endif
};
-
#ifdef RTWN_DEBUG
#define DPRINTF(x) do { if (rtwn_debug) printf x; } while (0)
#define DPRINTFN(n, x) do { if (rtwn_debug >= (n)) printf x; } while (0)
-int rtwn_debug = 0;
+extern int rtwn_debug;
#else
#define DPRINTF(x)
#define DPRINTFN(n, x)
@@ -265,123 +192,61 @@ static const struct pci_matchid rtwn_pci_devices[] = {
{ PCI_VENDOR_REALTEK, PCI_PRODUCT_REALTEK_RT8188 }
};
-int rtwn_match(struct device *, void *, void *);
-void rtwn_attach(struct device *, struct device *, void *);
-int rtwn_detach(struct device *, int);
-int rtwn_activate(struct device *, int);
-int rtwn_alloc_rx_list(struct rtwn_softc *);
-void rtwn_reset_rx_list(struct rtwn_softc *);
-void rtwn_free_rx_list(struct rtwn_softc *);
-void rtwn_setup_rx_desc(struct rtwn_softc *,
+int rtwn_pci_match(struct device *, void *, void *);
+void rtwn_pci_attach(struct device *, struct device *, void *);
+int rtwn_pci_detach(struct device *, int);
+int rtwn_pci_activate(struct device *, int);
+int rtwn_alloc_rx_list(struct rtwn_pci_softc *);
+void rtwn_reset_rx_list(struct rtwn_pci_softc *);
+void rtwn_free_rx_list(struct rtwn_pci_softc *);
+void rtwn_setup_rx_desc(struct rtwn_pci_softc *,
struct r92c_rx_desc_pci *, bus_addr_t, size_t, int);
-int rtwn_alloc_tx_list(struct rtwn_softc *, int);
-void rtwn_reset_tx_list(struct rtwn_softc *, int);
-void rtwn_free_tx_list(struct rtwn_softc *, int);
-void rtwn_write_1(struct rtwn_softc *, uint16_t, uint8_t);
-void rtwn_write_2(struct rtwn_softc *, uint16_t, uint16_t);
-void rtwn_write_4(struct rtwn_softc *, uint16_t, uint32_t);
-uint8_t rtwn_read_1(struct rtwn_softc *, uint16_t);
-uint16_t rtwn_read_2(struct rtwn_softc *, uint16_t);
-uint32_t rtwn_read_4(struct rtwn_softc *, uint16_t);
-int rtwn_fw_cmd(struct rtwn_softc *, uint8_t, const void *, int);
-void rtwn_rf_write(struct rtwn_softc *, int, uint8_t, uint32_t);
-uint32_t rtwn_rf_read(struct rtwn_softc *, int, uint8_t);
-void rtwn_cam_write(struct rtwn_softc *, uint32_t, uint32_t);
-int rtwn_llt_write(struct rtwn_softc *, uint32_t, uint32_t);
-uint8_t rtwn_efuse_read_1(struct rtwn_softc *, uint16_t);
-void rtwn_efuse_read(struct rtwn_softc *);
-int rtwn_read_chipid(struct rtwn_softc *);
-void rtwn_read_rom(struct rtwn_softc *);
-int rtwn_media_change(struct ifnet *);
-int rtwn_ra_init(struct rtwn_softc *);
-void rtwn_tsf_sync_enable(struct rtwn_softc *);
-void rtwn_set_led(struct rtwn_softc *, int, int);
-void rtwn_calib_to(void *);
-void rtwn_next_scan(void *);
-int rtwn_newstate(struct ieee80211com *, enum ieee80211_state,
- int);
-void rtwn_updateedca(struct ieee80211com *);
-int rtwn_set_key(struct ieee80211com *, struct ieee80211_node *,
- struct ieee80211_key *);
-void rtwn_delete_key(struct ieee80211com *,
- struct ieee80211_node *, struct ieee80211_key *);
-void rtwn_update_avgrssi(struct rtwn_softc *, int, int8_t);
-int8_t rtwn_get_rssi(struct rtwn_softc *, int, void *);
-void rtwn_rx_frame(struct rtwn_softc *, struct r92c_rx_desc_pci *,
- struct rtwn_rx_data *, int);
-int rtwn_tx(struct rtwn_softc *, struct mbuf *,
- struct ieee80211_node *);
-void rtwn_tx_done(struct rtwn_softc *, int);
-void rtwn_start(struct ifnet *);
-void rtwn_watchdog(struct ifnet *);
-int rtwn_ioctl(struct ifnet *, u_long, caddr_t);
-int rtwn_power_on(struct rtwn_softc *);
-int rtwn_llt_init(struct rtwn_softc *);
-void rtwn_fw_reset(struct rtwn_softc *);
-int rtwn_fw_loadpage(struct rtwn_softc *, int, uint8_t *, int);
-int rtwn_load_firmware(struct rtwn_softc *);
-int rtwn_dma_init(struct rtwn_softc *);
-void rtwn_mac_init(struct rtwn_softc *);
-void rtwn_bb_init(struct rtwn_softc *);
-void rtwn_rf_init(struct rtwn_softc *);
-void rtwn_cam_init(struct rtwn_softc *);
-void rtwn_pa_bias_init(struct rtwn_softc *);
-void rtwn_rxfilter_init(struct rtwn_softc *);
-void rtwn_edca_init(struct rtwn_softc *);
-void rtwn_write_txpower(struct rtwn_softc *, int, uint16_t[]);
-void rtwn_get_txpower(struct rtwn_softc *, int,
- struct ieee80211_channel *, struct ieee80211_channel *,
- uint16_t[]);
-void rtwn_set_txpower(struct rtwn_softc *,
- struct ieee80211_channel *, struct ieee80211_channel *);
-void rtwn_set_chan(struct rtwn_softc *,
- struct ieee80211_channel *, struct ieee80211_channel *);
-int rtwn_iq_calib_chain(struct rtwn_softc *, int, uint16_t[2],
- uint16_t[2]);
-void rtwn_iq_calib_run(struct rtwn_softc *, int, uint16_t[2][2],
- uint16_t[2][2]);
-int rtwn_iq_calib_compare_results(uint16_t[2][2], uint16_t[2][2],
- uint16_t[2][2], uint16_t[2][2], int);
-void rtwn_iq_calib_write_results(struct rtwn_softc *, uint16_t[2],
- uint16_t[2], int);
-void rtwn_iq_calib(struct rtwn_softc *);
-void rtwn_lc_calib(struct rtwn_softc *);
-void rtwn_temp_calib(struct rtwn_softc *);
-int rtwn_init(struct ifnet *);
-void rtwn_init_task(void *);
-void rtwn_stop(struct ifnet *);
+int rtwn_alloc_tx_list(struct rtwn_pci_softc *, int);
+void rtwn_reset_tx_list(struct rtwn_pci_softc *, int);
+void rtwn_free_tx_list(struct rtwn_pci_softc *, int);
+void rtwn_pci_write_1(void *, uint16_t, uint8_t);
+void rtwn_pci_write_2(void *, uint16_t, uint16_t);
+void rtwn_pci_write_4(void *, uint16_t, uint32_t);
+uint8_t rtwn_pci_read_1(void *, uint16_t);
+uint16_t rtwn_pci_read_2(void *, uint16_t);
+uint32_t rtwn_pci_read_4(void *, uint16_t);
+void rtwn_pci_next_scan(void *);
+void rtwn_rx_frame(struct rtwn_pci_softc *,
+ struct r92c_rx_desc_pci *, struct rtwn_rx_data *, int);
+int rtwn_tx(void *, struct mbuf *, struct ieee80211_node *);
+void rtwn_tx_done(struct rtwn_pci_softc *, int);
+void rtwn_pci_stop(void *);
int rtwn_intr(void *);
-
-/* Aliases. */
-#define rtwn_bb_write rtwn_write_4
-#define rtwn_bb_read rtwn_read_4
+int rtwn_is_oactive(void *);
+int rtwn_configure_dma(void *);
+void rtwn_enable_intr(void *);
+void rtwn_disable_intr(void *);
struct cfdriver rtwn_cd = {
NULL, "rtwn", DV_IFNET
};
-const struct cfattach rtwn_ca = {
- sizeof(struct rtwn_softc),
- rtwn_match,
- rtwn_attach,
- rtwn_detach,
- rtwn_activate
+const struct cfattach rtwn_pci_ca = {
+ sizeof(struct rtwn_pci_softc),
+ rtwn_pci_match,
+ rtwn_pci_attach,
+ rtwn_pci_detach,
+ rtwn_pci_activate
};
int
-rtwn_match(struct device *parent, void *match, void *aux)
+rtwn_pci_match(struct device *parent, void *match, void *aux)
{
return (pci_matchbyid(aux, rtwn_pci_devices,
nitems(rtwn_pci_devices)));
}
void
-rtwn_attach(struct device *parent, struct device *self, void *aux)
+rtwn_pci_attach(struct device *parent, struct device *self, void *aux)
{
- struct rtwn_softc *sc = (struct rtwn_softc *)self;
+ struct rtwn_pci_softc *sc = (struct rtwn_pci_softc*)self;
struct pci_attach_args *pa = aux;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifnet *ifp = &ic->ic_if;
+ struct ifnet *ifp;
int i, error;
pcireg_t memtype;
pci_intr_handle_t ih;
@@ -391,11 +256,6 @@ rtwn_attach(struct device *parent, struct device *self, void *aux)
sc->sc_pc = pa->pa_pc;
sc->sc_tag = pa->pa_tag;
- timeout_set(&sc->scan_to, rtwn_next_scan, sc);
- timeout_set(&sc->calib_to, rtwn_calib_to, sc);
-
- task_set(&sc->init_task, rtwn_init_task, sc);
-
pci_set_powerstate(pa->pa_pc, pa->pa_tag, PCI_PMCSR_STATE_D0);
/* Map control/status registers. */
@@ -423,12 +283,6 @@ rtwn_attach(struct device *parent, struct device *self, void *aux)
}
printf(": %s\n", intrstr);
- error = rtwn_read_chipid(sc);
- if (error != 0) {
- printf("%s: unsupported test chip\n", sc->sc_dev.dv_xname);
- return;
- }
-
/* Disable PCIe Active State Power Management (ASPM). */
if (pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS,
&sc->sc_cap_off, NULL)) {
@@ -455,85 +309,25 @@ rtwn_attach(struct device *parent, struct device *self, void *aux)
}
}
- /* Determine number of Tx/Rx chains. */
- if (sc->chip & RTWN_CHIP_92C) {
- sc->ntxchains = (sc->chip & RTWN_CHIP_92C_1T2R) ? 1 : 2;
- sc->nrxchains = 2;
- } else {
- sc->ntxchains = 1;
- sc->nrxchains = 1;
- }
- rtwn_read_rom(sc);
-
- printf("%s: MAC/BB RTL%s, RF 6052 %dT%dR, address %s\n",
- sc->sc_dev.dv_xname,
- (sc->chip & RTWN_CHIP_92C) ? "8192CE" : "8188CE",
- sc->ntxchains, sc->nrxchains,
- ether_sprintf(ic->ic_myaddr));
-
- ic->ic_phytype = IEEE80211_T_OFDM; /* Not only, but not used. */
- ic->ic_opmode = IEEE80211_M_STA; /* Default to BSS mode. */
- ic->ic_state = IEEE80211_S_INIT;
-
- /* Set device capabilities. */
- ic->ic_caps =
- IEEE80211_C_MONITOR | /* Monitor mode supported. */
- IEEE80211_C_SHPREAMBLE | /* Short preamble supported. */
- IEEE80211_C_SHSLOT | /* Short slot time supported. */
- IEEE80211_C_WEP | /* WEP. */
- IEEE80211_C_RSN; /* WPA/RSN. */
-
- /* Set HT capabilities. */
- ic->ic_htcaps =
- IEEE80211_HTCAP_CBW20_40 |
- IEEE80211_HTCAP_DSSSCCK40;
- /* Set supported HT rates. */
- for (i = 0; i < sc->nrxchains; i++)
- ic->ic_sup_mcs[i] = 0xff;
-
- /* Set supported .11b and .11g rates. */
- ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
- ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
-
- /* Set supported .11b and .11g channels (1 through 14). */
- for (i = 1; i <= 14; i++) {
- ic->ic_channels[i].ic_freq =
- ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ);
- ic->ic_channels[i].ic_flags =
- IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
- }
-
-#ifdef notyet
- /*
- * The number of STAs that we can support is limited by the number
- * of CAM entries used for hardware crypto.
- */
- ic->ic_max_nnodes = R92C_CAM_ENTRY_COUNT - 4;
- if (ic->ic_max_nnodes > IEEE80211_CACHE_SIZE)
- ic->ic_max_nnodes = IEEE80211_CACHE_SIZE;
-#endif
-
- ifp->if_softc = sc;
- ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_ioctl = rtwn_ioctl;
- ifp->if_start = rtwn_start;
- ifp->if_watchdog = rtwn_watchdog;
- IFQ_SET_READY(&ifp->if_snd);
- memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
-
- if_attach(ifp);
- ieee80211_ifattach(ifp);
- ic->ic_updateedca = rtwn_updateedca;
-#ifdef notyet
- ic->ic_set_key = rtwn_set_key;
- ic->ic_delete_key = rtwn_delete_key;
-#endif
- /* Override state transition machine. */
- sc->sc_newstate = ic->ic_newstate;
- ic->ic_newstate = rtwn_newstate;
- ieee80211_media_init(ifp, rtwn_media_change, ieee80211_media_status);
-
+ /* Attach the bus-agnostic driver. */
+ sc->sc_sc.sc_ops.cookie = sc;
+ sc->sc_sc.sc_ops.write_1 = rtwn_pci_write_1;
+ sc->sc_sc.sc_ops.write_2 = rtwn_pci_write_2;
+ sc->sc_sc.sc_ops.write_4 = rtwn_pci_write_4;
+ sc->sc_sc.sc_ops.read_1 = rtwn_pci_read_1;
+ sc->sc_sc.sc_ops.read_2 = rtwn_pci_read_2;
+ sc->sc_sc.sc_ops.read_4 = rtwn_pci_read_4;
+ sc->sc_sc.sc_ops.next_scan = rtwn_pci_next_scan;
+ sc->sc_sc.sc_ops.tx = rtwn_tx;
+ sc->sc_sc.sc_ops.configure_dma = rtwn_configure_dma;
+ sc->sc_sc.sc_ops.enable_intr = rtwn_enable_intr;
+ sc->sc_sc.sc_ops.disable_intr = rtwn_disable_intr;
+ sc->sc_sc.sc_ops.stop = rtwn_pci_stop;
+ sc->sc_sc.sc_ops.is_oactive = rtwn_is_oactive;
+ rtwn_attach(&sc->sc_dev, &sc->sc_sc);
+
+ /* ifp is now valid */
+ ifp = &sc->sc_sc.sc_ic.ic_if;
#if NBPFILTER > 0
bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
@@ -549,26 +343,14 @@ rtwn_attach(struct device *parent, struct device *self, void *aux)
}
int
-rtwn_detach(struct device *self, int flags)
+rtwn_pci_detach(struct device *self, int flags)
{
- struct rtwn_softc *sc = (struct rtwn_softc *)self;
- struct ifnet *ifp = &sc->sc_ic.ic_if;
+ struct rtwn_pci_softc *sc = (struct rtwn_pci_softc *)self;
int s, i;
- s = splnet();
-
- if (timeout_initialized(&sc->scan_to))
- timeout_del(&sc->scan_to);
- if (timeout_initialized(&sc->calib_to))
- timeout_del(&sc->calib_to);
-
- task_del(systq, &sc->init_task);
-
- if (ifp->if_softc != NULL) {
- ieee80211_ifdetach(ifp);
- if_detach(ifp);
- }
+ rtwn_detach(&sc->sc_sc, flags);
+ s = splnet();
/* Free Tx/Rx buffers. */
for (i = 0; i < RTWN_NTXQUEUES; i++)
rtwn_free_tx_list(sc, i);
@@ -579,25 +361,15 @@ rtwn_detach(struct device *self, int flags)
}
int
-rtwn_activate(struct device *self, int act)
+rtwn_pci_activate(struct device *self, int act)
{
- struct rtwn_softc *sc = (struct rtwn_softc *)self;
- struct ifnet *ifp = &sc->sc_ic.ic_if;
-
- switch (act) {
- case DVACT_SUSPEND:
- if (ifp->if_flags & IFF_RUNNING)
- rtwn_stop(ifp);
- break;
- case DVACT_WAKEUP:
- rtwn_init_task(sc);
- break;
- }
- return (0);
+ struct rtwn_pci_softc *sc = (struct rtwn_pci_softc *)self;
+
+ return rtwn_activate(&sc->sc_sc, act);
}
void
-rtwn_setup_rx_desc(struct rtwn_softc *sc, struct r92c_rx_desc_pci *desc,
+rtwn_setup_rx_desc(struct rtwn_pci_softc *sc, struct r92c_rx_desc_pci *desc,
bus_addr_t addr, size_t len, int idx)
{
memset(desc, 0, sizeof(*desc));
@@ -610,7 +382,7 @@ rtwn_setup_rx_desc(struct rtwn_softc *sc, struct r92c_rx_desc_pci *desc,
}
int
-rtwn_alloc_rx_list(struct rtwn_softc *sc)
+rtwn_alloc_rx_list(struct rtwn_pci_softc *sc)
{
struct rtwn_rx_ring *rx_ring = &sc->rx_ring;
struct rtwn_rx_data *rx_data;
@@ -695,7 +467,7 @@ fail: if (error != 0)
}
void
-rtwn_reset_rx_list(struct rtwn_softc *sc)
+rtwn_reset_rx_list(struct rtwn_pci_softc *sc)
{
struct rtwn_rx_ring *rx_ring = &sc->rx_ring;
struct rtwn_rx_data *rx_data;
@@ -709,7 +481,7 @@ rtwn_reset_rx_list(struct rtwn_softc *sc)
}
void
-rtwn_free_rx_list(struct rtwn_softc *sc)
+rtwn_free_rx_list(struct rtwn_pci_softc *sc)
{
struct rtwn_rx_ring *rx_ring = &sc->rx_ring;
struct rtwn_rx_data *rx_data;
@@ -747,7 +519,7 @@ rtwn_free_rx_list(struct rtwn_softc *sc)
}
int
-rtwn_alloc_tx_list(struct rtwn_softc *sc, int qid)
+rtwn_alloc_tx_list(struct rtwn_pci_softc *sc, int qid)
{
struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
struct rtwn_tx_data *tx_data;
@@ -817,9 +589,9 @@ fail:
}
void
-rtwn_reset_tx_list(struct rtwn_softc *sc, int qid)
+rtwn_reset_tx_list(struct rtwn_pci_softc *sc, int qid)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
int i;
@@ -849,7 +621,7 @@ rtwn_reset_tx_list(struct rtwn_softc *sc, int qid)
}
void
-rtwn_free_tx_list(struct rtwn_softc *sc, int qid)
+rtwn_free_tx_list(struct rtwn_pci_softc *sc, int qid)
{
struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
struct rtwn_tx_data *tx_data;
@@ -883,442 +655,60 @@ rtwn_free_tx_list(struct rtwn_softc *sc, int qid)
}
void
-rtwn_write_1(struct rtwn_softc *sc, uint16_t addr, uint8_t val)
+rtwn_pci_write_1(void *cookie, uint16_t addr, uint8_t val)
{
+ struct rtwn_pci_softc *sc = cookie;
+
bus_space_write_1(sc->sc_st, sc->sc_sh, addr, val);
}
void
-rtwn_write_2(struct rtwn_softc *sc, uint16_t addr, uint16_t val)
+rtwn_pci_write_2(void *cookie, uint16_t addr, uint16_t val)
{
+ struct rtwn_pci_softc *sc = cookie;
+
val = htole16(val);
bus_space_write_2(sc->sc_st, sc->sc_sh, addr, val);
}
void
-rtwn_write_4(struct rtwn_softc *sc, uint16_t addr, uint32_t val)
+rtwn_pci_write_4(void *cookie, uint16_t addr, uint32_t val)
{
+ struct rtwn_pci_softc *sc = cookie;
+
val = htole32(val);
bus_space_write_4(sc->sc_st, sc->sc_sh, addr, val);
}
uint8_t
-rtwn_read_1(struct rtwn_softc *sc, uint16_t addr)
+rtwn_pci_read_1(void *cookie, uint16_t addr)
{
+ struct rtwn_pci_softc *sc = cookie;
+
return bus_space_read_1(sc->sc_st, sc->sc_sh, addr);
}
uint16_t
-rtwn_read_2(struct rtwn_softc *sc, uint16_t addr)
-{
- return bus_space_read_2(sc->sc_st, sc->sc_sh, addr);
-}
-
-uint32_t
-rtwn_read_4(struct rtwn_softc *sc, uint16_t addr)
+rtwn_pci_read_2(void *cookie, uint16_t addr)
{
- return bus_space_read_4(sc->sc_st, sc->sc_sh, addr);
-}
-
-int
-rtwn_fw_cmd(struct rtwn_softc *sc, uint8_t id, const void *buf, int len)
-{
- struct r92c_fw_cmd cmd;
- int ntries;
+ struct rtwn_pci_softc *sc = cookie;
- /* Wait for current FW box to be empty. */
- for (ntries = 0; ntries < 100; ntries++) {
- if (!(rtwn_read_1(sc, R92C_HMETFR) & (1 << sc->fwcur)))
- break;
- DELAY(1);
- }
- if (ntries == 100) {
- printf("%s: could not send firmware command %d\n",
- sc->sc_dev.dv_xname, id);
- return (ETIMEDOUT);
- }
- memset(&cmd, 0, sizeof(cmd));
- cmd.id = id;
- if (len > 3)
- cmd.id |= R92C_CMD_FLAG_EXT;
- KASSERT(len <= sizeof(cmd.msg));
- memcpy(cmd.msg, buf, len);
-
- /* Write the first word last since that will trigger the FW. */
- rtwn_write_2(sc, R92C_HMEBOX_EXT(sc->fwcur), *((uint8_t *)&cmd + 4));
- rtwn_write_4(sc, R92C_HMEBOX(sc->fwcur), *((uint8_t *)&cmd + 0));
-
- sc->fwcur = (sc->fwcur + 1) % R92C_H2C_NBOX;
-
- /* Give firmware some time for processing. */
- DELAY(2000);
-
- return (0);
-}
-
-void
-rtwn_rf_write(struct rtwn_softc *sc, int chain, uint8_t addr, uint32_t val)
-{
- rtwn_bb_write(sc, R92C_LSSI_PARAM(chain),
- SM(R92C_LSSI_PARAM_ADDR, addr) |
- SM(R92C_LSSI_PARAM_DATA, val));
+ return bus_space_read_2(sc->sc_st, sc->sc_sh, addr);
}
uint32_t
-rtwn_rf_read(struct rtwn_softc *sc, int chain, uint8_t addr)
-{
- uint32_t reg[R92C_MAX_CHAINS], val;
-
- reg[0] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(0));
- if (chain != 0)
- reg[chain] = rtwn_bb_read(sc, R92C_HSSI_PARAM2(chain));
-
- rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
- reg[0] & ~R92C_HSSI_PARAM2_READ_EDGE);
- DELAY(1000);
-
- rtwn_bb_write(sc, R92C_HSSI_PARAM2(chain),
- RW(reg[chain], R92C_HSSI_PARAM2_READ_ADDR, addr) |
- R92C_HSSI_PARAM2_READ_EDGE);
- DELAY(1000);
-
- rtwn_bb_write(sc, R92C_HSSI_PARAM2(0),
- reg[0] | R92C_HSSI_PARAM2_READ_EDGE);
- DELAY(1000);
-
- if (rtwn_bb_read(sc, R92C_HSSI_PARAM1(chain)) & R92C_HSSI_PARAM1_PI)
- val = rtwn_bb_read(sc, R92C_HSPI_READBACK(chain));
- else
- val = rtwn_bb_read(sc, R92C_LSSI_READBACK(chain));
- return (MS(val, R92C_LSSI_READBACK_DATA));
-}
-
-void
-rtwn_cam_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
-{
- rtwn_write_4(sc, R92C_CAMWRITE, data);
- rtwn_write_4(sc, R92C_CAMCMD,
- R92C_CAMCMD_POLLING | R92C_CAMCMD_WRITE |
- SM(R92C_CAMCMD_ADDR, addr));
-}
-
-int
-rtwn_llt_write(struct rtwn_softc *sc, uint32_t addr, uint32_t data)
-{
- int ntries;
-
- rtwn_write_4(sc, R92C_LLT_INIT,
- SM(R92C_LLT_INIT_OP, R92C_LLT_INIT_OP_WRITE) |
- SM(R92C_LLT_INIT_ADDR, addr) |
- SM(R92C_LLT_INIT_DATA, data));
- /* Wait for write operation to complete. */
- for (ntries = 0; ntries < 20; ntries++) {
- if (MS(rtwn_read_4(sc, R92C_LLT_INIT), R92C_LLT_INIT_OP) ==
- R92C_LLT_INIT_OP_NO_ACTIVE)
- return (0);
- DELAY(5);
- }
- return (ETIMEDOUT);
-}
-
-uint8_t
-rtwn_efuse_read_1(struct rtwn_softc *sc, uint16_t addr)
-{
- uint32_t reg;
- int ntries;
-
- reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
- reg = RW(reg, R92C_EFUSE_CTRL_ADDR, addr);
- reg &= ~R92C_EFUSE_CTRL_VALID;
- rtwn_write_4(sc, R92C_EFUSE_CTRL, reg);
- /* Wait for read operation to complete. */
- for (ntries = 0; ntries < 100; ntries++) {
- reg = rtwn_read_4(sc, R92C_EFUSE_CTRL);
- if (reg & R92C_EFUSE_CTRL_VALID)
- return (MS(reg, R92C_EFUSE_CTRL_DATA));
- DELAY(5);
- }
- printf("%s: could not read efuse byte at address 0x%x\n",
- sc->sc_dev.dv_xname, addr);
- return (0xff);
-}
-
-void
-rtwn_efuse_read(struct rtwn_softc *sc)
-{
- uint8_t *rom = (uint8_t *)&sc->rom;
- uint16_t addr = 0;
- uint32_t reg;
- uint8_t off, msk;
- int i;
-
- reg = rtwn_read_2(sc, R92C_SYS_ISO_CTRL);
- if (!(reg & R92C_SYS_ISO_CTRL_PWC_EV12V)) {
- rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
- reg | R92C_SYS_ISO_CTRL_PWC_EV12V);
- }
- reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
- if (!(reg & R92C_SYS_FUNC_EN_ELDR)) {
- rtwn_write_2(sc, R92C_SYS_FUNC_EN,
- reg | R92C_SYS_FUNC_EN_ELDR);
- }
- reg = rtwn_read_2(sc, R92C_SYS_CLKR);
- if ((reg & (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) !=
- (R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M)) {
- rtwn_write_2(sc, R92C_SYS_CLKR,
- reg | R92C_SYS_CLKR_LOADER_EN | R92C_SYS_CLKR_ANA8M);
- }
- memset(&sc->rom, 0xff, sizeof(sc->rom));
- while (addr < 512) {
- reg = rtwn_efuse_read_1(sc, addr);
- if (reg == 0xff)
- break;
- addr++;
- off = reg >> 4;
- msk = reg & 0xf;
- for (i = 0; i < 4; i++) {
- if (msk & (1 << i))
- continue;
- rom[off * 8 + i * 2 + 0] =
- rtwn_efuse_read_1(sc, addr);
- addr++;
- rom[off * 8 + i * 2 + 1] =
- rtwn_efuse_read_1(sc, addr);
- addr++;
- }
- }
-#ifdef RTWN_DEBUG
- if (rtwn_debug >= 2) {
- /* Dump ROM content. */
- printf("\n");
- for (i = 0; i < sizeof(sc->rom); i++)
- printf("%02x:", rom[i]);
- printf("\n");
- }
-#endif
-}
-
-/* rtwn_read_chipid: reg=0x40073b chipid=0x0 */
-int
-rtwn_read_chipid(struct rtwn_softc *sc)
-{
- uint32_t reg;
-
- reg = rtwn_read_4(sc, R92C_SYS_CFG);
- if (reg & R92C_SYS_CFG_TRP_VAUX_EN)
- /* Unsupported test chip. */
- return (EIO);
-
- if (reg & R92C_SYS_CFG_TYPE_92C) {
- sc->chip |= RTWN_CHIP_92C;
- /* Check if it is a castrated 8192C. */
- if (MS(rtwn_read_4(sc, R92C_HPON_FSM),
- R92C_HPON_FSM_CHIP_BONDING_ID) ==
- R92C_HPON_FSM_CHIP_BONDING_ID_92C_1T2R)
- sc->chip |= RTWN_CHIP_92C_1T2R;
- }
- if (reg & R92C_SYS_CFG_VENDOR_UMC) {
- sc->chip |= RTWN_CHIP_UMC;
- if (MS(reg, R92C_SYS_CFG_CHIP_VER_RTL) == 0)
- sc->chip |= RTWN_CHIP_UMC_A_CUT;
- }
- return (0);
-}
-
-void
-rtwn_read_rom(struct rtwn_softc *sc)
-{
- struct ieee80211com *ic = &sc->sc_ic;
- struct r92c_rom *rom = &sc->rom;
-
- /* Read full ROM image. */
- rtwn_efuse_read(sc);
-
- if (rom->id != 0x8129) {
- printf("%s: invalid EEPROM ID 0x%x\n",
- sc->sc_dev.dv_xname, rom->id);
- }
-
- /* XXX Weird but this is what the vendor driver does. */
- sc->pa_setting = rtwn_efuse_read_1(sc, 0x1fa);
- DPRINTF(("PA setting=0x%x\n", sc->pa_setting));
-
- sc->board_type = MS(rom->rf_opt1, R92C_ROM_RF1_BOARD_TYPE);
-
- sc->regulatory = MS(rom->rf_opt1, R92C_ROM_RF1_REGULATORY);
- DPRINTF(("regulatory type=%d\n", sc->regulatory));
-
- IEEE80211_ADDR_COPY(ic->ic_myaddr, rom->macaddr);
-}
-
-int
-rtwn_media_change(struct ifnet *ifp)
-{
- int error;
-
- error = ieee80211_media_change(ifp);
- if (error != ENETRESET)
- return (error);
-
- if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
- (IFF_UP | IFF_RUNNING)) {
- rtwn_stop(ifp);
- rtwn_init(ifp);
- }
- return (0);
-}
-
-/*
- * Initialize rate adaptation in firmware.
- */
-int
-rtwn_ra_init(struct rtwn_softc *sc)
-{
- static const uint8_t map[] =
- { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 };
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211_node *ni = ic->ic_bss;
- struct ieee80211_rateset *rs = &ni->ni_rates;
- struct r92c_fw_cmd_macid_cfg cmd;
- uint32_t rates, basicrates;
- uint8_t mode;
- int maxrate, maxbasicrate, error, i, j;
-
- /* Get normal and basic rates mask. */
- rates = basicrates = 0;
- maxrate = maxbasicrate = 0;
- for (i = 0; i < rs->rs_nrates; i++) {
- /* Convert 802.11 rate to HW rate index. */
- for (j = 0; j < nitems(map); j++)
- if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == map[j])
- break;
- if (j == nitems(map)) /* Unknown rate, skip. */
- continue;
- rates |= 1 << j;
- if (j > maxrate)
- maxrate = j;
- if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) {
- basicrates |= 1 << j;
- if (j > maxbasicrate)
- maxbasicrate = j;
- }
- }
- if (ic->ic_curmode == IEEE80211_MODE_11B)
- mode = R92C_RAID_11B;
- else
- mode = R92C_RAID_11BG;
- DPRINTF(("mode=0x%x rates=0x%08x, basicrates=0x%08x\n",
- mode, rates, basicrates));
-
- /* Set rates mask for group addressed frames. */
- cmd.macid = R92C_MACID_BC | R92C_MACID_VALID;
- cmd.mask = htole32(mode << 28 | basicrates);
- error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
- if (error != 0) {
- printf("%s: could not add broadcast station\n",
- sc->sc_dev.dv_xname);
- return (error);
- }
- /* Set initial MRR rate. */
- DPRINTF(("maxbasicrate=%d\n", maxbasicrate));
- rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(R92C_MACID_BC),
- maxbasicrate);
-
- /* Set rates mask for unicast frames. */
- cmd.macid = R92C_MACID_BSS | R92C_MACID_VALID;
- cmd.mask = htole32(mode << 28 | rates);
- error = rtwn_fw_cmd(sc, R92C_CMD_MACID_CONFIG, &cmd, sizeof(cmd));
- if (error != 0) {
- printf("%s: could not add BSS station\n",
- sc->sc_dev.dv_xname);
- return (error);
- }
- /* Set initial MRR rate. */
- DPRINTF(("maxrate=%d\n", maxrate));
- rtwn_write_1(sc, R92C_INIDATA_RATE_SEL(R92C_MACID_BSS),
- maxrate);
-
- /* Configure Automatic Rate Fallback Register. */
- if (ic->ic_curmode == IEEE80211_MODE_11B) {
- if (rates & 0x0c)
- rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0d));
- else
- rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0f));
- } else
- rtwn_write_4(sc, R92C_ARFR(0), htole32(rates & 0x0ff5));
-
- /* Indicate highest supported rate. */
- ni->ni_txrate = rs->rs_nrates - 1;
- return (0);
-}
-
-void
-rtwn_tsf_sync_enable(struct rtwn_softc *sc)
-{
- struct ieee80211_node *ni = sc->sc_ic.ic_bss;
- uint64_t tsf;
-
- /* Enable TSF synchronization. */
- rtwn_write_1(sc, R92C_BCN_CTRL,
- rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_DIS_TSF_UDT0);
-
- rtwn_write_1(sc, R92C_BCN_CTRL,
- rtwn_read_1(sc, R92C_BCN_CTRL) & ~R92C_BCN_CTRL_EN_BCN);
-
- /* Set initial TSF. */
- memcpy(&tsf, ni->ni_tstamp, 8);
- tsf = letoh64(tsf);
- tsf = tsf - (tsf % (ni->ni_intval * IEEE80211_DUR_TU));
- tsf -= IEEE80211_DUR_TU;
- rtwn_write_4(sc, R92C_TSFTR + 0, tsf);
- rtwn_write_4(sc, R92C_TSFTR + 4, tsf >> 32);
-
- rtwn_write_1(sc, R92C_BCN_CTRL,
- rtwn_read_1(sc, R92C_BCN_CTRL) | R92C_BCN_CTRL_EN_BCN);
-}
-
-void
-rtwn_set_led(struct rtwn_softc *sc, int led, int on)
-{
- uint8_t reg;
-
- if (led == RTWN_LED_LINK) {
- reg = rtwn_read_1(sc, R92C_LEDCFG2) & 0xf0;
- if (!on)
- reg |= R92C_LEDCFG2_DIS;
- else
- reg |= R92C_LEDCFG2_EN;
- rtwn_write_1(sc, R92C_LEDCFG2, reg);
- sc->ledlink = on; /* Save LED state. */
- }
-}
-
-void
-rtwn_calib_to(void *arg)
+rtwn_pci_read_4(void *cookie, uint16_t addr)
{
- struct rtwn_softc *sc = arg;
- struct r92c_fw_cmd_rssi cmd;
-
- if (sc->avg_pwdb != -1) {
- /* Indicate Rx signal strength to FW for rate adaptation. */
- memset(&cmd, 0, sizeof(cmd));
- cmd.macid = 0; /* BSS. */
- cmd.pwdb = sc->avg_pwdb;
- DPRINTFN(3, ("sending RSSI command avg=%d\n", sc->avg_pwdb));
- rtwn_fw_cmd(sc, R92C_CMD_RSSI_SETTING, &cmd, sizeof(cmd));
- }
+ struct rtwn_pci_softc *sc = cookie;
- /* Do temperature compensation. */
- rtwn_temp_calib(sc);
-
- timeout_add_sec(&sc->calib_to, 2);
+ return bus_space_read_4(sc->sc_st, sc->sc_sh, addr);
}
void
-rtwn_next_scan(void *arg)
+rtwn_pci_next_scan(void *arg)
{
- struct rtwn_softc *sc = arg;
- struct ieee80211com *ic = &sc->sc_ic;
+ struct rtwn_pci_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
int s;
s = splnet();
@@ -1327,343 +717,11 @@ rtwn_next_scan(void *arg)
splx(s);
}
-int
-rtwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
-{
- struct rtwn_softc *sc = ic->ic_softc;
- struct ieee80211_node *ni;
- enum ieee80211_state ostate;
- uint32_t reg;
- int s;
-
- s = splnet();
- ostate = ic->ic_state;
-
- if (nstate != ostate)
- DPRINTF(("newstate %s -> %s\n",
- ieee80211_state_name[ostate],
- ieee80211_state_name[nstate]));
-
- if (ostate == IEEE80211_S_RUN) {
- /* Stop calibration. */
- timeout_del(&sc->calib_to);
-
- /* Turn link LED off. */
- rtwn_set_led(sc, RTWN_LED_LINK, 0);
-
- /* Set media status to 'No Link'. */
- reg = rtwn_read_4(sc, R92C_CR);
- reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_NOLINK);
- rtwn_write_4(sc, R92C_CR, reg);
-
- /* Stop Rx of data frames. */
- rtwn_write_2(sc, R92C_RXFLTMAP2, 0);
-
- /* Rest TSF. */
- rtwn_write_1(sc, R92C_DUAL_TSF_RST, 0x03);
-
- /* Disable TSF synchronization. */
- rtwn_write_1(sc, R92C_BCN_CTRL,
- rtwn_read_1(sc, R92C_BCN_CTRL) |
- R92C_BCN_CTRL_DIS_TSF_UDT0);
-
- /* Reset EDCA parameters. */
- rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3217);
- rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4317);
- rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x00105320);
- rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a444);
- }
- switch (nstate) {
- case IEEE80211_S_INIT:
- /* Turn link LED off. */
- rtwn_set_led(sc, RTWN_LED_LINK, 0);
- break;
- case IEEE80211_S_SCAN:
- if (ostate != IEEE80211_S_SCAN) {
- /* Allow Rx from any BSSID. */
- rtwn_write_4(sc, R92C_RCR,
- rtwn_read_4(sc, R92C_RCR) &
- ~(R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN));
-
- /* Set gain for scanning. */
- reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
- reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
- rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
- reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x20);
- rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
- }
-
- /* Make link LED blink during scan. */
- rtwn_set_led(sc, RTWN_LED_LINK, !sc->ledlink);
-
- /* Pause AC Tx queues. */
- rtwn_write_1(sc, R92C_TXPAUSE,
- rtwn_read_1(sc, R92C_TXPAUSE) | 0x0f);
- rtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL);
- timeout_add_msec(&sc->scan_to, 200);
- break;
-
- case IEEE80211_S_AUTH:
- /* Set initial gain under link. */
- reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(0));
- reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
- rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(0), reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_AGCCORE1(1));
- reg = RW(reg, R92C_OFDM0_AGCCORE1_GAIN, 0x32);
- rtwn_bb_write(sc, R92C_OFDM0_AGCCORE1(1), reg);
-
- rtwn_set_chan(sc, ic->ic_bss->ni_chan, NULL);
- break;
- case IEEE80211_S_ASSOC:
- break;
- case IEEE80211_S_RUN:
- if (ic->ic_opmode == IEEE80211_M_MONITOR) {
- rtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
-
- /* Enable Rx of data frames. */
- rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
-
- /* Turn link LED on. */
- rtwn_set_led(sc, RTWN_LED_LINK, 1);
- break;
- }
- ni = ic->ic_bss;
-
- /* Set media status to 'Associated'. */
- reg = rtwn_read_4(sc, R92C_CR);
- reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
- rtwn_write_4(sc, R92C_CR, reg);
-
- /* Set BSSID. */
- rtwn_write_4(sc, R92C_BSSID + 0, LE_READ_4(&ni->ni_bssid[0]));
- rtwn_write_4(sc, R92C_BSSID + 4, LE_READ_2(&ni->ni_bssid[4]));
-
- if (ic->ic_curmode == IEEE80211_MODE_11B)
- rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 0);
- else /* 802.11b/g */
- rtwn_write_1(sc, R92C_INIRTS_RATE_SEL, 3);
-
- /* Enable Rx of data frames. */
- rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
-
- /* Flush all AC queues. */
- rtwn_write_1(sc, R92C_TXPAUSE, 0);
-
- /* Set beacon interval. */
- rtwn_write_2(sc, R92C_BCN_INTERVAL, ni->ni_intval);
-
- /* Allow Rx from our BSSID only. */
- rtwn_write_4(sc, R92C_RCR,
- rtwn_read_4(sc, R92C_RCR) |
- R92C_RCR_CBSSID_DATA | R92C_RCR_CBSSID_BCN);
-
- /* Enable TSF synchronization. */
- rtwn_tsf_sync_enable(sc);
-
- rtwn_write_1(sc, R92C_SIFS_CCK + 1, 10);
- rtwn_write_1(sc, R92C_SIFS_OFDM + 1, 10);
- rtwn_write_1(sc, R92C_SPEC_SIFS + 1, 10);
- rtwn_write_1(sc, R92C_MAC_SPEC_SIFS + 1, 10);
- rtwn_write_1(sc, R92C_R2T_SIFS + 1, 10);
- rtwn_write_1(sc, R92C_T2T_SIFS + 1, 10);
-
- /* Intialize rate adaptation. */
- rtwn_ra_init(sc);
- /* Turn link LED on. */
- rtwn_set_led(sc, RTWN_LED_LINK, 1);
-
- sc->avg_pwdb = -1; /* Reset average RSSI. */
- /* Reset temperature calibration state machine. */
- sc->thcal_state = 0;
- sc->thcal_lctemp = 0;
- /* Start periodic calibration. */
- timeout_add_sec(&sc->calib_to, 2);
- break;
- }
- (void)sc->sc_newstate(ic, nstate, arg);
- splx(s);
-
- return (0);
-}
-
-void
-rtwn_updateedca(struct ieee80211com *ic)
-{
- struct rtwn_softc *sc = ic->ic_softc;
- const uint16_t aci2reg[EDCA_NUM_AC] = {
- R92C_EDCA_BE_PARAM,
- R92C_EDCA_BK_PARAM,
- R92C_EDCA_VI_PARAM,
- R92C_EDCA_VO_PARAM
- };
- struct ieee80211_edca_ac_params *ac;
- int s, aci, aifs, slottime;
-
- s = splnet();
- slottime = (ic->ic_flags & IEEE80211_F_SHSLOT) ? 9 : 20;
- for (aci = 0; aci < EDCA_NUM_AC; aci++) {
- ac = &ic->ic_edca_ac[aci];
- /* AIFS[AC] = AIFSN[AC] * aSlotTime + aSIFSTime. */
- aifs = ac->ac_aifsn * slottime + 10;
- rtwn_write_4(sc, aci2reg[aci],
- SM(R92C_EDCA_PARAM_TXOP, ac->ac_txoplimit) |
- SM(R92C_EDCA_PARAM_ECWMIN, ac->ac_ecwmin) |
- SM(R92C_EDCA_PARAM_ECWMAX, ac->ac_ecwmax) |
- SM(R92C_EDCA_PARAM_AIFS, aifs));
- }
- splx(s);
-}
-
-int
-rtwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
- struct ieee80211_key *k)
-{
- struct rtwn_softc *sc = ic->ic_softc;
- static const uint8_t etherzeroaddr[6] = { 0 };
- const uint8_t *macaddr;
- uint8_t keybuf[16], algo;
- int i, entry;
-
- /* Defer setting of WEP keys until interface is brought up. */
- if ((ic->ic_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
- (IFF_UP | IFF_RUNNING))
- return (0);
-
- /* Map net80211 cipher to HW crypto algorithm. */
- switch (k->k_cipher) {
- case IEEE80211_CIPHER_WEP40:
- algo = R92C_CAM_ALGO_WEP40;
- break;
- case IEEE80211_CIPHER_WEP104:
- algo = R92C_CAM_ALGO_WEP104;
- break;
- case IEEE80211_CIPHER_TKIP:
- algo = R92C_CAM_ALGO_TKIP;
- break;
- case IEEE80211_CIPHER_CCMP:
- algo = R92C_CAM_ALGO_AES;
- break;
- default:
- /* Fallback to software crypto for other ciphers. */
- return (ieee80211_set_key(ic, ni, k));
- }
- if (k->k_flags & IEEE80211_KEY_GROUP) {
- macaddr = etherzeroaddr;
- entry = k->k_id;
- } else {
- macaddr = ic->ic_bss->ni_macaddr;
- entry = 4;
- }
- /* Write key. */
- memset(keybuf, 0, sizeof(keybuf));
- memcpy(keybuf, k->k_key, MIN(k->k_len, sizeof(keybuf)));
- for (i = 0; i < 4; i++) {
- rtwn_cam_write(sc, R92C_CAM_KEY(entry, i),
- LE_READ_4(&keybuf[i * 4]));
- }
- /* Write CTL0 last since that will validate the CAM entry. */
- rtwn_cam_write(sc, R92C_CAM_CTL1(entry),
- LE_READ_4(&macaddr[2]));
- rtwn_cam_write(sc, R92C_CAM_CTL0(entry),
- SM(R92C_CAM_ALGO, algo) |
- SM(R92C_CAM_KEYID, k->k_id) |
- SM(R92C_CAM_MACLO, LE_READ_2(&macaddr[0])) |
- R92C_CAM_VALID);
-
- return (0);
-}
-
-void
-rtwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
- struct ieee80211_key *k)
-{
- struct rtwn_softc *sc = ic->ic_softc;
- int i, entry;
-
- if (!(ic->ic_if.if_flags & IFF_RUNNING) ||
- ic->ic_state != IEEE80211_S_RUN)
- return; /* Nothing to do. */
-
- if (k->k_flags & IEEE80211_KEY_GROUP)
- entry = k->k_id;
- else
- entry = 4;
- rtwn_cam_write(sc, R92C_CAM_CTL0(entry), 0);
- rtwn_cam_write(sc, R92C_CAM_CTL1(entry), 0);
- /* Clear key. */
- for (i = 0; i < 4; i++)
- rtwn_cam_write(sc, R92C_CAM_KEY(entry, i), 0);
-}
-
-void
-rtwn_update_avgrssi(struct rtwn_softc *sc, int rate, int8_t rssi)
-{
- int pwdb;
-
- /* Convert antenna signal to percentage. */
- if (rssi <= -100 || rssi >= 20)
- pwdb = 0;
- else if (rssi >= 0)
- pwdb = 100;
- else
- pwdb = 100 + rssi;
- if (rate <= 3) {
- /* CCK gain is smaller than OFDM/MCS gain. */
- pwdb += 6;
- if (pwdb > 100)
- pwdb = 100;
- if (pwdb <= 14)
- pwdb -= 4;
- else if (pwdb <= 26)
- pwdb -= 8;
- else if (pwdb <= 34)
- pwdb -= 6;
- else if (pwdb <= 42)
- pwdb -= 2;
- }
- if (sc->avg_pwdb == -1) /* Init. */
- sc->avg_pwdb = pwdb;
- else if (sc->avg_pwdb < pwdb)
- sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20) + 1;
- else
- sc->avg_pwdb = ((sc->avg_pwdb * 19 + pwdb) / 20);
- DPRINTFN(4, ("PWDB=%d EMA=%d\n", pwdb, sc->avg_pwdb));
-}
-
-int8_t
-rtwn_get_rssi(struct rtwn_softc *sc, int rate, void *physt)
-{
- static const int8_t cckoff[] = { 16, -12, -26, -46 };
- struct r92c_rx_phystat *phy;
- struct r92c_rx_cck *cck;
- uint8_t rpt;
- int8_t rssi;
-
- if (rate <= 3) {
- cck = (struct r92c_rx_cck *)physt;
- if (sc->sc_flags & RTWN_FLAG_CCK_HIPWR) {
- rpt = (cck->agc_rpt >> 5) & 0x3;
- rssi = (cck->agc_rpt & 0x1f) << 1;
- } else {
- rpt = (cck->agc_rpt >> 6) & 0x3;
- rssi = cck->agc_rpt & 0x3e;
- }
- rssi = cckoff[rpt] - rssi;
- } else { /* OFDM/HT. */
- phy = (struct r92c_rx_phystat *)physt;
- rssi = ((letoh32(phy->phydw1) >> 1) & 0x7f) - 110;
- }
- return (rssi);
-}
-
void
-rtwn_rx_frame(struct rtwn_softc *sc, struct r92c_rx_desc_pci *rx_desc,
+rtwn_rx_frame(struct rtwn_pci_softc *sc, struct r92c_rx_desc_pci *rx_desc,
struct rtwn_rx_data *rx_data, int desc_idx)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
struct ifnet *ifp = &ic->ic_if;
struct ieee80211_rxinfo rxi;
struct ieee80211_frame *wh;
@@ -1702,9 +760,9 @@ rtwn_rx_frame(struct rtwn_softc *sc, struct r92c_rx_desc_pci *rx_desc,
/* Get RSSI from PHY status descriptor if present. */
if (infosz != 0 && (rxdw0 & R92C_RXDW0_PHYST)) {
phy = mtod(rx_data->m, struct r92c_rx_phystat *);
- rssi = rtwn_get_rssi(sc, rate, phy);
+ rssi = rtwn_get_rssi(&sc->sc_sc, rate, phy);
/* Update our average RSSI. */
- rtwn_update_avgrssi(sc, rate, rssi);
+ rtwn_update_avgrssi(&sc->sc_sc, rate, rssi);
}
DPRINTFN(5, ("Rx frame len=%d rate=%d infosz=%d shift=%d rssi=%d\n",
@@ -1804,9 +862,10 @@ rtwn_rx_frame(struct rtwn_softc *sc, struct r92c_rx_desc_pci *rx_desc,
}
int
-rtwn_tx(struct rtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
+rtwn_tx(void *cookie, struct mbuf *m, struct ieee80211_node *ni)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct rtwn_pci_softc *sc = cookie;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
struct ieee80211_frame *wh;
struct ieee80211_key *k = NULL;
struct rtwn_tx_ring *tx_ring;
@@ -1989,15 +1048,15 @@ rtwn_tx(struct rtwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
sc->qfullmsk |= (1 << qid);
/* Kick TX. */
- rtwn_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid));
+ rtwn_pci_write_2(sc, R92C_PCIE_CTRL_REG, (1 << qid));
return (0);
}
void
-rtwn_tx_done(struct rtwn_softc *sc, int qid)
+rtwn_tx_done(struct rtwn_pci_softc *sc, int qid)
{
- struct ieee80211com *ic = &sc->sc_ic;
+ struct ieee80211com *ic = &sc->sc_sc.sc_ic;
struct ifnet *ifp = &ic->ic_if;
struct rtwn_tx_ring *tx_ring = &sc->tx_ring[qid];
struct rtwn_tx_data *tx_data;
@@ -2023,7 +1082,7 @@ rtwn_tx_done(struct rtwn_softc *sc, int qid)
tx_data->ni = NULL;
ifp->if_opackets++;
- sc->sc_tx_timer = 0;
+ sc->sc_sc.sc_tx_timer = 0;
tx_ring->queued--;
}
@@ -2037,1672 +1096,32 @@ rtwn_tx_done(struct rtwn_softc *sc, int qid)
}
void
-rtwn_start(struct ifnet *ifp)
-{
- struct rtwn_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ieee80211_node *ni;
- struct mbuf *m;
-
- if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
- return;
-
- for (;;) {
- if (sc->qfullmsk != 0) {
- ifq_set_oactive(&ifp->if_snd);
- break;
- }
- /* Send pending management frames first. */
- m = mq_dequeue(&ic->ic_mgtq);
- if (m != NULL) {
- ni = m->m_pkthdr.ph_cookie;
- goto sendit;
- }
- if (ic->ic_state != IEEE80211_S_RUN)
- break;
-
- /* Encapsulate and send data frames. */
- IFQ_DEQUEUE(&ifp->if_snd, m);
- if (m == NULL)
- break;
-#if NBPFILTER > 0
- if (ifp->if_bpf != NULL)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
-#endif
- if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
- continue;
-sendit:
-#if NBPFILTER > 0
- if (ic->ic_rawbpf != NULL)
- bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
-#endif
- if (rtwn_tx(sc, m, ni) != 0) {
- ieee80211_release_node(ic, ni);
- ifp->if_oerrors++;
- continue;
- }
-
- sc->sc_tx_timer = 5;
- ifp->if_timer = 1;
- }
-}
-
-void
-rtwn_watchdog(struct ifnet *ifp)
-{
- struct rtwn_softc *sc = ifp->if_softc;
-
- ifp->if_timer = 0;
-
- if (sc->sc_tx_timer > 0) {
- if (--sc->sc_tx_timer == 0) {
- printf("%s: device timeout\n", sc->sc_dev.dv_xname);
- task_add(systq, &sc->init_task);
- ifp->if_oerrors++;
- return;
- }
- ifp->if_timer = 1;
- }
- ieee80211_watchdog(ifp);
-}
-
-int
-rtwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
-{
- struct rtwn_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
- struct ifreq *ifr;
- int s, error = 0;
-
- s = splnet();
- /*
- * Prevent processes from entering this function while another
- * process is tsleep'ing in it.
- */
- while ((sc->sc_flags & RTWN_FLAG_BUSY) && error == 0)
- error = tsleep(&sc->sc_flags, PCATCH, "rtwnioc", 0);
- if (error != 0) {
- splx(s);
- return error;
- }
- sc->sc_flags |= RTWN_FLAG_BUSY;
-
- switch (cmd) {
- case SIOCSIFADDR:
- ifp->if_flags |= IFF_UP;
- /* FALLTHROUGH */
- case SIOCSIFFLAGS:
- if (ifp->if_flags & IFF_UP) {
- if (!(ifp->if_flags & IFF_RUNNING))
- rtwn_init(ifp);
- } else {
- if (ifp->if_flags & IFF_RUNNING)
- rtwn_stop(ifp);
- }
- break;
- case SIOCADDMULTI:
- case SIOCDELMULTI:
- ifr = (struct ifreq *)data;
- error = (cmd == SIOCADDMULTI) ?
- ether_addmulti(ifr, &ic->ic_ac) :
- ether_delmulti(ifr, &ic->ic_ac);
- if (error == ENETRESET)
- error = 0;
- break;
- case SIOCS80211CHANNEL:
- error = ieee80211_ioctl(ifp, cmd, data);
- if (error == ENETRESET &&
- ic->ic_opmode == IEEE80211_M_MONITOR) {
- if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
- (IFF_UP | IFF_RUNNING))
- rtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
- error = 0;
- }
- break;
- default:
- error = ieee80211_ioctl(ifp, cmd, data);
- }
-
- if (error == ENETRESET) {
- if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
- (IFF_UP | IFF_RUNNING)) {
- rtwn_stop(ifp);
- rtwn_init(ifp);
- }
- error = 0;
- }
- sc->sc_flags &= ~RTWN_FLAG_BUSY;
- wakeup(&sc->sc_flags);
- splx(s);
-
- return (error);
-}
-
-int
-rtwn_power_on(struct rtwn_softc *sc)
-{
- uint32_t reg;
- int ntries;
-
- /* Wait for autoload done bit. */
- for (ntries = 0; ntries < 1000; ntries++) {
- if (rtwn_read_1(sc, R92C_APS_FSMCO) & R92C_APS_FSMCO_PFM_ALDN)
- break;
- DELAY(5);
- }
- if (ntries == 1000) {
- printf("%s: timeout waiting for chip autoload\n",
- sc->sc_dev.dv_xname);
- return (ETIMEDOUT);
- }
-
- /* Unlock ISO/CLK/Power control register. */
- rtwn_write_1(sc, R92C_RSV_CTRL, 0);
-
- /* TODO: check if we need this for 8188CE */
- if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
- /* bt coex */
- reg = rtwn_read_4(sc, R92C_APS_FSMCO);
- reg |= (R92C_APS_FSMCO_SOP_ABG |
- R92C_APS_FSMCO_SOP_AMB |
- R92C_APS_FSMCO_XOP_BTCK);
- rtwn_write_4(sc, R92C_APS_FSMCO, reg);
- }
-
- /* Move SPS into PWM mode. */
- rtwn_write_1(sc, R92C_SPS0_CTRL, 0x2b);
-
- /* Set low byte to 0x0f, leave others unchanged. */
- rtwn_write_4(sc, R92C_AFE_XTAL_CTRL,
- (rtwn_read_4(sc, R92C_AFE_XTAL_CTRL) & 0xffffff00) | 0x0f);
-
- /* TODO: check if we need this for 8188CE */
- if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
- /* bt coex */
- reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL);
- reg &= (~0x00024800); /* XXX magic from linux */
- rtwn_write_4(sc, R92C_AFE_XTAL_CTRL, reg);
- }
-
- rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
- (rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & 0xff) |
- R92C_SYS_ISO_CTRL_PWC_EV12V | R92C_SYS_ISO_CTRL_DIOR);
- DELAY(200);
-
- /* TODO: linux does additional btcoex stuff here */
-
- /* Auto enable WLAN. */
- rtwn_write_2(sc, R92C_APS_FSMCO,
- rtwn_read_2(sc, R92C_APS_FSMCO) | R92C_APS_FSMCO_APFM_ONMAC);
- for (ntries = 0; ntries < 1000; ntries++) {
- if (!(rtwn_read_2(sc, R92C_APS_FSMCO) &
- R92C_APS_FSMCO_APFM_ONMAC))
- break;
- DELAY(5);
- }
- if (ntries == 1000) {
- printf("%s: timeout waiting for MAC auto ON\n",
- sc->sc_dev.dv_xname);
- return (ETIMEDOUT);
- }
-
- /* Enable radio, GPIO and LED functions. */
- rtwn_write_2(sc, R92C_APS_FSMCO,
- R92C_APS_FSMCO_AFSM_PCIE |
- R92C_APS_FSMCO_PDN_EN |
- R92C_APS_FSMCO_PFM_ALDN);
- /* Release RF digital isolation. */
- rtwn_write_2(sc, R92C_SYS_ISO_CTRL,
- rtwn_read_2(sc, R92C_SYS_ISO_CTRL) & ~R92C_SYS_ISO_CTRL_DIOR);
-
- if (sc->chip & RTWN_CHIP_92C)
- rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x77);
- else
- rtwn_write_1(sc, R92C_PCIE_CTRL_REG + 3, 0x22);
-
- rtwn_write_4(sc, R92C_INT_MIG, 0);
-
- if (sc->board_type != R92C_BOARD_TYPE_DONGLE) {
- /* bt coex */
- reg = rtwn_read_4(sc, R92C_AFE_XTAL_CTRL + 2);
- reg &= 0xfd; /* XXX magic from linux */
- rtwn_write_4(sc, R92C_AFE_XTAL_CTRL + 2, reg);
- }
-
- rtwn_write_1(sc, R92C_GPIO_MUXCFG,
- rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_RFKILL);
-
- reg = rtwn_read_1(sc, R92C_GPIO_IO_SEL);
- if (!(reg & R92C_GPIO_IO_SEL_RFKILL)) {
- printf("%s: radio is disabled by hardware switch\n",
- sc->sc_dev.dv_xname);
- return (EPERM); /* :-) */
- }
-
- /* Initialize MAC. */
- reg = rtwn_read_1(sc, R92C_APSD_CTRL);
- rtwn_write_1(sc, R92C_APSD_CTRL,
- rtwn_read_1(sc, R92C_APSD_CTRL) & ~R92C_APSD_CTRL_OFF);
- for (ntries = 0; ntries < 200; ntries++) {
- if (!(rtwn_read_1(sc, R92C_APSD_CTRL) &
- R92C_APSD_CTRL_OFF_STATUS))
- break;
- DELAY(500);
- }
- if (ntries == 200) {
- printf("%s: timeout waiting for MAC initialization\n",
- sc->sc_dev.dv_xname);
- return (ETIMEDOUT);
- }
-
- /* Enable MAC DMA/WMAC/SCHEDULE/SEC blocks. */
- reg = rtwn_read_2(sc, R92C_CR);
- reg |= R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
- R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
- R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
- R92C_CR_ENSEC;
- rtwn_write_2(sc, R92C_CR, reg);
-
- rtwn_write_1(sc, 0xfe10, 0x19);
-
- return (0);
-}
-
-int
-rtwn_llt_init(struct rtwn_softc *sc)
-{
- int i, error;
-
- /* Reserve pages [0; R92C_TX_PAGE_COUNT]. */
- for (i = 0; i < R92C_TX_PAGE_COUNT; i++) {
- if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
- return (error);
- }
- /* NB: 0xff indicates end-of-list. */
- if ((error = rtwn_llt_write(sc, i, 0xff)) != 0)
- return (error);
- /*
- * Use pages [R92C_TX_PAGE_COUNT + 1; R92C_TXPKTBUF_COUNT - 1]
- * as ring buffer.
- */
- for (++i; i < R92C_TXPKTBUF_COUNT - 1; i++) {
- if ((error = rtwn_llt_write(sc, i, i + 1)) != 0)
- return (error);
- }
- /* Make the last page point to the beginning of the ring buffer. */
- error = rtwn_llt_write(sc, i, R92C_TX_PAGE_COUNT + 1);
- return (error);
-}
-
-void
-rtwn_fw_reset(struct rtwn_softc *sc)
-{
- uint16_t reg;
- int ntries;
-
- /* Tell 8051 to reset itself. */
- rtwn_write_1(sc, R92C_HMETFR + 3, 0x20);
-
- /* Wait until 8051 resets by itself. */
- for (ntries = 0; ntries < 100; ntries++) {
- reg = rtwn_read_2(sc, R92C_SYS_FUNC_EN);
- if (!(reg & R92C_SYS_FUNC_EN_CPUEN))
- goto sleep;
- DELAY(50);
- }
- /* Force 8051 reset. */
- rtwn_write_2(sc, R92C_SYS_FUNC_EN, reg & ~R92C_SYS_FUNC_EN_CPUEN);
-sleep:
- /*
- * We must sleep for one second to let the firmware settle.
- * Accessing registers too early will hang the whole system.
- */
- tsleep(&reg, 0, "rtwnrst", hz);
-}
-
-int
-rtwn_fw_loadpage(struct rtwn_softc *sc, int page, uint8_t *buf, int len)
-{
- uint32_t reg;
- int off, mlen, error = 0, i;
-
- reg = rtwn_read_4(sc, R92C_MCUFWDL);
- reg = RW(reg, R92C_MCUFWDL_PAGE, page);
- rtwn_write_4(sc, R92C_MCUFWDL, reg);
-
- DELAY(5);
-
- off = R92C_FW_START_ADDR;
- while (len > 0) {
- if (len > 196)
- mlen = 196;
- else if (len > 4)
- mlen = 4;
- else
- mlen = 1;
- for (i = 0; i < mlen; i++)
- rtwn_write_1(sc, off++, buf[i]);
- buf += mlen;
- len -= mlen;
- }
-
- return (error);
-}
-
-int
-rtwn_load_firmware(struct rtwn_softc *sc)
-{
- const struct r92c_fw_hdr *hdr;
- const char *name;
- u_char *fw, *ptr;
- size_t len;
- uint32_t reg;
- int mlen, ntries, page, error;
-
- /* Read firmware image from the filesystem. */
- if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
- RTWN_CHIP_UMC_A_CUT)
- name = "rtwn-rtl8192cfwU";
- else
- name = "rtwn-rtl8192cfwU_B";
- if ((error = loadfirmware(name, &fw, &len)) != 0) {
- printf("%s: could not read firmware %s (error %d)\n",
- sc->sc_dev.dv_xname, name, error);
- return (error);
- }
- if (len < sizeof(*hdr)) {
- printf("%s: firmware too short\n", sc->sc_dev.dv_xname);
- error = EINVAL;
- goto fail;
- }
- ptr = fw;
- hdr = (const struct r92c_fw_hdr *)ptr;
- /* Check if there is a valid FW header and skip it. */
- if ((letoh16(hdr->signature) >> 4) == 0x88c ||
- (letoh16(hdr->signature) >> 4) == 0x92c) {
- DPRINTF(("FW V%d.%d %02d-%02d %02d:%02d\n",
- letoh16(hdr->version), letoh16(hdr->subversion),
- hdr->month, hdr->date, hdr->hour, hdr->minute));
- ptr += sizeof(*hdr);
- len -= sizeof(*hdr);
- }
-
- if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
- rtwn_fw_reset(sc);
-
- /* Enable FW download. */
- rtwn_write_2(sc, R92C_SYS_FUNC_EN,
- rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
- R92C_SYS_FUNC_EN_CPUEN);
- rtwn_write_1(sc, R92C_MCUFWDL,
- rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_EN);
- rtwn_write_1(sc, R92C_MCUFWDL + 2,
- rtwn_read_1(sc, R92C_MCUFWDL + 2) & ~0x08);
-
- /* Reset the FWDL checksum. */
- rtwn_write_1(sc, R92C_MCUFWDL,
- rtwn_read_1(sc, R92C_MCUFWDL) | R92C_MCUFWDL_CHKSUM_RPT);
-
- for (page = 0; len > 0; page++) {
- mlen = MIN(len, R92C_FW_PAGE_SIZE);
- error = rtwn_fw_loadpage(sc, page, ptr, mlen);
- if (error != 0) {
- printf("%s: could not load firmware page %d\n",
- sc->sc_dev.dv_xname, page);
- goto fail;
- }
- ptr += mlen;
- len -= mlen;
- }
-
- /* Disable FW download. */
- rtwn_write_1(sc, R92C_MCUFWDL,
- rtwn_read_1(sc, R92C_MCUFWDL) & ~R92C_MCUFWDL_EN);
- rtwn_write_1(sc, R92C_MCUFWDL + 1, 0);
-
- /* Wait for checksum report. */
- for (ntries = 0; ntries < 1000; ntries++) {
- if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_CHKSUM_RPT)
- break;
- DELAY(5);
- }
- if (ntries == 1000) {
- printf("%s: timeout waiting for checksum report\n",
- sc->sc_dev.dv_xname);
- error = ETIMEDOUT;
- goto fail;
- }
-
- reg = rtwn_read_4(sc, R92C_MCUFWDL);
- reg = (reg & ~R92C_MCUFWDL_WINTINI_RDY) | R92C_MCUFWDL_RDY;
- rtwn_write_4(sc, R92C_MCUFWDL, reg);
- /* Wait for firmware readiness. */
- for (ntries = 0; ntries < 1000; ntries++) {
- if (rtwn_read_4(sc, R92C_MCUFWDL) & R92C_MCUFWDL_WINTINI_RDY)
- break;
- DELAY(5);
- }
- if (ntries == 1000) {
- printf("%s: timeout waiting for firmware readiness\n",
- sc->sc_dev.dv_xname);
- error = ETIMEDOUT;
- goto fail;
- }
- fail:
- free(fw, M_DEVBUF, len);
- return (error);
-}
-
-int
-rtwn_dma_init(struct rtwn_softc *sc)
-{
- uint32_t reg;
- int error;
-
- /* Initialize LLT table. */
- error = rtwn_llt_init(sc);
- if (error != 0)
- return error;
-
- /* Set number of pages for normal priority queue. */
- rtwn_write_2(sc, R92C_RQPN_NPQ, 0);
- rtwn_write_4(sc, R92C_RQPN,
- /* Set number of pages for public queue. */
- SM(R92C_RQPN_PUBQ, R92C_PUBQ_NPAGES) |
- /* Set number of pages for high priority queue. */
- SM(R92C_RQPN_HPQ, R92C_HPQ_NPAGES) |
- /* Set number of pages for low priority queue. */
- SM(R92C_RQPN_LPQ, R92C_LPQ_NPAGES) |
- /* Load values. */
- R92C_RQPN_LD);
-
- rtwn_write_1(sc, R92C_TXPKTBUF_BCNQ_BDNY, R92C_TX_PAGE_BOUNDARY);
- rtwn_write_1(sc, R92C_TXPKTBUF_MGQ_BDNY, R92C_TX_PAGE_BOUNDARY);
- rtwn_write_1(sc, R92C_TXPKTBUF_WMAC_LBK_BF_HD, R92C_TX_PAGE_BOUNDARY);
- rtwn_write_1(sc, R92C_TRXFF_BNDY, R92C_TX_PAGE_BOUNDARY);
- rtwn_write_1(sc, R92C_TDECTRL + 1, R92C_TX_PAGE_BOUNDARY);
-
- reg = rtwn_read_2(sc, R92C_TRXDMA_CTRL);
- reg &= ~R92C_TRXDMA_CTRL_QMAP_M;
- reg |= 0xF771;
- rtwn_write_2(sc, R92C_TRXDMA_CTRL, reg);
-
- rtwn_write_4(sc, R92C_TCR, R92C_TCR_CFENDFORM | (1 << 12) | (1 << 13));
-
- /* Configure Tx DMA. */
- rtwn_write_4(sc, R92C_BKQ_DESA,
- sc->tx_ring[RTWN_BK_QUEUE].map->dm_segs[0].ds_addr);
- rtwn_write_4(sc, R92C_BEQ_DESA,
- sc->tx_ring[RTWN_BE_QUEUE].map->dm_segs[0].ds_addr);
- rtwn_write_4(sc, R92C_VIQ_DESA,
- sc->tx_ring[RTWN_VI_QUEUE].map->dm_segs[0].ds_addr);
- rtwn_write_4(sc, R92C_VOQ_DESA,
- sc->tx_ring[RTWN_VO_QUEUE].map->dm_segs[0].ds_addr);
- rtwn_write_4(sc, R92C_BCNQ_DESA,
- sc->tx_ring[RTWN_BEACON_QUEUE].map->dm_segs[0].ds_addr);
- rtwn_write_4(sc, R92C_MGQ_DESA,
- sc->tx_ring[RTWN_MGNT_QUEUE].map->dm_segs[0].ds_addr);
- rtwn_write_4(sc, R92C_HQ_DESA,
- sc->tx_ring[RTWN_HIGH_QUEUE].map->dm_segs[0].ds_addr);
-
- /* Configure Rx DMA. */
- rtwn_write_4(sc, R92C_RX_DESA, sc->rx_ring.map->dm_segs[0].ds_addr);
-
- /* Set Tx/Rx transfer page boundary. */
- rtwn_write_2(sc, R92C_TRXFF_BNDY + 2, 0x27ff);
-
- /* Set Tx/Rx transfer page size. */
- rtwn_write_1(sc, R92C_PBP,
- SM(R92C_PBP_PSRX, R92C_PBP_128) |
- SM(R92C_PBP_PSTX, R92C_PBP_128));
- return (0);
-}
-
-void
-rtwn_mac_init(struct rtwn_softc *sc)
-{
- int i;
-
- /* Write MAC initialization values. */
- for (i = 0; i < nitems(rtl8192ce_mac); i++)
- rtwn_write_1(sc, rtl8192ce_mac[i].reg, rtl8192ce_mac[i].val);
-}
-
-void
-rtwn_bb_init(struct rtwn_softc *sc)
-{
- const struct r92c_bb_prog *prog;
- uint32_t reg;
- int i;
-
- /* Enable BB and RF. */
- rtwn_write_2(sc, R92C_SYS_FUNC_EN,
- rtwn_read_2(sc, R92C_SYS_FUNC_EN) |
- R92C_SYS_FUNC_EN_BBRSTB | R92C_SYS_FUNC_EN_BB_GLB_RST |
- R92C_SYS_FUNC_EN_DIO_RF);
-
- rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0xdb83);
-
- rtwn_write_1(sc, R92C_RF_CTRL,
- R92C_RF_CTRL_EN | R92C_RF_CTRL_RSTB | R92C_RF_CTRL_SDMRSTB);
-
- rtwn_write_1(sc, R92C_SYS_FUNC_EN,
- R92C_SYS_FUNC_EN_DIO_PCIE | R92C_SYS_FUNC_EN_PCIEA |
- R92C_SYS_FUNC_EN_PPLL | R92C_SYS_FUNC_EN_BB_GLB_RST |
- R92C_SYS_FUNC_EN_BBRSTB);
-
- rtwn_write_1(sc, R92C_AFE_XTAL_CTRL + 1, 0x80);
-
- rtwn_write_4(sc, R92C_LEDCFG0,
- rtwn_read_4(sc, R92C_LEDCFG0) | 0x00800000);
-
- /* Select BB programming. */
- prog = (sc->chip & RTWN_CHIP_92C) ?
- &rtl8192ce_bb_prog_2t : &rtl8192ce_bb_prog_1t;
-
- /* Write BB initialization values. */
- for (i = 0; i < prog->count; i++) {
- rtwn_bb_write(sc, prog->regs[i], prog->vals[i]);
- DELAY(1);
- }
-
- if (sc->chip & RTWN_CHIP_92C_1T2R) {
- /* 8192C 1T only configuration. */
- reg = rtwn_bb_read(sc, R92C_FPGA0_TXINFO);
- reg = (reg & ~0x00000003) | 0x2;
- rtwn_bb_write(sc, R92C_FPGA0_TXINFO, reg);
-
- reg = rtwn_bb_read(sc, R92C_FPGA1_TXINFO);
- reg = (reg & ~0x00300033) | 0x00200022;
- rtwn_bb_write(sc, R92C_FPGA1_TXINFO, reg);
-
- reg = rtwn_bb_read(sc, R92C_CCK0_AFESETTING);
- reg = (reg & ~0xff000000) | 0x45 << 24;
- rtwn_bb_write(sc, R92C_CCK0_AFESETTING, reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
- reg = (reg & ~0x000000ff) | 0x23;
- rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_AGCPARAM1);
- reg = (reg & ~0x00000030) | 1 << 4;
- rtwn_bb_write(sc, R92C_OFDM0_AGCPARAM1, reg);
-
- reg = rtwn_bb_read(sc, 0xe74);
- reg = (reg & ~0x0c000000) | 2 << 26;
- rtwn_bb_write(sc, 0xe74, reg);
- reg = rtwn_bb_read(sc, 0xe78);
- reg = (reg & ~0x0c000000) | 2 << 26;
- rtwn_bb_write(sc, 0xe78, reg);
- reg = rtwn_bb_read(sc, 0xe7c);
- reg = (reg & ~0x0c000000) | 2 << 26;
- rtwn_bb_write(sc, 0xe7c, reg);
- reg = rtwn_bb_read(sc, 0xe80);
- reg = (reg & ~0x0c000000) | 2 << 26;
- rtwn_bb_write(sc, 0xe80, reg);
- reg = rtwn_bb_read(sc, 0xe88);
- reg = (reg & ~0x0c000000) | 2 << 26;
- rtwn_bb_write(sc, 0xe88, reg);
- }
-
- /* Write AGC values. */
- for (i = 0; i < prog->agccount; i++) {
- rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE,
- prog->agcvals[i]);
- DELAY(1);
- }
-
- if (rtwn_bb_read(sc, R92C_HSSI_PARAM2(0)) &
- R92C_HSSI_PARAM2_CCK_HIPWR)
- sc->sc_flags |= RTWN_FLAG_CCK_HIPWR;
-}
-
-void
-rtwn_rf_init(struct rtwn_softc *sc)
-{
- const struct r92c_rf_prog *prog;
- uint32_t reg, type;
- int i, j, idx, off;
-
- /* Select RF programming based on board type. */
- if (!(sc->chip & RTWN_CHIP_92C)) {
- if (sc->board_type == R92C_BOARD_TYPE_MINICARD)
- prog = rtl8188ce_rf_prog;
- else if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
- prog = rtl8188ru_rf_prog;
- else
- prog = rtl8188cu_rf_prog;
- } else
- prog = rtl8192ce_rf_prog;
-
- for (i = 0; i < sc->nrxchains; i++) {
- /* Save RF_ENV control type. */
- idx = i / 2;
- off = (i % 2) * 16;
- reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
- type = (reg >> off) & 0x10;
-
- /* Set RF_ENV enable. */
- reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
- reg |= 0x100000;
- rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
- DELAY(1);
- /* Set RF_ENV output high. */
- reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACEOE(i));
- reg |= 0x10;
- rtwn_bb_write(sc, R92C_FPGA0_RFIFACEOE(i), reg);
- DELAY(1);
- /* Set address and data lengths of RF registers. */
- reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
- reg &= ~R92C_HSSI_PARAM2_ADDR_LENGTH;
- rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
- DELAY(1);
- reg = rtwn_bb_read(sc, R92C_HSSI_PARAM2(i));
- reg &= ~R92C_HSSI_PARAM2_DATA_LENGTH;
- rtwn_bb_write(sc, R92C_HSSI_PARAM2(i), reg);
- DELAY(1);
-
- /* Write RF initialization values for this chain. */
- for (j = 0; j < prog[i].count; j++) {
- if (prog[i].regs[j] >= 0xf9 &&
- prog[i].regs[j] <= 0xfe) {
- /*
- * These are fake RF registers offsets that
- * indicate a delay is required.
- */
- DELAY(50);
- continue;
- }
- rtwn_rf_write(sc, i, prog[i].regs[j],
- prog[i].vals[j]);
- DELAY(1);
- }
-
- /* Restore RF_ENV control type. */
- reg = rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(idx));
- reg &= ~(0x10 << off) | (type << off);
- rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(idx), reg);
-
- /* Cache RF register CHNLBW. */
- sc->rf_chnlbw[i] = rtwn_rf_read(sc, i, R92C_RF_CHNLBW);
- }
-
- if ((sc->chip & (RTWN_CHIP_UMC_A_CUT | RTWN_CHIP_92C)) ==
- RTWN_CHIP_UMC_A_CUT) {
- rtwn_rf_write(sc, 0, R92C_RF_RX_G1, 0x30255);
- rtwn_rf_write(sc, 0, R92C_RF_RX_G2, 0x50a00);
- }
-}
-
-void
-rtwn_cam_init(struct rtwn_softc *sc)
-{
- /* Invalidate all CAM entries. */
- rtwn_write_4(sc, R92C_CAMCMD,
- R92C_CAMCMD_POLLING | R92C_CAMCMD_CLR);
-}
-
-void
-rtwn_pa_bias_init(struct rtwn_softc *sc)
-{
- uint8_t reg;
- int i;
-
- for (i = 0; i < sc->nrxchains; i++) {
- if (sc->pa_setting & (1 << i))
- continue;
- rtwn_rf_write(sc, i, R92C_RF_IPA, 0x0f406);
- rtwn_rf_write(sc, i, R92C_RF_IPA, 0x4f406);
- rtwn_rf_write(sc, i, R92C_RF_IPA, 0x8f406);
- rtwn_rf_write(sc, i, R92C_RF_IPA, 0xcf406);
- }
- if (!(sc->pa_setting & 0x10)) {
- reg = rtwn_read_1(sc, 0x16);
- reg = (reg & ~0xf0) | 0x90;
- rtwn_write_1(sc, 0x16, reg);
- }
-}
-
-void
-rtwn_rxfilter_init(struct rtwn_softc *sc)
-{
- /* Initialize Rx filter. */
- /* TODO: use better filter for monitor mode. */
- rtwn_write_4(sc, R92C_RCR,
- R92C_RCR_AAP | R92C_RCR_APM | R92C_RCR_AM | R92C_RCR_AB |
- R92C_RCR_APP_ICV | R92C_RCR_AMF | R92C_RCR_HTC_LOC_CTRL |
- R92C_RCR_APP_MIC | R92C_RCR_APP_PHYSTS);
- /* Accept all multicast frames. */
- rtwn_write_4(sc, R92C_MAR + 0, 0xffffffff);
- rtwn_write_4(sc, R92C_MAR + 4, 0xffffffff);
- /* Accept all management frames. */
- rtwn_write_2(sc, R92C_RXFLTMAP0, 0xffff);
- /* Reject all control frames. */
- rtwn_write_2(sc, R92C_RXFLTMAP1, 0x0000);
- /* Accept all data frames. */
- rtwn_write_2(sc, R92C_RXFLTMAP2, 0xffff);
-}
-
-void
-rtwn_edca_init(struct rtwn_softc *sc)
-{
- rtwn_write_2(sc, R92C_SPEC_SIFS, 0x1010);
- rtwn_write_2(sc, R92C_MAC_SPEC_SIFS, 0x1010);
- rtwn_write_2(sc, R92C_SIFS_CCK, 0x1010);
- rtwn_write_2(sc, R92C_SIFS_OFDM, 0x0e0e);
- rtwn_write_4(sc, R92C_EDCA_BE_PARAM, 0x005ea42b);
- rtwn_write_4(sc, R92C_EDCA_BK_PARAM, 0x0000a44f);
- rtwn_write_4(sc, R92C_EDCA_VI_PARAM, 0x005e4322);
- rtwn_write_4(sc, R92C_EDCA_VO_PARAM, 0x002f3222);
-}
-
-void
-rtwn_write_txpower(struct rtwn_softc *sc, int chain,
- uint16_t power[RTWN_RIDX_COUNT])
-{
- uint32_t reg;
-
- /* Write per-CCK rate Tx power. */
- if (chain == 0) {
- reg = rtwn_bb_read(sc, R92C_TXAGC_A_CCK1_MCS32);
- reg = RW(reg, R92C_TXAGC_A_CCK1, power[0]);
- rtwn_bb_write(sc, R92C_TXAGC_A_CCK1_MCS32, reg);
- reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
- reg = RW(reg, R92C_TXAGC_A_CCK2, power[1]);
- reg = RW(reg, R92C_TXAGC_A_CCK55, power[2]);
- reg = RW(reg, R92C_TXAGC_A_CCK11, power[3]);
- rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
- } else {
- reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK1_55_MCS32);
- reg = RW(reg, R92C_TXAGC_B_CCK1, power[0]);
- reg = RW(reg, R92C_TXAGC_B_CCK2, power[1]);
- reg = RW(reg, R92C_TXAGC_B_CCK55, power[2]);
- rtwn_bb_write(sc, R92C_TXAGC_B_CCK1_55_MCS32, reg);
- reg = rtwn_bb_read(sc, R92C_TXAGC_B_CCK11_A_CCK2_11);
- reg = RW(reg, R92C_TXAGC_B_CCK11, power[3]);
- rtwn_bb_write(sc, R92C_TXAGC_B_CCK11_A_CCK2_11, reg);
- }
- /* Write per-OFDM rate Tx power. */
- rtwn_bb_write(sc, R92C_TXAGC_RATE18_06(chain),
- SM(R92C_TXAGC_RATE06, power[ 4]) |
- SM(R92C_TXAGC_RATE09, power[ 5]) |
- SM(R92C_TXAGC_RATE12, power[ 6]) |
- SM(R92C_TXAGC_RATE18, power[ 7]));
- rtwn_bb_write(sc, R92C_TXAGC_RATE54_24(chain),
- SM(R92C_TXAGC_RATE24, power[ 8]) |
- SM(R92C_TXAGC_RATE36, power[ 9]) |
- SM(R92C_TXAGC_RATE48, power[10]) |
- SM(R92C_TXAGC_RATE54, power[11]));
- /* Write per-MCS Tx power. */
- rtwn_bb_write(sc, R92C_TXAGC_MCS03_MCS00(chain),
- SM(R92C_TXAGC_MCS00, power[12]) |
- SM(R92C_TXAGC_MCS01, power[13]) |
- SM(R92C_TXAGC_MCS02, power[14]) |
- SM(R92C_TXAGC_MCS03, power[15]));
- rtwn_bb_write(sc, R92C_TXAGC_MCS07_MCS04(chain),
- SM(R92C_TXAGC_MCS04, power[16]) |
- SM(R92C_TXAGC_MCS05, power[17]) |
- SM(R92C_TXAGC_MCS06, power[18]) |
- SM(R92C_TXAGC_MCS07, power[19]));
- rtwn_bb_write(sc, R92C_TXAGC_MCS11_MCS08(chain),
- SM(R92C_TXAGC_MCS08, power[20]) |
- SM(R92C_TXAGC_MCS09, power[21]) |
- SM(R92C_TXAGC_MCS10, power[22]) |
- SM(R92C_TXAGC_MCS11, power[23]));
- rtwn_bb_write(sc, R92C_TXAGC_MCS15_MCS12(chain),
- SM(R92C_TXAGC_MCS12, power[24]) |
- SM(R92C_TXAGC_MCS13, power[25]) |
- SM(R92C_TXAGC_MCS14, power[26]) |
- SM(R92C_TXAGC_MCS15, power[27]));
-}
-
-void
-rtwn_get_txpower(struct rtwn_softc *sc, int chain,
- struct ieee80211_channel *c, struct ieee80211_channel *extc,
- uint16_t power[RTWN_RIDX_COUNT])
-{
- struct ieee80211com *ic = &sc->sc_ic;
- struct r92c_rom *rom = &sc->rom;
- uint16_t cckpow, ofdmpow, htpow, diff, max;
- const struct r92c_txpwr *base;
- int ridx, chan, group;
-
- /* Determine channel group. */
- chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
- if (chan <= 3)
- group = 0;
- else if (chan <= 9)
- group = 1;
- else
- group = 2;
-
- /* Get original Tx power based on board type and RF chain. */
- if (!(sc->chip & RTWN_CHIP_92C)) {
- if (sc->board_type == R92C_BOARD_TYPE_HIGHPA)
- base = &rtl8188ru_txagc[chain];
- else
- base = &rtl8192cu_txagc[chain];
- } else
- base = &rtl8192cu_txagc[chain];
-
- memset(power, 0, RTWN_RIDX_COUNT * sizeof(power[0]));
- if (sc->regulatory == 0) {
- for (ridx = 0; ridx <= 3; ridx++)
- power[ridx] = base->pwr[0][ridx];
- }
- for (ridx = 4; ridx < RTWN_RIDX_COUNT; ridx++) {
- if (sc->regulatory == 3) {
- power[ridx] = base->pwr[0][ridx];
- /* Apply vendor limits. */
- if (extc != NULL)
- max = rom->ht40_max_pwr[group];
- else
- max = rom->ht20_max_pwr[group];
- max = (max >> (chain * 4)) & 0xf;
- if (power[ridx] > max)
- power[ridx] = max;
- } else if (sc->regulatory == 1) {
- if (extc == NULL)
- power[ridx] = base->pwr[group][ridx];
- } else if (sc->regulatory != 2)
- power[ridx] = base->pwr[0][ridx];
- }
-
- /* Compute per-CCK rate Tx power. */
- cckpow = rom->cck_tx_pwr[chain][group];
- for (ridx = 0; ridx <= 3; ridx++) {
- power[ridx] += cckpow;
- if (power[ridx] > R92C_MAX_TX_PWR)
- power[ridx] = R92C_MAX_TX_PWR;
- }
-
- htpow = rom->ht40_1s_tx_pwr[chain][group];
- if (sc->ntxchains > 1) {
- /* Apply reduction for 2 spatial streams. */
- diff = rom->ht40_2s_tx_pwr_diff[group];
- diff = (diff >> (chain * 4)) & 0xf;
- htpow = (htpow > diff) ? htpow - diff : 0;
- }
-
- /* Compute per-OFDM rate Tx power. */
- diff = rom->ofdm_tx_pwr_diff[group];
- diff = (diff >> (chain * 4)) & 0xf;
- ofdmpow = htpow + diff; /* HT->OFDM correction. */
- for (ridx = 4; ridx <= 11; ridx++) {
- power[ridx] += ofdmpow;
- if (power[ridx] > R92C_MAX_TX_PWR)
- power[ridx] = R92C_MAX_TX_PWR;
- }
-
- /* Compute per-MCS Tx power. */
- if (extc == NULL) {
- diff = rom->ht20_tx_pwr_diff[group];
- diff = (diff >> (chain * 4)) & 0xf;
- htpow += diff; /* HT40->HT20 correction. */
- }
- for (ridx = 12; ridx <= 27; ridx++) {
- power[ridx] += htpow;
- if (power[ridx] > R92C_MAX_TX_PWR)
- power[ridx] = R92C_MAX_TX_PWR;
- }
-#ifdef RTWN_DEBUG
- if (rtwn_debug >= 4) {
- /* Dump per-rate Tx power values. */
- printf("Tx power for chain %d:\n", chain);
- for (ridx = 0; ridx < RTWN_RIDX_COUNT; ridx++)
- printf("Rate %d = %u\n", ridx, power[ridx]);
- }
-#endif
-}
-
-void
-rtwn_set_txpower(struct rtwn_softc *sc, struct ieee80211_channel *c,
- struct ieee80211_channel *extc)
+rtwn_pci_stop(void *cookie)
{
- uint16_t power[RTWN_RIDX_COUNT];
+ struct rtwn_pci_softc *sc = cookie;
int i;
- for (i = 0; i < sc->ntxchains; i++) {
- /* Compute per-rate Tx power values. */
- rtwn_get_txpower(sc, i, c, extc, power);
- /* Write per-rate Tx power values to hardware. */
- rtwn_write_txpower(sc, i, power);
- }
-}
-
-void
-rtwn_set_chan(struct rtwn_softc *sc, struct ieee80211_channel *c,
- struct ieee80211_channel *extc)
-{
- struct ieee80211com *ic = &sc->sc_ic;
- u_int chan;
- int i;
-
- chan = ieee80211_chan2ieee(ic, c); /* XXX center freq! */
-
- /* Set Tx power for this new channel. */
- rtwn_set_txpower(sc, c, extc);
-
- for (i = 0; i < sc->nrxchains; i++) {
- rtwn_rf_write(sc, i, R92C_RF_CHNLBW,
- RW(sc->rf_chnlbw[i], R92C_RF_CHNLBW_CHNL, chan));
- }
- if (extc != NULL) {
- uint32_t reg;
-
- /* Is secondary channel below or above primary? */
- int prichlo = c->ic_freq < extc->ic_freq;
-
- rtwn_write_1(sc, R92C_BWOPMODE,
- rtwn_read_1(sc, R92C_BWOPMODE) & ~R92C_BWOPMODE_20MHZ);
-
- reg = rtwn_read_1(sc, R92C_RRSR + 2);
- reg = (reg & ~0x6f) | (prichlo ? 1 : 2) << 5;
- rtwn_write_1(sc, R92C_RRSR + 2, reg);
-
- rtwn_bb_write(sc, R92C_FPGA0_RFMOD,
- rtwn_bb_read(sc, R92C_FPGA0_RFMOD) | R92C_RFMOD_40MHZ);
- rtwn_bb_write(sc, R92C_FPGA1_RFMOD,
- rtwn_bb_read(sc, R92C_FPGA1_RFMOD) | R92C_RFMOD_40MHZ);
-
- /* Set CCK side band. */
- reg = rtwn_bb_read(sc, R92C_CCK0_SYSTEM);
- reg = (reg & ~0x00000010) | (prichlo ? 0 : 1) << 4;
- rtwn_bb_write(sc, R92C_CCK0_SYSTEM, reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM1_LSTF);
- reg = (reg & ~0x00000c00) | (prichlo ? 1 : 2) << 10;
- rtwn_bb_write(sc, R92C_OFDM1_LSTF, reg);
-
- rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
- rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) &
- ~R92C_FPGA0_ANAPARAM2_CBW20);
-
- reg = rtwn_bb_read(sc, 0x818);
- reg = (reg & ~0x0c000000) | (prichlo ? 2 : 1) << 26;
- rtwn_bb_write(sc, 0x818, reg);
-
- /* Select 40MHz bandwidth. */
- rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
- (sc->rf_chnlbw[0] & ~0xfff) | chan);
- } else {
- rtwn_write_1(sc, R92C_BWOPMODE,
- rtwn_read_1(sc, R92C_BWOPMODE) | R92C_BWOPMODE_20MHZ);
-
- rtwn_bb_write(sc, R92C_FPGA0_RFMOD,
- rtwn_bb_read(sc, R92C_FPGA0_RFMOD) & ~R92C_RFMOD_40MHZ);
- rtwn_bb_write(sc, R92C_FPGA1_RFMOD,
- rtwn_bb_read(sc, R92C_FPGA1_RFMOD) & ~R92C_RFMOD_40MHZ);
-
- rtwn_bb_write(sc, R92C_FPGA0_ANAPARAM2,
- rtwn_bb_read(sc, R92C_FPGA0_ANAPARAM2) |
- R92C_FPGA0_ANAPARAM2_CBW20);
-
- /* Select 20MHz bandwidth. */
- rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
- (sc->rf_chnlbw[0] & ~0xfff) | R92C_RF_CHNLBW_BW20 | chan);
- }
-}
-
-int
-rtwn_iq_calib_chain(struct rtwn_softc *sc, int chain, uint16_t tx[2],
- uint16_t rx[2])
-{
- uint32_t status;
- int offset = chain * 0x20;
-
- if (chain == 0) { /* IQ calibration for chain 0. */
- /* IQ calibration settings for chain 0. */
- rtwn_bb_write(sc, 0xe30, 0x10008c1f);
- rtwn_bb_write(sc, 0xe34, 0x10008c1f);
- rtwn_bb_write(sc, 0xe38, 0x82140102);
-
- if (sc->ntxchains > 1) {
- rtwn_bb_write(sc, 0xe3c, 0x28160202); /* 2T */
- /* IQ calibration settings for chain 1. */
- rtwn_bb_write(sc, 0xe50, 0x10008c22);
- rtwn_bb_write(sc, 0xe54, 0x10008c22);
- rtwn_bb_write(sc, 0xe58, 0x82140102);
- rtwn_bb_write(sc, 0xe5c, 0x28160202);
- } else
- rtwn_bb_write(sc, 0xe3c, 0x28160502); /* 1T */
-
- /* LO calibration settings. */
- rtwn_bb_write(sc, 0xe4c, 0x001028d1);
- /* We're doing LO and IQ calibration in one shot. */
- rtwn_bb_write(sc, 0xe48, 0xf9000000);
- rtwn_bb_write(sc, 0xe48, 0xf8000000);
-
- } else { /* IQ calibration for chain 1. */
- /* We're doing LO and IQ calibration in one shot. */
- rtwn_bb_write(sc, 0xe60, 0x00000002);
- rtwn_bb_write(sc, 0xe60, 0x00000000);
- }
-
- /* Give LO and IQ calibrations the time to complete. */
- DELAY(1000);
-
- /* Read IQ calibration status. */
- status = rtwn_bb_read(sc, 0xeac);
-
- if (status & (1 << (28 + chain * 3)))
- return (0); /* Tx failed. */
- /* Read Tx IQ calibration results. */
- tx[0] = (rtwn_bb_read(sc, 0xe94 + offset) >> 16) & 0x3ff;
- tx[1] = (rtwn_bb_read(sc, 0xe9c + offset) >> 16) & 0x3ff;
- if (tx[0] == 0x142 || tx[1] == 0x042)
- return (0); /* Tx failed. */
-
- if (status & (1 << (27 + chain * 3)))
- return (1); /* Rx failed. */
- /* Read Rx IQ calibration results. */
- rx[0] = (rtwn_bb_read(sc, 0xea4 + offset) >> 16) & 0x3ff;
- rx[1] = (rtwn_bb_read(sc, 0xeac + offset) >> 16) & 0x3ff;
- if (rx[0] == 0x132 || rx[1] == 0x036)
- return (1); /* Rx failed. */
-
- return (3); /* Both Tx and Rx succeeded. */
-}
-
-void
-rtwn_iq_calib_run(struct rtwn_softc *sc, int n, uint16_t tx[2][2],
- uint16_t rx[2][2])
-{
- /* Registers to save and restore during IQ calibration. */
- struct iq_cal_regs {
- uint32_t adda[16];
- uint8_t txpause;
- uint8_t bcn_ctrl;
- uint8_t ustime_tsf;
- uint32_t gpio_muxcfg;
- uint32_t ofdm0_trxpathena;
- uint32_t ofdm0_trmuxpar;
- uint32_t fpga0_rfifacesw1;
- } iq_cal_regs;
- static const uint16_t reg_adda[16] = {
- 0x85c, 0xe6c, 0xe70, 0xe74,
- 0xe78, 0xe7c, 0xe80, 0xe84,
- 0xe88, 0xe8c, 0xed0, 0xed4,
- 0xed8, 0xedc, 0xee0, 0xeec
- };
- int i, chain;
- uint32_t hssi_param1;
-
- if (n == 0) {
- for (i = 0; i < nitems(reg_adda); i++)
- iq_cal_regs.adda[i] = rtwn_bb_read(sc, reg_adda[i]);
-
- iq_cal_regs.txpause = rtwn_read_1(sc, R92C_TXPAUSE);
- iq_cal_regs.bcn_ctrl = rtwn_read_1(sc, R92C_BCN_CTRL);
- iq_cal_regs.ustime_tsf = rtwn_read_1(sc, R92C_USTIME_TSF);
- iq_cal_regs.gpio_muxcfg = rtwn_read_4(sc, R92C_GPIO_MUXCFG);
- }
-
- if (sc->ntxchains == 1) {
- rtwn_bb_write(sc, reg_adda[0], 0x0b1b25a0);
- for (i = 1; i < nitems(reg_adda); i++)
- rtwn_bb_write(sc, reg_adda[i], 0x0bdb25a0);
- } else {
- for (i = 0; i < nitems(reg_adda); i++)
- rtwn_bb_write(sc, reg_adda[i], 0x04db25a4);
- }
-
- hssi_param1 = rtwn_bb_read(sc, R92C_HSSI_PARAM1(0));
- if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
- rtwn_bb_write(sc, R92C_HSSI_PARAM1(0),
- hssi_param1 | R92C_HSSI_PARAM1_PI);
- rtwn_bb_write(sc, R92C_HSSI_PARAM1(1),
- hssi_param1 | R92C_HSSI_PARAM1_PI);
- }
-
- if (n == 0) {
- iq_cal_regs.ofdm0_trxpathena =
- rtwn_bb_read(sc, R92C_OFDM0_TRXPATHENA);
- iq_cal_regs.ofdm0_trmuxpar =
- rtwn_bb_read(sc, R92C_OFDM0_TRMUXPAR);
- iq_cal_regs.fpga0_rfifacesw1 =
- rtwn_bb_read(sc, R92C_FPGA0_RFIFACESW(1));
- }
-
- rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA, 0x03a05600);
- rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, 0x000800e4);
- rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1), 0x22204000);
- if (sc->ntxchains > 1) {
- rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
- rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00010000);
- }
-
- rtwn_write_1(sc, R92C_TXPAUSE, 0x3f);
- rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl & ~(0x08));
- rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf & ~(0x08));
- rtwn_write_1(sc, R92C_GPIO_MUXCFG,
- iq_cal_regs.gpio_muxcfg & ~(0x20));
-
- rtwn_bb_write(sc, 0x0b68, 0x00080000);
- if (sc->ntxchains > 1)
- rtwn_bb_write(sc, 0x0b6c, 0x00080000);
-
- rtwn_bb_write(sc, 0x0e28, 0x80800000);
- rtwn_bb_write(sc, 0x0e40, 0x01007c00);
- rtwn_bb_write(sc, 0x0e44, 0x01004800);
-
- rtwn_bb_write(sc, 0x0b68, 0x00080000);
-
- for (chain = 0; chain < sc->ntxchains; chain++) {
- if (chain > 0) {
- /* Put chain 0 on standby. */
- rtwn_bb_write(sc, 0x0e28, 0x00);
- rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00010000);
- rtwn_bb_write(sc, 0x0e28, 0x80800000);
-
- /* Enable chain 1. */
- for (i = 0; i < nitems(reg_adda); i++)
- rtwn_bb_write(sc, reg_adda[i], 0x0b1b25a4);
- }
-
- /* Run IQ calibration twice. */
- for (i = 0; i < 2; i++) {
- int ret;
-
- ret = rtwn_iq_calib_chain(sc, chain,
- tx[chain], rx[chain]);
- if (ret == 0) {
- DPRINTF(("%s: chain %d: Tx failed.\n",
- __func__, chain));
- tx[chain][0] = 0xff;
- tx[chain][1] = 0xff;
- rx[chain][0] = 0xff;
- rx[chain][1] = 0xff;
- } else if (ret == 1) {
- DPRINTF(("%s: chain %d: Rx failed.\n",
- __func__, chain));
- rx[chain][0] = 0xff;
- rx[chain][1] = 0xff;
- } else if (ret == 3) {
- DPRINTF(("%s: chain %d: Both Tx and Rx "
- "succeeded.\n", __func__, chain));
- }
- }
-
- DPRINTF(("%s: results for run %d chain %d: tx[0]=0x%x, "
- "tx[1]=0x%x rx[0]=0x%x rx[1]=0x%x\n", __func__, n, chain,
- tx[chain][0], tx[chain][1], rx[chain][0], rx[chain][1]));
- }
-
- rtwn_bb_write(sc, R92C_OFDM0_TRXPATHENA,
- iq_cal_regs.ofdm0_trxpathena);
- rtwn_bb_write(sc, R92C_FPGA0_RFIFACESW(1),
- iq_cal_regs.fpga0_rfifacesw1);
- rtwn_bb_write(sc, R92C_OFDM0_TRMUXPAR, iq_cal_regs.ofdm0_trmuxpar);
-
- rtwn_bb_write(sc, 0x0e28, 0x00);
- rtwn_bb_write(sc, R92C_LSSI_PARAM(0), 0x00032ed3);
- if (sc->ntxchains > 1)
- rtwn_bb_write(sc, R92C_LSSI_PARAM(1), 0x00032ed3);
-
- if (n != 0) {
- if (!(hssi_param1 & R92C_HSSI_PARAM1_PI)) {
- rtwn_bb_write(sc, R92C_HSSI_PARAM1(0), hssi_param1);
- rtwn_bb_write(sc, R92C_HSSI_PARAM1(1), hssi_param1);
- }
-
- for (i = 0; i < nitems(reg_adda); i++)
- rtwn_bb_write(sc, reg_adda[i], iq_cal_regs.adda[i]);
-
- rtwn_write_1(sc, R92C_TXPAUSE, iq_cal_regs.txpause);
- rtwn_write_1(sc, R92C_BCN_CTRL, iq_cal_regs.bcn_ctrl);
- rtwn_write_1(sc, R92C_USTIME_TSF, iq_cal_regs.ustime_tsf);
- rtwn_write_4(sc, R92C_GPIO_MUXCFG, iq_cal_regs.gpio_muxcfg);
- }
-}
-
-#define RTWN_IQ_CAL_MAX_TOLERANCE 5
-int
-rtwn_iq_calib_compare_results(uint16_t tx1[2][2], uint16_t rx1[2][2],
- uint16_t tx2[2][2], uint16_t rx2[2][2], int ntxchains)
-{
- int chain, i, tx_ok[2], rx_ok[2];
-
- tx_ok[0] = tx_ok[1] = rx_ok[0] = rx_ok[1] = 0;
- for (chain = 0; chain < ntxchains; chain++) {
- for (i = 0; i < 2; i++) {
- if (tx1[chain][i] == 0xff || tx2[chain][i] == 0xff ||
- rx1[chain][i] == 0xff || rx2[chain][i] == 0xff)
- continue;
-
- tx_ok[chain] = (abs(tx1[chain][i] - tx2[chain][i]) <=
- RTWN_IQ_CAL_MAX_TOLERANCE);
-
- rx_ok[chain] = (abs(rx1[chain][i] - rx2[chain][i]) <=
- RTWN_IQ_CAL_MAX_TOLERANCE);
- }
- }
-
- if (ntxchains > 1)
- return (tx_ok[0] && tx_ok[1] && rx_ok[0] && rx_ok[1]);
- else
- return (tx_ok[0] && rx_ok[0]);
-}
-#undef RTWN_IQ_CAL_MAX_TOLERANCE
-
-void
-rtwn_iq_calib_write_results(struct rtwn_softc *sc, uint16_t tx[2],
- uint16_t rx[2], int chain)
-{
- uint32_t reg, val, x;
- long y, tx_c;
-
- if (tx[0] == 0xff || tx[1] == 0xff)
- return;
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
- val = ((reg >> 22) & 0x3ff);
- x = tx[0];
- if (x & 0x0200)
- x |= 0xfc00;
- reg = (((x * val) >> 8) & 0x3ff);
- rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD);
- if (((x * val) >> 7) & 0x01)
- reg |= 0x80000000;
- else
- reg &= ~0x80000000;
- rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg);
-
- y = tx[1];
- if (y & 0x00000200)
- y |= 0xfffffc00;
- tx_c = (y * val) >> 8;
- reg = rtwn_bb_read(sc, R92C_OFDM0_TXAFE(chain));
- reg |= ((((tx_c & 0x3c0) >> 6) << 24) & 0xf0000000);
- rtwn_bb_write(sc, R92C_OFDM0_TXAFE(chain), reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_TXIQIMBALANCE(chain));
- reg |= (((tx_c & 0x3f) << 16) & 0x003F0000);
- rtwn_bb_write(sc, R92C_OFDM0_TXIQIMBALANCE(chain), reg);
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_ECCATHRESHOLD);
- if (((y * val) >> 7) & 0x01)
- reg |= 0x20000000;
- else
- reg &= ~0x20000000;
- rtwn_bb_write(sc, R92C_OFDM0_ECCATHRESHOLD, reg);
-
- if (rx[0] == 0xff || rx[1] == 0xff)
- return;
-
- reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQIMBALANCE(chain));
- reg |= (rx[0] & 0x3ff);
- rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg);
- reg |= (((rx[1] & 0x03f) << 8) & 0xFC00);
- rtwn_bb_write(sc, R92C_OFDM0_RXIQIMBALANCE(chain), reg);
-
- if (chain == 0) {
- reg = rtwn_bb_read(sc, R92C_OFDM0_RXIQEXTANTA);
- reg |= (((rx[1] & 0xf) >> 6) & 0x000f);
- rtwn_bb_write(sc, R92C_OFDM0_RXIQEXTANTA, reg);
- } else {
- reg = rtwn_bb_read(sc, R92C_OFDM0_AGCRSSITABLE);
- reg |= ((((rx[1] & 0xf) >> 6) << 12) & 0xf000);
- rtwn_bb_write(sc, R92C_OFDM0_AGCRSSITABLE, reg);
- }
-}
-
-#define RTWN_IQ_CAL_NRUN 3
-void
-rtwn_iq_calib(struct rtwn_softc *sc)
-{
- uint16_t tx[RTWN_IQ_CAL_NRUN][2][2], rx[RTWN_IQ_CAL_NRUN][2][2];
- int n, valid;
-
- valid = 0;
- for (n = 0; n < RTWN_IQ_CAL_NRUN; n++) {
- rtwn_iq_calib_run(sc, n, tx[n], rx[n]);
-
- if (n == 0)
- continue;
-
- /* Valid results remain stable after consecutive runs. */
- valid = rtwn_iq_calib_compare_results(tx[n - 1], rx[n - 1],
- tx[n], rx[n], sc->ntxchains);
- if (valid)
- break;
- }
-
- if (valid) {
- rtwn_iq_calib_write_results(sc, tx[n][0], rx[n][0], 0);
- if (sc->ntxchains > 1)
- rtwn_iq_calib_write_results(sc, tx[n][1], rx[n][1], 1);
- }
-}
-#undef RTWN_IQ_CAL_NRUN
-
-void
-rtwn_lc_calib(struct rtwn_softc *sc)
-{
- uint32_t rf_ac[2];
- uint8_t txmode;
- int i;
-
- txmode = rtwn_read_1(sc, R92C_OFDM1_LSTF + 3);
- if ((txmode & 0x70) != 0) {
- /* Disable all continuous Tx. */
- rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode & ~0x70);
-
- /* Set RF mode to standby mode. */
- for (i = 0; i < sc->nrxchains; i++) {
- rf_ac[i] = rtwn_rf_read(sc, i, R92C_RF_AC);
- rtwn_rf_write(sc, i, R92C_RF_AC,
- RW(rf_ac[i], R92C_RF_AC_MODE,
- R92C_RF_AC_MODE_STANDBY));
- }
- } else {
- /* Block all Tx queues. */
- rtwn_write_1(sc, R92C_TXPAUSE, 0xff);
- }
- /* Start calibration. */
- rtwn_rf_write(sc, 0, R92C_RF_CHNLBW,
- rtwn_rf_read(sc, 0, R92C_RF_CHNLBW) | R92C_RF_CHNLBW_LCSTART);
-
- /* Give calibration the time to complete. */
- DELAY(100);
-
- /* Restore configuration. */
- if ((txmode & 0x70) != 0) {
- /* Restore Tx mode. */
- rtwn_write_1(sc, R92C_OFDM1_LSTF + 3, txmode);
- /* Restore RF mode. */
- for (i = 0; i < sc->nrxchains; i++)
- rtwn_rf_write(sc, i, R92C_RF_AC, rf_ac[i]);
- } else {
- /* Unblock all Tx queues. */
- rtwn_write_1(sc, R92C_TXPAUSE, 0x00);
- }
-}
-
-void
-rtwn_temp_calib(struct rtwn_softc *sc)
-{
- int temp;
-
- if (sc->thcal_state == 0) {
- /* Start measuring temperature. */
- rtwn_rf_write(sc, 0, R92C_RF_T_METER, 0x60);
- sc->thcal_state = 1;
- return;
- }
- sc->thcal_state = 0;
-
- /* Read measured temperature. */
- temp = rtwn_rf_read(sc, 0, R92C_RF_T_METER) & 0x1f;
- if (temp == 0) /* Read failed, skip. */
- return;
- DPRINTFN(2, ("temperature=%d\n", temp));
-
- /*
- * Redo IQ and LC calibration if temperature changed significantly
- * since last calibration.
- */
- if (sc->thcal_lctemp == 0) {
- /* First calibration is performed in rtwn_init(). */
- sc->thcal_lctemp = temp;
- } else if (abs(temp - sc->thcal_lctemp) > 1) {
- DPRINTF(("IQ/LC calib triggered by temp: %d -> %d\n",
- sc->thcal_lctemp, temp));
- rtwn_iq_calib(sc);
- rtwn_lc_calib(sc);
- /* Record temperature of last calibration. */
- sc->thcal_lctemp = temp;
- }
-}
-
-int
-rtwn_init(struct ifnet *ifp)
-{
- struct rtwn_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
- uint32_t reg;
- int i, error;
-
- /* Init firmware commands ring. */
- sc->fwcur = 0;
-
- /* Power on adapter. */
- error = rtwn_power_on(sc);
- if (error != 0) {
- printf("%s: could not power on adapter\n",
- sc->sc_dev.dv_xname);
- goto fail;
- }
-
- /* Initialize DMA. */
- error = rtwn_dma_init(sc);
- if (error != 0) {
- printf("%s: could not initialize DMA\n",
- sc->sc_dev.dv_xname);
- goto fail;
- }
-
- /* Set info size in Rx descriptors (in 64-bit words). */
- rtwn_write_1(sc, R92C_RX_DRVINFO_SZ, 4);
-
- /* Disable interrupts. */
- rtwn_write_4(sc, R92C_HISR, 0x00000000);
- rtwn_write_4(sc, R92C_HIMR, 0x00000000);
-
- /* Set MAC address. */
- IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
- for (i = 0; i < IEEE80211_ADDR_LEN; i++)
- rtwn_write_1(sc, R92C_MACID + i, ic->ic_myaddr[i]);
-
- /* Set initial network type. */
- reg = rtwn_read_4(sc, R92C_CR);
- reg = RW(reg, R92C_CR_NETTYPE, R92C_CR_NETTYPE_INFRA);
- rtwn_write_4(sc, R92C_CR, reg);
-
- rtwn_rxfilter_init(sc);
-
- reg = rtwn_read_4(sc, R92C_RRSR);
- reg = RW(reg, R92C_RRSR_RATE_BITMAP, R92C_RRSR_RATE_ALL);
- rtwn_write_4(sc, R92C_RRSR, reg);
-
- /* Set short/long retry limits. */
- rtwn_write_2(sc, R92C_RL,
- SM(R92C_RL_SRL, 0x07) | SM(R92C_RL_LRL, 0x07));
-
- /* Initialize EDCA parameters. */
- rtwn_edca_init(sc);
-
- /* Set data and response automatic rate fallback retry counts. */
- rtwn_write_4(sc, R92C_DARFRC + 0, 0x01000000);
- rtwn_write_4(sc, R92C_DARFRC + 4, 0x07060504);
- rtwn_write_4(sc, R92C_RARFRC + 0, 0x01000000);
- rtwn_write_4(sc, R92C_RARFRC + 4, 0x07060504);
-
- rtwn_write_2(sc, R92C_FWHW_TXQ_CTRL, 0x1f80);
-
- /* Set ACK timeout. */
- rtwn_write_1(sc, R92C_ACKTO, 0x40);
-
- /* Initialize beacon parameters. */
- rtwn_write_2(sc, R92C_TBTT_PROHIBIT, 0x6404);
- rtwn_write_1(sc, R92C_DRVERLYINT, 0x05);
- rtwn_write_1(sc, R92C_BCNDMATIM, 0x02);
- rtwn_write_2(sc, R92C_BCNTCFG, 0x660f);
-
- /* Setup AMPDU aggregation. */
- rtwn_write_4(sc, R92C_AGGLEN_LMT, 0x99997631); /* MCS7~0 */
- rtwn_write_1(sc, R92C_AGGR_BREAK_TIME, 0x16);
-
- rtwn_write_1(sc, R92C_BCN_MAX_ERR, 0xff);
- rtwn_write_1(sc, R92C_BCN_CTRL, R92C_BCN_CTRL_DIS_TSF_UDT0);
-
- rtwn_write_4(sc, R92C_PIFS, 0x1c);
- rtwn_write_4(sc, R92C_MCUTST_1, 0x0);
-
- /* Load 8051 microcode. */
- error = rtwn_load_firmware(sc);
- if (error != 0)
- goto fail;
-
- /* Initialize MAC/BB/RF blocks. */
- rtwn_mac_init(sc);
- rtwn_bb_init(sc);
- rtwn_rf_init(sc);
-
- /* Turn CCK and OFDM blocks on. */
- reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD);
- reg |= R92C_RFMOD_CCK_EN;
- rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
- reg = rtwn_bb_read(sc, R92C_FPGA0_RFMOD);
- reg |= R92C_RFMOD_OFDM_EN;
- rtwn_bb_write(sc, R92C_FPGA0_RFMOD, reg);
-
- /* Clear per-station keys table. */
- rtwn_cam_init(sc);
-
- /* Enable hardware sequence numbering. */
- rtwn_write_1(sc, R92C_HWSEQ_CTRL, 0xff);
-
- /* Perform LO and IQ calibrations. */
- rtwn_iq_calib(sc);
- /* Perform LC calibration. */
- rtwn_lc_calib(sc);
-
- rtwn_pa_bias_init(sc);
-
- /* Initialize GPIO setting. */
- rtwn_write_1(sc, R92C_GPIO_MUXCFG,
- rtwn_read_1(sc, R92C_GPIO_MUXCFG) & ~R92C_GPIO_MUXCFG_ENBT);
-
- /* Fix for lower temperature. */
- rtwn_write_1(sc, 0x15, 0xe9);
-
- /* Set default channel. */
- ic->ic_bss->ni_chan = ic->ic_ibss_chan;
- rtwn_set_chan(sc, ic->ic_ibss_chan, NULL);
-
- /* CLear pending interrupts. */
- rtwn_write_4(sc, R92C_HISR, 0xffffffff);
-
- /* Enable interrupts. */
- rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
-
- /* We're ready to go. */
- ifq_clr_oactive(&ifp->if_snd);
- ifp->if_flags |= IFF_RUNNING;
-
-#ifdef notyet
- if (ic->ic_flags & IEEE80211_F_WEPON) {
- /* Install WEP keys. */
- for (i = 0; i < IEEE80211_WEP_NKID; i++)
- rtwn_set_key(ic, NULL, &ic->ic_nw_keys[i]);
- }
-#endif
- if (ic->ic_opmode == IEEE80211_M_MONITOR)
- ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
- else
- ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
- return (0);
- fail:
- rtwn_stop(ifp);
- return (error);
-}
-
-void
-rtwn_init_task(void *arg1)
-{
- struct rtwn_softc *sc = arg1;
- struct ifnet *ifp = &sc->sc_ic.ic_if;
- int s;
-
- s = splnet();
- while (sc->sc_flags & RTWN_FLAG_BUSY)
- tsleep(&sc->sc_flags, 0, "rtwnpwr", 0);
- sc->sc_flags |= RTWN_FLAG_BUSY;
-
- rtwn_stop(ifp);
-
- if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
- rtwn_init(ifp);
-
- sc->sc_flags &= ~RTWN_FLAG_BUSY;
- wakeup(&sc->sc_flags);
- splx(s);
-}
-
-void
-rtwn_stop(struct ifnet *ifp)
-{
- struct rtwn_softc *sc = ifp->if_softc;
- struct ieee80211com *ic = &sc->sc_ic;
- int s, i;
- u_int16_t reg;
-
- sc->sc_tx_timer = 0;
- ifp->if_timer = 0;
- ifp->if_flags &= ~IFF_RUNNING;
- ifq_clr_oactive(&ifp->if_snd);
-
- s = splnet();
- ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
-
- timeout_del(&sc->scan_to);
- timeout_del(&sc->calib_to);
-
- task_del(systq, &sc->init_task);
-
- /* Disable interrupts. */
- rtwn_write_4(sc, R92C_HISR, 0x00000000);
- rtwn_write_4(sc, R92C_HIMR, 0x00000000);
-
- /* Stop hardware. */
- rtwn_write_1(sc, R92C_TXPAUSE, 0xff);
- rtwn_write_1(sc, R92C_RF_CTRL, 0x00);
- reg = rtwn_read_1(sc, R92C_SYS_FUNC_EN);
- reg |= R92C_SYS_FUNC_EN_BB_GLB_RST;
- rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg);
- reg &= ~R92C_SYS_FUNC_EN_BB_GLB_RST;
- rtwn_write_1(sc, R92C_SYS_FUNC_EN, reg);
- reg = rtwn_read_2(sc, R92C_CR);
- reg &= ~(R92C_CR_HCI_TXDMA_EN | R92C_CR_HCI_RXDMA_EN |
- R92C_CR_TXDMA_EN | R92C_CR_RXDMA_EN | R92C_CR_PROTOCOL_EN |
- R92C_CR_SCHEDULE_EN | R92C_CR_MACTXEN | R92C_CR_MACRXEN |
- R92C_CR_ENSEC);
- rtwn_write_2(sc, R92C_CR, reg);
- if (rtwn_read_1(sc, R92C_MCUFWDL) & R92C_MCUFWDL_RAM_DL_SEL)
- rtwn_fw_reset(sc);
- /* TODO: linux does additional btcoex stuff here */
- rtwn_write_2(sc, R92C_AFE_PLL_CTRL, 0x80); /* linux magic number */
- rtwn_write_1(sc, R92C_SPS0_CTRL, 0x23); /* ditto */
- rtwn_write_1(sc, R92C_AFE_XTAL_CTRL, 0x0e); /* different with btcoex */
- rtwn_write_1(sc, R92C_RSV_CTRL, 0x0e);
- rtwn_write_1(sc, R92C_APS_FSMCO, R92C_APS_FSMCO_PDN_EN);
-
for (i = 0; i < RTWN_NTXQUEUES; i++)
rtwn_reset_tx_list(sc, i);
rtwn_reset_rx_list(sc);
-
- splx(s);
}
int
rtwn_intr(void *xsc)
{
- struct rtwn_softc *sc = xsc;
+ struct rtwn_pci_softc *sc = xsc;
u_int32_t status;
int i;
- status = rtwn_read_4(sc, R92C_HISR);
+ status = rtwn_pci_read_4(sc, R92C_HISR);
if (status == 0 || status == 0xffffffff)
return (0);
/* Disable interrupts. */
- rtwn_write_4(sc, R92C_HIMR, 0x00000000);
+ rtwn_pci_write_4(sc, R92C_HIMR, 0x00000000);
/* Ack interrupts. */
- rtwn_write_4(sc, R92C_HISR, status);
+ rtwn_pci_write_4(sc, R92C_HISR, status);
/* Vendor driver treats RX errors like ROK... */
if (status & (R92C_IMR_ROK | R92C_IMR_RXFOVW | R92C_IMR_RDU)) {
@@ -3737,7 +1156,64 @@ rtwn_intr(void *xsc)
rtwn_tx_done(sc, RTWN_VO_QUEUE);
/* Enable interrupts. */
- rtwn_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
+ rtwn_pci_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
return (1);
}
+
+int
+rtwn_is_oactive(void *cookie)
+{
+ struct rtwn_pci_softc *sc = cookie;
+
+ return (sc->qfullmsk != 0);
+}
+
+int
+rtwn_configure_dma(void *cookie)
+{
+ struct rtwn_pci_softc *sc = cookie;
+
+ /* Configure Tx DMA. */
+ rtwn_pci_write_4(sc, R92C_BKQ_DESA,
+ sc->tx_ring[RTWN_BK_QUEUE].map->dm_segs[0].ds_addr);
+ rtwn_pci_write_4(sc, R92C_BEQ_DESA,
+ sc->tx_ring[RTWN_BE_QUEUE].map->dm_segs[0].ds_addr);
+ rtwn_pci_write_4(sc, R92C_VIQ_DESA,
+ sc->tx_ring[RTWN_VI_QUEUE].map->dm_segs[0].ds_addr);
+ rtwn_pci_write_4(sc, R92C_VOQ_DESA,
+ sc->tx_ring[RTWN_VO_QUEUE].map->dm_segs[0].ds_addr);
+ rtwn_pci_write_4(sc, R92C_BCNQ_DESA,
+ sc->tx_ring[RTWN_BEACON_QUEUE].map->dm_segs[0].ds_addr);
+ rtwn_pci_write_4(sc, R92C_MGQ_DESA,
+ sc->tx_ring[RTWN_MGNT_QUEUE].map->dm_segs[0].ds_addr);
+ rtwn_pci_write_4(sc, R92C_HQ_DESA,
+ sc->tx_ring[RTWN_HIGH_QUEUE].map->dm_segs[0].ds_addr);
+
+ /* Configure Rx DMA. */
+ rtwn_pci_write_4(sc, R92C_RX_DESA, sc->rx_ring.map->dm_segs[0].ds_addr);
+
+ return (0);
+}
+
+void
+rtwn_enable_intr(void *cookie)
+{
+ struct rtwn_pci_softc *sc = cookie;
+
+ /* CLear pending interrupts. */
+ rtwn_pci_write_4(sc, R92C_HISR, 0xffffffff);
+
+ /* Enable interrupts. */
+ rtwn_pci_write_4(sc, R92C_HIMR, RTWN_INT_ENABLE);
+}
+
+void
+rtwn_disable_intr(void *cookie)
+{
+ struct rtwn_pci_softc *sc = cookie;
+
+ /* Disable interrupts. */
+ rtwn_pci_write_4(sc, R92C_HISR, 0x00000000);
+ rtwn_pci_write_4(sc, R92C_HIMR, 0x00000000);
+}