summaryrefslogtreecommitdiffstats
path: root/sys/dev/iwn
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2015-08-17 13:55:50 -0300
committerRenato Botelho <renato@netgate.com>2015-08-17 13:55:50 -0300
commit6ee75bdd7bf7c20359dd6e38c243586cb062edea (patch)
tree2a1f5febde659ebdcabbb46159fce1457b3dc98a /sys/dev/iwn
parent924a927559577e9cea5abf4a725e679acad834bf (diff)
downloadFreeBSD-src-6ee75bdd7bf7c20359dd6e38c243586cb062edea.zip
FreeBSD-src-6ee75bdd7bf7c20359dd6e38c243586cb062edea.tar.gz
Importing pfSense patches net80211HEAD.tgz and conf.file.ieee80211.diff
Diffstat (limited to 'sys/dev/iwn')
-rw-r--r--sys/dev/iwn/if_iwn.c2094
-rw-r--r--sys/dev/iwn/if_iwn_chip_cfg.h413
-rw-r--r--sys/dev/iwn/if_iwn_debug.h123
-rw-r--r--sys/dev/iwn/if_iwn_devid.h39
-rw-r--r--sys/dev/iwn/if_iwn_ioctl.h25
-rw-r--r--sys/dev/iwn/if_iwnreg.h326
-rw-r--r--sys/dev/iwn/if_iwnvar.h36
7 files changed, 2616 insertions, 440 deletions
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index 806a408..ab98204 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -1,11 +1,10 @@
/*-
- * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr>
- * Copyright (c) 2011 Intel Corporation
- * Copyright (c) 2007-2009
- * Damien Bergamini <damien.bergamini@free.fr>
- * Copyright (c) 2008
- * Benjamin Close <benjsc@FreeBSD.org>
+ * Copyright (c) 2007-2009 Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2008 Benjamin Close <benjsc@FreeBSD.org>
* Copyright (c) 2008 Sam Leffler, Errno Consulting
+ * Copyright (c) 2011 Intel Corporation
+ * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr>
+ * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -57,6 +56,7 @@ __FBSDID("$FreeBSD$");
#include <net/bpf.h>
#include <net/if.h>
+#include <net/if_var.h>
#include <net/if_arp.h>
#include <net/ethernet.h>
#include <net/if_dl.h>
@@ -77,6 +77,9 @@ __FBSDID("$FreeBSD$");
#include <dev/iwn/if_iwnreg.h>
#include <dev/iwn/if_iwnvar.h>
#include <dev/iwn/if_iwn_devid.h>
+#include <dev/iwn/if_iwn_chip_cfg.h>
+#include <dev/iwn/if_iwn_debug.h>
+#include <dev/iwn/if_iwn_ioctl.h>
struct iwn_ident {
uint16_t vendor;
@@ -97,12 +100,19 @@ static const struct iwn_ident iwn_ident_table[] = {
{ 0x8086, IWN_DID_x030_4, "Intel Centrino Advanced-N 6230" },
{ 0x8086, IWN_DID_6150_1, "Intel Centrino Wireless-N + WiMAX 6150" },
{ 0x8086, IWN_DID_6150_2, "Intel Centrino Wireless-N + WiMAX 6150" },
+ { 0x8086, IWN_DID_2x00_1, "Intel(R) Centrino(R) Wireless-N 2200 BGN" },
+ { 0x8086, IWN_DID_2x00_2, "Intel(R) Centrino(R) Wireless-N 2200 BGN" },
+ /* XXX 2200D is IWN_SDID_2x00_4; there's no way to express this here! */
{ 0x8086, IWN_DID_2x30_1, "Intel Centrino Wireless-N 2230" },
{ 0x8086, IWN_DID_2x30_2, "Intel Centrino Wireless-N 2230" },
{ 0x8086, IWN_DID_130_1, "Intel Centrino Wireless-N 130" },
{ 0x8086, IWN_DID_130_2, "Intel Centrino Wireless-N 130" },
{ 0x8086, IWN_DID_100_1, "Intel Centrino Wireless-N 100" },
{ 0x8086, IWN_DID_100_2, "Intel Centrino Wireless-N 100" },
+ { 0x8086, IWN_DID_105_1, "Intel Centrino Wireless-N 105" },
+ { 0x8086, IWN_DID_105_2, "Intel Centrino Wireless-N 105" },
+ { 0x8086, IWN_DID_135_1, "Intel Centrino Wireless-N 135" },
+ { 0x8086, IWN_DID_135_2, "Intel Centrino Wireless-N 135" },
{ 0x8086, IWN_DID_4965_1, "Intel Wireless WiFi Link 4965" },
{ 0x8086, IWN_DID_6x00_1, "Intel Centrino Ultimate-N 6300" },
{ 0x8086, IWN_DID_6x00_2, "Intel Centrino Advanced-N 6200" },
@@ -119,6 +129,8 @@ static const struct iwn_ident iwn_ident_table[] = {
{ 0x8086, IWN_DID_5x50_2, "Intel WiMAX/WiFi Link 5350" },
{ 0x8086, IWN_DID_5x50_3, "Intel WiMAX/WiFi Link 5150" },
{ 0x8086, IWN_DID_5x50_4, "Intel WiMAX/WiFi Link 5150" },
+ { 0x8086, IWN_DID_6035_1, "Intel Centrino Advanced 6235" },
+ { 0x8086, IWN_DID_6035_2, "Intel Centrino Advanced 6235" },
{ 0, 0, NULL }
};
@@ -126,6 +138,7 @@ static int iwn_probe(device_t);
static int iwn_attach(device_t);
static int iwn4965_attach(struct iwn_softc *, uint16_t);
static int iwn5000_attach(struct iwn_softc *, uint16_t);
+static int iwn_config_specific(struct iwn_softc *, uint16_t);
static void iwn_radiotap_attach(struct iwn_softc *);
static void iwn_sysctlattach(struct iwn_softc *);
static struct ieee80211vap *iwn_vap_create(struct ieee80211com *,
@@ -200,7 +213,7 @@ static void iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
struct iwn_rx_data *);
static void iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *, int,
uint8_t);
-static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, void *);
+static void iwn_ampdu_tx_done(struct iwn_softc *, int, int, int, int, void *);
static void iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
static void iwn_notif_intr(struct iwn_softc *);
static void iwn_wakeup_intr(struct iwn_softc *);
@@ -257,14 +270,17 @@ static int iwn4965_set_gains(struct iwn_softc *);
static int iwn5000_set_gains(struct iwn_softc *);
static void iwn_tune_sensitivity(struct iwn_softc *,
const struct iwn_rx_stats *);
+static void iwn_save_stats_counters(struct iwn_softc *,
+ const struct iwn_stats *);
static int iwn_send_sensitivity(struct iwn_softc *);
+static void iwn_check_rx_recovery(struct iwn_softc *, struct iwn_stats *);
static int iwn_set_pslevel(struct iwn_softc *, int, int, int);
static int iwn_send_btcoex(struct iwn_softc *);
static int iwn_send_advanced_btcoex(struct iwn_softc *);
static int iwn5000_runtime_calib(struct iwn_softc *);
static int iwn_config(struct iwn_softc *);
-static uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int);
-static int iwn_scan(struct iwn_softc *);
+static int iwn_scan(struct iwn_softc *, struct ieee80211vap *,
+ struct ieee80211_scan_state *, struct ieee80211_channel *);
static int iwn_auth(struct iwn_softc *, struct ieee80211vap *vap);
static int iwn_run(struct iwn_softc *, struct ieee80211vap *vap);
static int iwn_ampdu_rx_start(struct ieee80211_node *,
@@ -292,6 +308,7 @@ static int iwn5000_send_calibration(struct iwn_softc *);
static int iwn5000_send_wimax_coex(struct iwn_softc *);
static int iwn5000_crystal_calib(struct iwn_softc *);
static int iwn5000_temp_offset_calib(struct iwn_softc *);
+static int iwn5000_temp_offset_calibv2(struct iwn_softc *);
static int iwn4965_post_alive(struct iwn_softc *);
static int iwn5000_post_alive(struct iwn_softc *);
static int iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *,
@@ -316,6 +333,7 @@ static int iwn_hw_init(struct iwn_softc *);
static void iwn_hw_stop(struct iwn_softc *);
static void iwn_radio_on(void *, int);
static void iwn_radio_off(void *, int);
+static void iwn_panicked(void *, int);
static void iwn_init_locked(struct iwn_softc *);
static void iwn_init(void *);
static void iwn_stop_locked(struct iwn_softc *);
@@ -331,80 +349,6 @@ static char *iwn_get_csr_string(int);
static void iwn_debug_register(struct iwn_softc *);
#endif
-#ifdef IWN_DEBUG
-enum {
- IWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
- IWN_DEBUG_RECV = 0x00000002, /* basic recv operation */
- IWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */
- IWN_DEBUG_TXPOW = 0x00000008, /* tx power processing */
- IWN_DEBUG_RESET = 0x00000010, /* reset processing */
- IWN_DEBUG_OPS = 0x00000020, /* iwn_ops processing */
- IWN_DEBUG_BEACON = 0x00000040, /* beacon handling */
- IWN_DEBUG_WATCHDOG = 0x00000080, /* watchdog timeout */
- IWN_DEBUG_INTR = 0x00000100, /* ISR */
- IWN_DEBUG_CALIBRATE = 0x00000200, /* periodic calibration */
- IWN_DEBUG_NODE = 0x00000400, /* node management */
- IWN_DEBUG_LED = 0x00000800, /* led management */
- IWN_DEBUG_CMD = 0x00001000, /* cmd submission */
- IWN_DEBUG_TXRATE = 0x00002000, /* TX rate debugging */
- IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */
- IWN_DEBUG_REGISTER = 0x20000000, /* print chipset register */
- IWN_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */
- IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */
- IWN_DEBUG_ANY = 0xffffffff
-};
-
-#define DPRINTF(sc, m, fmt, ...) do { \
- if (sc->sc_debug & (m)) \
- printf(fmt, __VA_ARGS__); \
-} while (0)
-
-static const char *
-iwn_intr_str(uint8_t cmd)
-{
- switch (cmd) {
- /* Notifications */
- case IWN_UC_READY: return "UC_READY";
- case IWN_ADD_NODE_DONE: return "ADD_NODE_DONE";
- case IWN_TX_DONE: return "TX_DONE";
- case IWN_START_SCAN: return "START_SCAN";
- case IWN_STOP_SCAN: return "STOP_SCAN";
- case IWN_RX_STATISTICS: return "RX_STATS";
- case IWN_BEACON_STATISTICS: return "BEACON_STATS";
- case IWN_STATE_CHANGED: return "STATE_CHANGED";
- case IWN_BEACON_MISSED: return "BEACON_MISSED";
- case IWN_RX_PHY: return "RX_PHY";
- case IWN_MPDU_RX_DONE: return "MPDU_RX_DONE";
- case IWN_RX_DONE: return "RX_DONE";
-
- /* Command Notifications */
- case IWN_CMD_RXON: return "IWN_CMD_RXON";
- case IWN_CMD_RXON_ASSOC: return "IWN_CMD_RXON_ASSOC";
- case IWN_CMD_EDCA_PARAMS: return "IWN_CMD_EDCA_PARAMS";
- case IWN_CMD_TIMING: return "IWN_CMD_TIMING";
- case IWN_CMD_LINK_QUALITY: return "IWN_CMD_LINK_QUALITY";
- case IWN_CMD_SET_LED: return "IWN_CMD_SET_LED";
- case IWN5000_CMD_WIMAX_COEX: return "IWN5000_CMD_WIMAX_COEX";
- case IWN5000_CMD_CALIB_CONFIG: return "IWN5000_CMD_CALIB_CONFIG";
- case IWN5000_CMD_CALIB_RESULT: return "IWN5000_CMD_CALIB_RESULT";
- case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE";
- case IWN_CMD_SET_POWER_MODE: return "IWN_CMD_SET_POWER_MODE";
- case IWN_CMD_SCAN: return "IWN_CMD_SCAN";
- case IWN_CMD_SCAN_RESULTS: return "IWN_CMD_SCAN_RESULTS";
- case IWN_CMD_TXPOWER: return "IWN_CMD_TXPOWER";
- case IWN_CMD_TXPOWER_DBM: return "IWN_CMD_TXPOWER_DBM";
- case IWN5000_CMD_TX_ANT_CONFIG: return "IWN5000_CMD_TX_ANT_CONFIG";
- case IWN_CMD_BT_COEX: return "IWN_CMD_BT_COEX";
- case IWN_CMD_SET_CRITICAL_TEMP: return "IWN_CMD_SET_CRITICAL_TEMP";
- case IWN_CMD_SET_SENSITIVITY: return "IWN_CMD_SET_SENSITIVITY";
- case IWN_CMD_PHY_CALIB: return "IWN_CMD_PHY_CALIB";
- }
- return "UNKNOWN INTR NOTIF/CMD";
-}
-#else
-#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
-#endif
-
static device_method_t iwn_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, iwn_probe),
@@ -448,6 +392,15 @@ iwn_probe(device_t dev)
}
static int
+iwn_is_3stream_device(struct iwn_softc *sc)
+{
+ /* XXX for now only 5300, until the 5350 can be tested */
+ if (sc->hw_type == IWN_HW_REV_TYPE_5300)
+ return (1);
+ return (0);
+}
+
+static int
iwn_attach(device_t dev)
{
struct iwn_softc *sc = (struct iwn_softc *)device_get_softc(dev);
@@ -515,6 +468,11 @@ iwn_attach(device_t dev)
sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> IWN_HW_REV_TYPE_SHIFT)
& IWN_HW_REV_TYPE_MASK;
sc->subdevice_id = pci_get_subdevice(dev);
+
+ /*
+ * 4965 versus 5000 and later have different methods.
+ * Let's set those up first.
+ */
if (sc->hw_type == IWN_HW_REV_TYPE_4965)
error = iwn4965_attach(sc, pci_get_device(dev));
else
@@ -525,6 +483,16 @@ iwn_attach(device_t dev)
goto fail;
}
+ /*
+ * Next, let's setup the various parameters of each NIC.
+ */
+ error = iwn_config_specific(sc, pci_get_device(dev));
+ if (error != 0) {
+ device_printf(dev, "could not attach device, error %d\n",
+ error);
+ goto fail;
+ }
+
if ((error = iwn_hw_prepare(sc)) != 0) {
device_printf(dev, "hardware not ready, error %d\n", error);
goto fail;
@@ -634,17 +602,16 @@ iwn_attach(device_t dev)
ic->ic_txstream = sc->ntxchains;
/*
- * The NICs we currently support cap out at 2x2 support
- * separate from the chains being used.
- *
- * This is a total hack to work around that until some
- * per-device method is implemented to return the
- * actual stream support.
+ * Some of the 3 antenna devices (ie, the 4965) only supports
+ * 2x2 operation. So correct the number of streams if
+ * it's not a 3-stream device.
*/
- if (ic->ic_rxstream > 2)
- ic->ic_rxstream = 2;
- if (ic->ic_txstream > 2)
- ic->ic_txstream = 2;
+ if (! iwn_is_3stream_device(sc)) {
+ if (ic->ic_rxstream > 2)
+ ic->ic_rxstream = 2;
+ if (ic->ic_txstream > 2)
+ ic->ic_txstream = 2;
+ }
ic->ic_htcaps =
IEEE80211_HTCAP_SMPS_OFF /* SMPS mode disabled */
@@ -710,6 +677,15 @@ iwn_attach(device_t dev)
TASK_INIT(&sc->sc_reinit_task, 0, iwn_hw_reset, sc);
TASK_INIT(&sc->sc_radioon_task, 0, iwn_radio_on, sc);
TASK_INIT(&sc->sc_radiooff_task, 0, iwn_radio_off, sc);
+ TASK_INIT(&sc->sc_panic_task, 0, iwn_panicked, sc);
+
+ sc->sc_tq = taskqueue_create("iwn_taskq", M_WAITOK,
+ taskqueue_thread_enqueue, &sc->sc_tq);
+ error = taskqueue_start_threads(&sc->sc_tq, 1, 0, "iwn_taskq");
+ if (error != 0) {
+ device_printf(dev, "can't start threads, error %d\n", error);
+ goto fail;
+ }
iwn_sysctlattach(sc);
@@ -724,6 +700,13 @@ iwn_attach(device_t dev)
goto fail;
}
+#if 0
+ device_printf(sc->sc_dev, "%s: rx_stats=%d, rx_stats_bt=%d\n",
+ __func__,
+ sizeof(struct iwn_stats),
+ sizeof(struct iwn_stats_bt));
+#endif
+
if (bootverbose)
ieee80211_announce(ic);
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
@@ -734,6 +717,488 @@ fail:
return error;
}
+/*
+ * Define specific configuration based on device id and subdevice id
+ * pid : PCI device id
+ */
+static int
+iwn_config_specific(struct iwn_softc *sc, uint16_t pid)
+{
+
+ switch (pid) {
+/* 4965 series */
+ case IWN_DID_4965_1:
+ case IWN_DID_4965_2:
+ case IWN_DID_4965_3:
+ case IWN_DID_4965_4:
+ sc->base_params = &iwn4965_base_params;
+ sc->limits = &iwn4965_sensitivity_limits;
+ sc->fwname = "iwn4965fw";
+ /* Override chains masks, ROM is known to be broken. */
+ sc->txchainmask = IWN_ANT_AB;
+ sc->rxchainmask = IWN_ANT_ABC;
+ /* Enable normal btcoex */
+ sc->sc_flags |= IWN_FLAG_BTCOEX;
+ break;
+/* 1000 Series */
+ case IWN_DID_1000_1:
+ case IWN_DID_1000_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_1000_1:
+ case IWN_SDID_1000_2:
+ case IWN_SDID_1000_3:
+ case IWN_SDID_1000_4:
+ case IWN_SDID_1000_5:
+ case IWN_SDID_1000_6:
+ case IWN_SDID_1000_7:
+ case IWN_SDID_1000_8:
+ case IWN_SDID_1000_9:
+ case IWN_SDID_1000_10:
+ case IWN_SDID_1000_11:
+ case IWN_SDID_1000_12:
+ sc->limits = &iwn1000_sensitivity_limits;
+ sc->base_params = &iwn1000_base_params;
+ sc->fwname = "iwn1000fw";
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 6x00 Series */
+ case IWN_DID_6x00_2:
+ case IWN_DID_6x00_4:
+ case IWN_DID_6x00_1:
+ case IWN_DID_6x00_3:
+ sc->fwname = "iwn6000fw";
+ sc->limits = &iwn6000_sensitivity_limits;
+ switch(sc->subdevice_id) {
+ case IWN_SDID_6x00_1:
+ case IWN_SDID_6x00_2:
+ case IWN_SDID_6x00_8:
+ //iwl6000_3agn_cfg
+ sc->base_params = &iwn_6000_base_params;
+ break;
+ case IWN_SDID_6x00_3:
+ case IWN_SDID_6x00_6:
+ case IWN_SDID_6x00_9:
+ ////iwl6000i_2agn
+ case IWN_SDID_6x00_4:
+ case IWN_SDID_6x00_7:
+ case IWN_SDID_6x00_10:
+ //iwl6000i_2abg_cfg
+ case IWN_SDID_6x00_5:
+ //iwl6000i_2bg_cfg
+ sc->base_params = &iwn_6000i_base_params;
+ sc->sc_flags |= IWN_FLAG_INTERNAL_PA;
+ sc->txchainmask = IWN_ANT_BC;
+ sc->rxchainmask = IWN_ANT_BC;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 6x05 Series */
+ case IWN_DID_6x05_1:
+ case IWN_DID_6x05_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_6x05_1:
+ case IWN_SDID_6x05_4:
+ case IWN_SDID_6x05_6:
+ //iwl6005_2agn_cfg
+ case IWN_SDID_6x05_2:
+ case IWN_SDID_6x05_5:
+ case IWN_SDID_6x05_7:
+ //iwl6005_2abg_cfg
+ case IWN_SDID_6x05_3:
+ //iwl6005_2bg_cfg
+ case IWN_SDID_6x05_8:
+ case IWN_SDID_6x05_9:
+ //iwl6005_2agn_sff_cfg
+ case IWN_SDID_6x05_10:
+ //iwl6005_2agn_d_cfg
+ case IWN_SDID_6x05_11:
+ //iwl6005_2agn_mow1_cfg
+ case IWN_SDID_6x05_12:
+ //iwl6005_2agn_mow2_cfg
+ sc->fwname = "iwn6000g2afw";
+ sc->limits = &iwn6000_sensitivity_limits;
+ sc->base_params = &iwn_6000g2_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 6x35 Series */
+ case IWN_DID_6035_1:
+ case IWN_DID_6035_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_6035_1:
+ case IWN_SDID_6035_2:
+ case IWN_SDID_6035_3:
+ case IWN_SDID_6035_4:
+ sc->fwname = "iwn6000g2bfw";
+ sc->limits = &iwn6235_sensitivity_limits;
+ sc->base_params = &iwn_6235_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 6x50 WiFi/WiMax Series */
+ case IWN_DID_6050_1:
+ case IWN_DID_6050_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_6050_1:
+ case IWN_SDID_6050_3:
+ case IWN_SDID_6050_5:
+ //iwl6050_2agn_cfg
+ case IWN_SDID_6050_2:
+ case IWN_SDID_6050_4:
+ case IWN_SDID_6050_6:
+ //iwl6050_2abg_cfg
+ sc->fwname = "iwn6050fw";
+ sc->txchainmask = IWN_ANT_AB;
+ sc->rxchainmask = IWN_ANT_AB;
+ sc->limits = &iwn6000_sensitivity_limits;
+ sc->base_params = &iwn_6050_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 6150 WiFi/WiMax Series */
+ case IWN_DID_6150_1:
+ case IWN_DID_6150_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_6150_1:
+ case IWN_SDID_6150_3:
+ case IWN_SDID_6150_5:
+ // iwl6150_bgn_cfg
+ case IWN_SDID_6150_2:
+ case IWN_SDID_6150_4:
+ case IWN_SDID_6150_6:
+ //iwl6150_bg_cfg
+ sc->fwname = "iwn6050fw";
+ sc->limits = &iwn6000_sensitivity_limits;
+ sc->base_params = &iwn_6150_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 6030 Series and 1030 Series */
+ case IWN_DID_x030_1:
+ case IWN_DID_x030_2:
+ case IWN_DID_x030_3:
+ case IWN_DID_x030_4:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_x030_1:
+ case IWN_SDID_x030_3:
+ case IWN_SDID_x030_5:
+ // iwl1030_bgn_cfg
+ case IWN_SDID_x030_2:
+ case IWN_SDID_x030_4:
+ case IWN_SDID_x030_6:
+ //iwl1030_bg_cfg
+ case IWN_SDID_x030_7:
+ case IWN_SDID_x030_10:
+ case IWN_SDID_x030_14:
+ //iwl6030_2agn_cfg
+ case IWN_SDID_x030_8:
+ case IWN_SDID_x030_11:
+ case IWN_SDID_x030_15:
+ // iwl6030_2bgn_cfg
+ case IWN_SDID_x030_9:
+ case IWN_SDID_x030_12:
+ case IWN_SDID_x030_16:
+ // iwl6030_2abg_cfg
+ case IWN_SDID_x030_13:
+ //iwl6030_2bg_cfg
+ sc->fwname = "iwn6000g2bfw";
+ sc->limits = &iwn6000_sensitivity_limits;
+ sc->base_params = &iwn_6000g2b_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 130 Series WiFi */
+/* XXX: This series will need adjustment for rate.
+ * see rx_with_siso_diversity in linux kernel
+ */
+ case IWN_DID_130_1:
+ case IWN_DID_130_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_130_1:
+ case IWN_SDID_130_3:
+ case IWN_SDID_130_5:
+ //iwl130_bgn_cfg
+ case IWN_SDID_130_2:
+ case IWN_SDID_130_4:
+ case IWN_SDID_130_6:
+ //iwl130_bg_cfg
+ sc->fwname = "iwn6000g2bfw";
+ sc->limits = &iwn6000_sensitivity_limits;
+ sc->base_params = &iwn_6000g2b_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 100 Series WiFi */
+ case IWN_DID_100_1:
+ case IWN_DID_100_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_100_1:
+ case IWN_SDID_100_2:
+ case IWN_SDID_100_3:
+ case IWN_SDID_100_4:
+ case IWN_SDID_100_5:
+ case IWN_SDID_100_6:
+ sc->limits = &iwn1000_sensitivity_limits;
+ sc->base_params = &iwn1000_base_params;
+ sc->fwname = "iwn100fw";
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+
+/* 105 Series */
+/* XXX: This series will need adjustment for rate.
+ * see rx_with_siso_diversity in linux kernel
+ */
+ case IWN_DID_105_1:
+ case IWN_DID_105_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_105_1:
+ case IWN_SDID_105_2:
+ case IWN_SDID_105_3:
+ //iwl105_bgn_cfg
+ case IWN_SDID_105_4:
+ //iwl105_bgn_d_cfg
+ sc->limits = &iwn2030_sensitivity_limits;
+ sc->base_params = &iwn2000_base_params;
+ sc->fwname = "iwn105fw";
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+
+/* 135 Series */
+/* XXX: This series will need adjustment for rate.
+ * see rx_with_siso_diversity in linux kernel
+ */
+ case IWN_DID_135_1:
+ case IWN_DID_135_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_135_1:
+ case IWN_SDID_135_2:
+ case IWN_SDID_135_3:
+ sc->limits = &iwn2030_sensitivity_limits;
+ sc->base_params = &iwn2030_base_params;
+ sc->fwname = "iwn135fw";
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+
+/* 2x00 Series */
+ case IWN_DID_2x00_1:
+ case IWN_DID_2x00_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_2x00_1:
+ case IWN_SDID_2x00_2:
+ case IWN_SDID_2x00_3:
+ //iwl2000_2bgn_cfg
+ case IWN_SDID_2x00_4:
+ //iwl2000_2bgn_d_cfg
+ sc->limits = &iwn2030_sensitivity_limits;
+ sc->base_params = &iwn2000_base_params;
+ sc->fwname = "iwn2000fw";
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice) \n",
+ pid, sc->subdevice_id, sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 2x30 Series */
+ case IWN_DID_2x30_1:
+ case IWN_DID_2x30_2:
+ switch(sc->subdevice_id) {
+ case IWN_SDID_2x30_1:
+ case IWN_SDID_2x30_3:
+ case IWN_SDID_2x30_5:
+ //iwl100_bgn_cfg
+ case IWN_SDID_2x30_2:
+ case IWN_SDID_2x30_4:
+ case IWN_SDID_2x30_6:
+ //iwl100_bg_cfg
+ sc->limits = &iwn2030_sensitivity_limits;
+ sc->base_params = &iwn2030_base_params;
+ sc->fwname = "iwn2030fw";
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 5x00 Series */
+ case IWN_DID_5x00_1:
+ case IWN_DID_5x00_2:
+ case IWN_DID_5x00_3:
+ case IWN_DID_5x00_4:
+ sc->limits = &iwn5000_sensitivity_limits;
+ sc->base_params = &iwn5000_base_params;
+ sc->fwname = "iwn5000fw";
+ switch(sc->subdevice_id) {
+ case IWN_SDID_5x00_1:
+ case IWN_SDID_5x00_2:
+ case IWN_SDID_5x00_3:
+ case IWN_SDID_5x00_4:
+ case IWN_SDID_5x00_9:
+ case IWN_SDID_5x00_10:
+ case IWN_SDID_5x00_11:
+ case IWN_SDID_5x00_12:
+ case IWN_SDID_5x00_17:
+ case IWN_SDID_5x00_18:
+ case IWN_SDID_5x00_19:
+ case IWN_SDID_5x00_20:
+ //iwl5100_agn_cfg
+ sc->txchainmask = IWN_ANT_B;
+ sc->rxchainmask = IWN_ANT_AB;
+ break;
+ case IWN_SDID_5x00_5:
+ case IWN_SDID_5x00_6:
+ case IWN_SDID_5x00_13:
+ case IWN_SDID_5x00_14:
+ case IWN_SDID_5x00_21:
+ case IWN_SDID_5x00_22:
+ //iwl5100_bgn_cfg
+ sc->txchainmask = IWN_ANT_B;
+ sc->rxchainmask = IWN_ANT_AB;
+ break;
+ case IWN_SDID_5x00_7:
+ case IWN_SDID_5x00_8:
+ case IWN_SDID_5x00_15:
+ case IWN_SDID_5x00_16:
+ case IWN_SDID_5x00_23:
+ case IWN_SDID_5x00_24:
+ //iwl5100_abg_cfg
+ sc->txchainmask = IWN_ANT_B;
+ sc->rxchainmask = IWN_ANT_AB;
+ break;
+ case IWN_SDID_5x00_25:
+ case IWN_SDID_5x00_26:
+ case IWN_SDID_5x00_27:
+ case IWN_SDID_5x00_28:
+ case IWN_SDID_5x00_29:
+ case IWN_SDID_5x00_30:
+ case IWN_SDID_5x00_31:
+ case IWN_SDID_5x00_32:
+ case IWN_SDID_5x00_33:
+ case IWN_SDID_5x00_34:
+ case IWN_SDID_5x00_35:
+ case IWN_SDID_5x00_36:
+ //iwl5300_agn_cfg
+ sc->txchainmask = IWN_ANT_ABC;
+ sc->rxchainmask = IWN_ANT_ABC;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+/* 5x50 Series */
+ case IWN_DID_5x50_1:
+ case IWN_DID_5x50_2:
+ case IWN_DID_5x50_3:
+ case IWN_DID_5x50_4:
+ sc->limits = &iwn5000_sensitivity_limits;
+ sc->base_params = &iwn5000_base_params;
+ sc->fwname = "iwn5000fw";
+ switch(sc->subdevice_id) {
+ case IWN_SDID_5x50_1:
+ case IWN_SDID_5x50_2:
+ case IWN_SDID_5x50_3:
+ //iwl5350_agn_cfg
+ sc->limits = &iwn5000_sensitivity_limits;
+ sc->base_params = &iwn5000_base_params;
+ sc->fwname = "iwn5000fw";
+ break;
+ case IWN_SDID_5x50_4:
+ case IWN_SDID_5x50_5:
+ case IWN_SDID_5x50_8:
+ case IWN_SDID_5x50_9:
+ case IWN_SDID_5x50_10:
+ case IWN_SDID_5x50_11:
+ //iwl5150_agn_cfg
+ case IWN_SDID_5x50_6:
+ case IWN_SDID_5x50_7:
+ case IWN_SDID_5x50_12:
+ case IWN_SDID_5x50_13:
+ //iwl5150_abg_cfg
+ sc->limits = &iwn5000_sensitivity_limits;
+ sc->fwname = "iwn5150fw";
+ sc->base_params = &iwn_5x50_base_params;
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id :"
+ "0x%04x rev %d not supported (subdevice)\n", pid,
+ sc->subdevice_id,sc->hw_type);
+ return ENOTSUP;
+ }
+ break;
+ default:
+ device_printf(sc->sc_dev, "adapter type id : 0x%04x sub id : 0x%04x"
+ "rev 0x%08x not supported (device)\n", pid, sc->subdevice_id,
+ sc->hw_type);
+ return ENOTSUP;
+ }
+ return 0;
+}
+
static int
iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
{
@@ -769,6 +1234,8 @@ iwn4965_attach(struct iwn_softc *sc, uint16_t pid)
/* Override chains masks, ROM is known to be broken. */
sc->txchainmask = IWN_ANT_AB;
sc->rxchainmask = IWN_ANT_ABC;
+ /* Enable normal btcoex */
+ sc->sc_flags |= IWN_FLAG_BTCOEX;
DPRINTF(sc, IWN_DEBUG_TRACE, "%s: end\n",__func__);
@@ -809,58 +1276,6 @@ iwn5000_attach(struct iwn_softc *sc, uint16_t pid)
sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN;
sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN;
- switch (sc->hw_type) {
- case IWN_HW_REV_TYPE_5100:
- sc->limits = &iwn5000_sensitivity_limits;
- sc->fwname = "iwn5000fw";
- /* Override chains masks, ROM is known to be broken. */
- sc->txchainmask = IWN_ANT_B;
- sc->rxchainmask = IWN_ANT_AB;
- break;
- case IWN_HW_REV_TYPE_5150:
- sc->limits = &iwn5150_sensitivity_limits;
- sc->fwname = "iwn5150fw";
- break;
- case IWN_HW_REV_TYPE_5300:
- case IWN_HW_REV_TYPE_5350:
- sc->limits = &iwn5000_sensitivity_limits;
- sc->fwname = "iwn5000fw";
- break;
- case IWN_HW_REV_TYPE_1000:
- sc->limits = &iwn1000_sensitivity_limits;
- sc->fwname = "iwn1000fw";
- break;
- case IWN_HW_REV_TYPE_6000:
- sc->limits = &iwn6000_sensitivity_limits;
- sc->fwname = "iwn6000fw";
- if (pid == 0x422c || pid == 0x4239) {
- sc->sc_flags |= IWN_FLAG_INTERNAL_PA;
- /* Override chains masks, ROM is known to be broken. */
- sc->txchainmask = IWN_ANT_BC;
- sc->rxchainmask = IWN_ANT_BC;
- }
- break;
- case IWN_HW_REV_TYPE_6050:
- sc->limits = &iwn6000_sensitivity_limits;
- sc->fwname = "iwn6050fw";
- /* Override chains masks, ROM is known to be broken. */
- sc->txchainmask = IWN_ANT_AB;
- sc->rxchainmask = IWN_ANT_AB;
- break;
- case IWN_HW_REV_TYPE_6005:
- sc->limits = &iwn6000_sensitivity_limits;
- if (pid != 0x0082 && pid != 0x0085) {
- sc->fwname = "iwn6000g2bfw";
- sc->sc_flags |= IWN_FLAG_ADV_BTCOEX;
- } else
- sc->fwname = "iwn6000g2afw";
- break;
- default:
- device_printf(sc->sc_dev, "adapter type %d not supported\n",
- sc->hw_type);
- DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end in error\n",__func__);
- return ENOTSUP;
- }
return 0;
}
@@ -959,6 +1374,10 @@ iwn_detach(device_t dev)
ieee80211_draintask(ic, &sc->sc_radiooff_task);
iwn_stop(sc);
+
+ taskqueue_drain_all(sc->sc_tq);
+ taskqueue_free(sc->sc_tq);
+
callout_drain(&sc->watchdog_to);
callout_drain(&sc->calib_to);
ieee80211_ifdetach(ic);
@@ -1184,7 +1603,7 @@ iwn_init_otprom(struct iwn_softc *sc)
iwn_nic_unlock(sc);
/* Set auto clock gate disable bit for HW with OTP shadow RAM. */
- if (sc->hw_type != IWN_HW_REV_TYPE_1000) {
+ if (sc->base_params->shadow_ram_support) {
IWN_SETBITS(sc, IWN_DBG_LINK_PWR_MGMT,
IWN_RESET_LINK_PWR_MGMT_DIS);
}
@@ -1197,11 +1616,12 @@ iwn_init_otprom(struct iwn_softc *sc)
* Find the block before last block (contains the EEPROM image)
* for HW without OTP shadow RAM.
*/
- if (sc->hw_type == IWN_HW_REV_TYPE_1000) {
+ if (! sc->base_params->shadow_ram_support) {
/* Switch to absolute addressing mode. */
IWN_CLRBITS(sc, IWN_OTP_GP, IWN_OTP_GP_RELATIVE_ACCESS);
base = prev = 0;
- for (count = 0; count < IWN1000_OTP_NBLOCKS; count++) {
+ for (count = 0; count < sc->base_params->max_ll_items;
+ count++) {
error = iwn_read_prom_data(sc, base, &next, 2);
if (error != 0)
return error;
@@ -1210,7 +1630,7 @@ iwn_init_otprom(struct iwn_softc *sc)
prev = base;
base = le16toh(next);
}
- if (count == 0 || count == IWN1000_OTP_NBLOCKS)
+ if (count == 0 || count == sc->base_params->max_ll_items)
return EIO;
/* Skip "next" word. */
sc->prom_base = prev + 1;
@@ -1316,16 +1736,12 @@ fail: iwn_dma_contig_free(dma);
static void
iwn_dma_contig_free(struct iwn_dma_info *dma)
{
- if (dma->map != NULL) {
- if (dma->vaddr != NULL) {
- bus_dmamap_sync(dma->tag, dma->map,
- BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
- bus_dmamap_unload(dma->tag, dma->map);
- bus_dmamem_free(dma->tag, dma->vaddr, dma->map);
- dma->vaddr = NULL;
- }
- bus_dmamap_destroy(dma->tag, dma->map);
- dma->map = NULL;
+ if (dma->vaddr != NULL) {
+ bus_dmamap_sync(dma->tag, dma->map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(dma->tag, dma->map);
+ bus_dmamem_free(dma->tag, dma->vaddr, dma->map);
+ dma->vaddr = NULL;
}
if (dma->tag != NULL) {
bus_dma_tag_destroy(dma->tag);
@@ -1459,7 +1875,7 @@ iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring)
&paddr, BUS_DMA_NOWAIT);
if (error != 0 && error != EFBIG) {
device_printf(sc->sc_dev,
- "%s: can't not map mbuf, error %d\n", __func__,
+ "%s: can't map mbuf, error %d\n", __func__,
error);
goto fail;
}
@@ -1620,6 +2036,10 @@ iwn_reset_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring)
m_freem(data->m);
data->m = NULL;
}
+ if (data->ni != NULL) {
+ ieee80211_free_node(data->ni);
+ data->ni = NULL;
+ }
}
/* Clear TX descriptors. */
memset(ring->desc, 0, ring->desc_dma.size);
@@ -1768,7 +2188,7 @@ iwn4965_read_eeprom(struct iwn_softc *sc)
iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4);
/* Read the list of authorized channels (20MHz ones only). */
- for (i = 0; i < 7; i++) {
+ for (i = 0; i < IWN_NBANDS - 1; i++) {
addr = iwn4965_regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
@@ -1798,7 +2218,7 @@ iwn4965_read_eeprom(struct iwn_softc *sc)
#ifdef IWN_DEBUG
/* Print samples. */
if (sc->sc_debug & IWN_DEBUG_ANY) {
- for (i = 0; i < IWN_NBANDS; i++)
+ for (i = 0; i < IWN_NBANDS - 1; i++)
iwn4965_print_power_group(sc, i);
}
#endif
@@ -1859,16 +2279,13 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
sc->eeprom_domain, 4);
/* Read the list of authorized channels (20MHz ones only). */
- for (i = 0; i < 7; i++) {
- if (sc->hw_type >= IWN_HW_REV_TYPE_6000)
- addr = base + iwn6000_regulatory_bands[i];
- else
- addr = base + iwn5000_regulatory_bands[i];
+ for (i = 0; i < IWN_NBANDS - 1; i++) {
+ addr = base + sc->base_params->regulatory_bands[i];
iwn_read_eeprom_channels(sc, i, addr);
}
/* Read enhanced TX power information for 6000 Series. */
- if (sc->hw_type >= IWN_HW_REV_TYPE_6000)
+ if (sc->base_params->enhanced_TX_power)
iwn_read_eeprom_enhinfo(sc);
iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2);
@@ -1879,6 +2296,14 @@ iwn5000_read_eeprom(struct iwn_softc *sc)
hdr.version, hdr.pa_type, le16toh(hdr.volt));
sc->calib_ver = hdr.version;
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2) {
+ sc->eeprom_voltage = le16toh(hdr.volt);
+ iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
+ sc->eeprom_temp_high=le16toh(val);
+ iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2);
+ sc->eeprom_temp = le16toh(val);
+ }
+
if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
/* Compute temperature offset. */
iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
@@ -2215,6 +2640,52 @@ rate2plcp(int rate)
return 0;
}
+static int
+iwn_get_1stream_tx_antmask(struct iwn_softc *sc)
+{
+
+ return IWN_LSB(sc->txchainmask);
+}
+
+static int
+iwn_get_2stream_tx_antmask(struct iwn_softc *sc)
+{
+ int tx;
+
+ /*
+ * The '2 stream' setup is a bit .. odd.
+ *
+ * For NICs that support only 1 antenna, default to IWN_ANT_AB or
+ * the firmware panics (eg Intel 5100.)
+ *
+ * For NICs that support two antennas, we use ANT_AB.
+ *
+ * For NICs that support three antennas, we use the two that
+ * wasn't the default one.
+ *
+ * XXX TODO: if bluetooth (full concurrent) is enabled, restrict
+ * this to only one antenna.
+ */
+
+ /* Default - transmit on the other antennas */
+ tx = (sc->txchainmask & ~IWN_LSB(sc->txchainmask));
+
+ /* Now, if it's zero, set it to IWN_ANT_AB, so to not panic firmware */
+ if (tx == 0)
+ tx = IWN_ANT_AB;
+
+ /*
+ * If the NIC is a two-stream TX NIC, configure the TX mask to
+ * the default chainmask
+ */
+ else if (sc->ntxchains == 2)
+ tx = sc->txchainmask;
+
+ return (tx);
+}
+
+
+
/*
* Calculate the required PLCP value from the given rate,
* to the given node.
@@ -2228,19 +2699,14 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni,
{
#define RV(v) ((v) & IEEE80211_RATE_VAL)
struct ieee80211com *ic = ni->ni_ic;
- uint8_t txant1, txant2;
uint32_t plcp = 0;
int ridx;
- /* Use the first valid TX antenna. */
- txant1 = IWN_LSB(sc->txchainmask);
- txant2 = IWN_LSB(sc->txchainmask & ~txant1);
-
/*
* If it's an MCS rate, let's set the plcp correctly
* and set the relevant flags based on the node config.
*/
- if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
+ if (rate & IEEE80211_RATE_MCS) {
/*
* Set the initial PLCP value to be between 0->31 for
* MCS 0 -> MCS 31, then set the "I'm an MCS rate!"
@@ -2267,15 +2733,15 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni,
}
/*
- * If it's a two stream rate, enable TX on both
- * antennas.
- *
- * XXX three stream rates?
+ * Ensure the selected rate matches the link quality
+ * table entries being used.
*/
- if (rate > 0x87)
- plcp |= IWN_RFLAG_ANT(txant1 | txant2);
+ if (rate > 0x8f)
+ plcp |= IWN_RFLAG_ANT(sc->txchainmask);
+ else if (rate > 0x87)
+ plcp |= IWN_RFLAG_ANT(iwn_get_2stream_tx_antmask(sc));
else
- plcp |= IWN_RFLAG_ANT(txant1);
+ plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc));
} else {
/*
* Set the initial PLCP - fine for both
@@ -2297,7 +2763,8 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni,
plcp |= IWN_RFLAG_CCK;
/* Set antenna configuration */
- plcp |= IWN_RFLAG_ANT(txant1);
+ /* XXX TODO: is this the right antenna to use for legacy? */
+ plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc));
}
DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n",
@@ -2502,14 +2969,14 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) {
DPRINTF(sc, IWN_DEBUG_RECV, "%s: RX flags error %x\n",
__func__, flags);
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
return;
}
/* Discard frames that are too short. */
- if (len < sizeof (*wh)) {
+ if (len < sizeof (struct ieee80211_frame_ack)) {
DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too short: %d\n",
__func__, len);
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
return;
}
@@ -2517,7 +2984,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
if (m1 == NULL) {
DPRINTF(sc, IWN_DEBUG_ANY, "%s: no mbuf to restock ring\n",
__func__);
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
return;
}
bus_dmamap_unload(ring->data_dmat, data->map);
@@ -2540,7 +3007,7 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
ring->desc[ring->cur] = htole32(paddr >> 8);
bus_dmamap_sync(ring->data_dmat, ring->desc_dma.map,
BUS_DMASYNC_PREWRITE);
- ifp->if_ierrors++;
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
return;
}
@@ -2558,7 +3025,10 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
/* Grab a reference to the source node. */
wh = mtod(m, struct ieee80211_frame *);
- ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
+ if (len >= sizeof(struct ieee80211_frame_min))
+ ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
+ else
+ ni = NULL;
nf = (ni != NULL && ni->ni_vap->iv_state == IEEE80211_S_RUN &&
(ic->ic_flags & IEEE80211_F_SCAN) == 0) ? sc->noise : -95;
@@ -2629,8 +3099,9 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
uint16_t ssn;
uint8_t tid;
int ackfailcnt = 0, i, lastidx, qid, *res, shift;
+ int tx_ok = 0, tx_err = 0;
- DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+ DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s begin\n", __func__);
bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
@@ -2660,6 +3131,7 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
KASSERT(ni != NULL, ("no node"));
KASSERT(m != NULL, ("no mbuf"));
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m);
ieee80211_tx_complete(ni, m, 1);
txq->queued--;
@@ -2685,22 +3157,32 @@ iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
if (wn->agg[tid].nframes > (64 - shift))
return;
+ /*
+ * Walk the bitmap and calculate how many successful and failed
+ * attempts are made.
+ *
+ * Yes, the rate control code doesn't know these are A-MPDU
+ * subframes and that it's okay to fail some of these.
+ */
ni = tap->txa_ni;
bitmap = (le64toh(ba->bitmap) >> shift) & wn->agg[tid].bitmap;
for (i = 0; bitmap; i++) {
if ((bitmap & 1) == 0) {
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ tx_err ++;
ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL);
} else {
- ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+ tx_ok ++;
ieee80211_ratectl_tx_complete(ni->ni_vap, ni,
IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL);
}
bitmap >>= 1;
}
- DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
+ DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT,
+ "->%s: end; %d ok; %d err\n",__func__, tx_ok, tx_err);
}
@@ -2728,25 +3210,24 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
switch (calib->code) {
case IWN5000_PHY_CALIB_DC:
- if ((sc->sc_flags & IWN_FLAG_INTERNAL_PA) == 0 &&
- (sc->hw_type == IWN_HW_REV_TYPE_5150 ||
- sc->hw_type >= IWN_HW_REV_TYPE_6000) &&
- sc->hw_type != IWN_HW_REV_TYPE_6050)
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_DC)
idx = 0;
break;
case IWN5000_PHY_CALIB_LO:
- idx = 1;
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_LO)
+ idx = 1;
break;
case IWN5000_PHY_CALIB_TX_IQ:
- idx = 2;
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ)
+ idx = 2;
break;
case IWN5000_PHY_CALIB_TX_IQ_PERIODIC:
- if (sc->hw_type < IWN_HW_REV_TYPE_6000 &&
- sc->hw_type != IWN_HW_REV_TYPE_5150)
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC)
idx = 3;
break;
case IWN5000_PHY_CALIB_BASE_BAND:
- idx = 4;
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_BASE_BAND)
+ idx = 4;
break;
}
if (idx == -1) /* Ignore other results. */
@@ -2763,11 +3244,72 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
return;
}
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
- "saving calibration result code=%d len=%d\n", calib->code, len);
+ "saving calibration result idx=%d, code=%d len=%d\n", idx, calib->code, len);
sc->calibcmd[idx].len = len;
memcpy(sc->calibcmd[idx].buf, calib, len);
}
+static void
+iwn_stats_update(struct iwn_softc *sc, struct iwn_calib_state *calib,
+ struct iwn_stats *stats, int len)
+{
+ struct iwn_stats_bt *stats_bt;
+ struct iwn_stats *lstats;
+
+ /*
+ * First - check whether the length is the bluetooth or normal.
+ *
+ * If it's normal - just copy it and bump out.
+ * Otherwise we have to convert things.
+ */
+
+ if (len == sizeof(struct iwn_stats) + 4) {
+ memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats));
+ sc->last_stat_valid = 1;
+ return;
+ }
+
+ /*
+ * If it's not the bluetooth size - log, then just copy.
+ */
+ if (len != sizeof(struct iwn_stats_bt) + 4) {
+ DPRINTF(sc, IWN_DEBUG_STATS,
+ "%s: size of rx statistics (%d) not an expected size!\n",
+ __func__,
+ len);
+ memcpy(&sc->last_stat, stats, sizeof(struct iwn_stats));
+ sc->last_stat_valid = 1;
+ return;
+ }
+
+ /*
+ * Ok. Time to copy.
+ */
+ stats_bt = (struct iwn_stats_bt *) stats;
+ lstats = &sc->last_stat;
+
+ /* flags */
+ lstats->flags = stats_bt->flags;
+ /* rx_bt */
+ memcpy(&lstats->rx.ofdm, &stats_bt->rx_bt.ofdm,
+ sizeof(struct iwn_rx_phy_stats));
+ memcpy(&lstats->rx.cck, &stats_bt->rx_bt.cck,
+ sizeof(struct iwn_rx_phy_stats));
+ memcpy(&lstats->rx.general, &stats_bt->rx_bt.general_bt.common,
+ sizeof(struct iwn_rx_general_stats));
+ memcpy(&lstats->rx.ht, &stats_bt->rx_bt.ht,
+ sizeof(struct iwn_rx_ht_phy_stats));
+ /* tx */
+ memcpy(&lstats->tx, &stats_bt->tx,
+ sizeof(struct iwn_tx_stats));
+ /* general */
+ memcpy(&lstats->general, &stats_bt->general,
+ sizeof(struct iwn_general_stats));
+
+ /* XXX TODO: Squirrel away the extra bluetooth stats somewhere */
+ sc->last_stat_valid = 1;
+}
+
/*
* Process an RX_STATISTICS or BEACON_STATISTICS firmware notification.
* The latter is sent by the firmware after each received beacon.
@@ -2782,6 +3324,7 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
struct iwn_calib_state *calib = &sc->calib;
struct iwn_stats *stats = (struct iwn_stats *)(desc + 1);
+ struct iwn_stats *lstats;
int temp;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@@ -2796,12 +3339,26 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD);
- DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received statistics, cmd %d\n",
- __func__, desc->type);
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_STATS,
+ "%s: received statistics, cmd %d, len %d\n",
+ __func__, desc->type, le16toh(desc->len));
sc->calib_cnt = 0; /* Reset TX power calibration timeout. */
+ /*
+ * Collect/track general statistics for reporting.
+ *
+ * This takes care of ensuring that the bluetooth sized message
+ * will be correctly converted to the legacy sized message.
+ */
+ iwn_stats_update(sc, calib, stats, le16toh(desc->len));
+
+ /*
+ * And now, let's take a reference of it to use!
+ */
+ lstats = &sc->last_stat;
+
/* Test if temperature has changed. */
- if (stats->general.temp != sc->rawtemp) {
+ if (lstats->general.temp != sc->rawtemp) {
/* Convert "raw" temperature to degC. */
sc->rawtemp = stats->general.temp;
temp = ops->get_temperature(sc);
@@ -2816,25 +3373,51 @@ iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
if (desc->type != IWN_BEACON_STATISTICS)
return; /* Reply to a statistics request. */
- sc->noise = iwn_get_noise(&stats->rx.general);
+ sc->noise = iwn_get_noise(&lstats->rx.general);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: noise %d\n", __func__, sc->noise);
/* Test that RSSI and noise are present in stats report. */
- if (le32toh(stats->rx.general.flags) != 1) {
+ if (le32toh(lstats->rx.general.flags) != 1) {
DPRINTF(sc, IWN_DEBUG_ANY, "%s\n",
"received statistics without RSSI");
return;
}
if (calib->state == IWN_CALIB_STATE_ASSOC)
- iwn_collect_noise(sc, &stats->rx.general);
- else if (calib->state == IWN_CALIB_STATE_RUN)
- iwn_tune_sensitivity(sc, &stats->rx);
+ iwn_collect_noise(sc, &lstats->rx.general);
+ else if (calib->state == IWN_CALIB_STATE_RUN) {
+ iwn_tune_sensitivity(sc, &lstats->rx);
+ /*
+ * XXX TODO: Only run the RX recovery if we're associated!
+ */
+ iwn_check_rx_recovery(sc, lstats);
+ iwn_save_stats_counters(sc, lstats);
+ }
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
}
/*
+ * Save the relevant statistic counters for the next calibration
+ * pass.
+ */
+static void
+iwn_save_stats_counters(struct iwn_softc *sc, const struct iwn_stats *rs)
+{
+ struct iwn_calib_state *calib = &sc->calib;
+
+ /* Save counters values for next call. */
+ calib->bad_plcp_cck = le32toh(rs->rx.cck.bad_plcp);
+ calib->fa_cck = le32toh(rs->rx.cck.fa);
+ calib->bad_plcp_ht = le32toh(rs->rx.ht.bad_plcp);
+ calib->bad_plcp_ofdm = le32toh(rs->rx.ofdm.bad_plcp);
+ calib->fa_ofdm = le32toh(rs->rx.ofdm.fa);
+
+ /* Last time we received these tick values */
+ sc->last_calib_ticks = ticks;
+}
+
+/*
* Process a TX_DONE firmware notification. Unfortunately, the 4965AGN
* and 5000 adapters have different incompatible TX status formats.
*/
@@ -2850,15 +3433,18 @@ iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
ring = &sc->txq[qid];
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: "
- "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n",
- __func__, desc->qid, desc->idx, stat->ackfailcnt,
- stat->btkillcnt, stat->rate, le16toh(stat->duration),
+ "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x duration %d status %x\n",
+ __func__, desc->qid, desc->idx,
+ stat->rtsfailcnt,
+ stat->ackfailcnt,
+ stat->btkillcnt,
+ stat->rate, le16toh(stat->duration),
le32toh(stat->status));
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
if (qid >= sc->firstaggqueue) {
iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
- &stat->status);
+ stat->ackfailcnt, &stat->status);
} else {
iwn_tx_done(sc, desc, stat->ackfailcnt,
le32toh(stat->status) & 0xff);
@@ -2877,9 +3463,12 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
ring = &sc->txq[qid];
DPRINTF(sc, IWN_DEBUG_XMIT, "%s: "
- "qid %d idx %d retries %d nkill %d rate %x duration %d status %x\n",
- __func__, desc->qid, desc->idx, stat->ackfailcnt,
- stat->btkillcnt, stat->rate, le16toh(stat->duration),
+ "qid %d idx %d RTS retries %d ACK retries %d nkill %d rate %x duration %d status %x\n",
+ __func__, desc->qid, desc->idx,
+ stat->rtsfailcnt,
+ stat->ackfailcnt,
+ stat->btkillcnt,
+ stat->rate, le16toh(stat->duration),
le32toh(stat->status));
#ifdef notyet
@@ -2890,7 +3479,7 @@ iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_POSTREAD);
if (qid >= sc->firstaggqueue) {
iwn_ampdu_tx_done(sc, qid, desc->idx, stat->nframes,
- &stat->status);
+ stat->ackfailcnt, &stat->status);
} else {
iwn_tx_done(sc, desc, stat->ackfailcnt,
le16toh(stat->status) & 0xff);
@@ -2926,11 +3515,11 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt,
* Update rate control statistics for the node.
*/
if (status & IWN_TX_FAIL) {
- ifp->if_oerrors++;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL);
} else {
- ifp->if_opackets++;
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
ieee80211_ratectl_tx_complete(vap, ni,
IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL);
}
@@ -2977,12 +3566,19 @@ iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, int ackfailcnt,
static void
iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
{
- struct iwn_tx_ring *ring = &sc->txq[4];
+ struct iwn_tx_ring *ring;
struct iwn_tx_data *data;
+ int cmd_queue_num;
- if ((desc->qid & 0xf) != 4)
+ if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT)
+ cmd_queue_num = IWN_PAN_CMD_QUEUE;
+ else
+ cmd_queue_num = IWN_CMD_QUEUE_NUM;
+
+ if ((desc->qid & IWN_RX_DESC_QID_MSK) != cmd_queue_num)
return; /* Not a command ack. */
+ ring = &sc->txq[cmd_queue_num];
data = &ring->data[desc->idx];
/* If the command was mapped in an mbuf, free it. */
@@ -2998,7 +3594,7 @@ iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
static void
iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
- void *stat)
+ int ackfailcnt, void *stat)
{
struct iwn_ops *ops = &sc->ops;
struct ifnet *ifp = sc->sc_ifp;
@@ -3015,14 +3611,60 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
uint8_t tid;
int bit, i, lastidx, *res, seqno, shift, start;
+ /* XXX TODO: status is le16 field! Grr */
+
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: nframes=%d, status=0x%08x\n",
+ __func__,
+ nframes,
+ *status);
-#ifdef NOT_YET
+ tap = sc->qid2tap[qid];
+ tid = tap->txa_tid;
+ wn = (void *)tap->txa_ni;
+ ni = tap->txa_ni;
+
+ /*
+ * XXX TODO: ACK and RTS failures would be nice here!
+ */
+
+ /*
+ * A-MPDU single frame status - if we failed to transmit it
+ * in A-MPDU, then it may be a permanent failure.
+ *
+ * XXX TODO: check what the Linux iwlwifi driver does here;
+ * there's some permanent and temporary failures that may be
+ * handled differently.
+ */
if (nframes == 1) {
- if ((*status & 0xff) != 1 && (*status & 0xff) != 2)
+ if ((*status & 0xff) != 1 && (*status & 0xff) != 2) {
+#ifdef NOT_YET
printf("ieee80211_send_bar()\n");
- }
#endif
+ /*
+ * If we completely fail a transmit, make sure a
+ * notification is pushed up to the rate control
+ * layer.
+ */
+ ieee80211_ratectl_tx_complete(ni->ni_vap,
+ ni,
+ IEEE80211_RATECTL_TX_FAILURE,
+ &ackfailcnt,
+ NULL);
+ } else {
+ /*
+ * If nframes=1, then we won't be getting a BA for
+ * this frame. Ensure that we correctly update the
+ * rate control code with how many retries were
+ * needed to send it.
+ */
+ ieee80211_ratectl_tx_complete(ni->ni_vap,
+ ni,
+ IEEE80211_RATECTL_TX_SUCCESS,
+ &ackfailcnt,
+ NULL);
+ }
+ }
bitmap = 0;
start = idx;
@@ -3061,6 +3703,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
ssn = tap->txa_start & 0xfff;
}
+ /* This is going nframes DWORDS into the descriptor? */
seqno = le32toh(*(status + nframes)) & 0xfff;
for (lastidx = (seqno & 0xff); ring->read != lastidx;) {
data = &ring->data[ring->read];
@@ -3074,7 +3717,7 @@ iwn_ampdu_tx_done(struct iwn_softc *sc, int qid, int idx, int nframes,
KASSERT(ni != NULL, ("no node"));
KASSERT(m != NULL, ("no mbuf"));
-
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: freeing m=%p\n", __func__, m);
ieee80211_tx_complete(ni, m, 1);
ring->queued--;
@@ -3129,12 +3772,12 @@ iwn_notif_intr(struct iwn_softc *sc)
desc = mtod(data->m, struct iwn_rx_desc *);
DPRINTF(sc, IWN_DEBUG_RECV,
- "%s: qid %x idx %d flags %x type %d(%s) len %d\n",
- __func__, desc->qid & 0xf, desc->idx, desc->flags,
+ "%s: cur=%d; qid %x idx %d flags %x type %d(%s) len %d\n",
+ __func__, sc->rxq.cur, desc->qid & 0xf, desc->idx, desc->flags,
desc->type, iwn_intr_str(desc->type),
le16toh(desc->len));
- if (!(desc->qid & 0x80)) /* Reply to a command. */
+ if (!(desc->qid & IWN_UNSOLICITED_RX_NOTIF)) /* Reply to a command. */
iwn_cmd_done(sc, desc);
switch (desc->type) {
@@ -3229,7 +3872,8 @@ iwn_notif_intr(struct iwn_softc *sc)
BUS_DMASYNC_POSTREAD);
#ifdef IWN_DEBUG
uint32_t *status = (uint32_t *)(desc + 1);
- DPRINTF(sc, IWN_DEBUG_INTR, "state changed to %x\n",
+ DPRINTF(sc, IWN_DEBUG_INTR | IWN_DEBUG_STATE,
+ "state changed to %x\n",
le32toh(*status));
#endif
break;
@@ -3254,11 +3898,11 @@ iwn_notif_intr(struct iwn_softc *sc)
#ifdef IWN_DEBUG
struct iwn_stop_scan *scan =
(struct iwn_stop_scan *)(desc + 1);
- DPRINTF(sc, IWN_DEBUG_STATE,
+ DPRINTF(sc, IWN_DEBUG_STATE | IWN_DEBUG_SCAN,
"scan finished nchan=%d status=%d chan=%d\n",
scan->nchan, scan->status, scan->chan);
#endif
-
+ sc->sc_is_scanning = 0;
IWN_UNLOCK(sc);
ieee80211_scan_next(vap);
IWN_LOCK(sc);
@@ -3410,8 +4054,10 @@ iwn_intr(void *arg)
r2 = 0; /* Unused. */
} else {
r1 = IWN_READ(sc, IWN_INT);
- if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
+ if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) {
+ IWN_UNLOCK(sc);
return; /* Hardware gone! */
+ }
r2 = IWN_READ(sc, IWN_FH_INT);
}
@@ -3442,8 +4088,8 @@ iwn_intr(void *arg)
#endif
/* Dump firmware error log and stop. */
iwn_fatal_intr(sc);
- ifp->if_flags &= ~IFF_UP;
- iwn_stop_locked(sc);
+
+ taskqueue_enqueue(sc->sc_tq, &sc->sc_panic_task);
goto done;
}
if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) ||
@@ -3541,6 +4187,115 @@ iwn5000_reset_sched(struct iwn_softc *sc, int qid, int idx)
}
#endif
+/*
+ * Check whether OFDM 11g protection will be enabled for the given rate.
+ *
+ * The original driver code only enabled protection for OFDM rates.
+ * It didn't check to see whether it was operating in 11a or 11bg mode.
+ */
+static int
+iwn_check_rate_needs_protection(struct iwn_softc *sc,
+ struct ieee80211vap *vap, uint8_t rate)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ /*
+ * Not in 2GHz mode? Then there's no need to enable OFDM
+ * 11bg protection.
+ */
+ if (! IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) {
+ return (0);
+ }
+
+ /*
+ * 11bg protection not enabled? Then don't use it.
+ */
+ if ((ic->ic_flags & IEEE80211_F_USEPROT) == 0)
+ return (0);
+
+ /*
+ * If it's an 11n rate - no protection.
+ * We'll do it via a specific 11n check.
+ */
+ if (rate & IEEE80211_RATE_MCS) {
+ return (0);
+ }
+
+ /*
+ * Do a rate table lookup. If the PHY is CCK,
+ * don't do protection.
+ */
+ if (ieee80211_rate2phytype(ic->ic_rt, rate) == IEEE80211_T_CCK)
+ return (0);
+
+ /*
+ * Yup, enable protection.
+ */
+ return (1);
+}
+
+/*
+ * return a value between 0 and IWN_MAX_TX_RETRIES-1 as an index into
+ * the link quality table that reflects this particular entry.
+ */
+static int
+iwn_tx_rate_to_linkq_offset(struct iwn_softc *sc, struct ieee80211_node *ni,
+ uint8_t rate)
+{
+ struct ieee80211_rateset *rs;
+ int is_11n;
+ int nr;
+ int i;
+ uint8_t cmp_rate;
+
+ /*
+ * Figure out if we're using 11n or not here.
+ */
+ if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0)
+ is_11n = 1;
+ else
+ is_11n = 0;
+
+ /*
+ * Use the correct rate table.
+ */
+ if (is_11n) {
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ nr = ni->ni_htrates.rs_nrates;
+ } else {
+ rs = &ni->ni_rates;
+ nr = rs->rs_nrates;
+ }
+
+ /*
+ * Find the relevant link quality entry in the table.
+ */
+ for (i = 0; i < nr && i < IWN_MAX_TX_RETRIES - 1 ; i++) {
+ /*
+ * The link quality table index starts at 0 == highest
+ * rate, so we walk the rate table backwards.
+ */
+ cmp_rate = rs->rs_rates[(nr - 1) - i];
+ if (rate & IEEE80211_RATE_MCS)
+ cmp_rate |= IEEE80211_RATE_MCS;
+
+#if 0
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: idx %d: nr=%d, rate=0x%02x, rateentry=0x%02x\n",
+ __func__,
+ i,
+ nr,
+ rate,
+ cmp_rate);
+#endif
+
+ if (cmp_rate == rate)
+ return (i);
+ }
+
+ /* Failed? Start at the end */
+ return (IWN_MAX_TX_RETRIES - 1);
+}
+
static int
iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
{
@@ -3561,7 +4316,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
uint16_t qos;
u_int hdrlen;
bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER];
- uint8_t tid, ridx, txant, type;
+ uint8_t tid, type;
int ac, i, totlen, error, pad, nsegs = 0, rate;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@@ -3582,6 +4337,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
}
ac = M_WME_GETAC(m);
if (m->m_flags & M_AMPDU_MPDU) {
+ uint16_t seqno;
struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac];
if (!IEEE80211_AMPDU_RUNNING(tap)) {
@@ -3589,9 +4345,27 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
return EINVAL;
}
+ /*
+ * Queue this frame to the hardware ring that we've
+ * negotiated AMPDU TX on.
+ *
+ * Note that the sequence number must match the TX slot
+ * being used!
+ */
ac = *(int *)tap->txa_private;
+ seqno = ni->ni_txseqs[tid];
*(uint16_t *)wh->i_seq =
- htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
+ htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
+ ring = &sc->txq[ac];
+ if ((seqno % 256) != ring->cur) {
+ device_printf(sc->sc_dev,
+ "%s: m=%p: seqno (%d) (%d) != ring index (%d) !\n",
+ __func__,
+ m,
+ seqno,
+ seqno % 256,
+ ring->cur);
+ }
ni->ni_txseqs[tid]++;
}
ring = &sc->txq[ac];
@@ -3606,13 +4380,13 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
rate = tp->mcastrate;
else if (tp->ucastrate != IEEE80211_FIXED_RATE_NONE)
rate = tp->ucastrate;
+ else if (m->m_flags & M_EAPOL)
+ rate = tp->mgmtrate;
else {
/* XXX pass pktlen */
(void) ieee80211_ratectl_rate(ni, NULL, 0);
rate = ni->ni_txrate;
}
- ridx = ieee80211_legacy_rate_lookup(ic->ic_rt,
- rate & IEEE80211_RATE_VAL);
/* Encrypt the frame if need be. */
if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
@@ -3669,13 +4443,18 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
/* NB: Group frames are sent using CCK in 802.11b/g. */
if (totlen + IEEE80211_CRC_LEN > vap->iv_rtsthreshold) {
flags |= IWN_TX_NEED_RTS;
- } else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
- ridx >= IWN_RIDX_OFDM6) {
+ } else if (iwn_check_rate_needs_protection(sc, vap, rate)) {
if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
flags |= IWN_TX_NEED_CTS;
else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
flags |= IWN_TX_NEED_RTS;
+ } else if ((rate & IEEE80211_RATE_MCS) &&
+ (ic->ic_htprotmode == IEEE80211_PROT_RTSCTS)) {
+ flags |= IWN_TX_NEED_RTS;
}
+
+ /* XXX HT protection? */
+
if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) {
if (sc->hw_type != IWN_HW_REV_TYPE_4965) {
/* 5000 autoselects RTS/CTS or CTS-to-self. */
@@ -3722,13 +4501,11 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
if (tx->id == sc->broadcast_id) {
/* Group or management frame. */
tx->linkq = 0;
- /* XXX Alternate between antenna A and B? */
- txant = IWN_LSB(sc->txchainmask);
- tx->rate |= htole32(IWN_RFLAG_ANT(txant));
} else {
- tx->linkq = ni->ni_rates.rs_nrates - ridx - 1;
+ tx->linkq = iwn_tx_rate_to_linkq_offset(sc, ni, rate);
flags |= IWN_TX_LINKQ; /* enable MRR */
}
+
/* Set physical address of "scratch area". */
tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));
tx->hiaddr = IWN_HIADDR(data->scratch_paddr);
@@ -3751,7 +4528,7 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
return error;
}
/* Too many DMA segments, linearize mbuf. */
- m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER);
+ m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER - 1);
if (m1 == NULL) {
device_printf(sc->sc_dev,
"%s: could not defrag mbuf\n", __func__);
@@ -3773,8 +4550,16 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
data->m = m;
data->ni = ni;
- DPRINTF(sc, IWN_DEBUG_XMIT, "%s: qid %d idx %d len %d nsegs %d\n",
- __func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs);
+ DPRINTF(sc, IWN_DEBUG_XMIT,
+ "%s: qid %d idx %d len %d nsegs %d flags 0x%08x rate 0x%04x plcp 0x%08x\n",
+ __func__,
+ ring->qid,
+ ring->cur,
+ m->m_pkthdr.len,
+ nsegs,
+ flags,
+ rate,
+ tx->rate);
/* Fill TX descriptor. */
desc->nsegs = 1;
@@ -3821,9 +4606,9 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
struct ieee80211_node *ni, const struct ieee80211_bpf_params *params)
{
struct iwn_ops *ops = &sc->ops;
- struct ifnet *ifp = sc->sc_ifp;
+// struct ifnet *ifp = sc->sc_ifp;
struct ieee80211vap *vap = ni->ni_vap;
- struct ieee80211com *ic = ifp->if_l2com;
+// struct ieee80211com *ic = ifp->if_l2com;
struct iwn_tx_cmd *cmd;
struct iwn_cmd_data *tx;
struct ieee80211_frame *wh;
@@ -3835,7 +4620,7 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
uint32_t flags;
u_int hdrlen;
int ac, totlen, error, pad, nsegs = 0, i, rate;
- uint8_t ridx, type, txant;
+ uint8_t type;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@@ -3851,16 +4636,8 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
desc = &ring->desc[ring->cur];
data = &ring->data[ring->cur];
- /* Choose a TX rate index. */
+ /* Choose a TX rate. */
rate = params->ibp_rate0;
- ridx = ieee80211_legacy_rate_lookup(ic->ic_rt,
- rate & IEEE80211_RATE_VAL);
- if (ridx == (uint8_t)-1) {
- /* XXX fall back to mcast/mgmt rate? */
- m_freem(m);
- return EINVAL;
- }
-
totlen = m->m_pkthdr.len;
/* Prepare TX firmware command. */
@@ -3930,17 +4707,10 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
tx->rts_ntries = params->ibp_try1;
tx->data_ntries = params->ibp_try0;
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
-
- /* XXX should just use iwn_rate_to_plcp() */
- tx->rate = htole32(rate2plcp(rate));
- if (ridx < IWN_RIDX_OFDM6 &&
- IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
- tx->rate |= htole32(IWN_RFLAG_CCK);
+ tx->rate = iwn_rate_to_plcp(sc, ni, rate);
/* Group or management frame. */
tx->linkq = 0;
- txant = IWN_LSB(sc->txchainmask);
- tx->rate |= htole32(IWN_RFLAG_ANT(txant));
/* Set physical address of "scratch area". */
tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));
@@ -3964,7 +4734,7 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
return error;
}
/* Too many DMA segments, linearize mbuf. */
- m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER);
+ m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER - 1);
if (m1 == NULL) {
device_printf(sc->sc_dev,
"%s: could not defrag mbuf\n", __func__);
@@ -4038,7 +4808,7 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
struct iwn_softc *sc = ifp->if_softc;
int error = 0;
- DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+ DPRINTF(sc, IWN_DEBUG_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
ieee80211_free_node(ni);
@@ -4063,13 +4833,13 @@ iwn_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
if (error != 0) {
/* NB: m is reclaimed on tx failure */
ieee80211_free_node(ni);
- ifp->if_oerrors++;
- }
- sc->sc_tx_timer = 5;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ } else
+ sc->sc_tx_timer = 5;
IWN_UNLOCK(sc);
- DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
+ DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end\n",__func__);
return error;
}
@@ -4093,6 +4863,8 @@ iwn_start_locked(struct ifnet *ifp)
IWN_LOCK_ASSERT(sc);
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: called\n", __func__);
+
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
(ifp->if_drv_flags & IFF_DRV_OACTIVE))
return;
@@ -4108,11 +4880,12 @@ iwn_start_locked(struct ifnet *ifp)
ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
if (iwn_tx_data(sc, m, ni) != 0) {
ieee80211_free_node(ni);
- ifp->if_oerrors++;
- continue;
- }
- sc->sc_tx_timer = 5;
+ if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ } else
+ sc->sc_tx_timer = 5;
}
+
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__);
}
static void
@@ -4174,6 +4947,18 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCGIFMEDIA:
error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd);
break;
+ case SIOCGIWNSTATS:
+ IWN_LOCK(sc);
+ /* XXX validate permissions/memory/etc? */
+ error = copyout(&sc->last_stat, ifr->ifr_data,
+ sizeof(struct iwn_stats));
+ IWN_UNLOCK(sc);
+ break;
+ case SIOCZIWNSTATS:
+ IWN_LOCK(sc);
+ memset(&sc->last_stat, 0, sizeof(struct iwn_stats));
+ IWN_UNLOCK(sc);
+ break;
default:
error = EINVAL;
break;
@@ -4187,19 +4972,26 @@ iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
static int
iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async)
{
- struct iwn_tx_ring *ring = &sc->txq[4];
+ struct iwn_tx_ring *ring;
struct iwn_tx_desc *desc;
struct iwn_tx_data *data;
struct iwn_tx_cmd *cmd;
struct mbuf *m;
bus_addr_t paddr;
int totlen, error;
+ int cmd_queue_num;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
if (async == 0)
IWN_LOCK_ASSERT(sc);
+ if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT)
+ cmd_queue_num = IWN_PAN_CMD_QUEUE;
+ else
+ cmd_queue_num = IWN_CMD_QUEUE_NUM;
+
+ ring = &sc->txq[cmd_queue_num];
desc = &ring->desc[ring->cur];
data = &ring->data[ring->cur];
totlen = 4 + size;
@@ -4293,42 +5085,87 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
{
#define RV(v) ((v) & IEEE80211_RATE_VAL)
struct iwn_node *wn = (void *)ni;
- struct ieee80211_rateset *rs = &ni->ni_rates;
+ struct ieee80211_rateset *rs;
struct iwn_cmd_link_quality linkq;
- uint8_t txant;
int i, rate, txrate;
+ int is_11n;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
- /* Use the first valid TX antenna. */
- txant = IWN_LSB(sc->txchainmask);
-
memset(&linkq, 0, sizeof linkq);
linkq.id = wn->id;
- linkq.antmsk_1stream = txant;
- linkq.antmsk_2stream = IWN_ANT_AB;
- linkq.ampdu_max = 64;
+ linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc);
+ linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc);
+
+ linkq.ampdu_max = 32; /* XXX negotiated? */
linkq.ampdu_threshold = 3;
linkq.ampdu_limit = htole16(4000); /* 4ms */
+ DPRINTF(sc, IWN_DEBUG_XMIT,
+ "%s: 1stream antenna=0x%02x, 2stream antenna=0x%02x, ntxstreams=%d\n",
+ __func__,
+ linkq.antmsk_1stream,
+ linkq.antmsk_2stream,
+ sc->ntxchains);
+
+ /*
+ * Are we using 11n rates? Ensure the channel is
+ * 11n _and_ we have some 11n rates, or don't
+ * try.
+ */
+ if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates > 0) {
+ rs = (struct ieee80211_rateset *) &ni->ni_htrates;
+ is_11n = 1;
+ } else {
+ rs = &ni->ni_rates;
+ is_11n = 0;
+ }
+
/* Start at highest available bit-rate. */
- if (IEEE80211_IS_CHAN_HT(ni->ni_chan))
+ /*
+ * XXX this is all very dirty!
+ */
+ if (is_11n)
txrate = ni->ni_htrates.rs_nrates - 1;
else
txrate = rs->rs_nrates - 1;
for (i = 0; i < IWN_MAX_TX_RETRIES; i++) {
uint32_t plcp;
- if (IEEE80211_IS_CHAN_HT(ni->ni_chan))
- rate = IEEE80211_RATE_MCS | txrate;
+ /*
+ * XXX TODO: ensure the last two slots are the two lowest
+ * rate entries, just for now.
+ */
+ if (i == 14 || i == 15)
+ txrate = 0;
+
+ if (is_11n)
+ rate = IEEE80211_RATE_MCS | rs->rs_rates[txrate];
else
rate = RV(rs->rs_rates[txrate]);
/* Do rate -> PLCP config mapping */
plcp = iwn_rate_to_plcp(sc, ni, rate);
linkq.retry[i] = plcp;
+ DPRINTF(sc, IWN_DEBUG_XMIT,
+ "%s: i=%d, txrate=%d, rate=0x%02x, plcp=0x%08x\n",
+ __func__,
+ i,
+ txrate,
+ rate,
+ le32toh(plcp));
- /* Special case for dual-stream rates? */
+ /*
+ * The mimo field is an index into the table which
+ * indicates the first index where it and subsequent entries
+ * will not be using MIMO.
+ *
+ * Since we're filling linkq from 0..15 and we're filling
+ * from the higest MCS rates to the lowest rates, if we
+ * _are_ doing a dual-stream rate, set mimo to idx+1 (ie,
+ * the next entry.) That way if the next entry is a non-MIMO
+ * entry, we're already pointing at it.
+ */
if ((le32toh(plcp) & IWN_RFLAG_MCS) &&
RV(le32toh(plcp)) > 7)
linkq.mimo = i + 1;
@@ -4337,6 +5174,15 @@ iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
if (txrate > 0)
txrate--;
}
+ /*
+ * If we reached the end of the list and indeed we hit
+ * all MIMO rates (eg 5300 doing MCS23-15) then yes,
+ * set mimo to 15. Setting it to 16 panics the firmware.
+ */
+ if (linkq.mimo > 15)
+ linkq.mimo = 15;
+
+ DPRINTF(sc, IWN_DEBUG_XMIT, "%s: mimo = %d\n", __func__, linkq.mimo);
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__);
@@ -4374,13 +5220,14 @@ iwn_add_broadcast_node(struct iwn_softc *sc, int async)
memset(&linkq, 0, sizeof linkq);
linkq.id = sc->broadcast_id;
- linkq.antmsk_1stream = txant;
- linkq.antmsk_2stream = IWN_ANT_AB;
+ linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc);
+ linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc);
linkq.ampdu_max = 64;
linkq.ampdu_threshold = 3;
linkq.ampdu_limit = htole16(4000); /* 4ms */
/* Use lowest mandatory bit-rate. */
+ /* XXX rate table lookup? */
if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan))
linkq.retry[0] = htole32(0xd);
else
@@ -4442,6 +5289,12 @@ iwn_set_led(struct iwn_softc *sc, uint8_t which, uint8_t off, uint8_t on)
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
+#if 0
+ /* XXX don't set LEDs during scan? */
+ if (sc->sc_is_scanning)
+ return;
+#endif
+
/* Clear microcode LED ownership. */
IWN_CLRBITS(sc, IWN_LED, IWN_LED_BSM_CTRL);
@@ -4681,6 +5534,7 @@ iwn5000_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch,
int async)
{
struct iwn5000_cmd_txpower cmd;
+ int cmdid;
DPRINTF(sc, IWN_DEBUG_TRACE, "->Doing %s\n", __func__);
@@ -4692,8 +5546,15 @@ iwn5000_set_txpower(struct iwn_softc *sc, struct ieee80211_channel *ch,
cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */
cmd.flags = IWN5000_TXPOWER_NO_CLOSED;
cmd.srv_limit = IWN5000_TXPOWER_AUTO;
- DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: setting TX power\n", __func__);
- return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async);
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT,
+ "%s: setting TX power; rev=%d\n",
+ __func__,
+ IWN_UCODE_API(sc->ucode_rev));
+ if (IWN_UCODE_API(sc->ucode_rev) == 1)
+ cmdid = IWN_CMD_TXPOWER_DBM_V1;
+ else
+ cmdid = IWN_CMD_TXPOWER_DBM;
+ return iwn_cmd(sc, cmdid, &cmd, sizeof cmd, async);
}
/*
@@ -4893,7 +5754,7 @@ iwn_collect_noise(struct iwn_softc *sc,
for (i = 0; i < 3; i++)
if (val - calib->rssi[i] > 15 * 20)
sc->chainmask &= ~(1 << i);
- DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT,
"%s: RX chains mask: theoretical=0x%x, actual=0x%x\n",
__func__, sc->rxchainmask, sc->chainmask);
@@ -4907,6 +5768,10 @@ iwn_collect_noise(struct iwn_softc *sc,
#ifdef notyet
/* XXX Disable RX chains with no antennas connected. */
sc->rxon->rxchain = htole16(IWN_RXCHAIN_SEL(sc->chainmask));
+ if (sc->sc_is_scanning)
+ device_printf(sc->sc_dev,
+ "%s: is_scanning set, before RXON\n",
+ __func__);
(void)iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1);
#endif
@@ -5014,7 +5879,7 @@ iwn5000_set_gains(struct iwn_softc *sc)
cmd.gain[i - 1] |= 1 << 2; /* sign bit */
}
}
- DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT,
"setting differential gains Ant B/C: %x/%x (%x)\n",
cmd.gain[0], cmd.gain[1], sc->chainmask);
return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
@@ -5064,10 +5929,6 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats)
fa += le32toh(stats->ofdm.fa) - calib->fa_ofdm;
fa *= 200 * IEEE80211_DUR_TU; /* 200TU */
- /* Save counters values for next call. */
- calib->bad_plcp_ofdm = le32toh(stats->ofdm.bad_plcp);
- calib->fa_ofdm = le32toh(stats->ofdm.fa);
-
if (fa > 50 * rxena) {
/* High false alarm count, decrease sensitivity. */
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
@@ -5121,10 +5982,6 @@ iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats)
fa += le32toh(stats->cck.fa) - calib->fa_cck;
fa *= 200 * IEEE80211_DUR_TU; /* 200TU */
- /* Save counters values for next call. */
- calib->bad_plcp_cck = le32toh(stats->cck.bad_plcp);
- calib->fa_cck = le32toh(stats->cck.fa);
-
if (fa > 50 * rxena) {
/* High false alarm count, decrease sensitivity. */
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
@@ -5205,7 +6062,7 @@ iwn_send_sensitivity(struct iwn_softc *sc)
cmd.energy_cck = htole16(calib->energy_cck);
/* Barker modulation: use default values. */
cmd.corr_barker = htole16(190);
- cmd.corr_barker_mrc = htole16(390);
+ cmd.corr_barker_mrc = htole16(sc->limits->barker_mrc);
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"%s: set sensitivity %d/%d/%d/%d/%d/%d/%d\n", __func__,
@@ -5230,6 +6087,86 @@ send:
}
/*
+ * Look at the increase of PLCP errors over time; if it exceeds
+ * a programmed threshold then trigger an RF retune.
+ */
+static void
+iwn_check_rx_recovery(struct iwn_softc *sc, struct iwn_stats *rs)
+{
+ int32_t delta_ofdm, delta_ht, delta_cck;
+ struct iwn_calib_state *calib = &sc->calib;
+ int delta_ticks, cur_ticks;
+ int delta_msec;
+ int thresh;
+
+ /*
+ * Calculate the difference between the current and
+ * previous statistics.
+ */
+ delta_cck = le32toh(rs->rx.cck.bad_plcp) - calib->bad_plcp_cck;
+ delta_ofdm = le32toh(rs->rx.ofdm.bad_plcp) - calib->bad_plcp_ofdm;
+ delta_ht = le32toh(rs->rx.ht.bad_plcp) - calib->bad_plcp_ht;
+
+ /*
+ * Calculate the delta in time between successive statistics
+ * messages. Yes, it can roll over; so we make sure that
+ * this doesn't happen.
+ *
+ * XXX go figure out what to do about rollover
+ * XXX go figure out what to do if ticks rolls over to -ve instead!
+ * XXX go stab signed integer overflow undefined-ness in the face.
+ */
+ cur_ticks = ticks;
+ delta_ticks = cur_ticks - sc->last_calib_ticks;
+
+ /*
+ * If any are negative, then the firmware likely reset; so just
+ * bail. We'll pick this up next time.
+ */
+ if (delta_cck < 0 || delta_ofdm < 0 || delta_ht < 0 || delta_ticks < 0)
+ return;
+
+ /*
+ * delta_ticks is in ticks; we need to convert it up to milliseconds
+ * so we can do some useful math with it.
+ */
+ delta_msec = ticks_to_msecs(delta_ticks);
+
+ /*
+ * Calculate what our threshold is given the current delta_msec.
+ */
+ thresh = sc->base_params->plcp_err_threshold * delta_msec;
+
+ DPRINTF(sc, IWN_DEBUG_STATE,
+ "%s: time delta: %d; cck=%d, ofdm=%d, ht=%d, total=%d, thresh=%d\n",
+ __func__,
+ delta_msec,
+ delta_cck,
+ delta_ofdm,
+ delta_ht,
+ (delta_msec + delta_cck + delta_ofdm + delta_ht),
+ thresh);
+
+ /*
+ * If we need a retune, then schedule a single channel scan
+ * to a channel that isn't the currently active one!
+ *
+ * The math from linux iwlwifi:
+ *
+ * if ((delta * 100 / msecs) > threshold)
+ */
+ if (thresh > 0 && (delta_cck + delta_ofdm + delta_ht) * 100 > thresh) {
+ DPRINTF(sc, IWN_DEBUG_ANY,
+ "%s: PLCP error threshold raw (%d) comparison (%d) "
+ "over limit (%d); retune!\n",
+ __func__,
+ (delta_cck + delta_ofdm + delta_ht),
+ (delta_cck + delta_ofdm + delta_ht) * 100,
+ thresh);
+ }
+}
+
+/*
* Set STA mode power saving level (between 0 and 5).
* Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving.
*/
@@ -5314,25 +6251,73 @@ iwn_send_advanced_btcoex(struct iwn_softc *sc)
0xc0004000, 0x00004000, 0xf0005000, 0xf0005000,
};
struct iwn6000_btcoex_config btconfig;
+ struct iwn2000_btcoex_config btconfig2k;
struct iwn_btcoex_priotable btprio;
struct iwn_btcoex_prot btprot;
int error, i;
+ uint8_t flags;
memset(&btconfig, 0, sizeof btconfig);
- btconfig.flags = 145;
- btconfig.max_kill = 5;
- btconfig.bt3_t7_timer = 1;
- btconfig.kill_ack = htole32(0xffff0000);
- btconfig.kill_cts = htole32(0xffff0000);
- btconfig.sample_time = 2;
- btconfig.bt3_t2_timer = 0xc;
- for (i = 0; i < 12; i++)
- btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
- btconfig.valid = htole16(0xff);
- btconfig.prio_boost = 0xf0;
- DPRINTF(sc, IWN_DEBUG_RESET,
- "%s: configuring advanced bluetooth coexistence\n", __func__);
- error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig, sizeof(btconfig), 1);
+ memset(&btconfig2k, 0, sizeof btconfig2k);
+
+ flags = IWN_BT_FLAG_COEX6000_MODE_3W <<
+ IWN_BT_FLAG_COEX6000_MODE_SHIFT; // Done as is in linux kernel 3.2
+
+ if (sc->base_params->bt_sco_disable)
+ flags &= ~IWN_BT_FLAG_SYNC_2_BT_DISABLE;
+ else
+ flags |= IWN_BT_FLAG_SYNC_2_BT_DISABLE;
+
+ flags |= IWN_BT_FLAG_COEX6000_CHAN_INHIBITION;
+
+ /* Default flags result is 145 as old value */
+
+ /*
+ * Flags value has to be review. Values must change if we
+ * which to disable it
+ */
+ if (sc->base_params->bt_session_2) {
+ btconfig2k.flags = flags;
+ btconfig2k.max_kill = 5;
+ btconfig2k.bt3_t7_timer = 1;
+ btconfig2k.kill_ack = htole32(0xffff0000);
+ btconfig2k.kill_cts = htole32(0xffff0000);
+ btconfig2k.sample_time = 2;
+ btconfig2k.bt3_t2_timer = 0xc;
+
+ for (i = 0; i < 12; i++)
+ btconfig2k.lookup_table[i] = htole32(btcoex_3wire[i]);
+ btconfig2k.valid = htole16(0xff);
+ btconfig2k.prio_boost = htole32(0xf0);
+ DPRINTF(sc, IWN_DEBUG_RESET,
+ "%s: configuring advanced bluetooth coexistence"
+ " session 2, flags : 0x%x\n",
+ __func__,
+ flags);
+ error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig2k,
+ sizeof(btconfig2k), 1);
+ } else {
+ btconfig.flags = flags;
+ btconfig.max_kill = 5;
+ btconfig.bt3_t7_timer = 1;
+ btconfig.kill_ack = htole32(0xffff0000);
+ btconfig.kill_cts = htole32(0xffff0000);
+ btconfig.sample_time = 2;
+ btconfig.bt3_t2_timer = 0xc;
+
+ for (i = 0; i < 12; i++)
+ btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
+ btconfig.valid = htole16(0xff);
+ btconfig.prio_boost = 0xf0;
+ DPRINTF(sc, IWN_DEBUG_RESET,
+ "%s: configuring advanced bluetooth coexistence,"
+ " flags : 0x%x\n",
+ __func__,
+ flags);
+ error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
+ sizeof(btconfig), 1);
+ }
+
if (error != 0)
return error;
@@ -5387,13 +6372,32 @@ iwn_config(struct iwn_softc *sc)
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
- if (sc->hw_type == IWN_HW_REV_TYPE_6005) {
- /* Set radio temperature sensor offset. */
+ if ((sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET)
+ && (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2)) {
+ device_printf(sc->sc_dev,"%s: temp_offset and temp_offsetv2 are"
+ " exclusive each together. Review NIC config file. Conf"
+ " : 0x%08x Flags : 0x%08x \n", __func__,
+ sc->base_params->calib_need,
+ (IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET |
+ IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2));
+ return (EINVAL);
+ }
+
+ /* Compute temperature calib if needed. Will be send by send calib */
+ if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET) {
error = iwn5000_temp_offset_calib(sc);
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not set temperature offset\n", __func__);
- return error;
+ return (error);
+ }
+ } else if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2) {
+ error = iwn5000_temp_offset_calibv2(sc);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not compute temperature offset v2\n",
+ __func__);
+ return (error);
}
}
@@ -5409,9 +6413,10 @@ iwn_config(struct iwn_softc *sc)
}
/* Configure valid TX chains for >=5000 Series. */
- if (sc->hw_type != IWN_HW_REV_TYPE_4965) {
+ if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
+ IWN_UCODE_API(sc->ucode_rev) > 1) {
txmask = htole32(sc->txchainmask);
- DPRINTF(sc, IWN_DEBUG_RESET,
+ DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT,
"%s: configuring valid TX chains 0x%x\n", __func__, txmask);
error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask,
sizeof txmask, 0);
@@ -5424,10 +6429,14 @@ iwn_config(struct iwn_softc *sc)
}
/* Configure bluetooth coexistence. */
- if (sc->sc_flags & IWN_FLAG_ADV_BTCOEX)
+ error = 0;
+
+ /* Configure bluetooth coexistence if needed. */
+ if (sc->base_params->bt_mode == IWN_BT_ADVANCED)
error = iwn_send_advanced_btcoex(sc);
- else
+ if (sc->base_params->bt_mode == IWN_BT_SIMPLE)
error = iwn_send_btcoex(sc);
+
if (error != 0) {
device_printf(sc->sc_dev,
"%s: could not configure bluetooth coexistence, error %d\n",
@@ -5463,12 +6472,29 @@ iwn_config(struct iwn_softc *sc)
sc->rxon->ht_single_mask = 0xff;
sc->rxon->ht_dual_mask = 0xff;
sc->rxon->ht_triple_mask = 0xff;
+ /*
+ * In active association mode, ensure that
+ * all the receive chains are enabled.
+ *
+ * Since we're not yet doing SMPS, don't allow the
+ * number of idle RX chains to be less than the active
+ * number.
+ */
rxchain =
IWN_RXCHAIN_VALID(sc->rxchainmask) |
- IWN_RXCHAIN_MIMO_COUNT(2) |
- IWN_RXCHAIN_IDLE_COUNT(2);
+ IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) |
+ IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains);
sc->rxon->rxchain = htole16(rxchain);
+ DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT,
+ "%s: rxchainmask=0x%x, nrxchains=%d\n",
+ __func__,
+ sc->rxchainmask,
+ sc->nrxchains);
DPRINTF(sc, IWN_DEBUG_RESET, "%s: setting configuration\n", __func__);
+ if (sc->sc_is_scanning)
+ device_printf(sc->sc_dev,
+ "%s: is_scanning set, before RXON\n",
+ __func__);
error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 0);
if (error != 0) {
device_printf(sc->sc_dev, "%s: RXON command failed\n",
@@ -5507,39 +6533,109 @@ iwn_config(struct iwn_softc *sc)
return 0;
}
+static uint16_t
+iwn_get_active_dwell_time(struct iwn_softc *sc,
+ struct ieee80211_channel *c, uint8_t n_probes)
+{
+ /* No channel? Default to 2GHz settings */
+ if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) {
+ return (IWN_ACTIVE_DWELL_TIME_2GHZ +
+ IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1));
+ }
+
+ /* 5GHz dwell time */
+ return (IWN_ACTIVE_DWELL_TIME_5GHZ +
+ IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1));
+}
+
/*
- * Add an ssid element to a frame.
+ * Limit the total dwell time to 85% of the beacon interval.
+ *
+ * Returns the dwell time in milliseconds.
*/
-static uint8_t *
-ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
+static uint16_t
+iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time)
+{
+ struct ieee80211com *ic = sc->sc_ifp->if_l2com;
+ struct ieee80211vap *vap = NULL;
+ int bintval = 0;
+
+ /* bintval is in TU (1.024mS) */
+ if (! TAILQ_EMPTY(&ic->ic_vaps)) {
+ vap = TAILQ_FIRST(&ic->ic_vaps);
+ bintval = vap->iv_bss->ni_intval;
+ }
+
+ /*
+ * If it's non-zero, we should calculate the minimum of
+ * it and the DWELL_BASE.
+ *
+ * XXX Yes, the math should take into account that bintval
+ * is 1.024mS, not 1mS..
+ */
+ if (bintval > 0) {
+ DPRINTF(sc, IWN_DEBUG_SCAN,
+ "%s: bintval=%d\n",
+ __func__,
+ bintval);
+ return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100)));
+ }
+
+ /* No association context? Default */
+ return (IWN_PASSIVE_DWELL_BASE);
+}
+
+static uint16_t
+iwn_get_passive_dwell_time(struct iwn_softc *sc, struct ieee80211_channel *c)
{
- *frm++ = IEEE80211_ELEMID_SSID;
- *frm++ = len;
- memcpy(frm, ssid, len);
- return frm + len;
+ uint16_t passive;
+
+ if (c == NULL || IEEE80211_IS_CHAN_2GHZ(c)) {
+ passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ;
+ } else {
+ passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ;
+ }
+
+ /* Clamp to the beacon interval if we're associated */
+ return (iwn_limit_dwell(sc, passive));
}
static int
-iwn_scan(struct iwn_softc *sc)
+iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap,
+ struct ieee80211_scan_state *ss, struct ieee80211_channel *c)
{
struct ifnet *ifp = sc->sc_ifp;
struct ieee80211com *ic = ifp->if_l2com;
- struct ieee80211_scan_state *ss = ic->ic_scan; /*XXX*/
- struct ieee80211_node *ni = ss->ss_vap->iv_bss;
+ struct ieee80211_node *ni = vap->iv_bss;
struct iwn_scan_hdr *hdr;
struct iwn_cmd_data *tx;
struct iwn_scan_essid *essid;
struct iwn_scan_chan *chan;
struct ieee80211_frame *wh;
struct ieee80211_rateset *rs;
- struct ieee80211_channel *c;
uint8_t *buf, *frm;
uint16_t rxchain;
uint8_t txant;
int buflen, error;
+ int is_active;
+ uint16_t dwell_active, dwell_passive;
+ uint32_t extra, scan_service_time;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
+ /*
+ * We are absolutely not allowed to send a scan command when another
+ * scan command is pending.
+ */
+ if (sc->sc_is_scanning) {
+ device_printf(sc->sc_dev, "%s: called whilst scanning!\n",
+ __func__);
+ return (EAGAIN);
+ }
+
+ /* Assign the scan channel */
+ c = ic->ic_curchan;
+
sc->rxon = &sc->rx_on[IWN_RXON_BSS_CTX];
buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO);
if (buf == NULL) {
@@ -5555,13 +6651,29 @@ iwn_scan(struct iwn_softc *sc)
*/
hdr->quiet_time = htole16(10); /* timeout in milliseconds */
hdr->quiet_threshold = htole16(1); /* min # of packets */
+ /*
+ * Max needs to be greater than active and passive and quiet!
+ * It's also in microseconds!
+ */
+ hdr->max_svc = htole32(250 * 1024);
+
+ /*
+ * Reset scan: interval=100
+ * Normal scan: interval=becaon interval
+ * suspend_time: 100 (TU)
+ *
+ */
+ extra = (100 /* suspend_time */ / 100 /* beacon interval */) << 22;
+ //scan_service_time = extra | ((100 /* susp */ % 100 /* int */) * 1024);
+ scan_service_time = (4 << 22) | (100 * 1024); /* Hardcode for now! */
+ hdr->pause_svc = htole32(scan_service_time);
/* Select antennas for scanning. */
rxchain =
IWN_RXCHAIN_VALID(sc->rxchainmask) |
IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask) |
IWN_RXCHAIN_DRIVER_FORCE;
- if (IEEE80211_IS_CHAN_A(ic->ic_curchan) &&
+ if (IEEE80211_IS_CHAN_A(c) &&
sc->hw_type == IWN_HW_REV_TYPE_4965) {
/* Ant A must be avoided in 5GHz because of an HW bug. */
rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_B);
@@ -5575,7 +6687,7 @@ iwn_scan(struct iwn_softc *sc)
tx->id = sc->broadcast_id;
tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
- if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) {
+ if (IEEE80211_IS_CHAN_5GHZ(c)) {
/* Send probe requests at 6Mbps. */
tx->rate = htole32(0xd);
rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
@@ -5594,12 +6706,35 @@ iwn_scan(struct iwn_softc *sc)
txant = IWN_LSB(sc->txchainmask);
tx->rate |= htole32(IWN_RFLAG_ANT(txant));
+ /*
+ * Only do active scanning if we're announcing a probe request
+ * for a given SSID (or more, if we ever add it to the driver.)
+ */
+ is_active = 0;
+
+ /*
+ * If we're scanning for a specific SSID, add it to the command.
+ *
+ * XXX maybe look at adding support for scanning multiple SSIDs?
+ */
essid = (struct iwn_scan_essid *)(tx + 1);
- if (ss->ss_ssid[0].len != 0) {
- essid[0].id = IEEE80211_ELEMID_SSID;
- essid[0].len = ss->ss_ssid[0].len;
- memcpy(essid[0].data, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len);
+ if (ss != NULL) {
+ if (ss->ss_ssid[0].len != 0) {
+ essid[0].id = IEEE80211_ELEMID_SSID;
+ essid[0].len = ss->ss_ssid[0].len;
+ memcpy(essid[0].data, ss->ss_ssid[0].ssid, ss->ss_ssid[0].len);
+ }
+
+ DPRINTF(sc, IWN_DEBUG_SCAN, "%s: ssid_len=%d, ssid=%*s\n",
+ __func__,
+ ss->ss_ssid[0].len,
+ ss->ss_ssid[0].len,
+ ss->ss_ssid[0].ssid);
+
+ if (ss->ss_nssid > 0)
+ is_active = 1;
}
+
/*
* Build a probe request frame. Most of the following code is a
* copy & paste of what is done in net80211.
@@ -5625,53 +6760,96 @@ iwn_scan(struct iwn_softc *sc)
/* Set length of probe request. */
tx->len = htole16(frm - (uint8_t *)wh);
- c = ic->ic_curchan;
+ /*
+ * If active scanning is requested but a certain channel is
+ * marked passive, we can do active scanning if we detect
+ * transmissions.
+ *
+ * There is an issue with some firmware versions that triggers
+ * a sysassert on a "good CRC threshold" of zero (== disabled),
+ * on a radar channel even though this means that we should NOT
+ * send probes.
+ *
+ * The "good CRC threshold" is the number of frames that we
+ * need to receive during our dwell time on a channel before
+ * sending out probes -- setting this to a huge value will
+ * mean we never reach it, but at the same time work around
+ * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+ * here instead of IWL_GOOD_CRC_TH_DISABLED.
+ *
+ * This was fixed in later versions along with some other
+ * scan changes, and the threshold behaves as a flag in those
+ * versions.
+ */
+
+ /*
+ * If we're doing active scanning, set the crc_threshold
+ * to a suitable value. This is different to active veruss
+ * passive scanning depending upon the channel flags; the
+ * firmware will obey that particular check for us.
+ */
+ if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN)
+ hdr->crc_threshold = is_active ?
+ IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED;
+ else
+ hdr->crc_threshold = is_active ?
+ IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER;
+
chan = (struct iwn_scan_chan *)frm;
chan->chan = htole16(ieee80211_chan2ieee(ic, c));
chan->flags = 0;
if (ss->ss_nssid > 0)
chan->flags |= htole32(IWN_CHAN_NPBREQS(1));
chan->dsp_gain = 0x6e;
- if (IEEE80211_IS_CHAN_5GHZ(c) &&
- !(c->ic_flags & IEEE80211_CHAN_PASSIVE)) {
- chan->rf_gain = 0x3b;
- chan->active = htole16(24);
- chan->passive = htole16(110);
+
+ /*
+ * Set the passive/active flag depending upon the channel mode.
+ * XXX TODO: take the is_active flag into account as well?
+ */
+ if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
+ chan->flags |= htole32(IWN_CHAN_PASSIVE);
+ else
chan->flags |= htole32(IWN_CHAN_ACTIVE);
- } else if (IEEE80211_IS_CHAN_5GHZ(c)) {
+
+ /*
+ * Calculate the active/passive dwell times.
+ */
+
+ dwell_active = iwn_get_active_dwell_time(sc, c, ss->ss_nssid);
+ dwell_passive = iwn_get_passive_dwell_time(sc, c);
+
+ /* Make sure they're valid */
+ if (dwell_passive <= dwell_active)
+ dwell_passive = dwell_active + 1;
+
+ chan->active = htole16(dwell_active);
+ chan->passive = htole16(dwell_passive);
+
+ if (IEEE80211_IS_CHAN_5GHZ(c))
chan->rf_gain = 0x3b;
- chan->active = htole16(24);
- if (sc->rxon->associd)
- chan->passive = htole16(78);
- else
- chan->passive = htole16(110);
- hdr->crc_threshold = 0xffff;
- } else if (!(c->ic_flags & IEEE80211_CHAN_PASSIVE)) {
- chan->rf_gain = 0x28;
- chan->active = htole16(36);
- chan->passive = htole16(120);
- chan->flags |= htole32(IWN_CHAN_ACTIVE);
- } else {
+ else
chan->rf_gain = 0x28;
- chan->active = htole16(36);
- if (sc->rxon->associd)
- chan->passive = htole16(88);
- else
- chan->passive = htole16(120);
- hdr->crc_threshold = 0xffff;
- }
DPRINTF(sc, IWN_DEBUG_STATE,
"%s: chan %u flags 0x%x rf_gain 0x%x "
- "dsp_gain 0x%x active 0x%x passive 0x%x\n", __func__,
+ "dsp_gain 0x%x active %d passive %d scan_svc_time %d crc 0x%x "
+ "isactive=%d numssid=%d\n", __func__,
chan->chan, chan->flags, chan->rf_gain, chan->dsp_gain,
- chan->active, chan->passive);
+ dwell_active, dwell_passive, scan_service_time,
+ hdr->crc_threshold, is_active, ss->ss_nssid);
hdr->nchan++;
chan++;
buflen = (uint8_t *)chan - buf;
hdr->len = htole16(buflen);
+ if (sc->sc_is_scanning) {
+ device_printf(sc->sc_dev,
+ "%s: called with is_scanning set!\n",
+ __func__);
+ }
+ sc->sc_is_scanning = 1;
+
DPRINTF(sc, IWN_DEBUG_STATE, "sending scan command nchan=%d\n",
hdr->nchan);
error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1);
@@ -5712,12 +6890,16 @@ iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap)
sc->rxon->ofdm_mask = 0;
} else {
/* Assume 802.11b/g. */
- sc->rxon->cck_mask = 0x0f;
+ sc->rxon->cck_mask = 0x03;
sc->rxon->ofdm_mask = 0x15;
}
DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n",
sc->rxon->chan, sc->rxon->flags, sc->rxon->cck_mask,
sc->rxon->ofdm_mask);
+ if (sc->sc_is_scanning)
+ device_printf(sc->sc_dev,
+ "%s: is_scanning set, before RXON\n",
+ __func__);
error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1);
if (error != 0) {
device_printf(sc->sc_dev, "%s: RXON command failed, error %d\n",
@@ -5813,6 +6995,10 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap)
sc->rxon->filter |= htole32(IWN_FILTER_BSS);
DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x\n",
sc->rxon->chan, sc->rxon->flags);
+ if (sc->sc_is_scanning)
+ device_printf(sc->sc_dev,
+ "%s: is_scanning set, before RXON\n",
+ __func__);
error = iwn_cmd(sc, IWN_CMD_RXON, sc->rxon, sc->rxonsz, 1);
if (error != 0) {
device_printf(sc->sc_dev,
@@ -6211,10 +7397,10 @@ iwn5000_query_calibration(struct iwn_softc *sc)
int error;
memset(&cmd, 0, sizeof cmd);
- cmd.ucode.once.enable = 0xffffffff;
- cmd.ucode.once.start = 0xffffffff;
- cmd.ucode.once.send = 0xffffffff;
- cmd.ucode.flags = 0xffffffff;
+ cmd.ucode.once.enable = htole32(0xffffffff);
+ cmd.ucode.once.start = htole32(0xffffffff);
+ cmd.ucode.once.send = htole32(0xffffffff);
+ cmd.ucode.flags = htole32(0xffffffff);
DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n",
__func__);
error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0);
@@ -6236,9 +7422,20 @@ iwn5000_send_calibration(struct iwn_softc *sc)
{
int idx, error;
- for (idx = 0; idx < 5; idx++) {
- if (sc->calibcmd[idx].buf == NULL)
- continue; /* No results available. */
+ for (idx = 0; idx < IWN5000_PHY_CALIB_MAX_RESULT; idx++) {
+ if (!(sc->base_params->calib_need & (1<<idx))) {
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ "No need of calib %d\n",
+ idx);
+ continue; /* no need for this calib */
+ }
+ if (sc->calibcmd[idx].buf == NULL) {
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ "Need calib idx : %d but no available data\n",
+ idx);
+ continue;
+ }
+
DPRINTF(sc, IWN_DEBUG_CALIBRATE,
"send calibration result idx=%d len=%d\n", idx,
sc->calibcmd[idx].len);
@@ -6259,7 +7456,7 @@ iwn5000_send_wimax_coex(struct iwn_softc *sc)
{
struct iwn5000_wimax_coex wimax;
-#ifdef notyet
+#if 0
if (sc->hw_type == IWN_HW_REV_TYPE_6050) {
/* Enable WiMAX coexistence for combo adapters. */
wimax.flags =
@@ -6315,6 +7512,33 @@ iwn5000_temp_offset_calib(struct iwn_softc *sc)
return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
}
+static int
+iwn5000_temp_offset_calibv2(struct iwn_softc *sc)
+{
+ struct iwn5000_phy_calib_temp_offsetv2 cmd;
+
+ memset(&cmd, 0, sizeof cmd);
+ cmd.code = IWN5000_PHY_CALIB_TEMP_OFFSET;
+ cmd.ngroups = 1;
+ cmd.isvalid = 1;
+ if (sc->eeprom_temp != 0) {
+ cmd.offset_low = htole16(sc->eeprom_temp);
+ cmd.offset_high = htole16(sc->eeprom_temp_high);
+ } else {
+ cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET);
+ cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET);
+ }
+ cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage);
+
+ DPRINTF(sc, IWN_DEBUG_CALIBRATE,
+ "setting radio sensor low offset to %d, high offset to %d, voltage to %d\n",
+ le16toh(cmd.offset_low),
+ le16toh(cmd.offset_high),
+ le16toh(cmd.burnt_voltage_ref));
+
+ return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
+}
+
/*
* This function is called after the runtime firmware notifies us of its
* readiness (called in a process context).
@@ -6400,7 +7624,10 @@ iwn5000_post_alive(struct iwn_softc *sc)
IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY);
/* Enable chain mode for all queues, except command queue. */
- iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef);
+ if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT)
+ iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffdf);
+ else
+ iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef);
iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0);
for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) {
@@ -6421,10 +7648,20 @@ iwn5000_post_alive(struct iwn_softc *sc)
iwn_prph_write(sc, IWN5000_SCHED_TXFACT, 0xff);
/* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
- for (qid = 0; qid < 7; qid++) {
- static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
- iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
- IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
+ if (sc->sc_flags & IWN_FLAG_PAN_SUPPORT) {
+ /* Mark TX rings as active. */
+ for (qid = 0; qid < 11; qid++) {
+ static uint8_t qid2fifo[] = { 3, 2, 1, 0, 0, 4, 2, 5, 4, 7, 5 };
+ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
+ IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
+ }
+ } else {
+ /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
+ for (qid = 0; qid < 7; qid++) {
+ static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
+ iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
+ IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
+ }
}
iwn_nic_unlock(sc);
@@ -6669,6 +7906,8 @@ iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw)
ptr = (const uint32_t *)fw->data;
rev = le32toh(*ptr++);
+ sc->ucode_rev = rev;
+
/* Check firmware API version. */
if (IWN_FW_API(rev) <= 1) {
device_printf(sc->sc_dev,
@@ -6734,6 +7973,7 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
}
DPRINTF(sc, IWN_DEBUG_RESET, "FW: \"%.64s\", build 0x%x\n", hdr->descr,
le32toh(hdr->build));
+ sc->ucode_rev = le32toh(hdr->rev);
/*
* Select the closest supported alternative that is less than
@@ -6789,7 +8029,7 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
sc->sc_flags |= IWN_FLAG_ENH_SENS;
break;
case IWN_FW_TLV_PHY_CALIB:
- tmp = htole32(*ptr);
+ tmp = le32toh(*ptr);
if (tmp < 253) {
sc->reset_noise_gain = tmp;
sc->noise_gain = tmp + 1;
@@ -6800,8 +8040,16 @@ iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
DPRINTF(sc, IWN_DEBUG_RESET,
"PAN Support found: %d\n", 1);
break;
- case IWN_FW_TLV_FLAGS :
- sc->tlv_feature_flags = htole32(*ptr);
+ case IWN_FW_TLV_FLAGS:
+ if (len < sizeof(uint32_t))
+ break;
+ if (len % sizeof(uint32_t))
+ break;
+ sc->tlv_feature_flags = le32toh(*ptr);
+ DPRINTF(sc, IWN_DEBUG_RESET,
+ "%s: feature: 0x%08x\n",
+ __func__,
+ sc->tlv_feature_flags);
break;
case IWN_FW_TLV_PBREQ_MAXLEN:
case IWN_FW_TLV_RUNT_EVTLOG_PTR:
@@ -6873,6 +8121,8 @@ iwn_read_firmware(struct iwn_softc *sc)
return error;
}
+ device_printf(sc->sc_dev, "%s: ucode rev=0x%08x\n", __func__, sc->ucode_rev);
+
/* Make sure text and data sections fit in hardware memory. */
if (fw->main.textsz > sc->fw_text_maxsz ||
fw->main.datasz > sc->fw_data_maxsz ||
@@ -6937,9 +8187,8 @@ iwn_apm_init(struct iwn_softc *sc)
else
IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA);
- if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
- sc->hw_type <= IWN_HW_REV_TYPE_1000)
- IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT);
+ if (sc->base_params->pll_cfg_val)
+ IWN_SETBITS(sc, IWN_ANA_PLL, sc->base_params->pll_cfg_val);
/* Wait for clock stabilization before accessing prph. */
if ((error = iwn_clock_wait(sc)) != 0)
@@ -7051,13 +8300,13 @@ iwn5000_nic_config(struct iwn_softc *sc)
/* Use internal power amplifier only. */
IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA);
}
- if ((sc->hw_type == IWN_HW_REV_TYPE_6050 ||
- sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) {
+ if (sc->base_params->additional_nic_config && sc->calib_ver >= 6) {
/* Indicate that ROM calibration version is >=6. */
IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
}
- if (sc->hw_type == IWN_HW_REV_TYPE_6005)
- IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2);
+ if (sc->base_params->additional_gp_drv_bit)
+ IWN_SETBITS(sc, IWN_GP_DRIVER,
+ sc->base_params->additional_gp_drv_bit);
return 0;
}
@@ -7192,7 +8441,7 @@ iwn_hw_init(struct iwn_softc *sc)
IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL);
/* Enable shadow registers. */
- if (sc->hw_type >= IWN_HW_REV_TYPE_6000)
+ if (sc->base_params->shadow_reg_enable)
IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff);
if ((error = ops->load_firmware(sc)) != 0) {
@@ -7305,6 +8554,44 @@ iwn_radio_off(void *arg0, int pending)
}
static void
+iwn_panicked(void *arg0, int pending)
+{
+ struct iwn_softc *sc = arg0;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+ struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+ int error;
+
+ if (vap == NULL) {
+ printf("%s: null vap\n", __func__);
+ return;
+ }
+
+ device_printf(sc->sc_dev, "%s: controller panicked, iv_state = %d; "
+ "resetting...\n", __func__, vap->iv_state);
+
+ IWN_LOCK(sc);
+
+ iwn_stop_locked(sc);
+ iwn_init_locked(sc);
+ if (vap->iv_state >= IEEE80211_S_AUTH &&
+ (error = iwn_auth(sc, vap)) != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not move to auth state\n", __func__);
+ }
+ if (vap->iv_state >= IEEE80211_S_RUN &&
+ (error = iwn_run(sc, vap)) != 0) {
+ device_printf(sc->sc_dev,
+ "%s: could not move to run state\n", __func__);
+ }
+
+ /* Only run start once the NIC is in a useful state, like associated */
+ iwn_start_locked(sc->sc_ifp);
+
+ IWN_UNLOCK(sc);
+}
+
+static void
iwn_init_locked(struct iwn_softc *sc)
{
struct ifnet *ifp = sc->sc_ifp;
@@ -7396,6 +8683,7 @@ iwn_stop_locked(struct iwn_softc *sc)
IWN_LOCK_ASSERT(sc);
+ sc->sc_is_scanning = 0;
sc->sc_tx_timer = 0;
callout_stop(&sc->watchdog_to);
callout_stop(&sc->calib_to);
@@ -7486,10 +8774,11 @@ iwn_scan_curchan(struct ieee80211_scan_state *ss, unsigned long maxdwell)
{
struct ieee80211vap *vap = ss->ss_vap;
struct iwn_softc *sc = vap->iv_ic->ic_ifp->if_softc;
+ struct ieee80211com *ic = vap->iv_ic;
int error;
IWN_LOCK(sc);
- error = iwn_scan(sc);
+ error = iwn_scan(sc, vap, ss, ic->ic_curchan);
IWN_UNLOCK(sc);
if (error != 0)
ieee80211_cancel_scan(vap);
@@ -7521,7 +8810,6 @@ iwn_hw_reset(void *arg0, int pending)
}
#ifdef IWN_DEBUG
#define IWN_DESC(x) case x: return #x
-#define COUNTOF(array) (sizeof(array) / sizeof(array[0]))
/*
* Translate CSR code to string
@@ -7592,7 +8880,7 @@ iwn_debug_register(struct iwn_softc *sc)
DPRINTF(sc, IWN_DEBUG_REGISTER,
"CSR values: (2nd byte of IWN_INT_COALESCING is IWN_INT_PERIODIC)%s",
"\n");
- for (i = 0; i < COUNTOF(csr_tbl); i++){
+ for (i = 0; i < nitems(csr_tbl); i++){
DPRINTF(sc, IWN_DEBUG_REGISTER," %10s: 0x%08x ",
iwn_get_csr_string(csr_tbl[i]), IWN_READ(sc, csr_tbl[i]));
if ((i+1) % 3 == 0)
diff --git a/sys/dev/iwn/if_iwn_chip_cfg.h b/sys/dev/iwn/if_iwn_chip_cfg.h
new file mode 100644
index 0000000..ea6f3e1
--- /dev/null
+++ b/sys/dev/iwn/if_iwn_chip_cfg.h
@@ -0,0 +1,413 @@
+/*-
+ * Copyright (c) 2013 Cedric GROSS <cg@cgross.info>
+ * Copyright (c) 2011 Intel Corporation
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __IF_IWN_CHIP_CFG_H__
+#define __IF_IWN_CHIP_CFG_H__
+
+/* ==========================================================================
+ * NIC PARAMETERS
+ *
+ * ==========================================================================
+ */
+
+/*
+ * Flags for managing calibration result. See calib_need
+ * in iwn_base_params struct
+ *
+ * These are bitmasks that determine which indexes in the calibcmd
+ * array are pushed up.
+ */
+#define IWN_FLG_NEED_PHY_CALIB_DC (1<<0)
+#define IWN_FLG_NEED_PHY_CALIB_LO (1<<1)
+#define IWN_FLG_NEED_PHY_CALIB_TX_IQ (1<<2)
+#define IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC (1<<3)
+#define IWN_FLG_NEED_PHY_CALIB_BASE_BAND (1<<4)
+/*
+ * These aren't (yet) included in the calibcmd array, but
+ * are used as flags for which calibrations to use.
+ *
+ * XXX I think they should be named differently and
+ * stuffed in a different member in the config struct!
+ */
+#define IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET (1<<5)
+#define IWN_FLG_NEED_PHY_CALIB_CRYSTAL (1<<6)
+#define IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2 (1<<7)
+
+/*
+ * Each chip has a different threshold for PLCP errors that should trigger a
+ * retune.
+ */
+#define IWN_PLCP_ERR_DEFAULT_THRESHOLD 50
+#define IWN_PLCP_ERR_LONG_THRESHOLD 100
+#define IWN_PLCP_ERR_EXT_LONG_THRESHOLD 200
+
+/*
+ * Define some parameters for managing different NIC.
+ * Refer to linux specific file like iwl-xxxx.c to determine correct value
+ * for NIC.
+ *
+ * @max_ll_items: max number of OTP blocks
+ * @shadow_ram_support: shadow support for OTP memory
+ * @shadow_reg_enable: HW shadhow register bit
+ * @no_idle_support: do not support idle mode
+ * @advanced_bt_coexist : Advanced BT management
+ * @bt_session_2 : NIC need a new struct for configure BT coexistence. Needed
+ * only if advanced_bt_coexist is true
+ * @bt_sco_disable :
+ * @additional_nic_config: For 6005 series
+ * @iq_invert : ? But need it for N 2000 series
+ * @regulatory_bands : XXX
+ * @enhanced_TX_power : EEPROM Has advanced TX power options. Set 'True'
+ * if update_enhanced_txpower = iwl_eeprom_enhanced_txpower.
+ * See iwl-agn-devices.c file to determine that(enhanced_txpower)
+ * @need_temp_offset_calib : Need to compute some temp offset for calibration.
+ * @calib_need : Use IWN_FLG_NEED_PHY_CALIB_* flags to specify which
+ * calibration data ucode need. See calib_init_cfg in iwl-xxxx.c
+ * linux kernel file
+ * @support_hostap: Define IEEE80211_C_HOSTAP for ic_caps
+ * @no_multi_vaps: See iwn_vap_create
+ * @additional_gp_drv_bit : Specific bit to defined during nic_config
+ * @bt_mode: BT configuration mode
+ */
+enum bt_mode_enum {
+ IWN_BT_NONE,
+ IWN_BT_SIMPLE,
+ IWN_BT_ADVANCED
+};
+
+struct iwn_base_params {
+ uint32_t pll_cfg_val;
+ const uint16_t max_ll_items;
+#define IWN_OTP_MAX_LL_ITEMS_1000 (3) /* OTP blocks for 1000 */
+#define IWN_OTP_MAX_LL_ITEMS_6x00 (4) /* OTP blocks for 6x00 */
+#define IWN_OTP_MAX_LL_ITEMS_6x50 (7) /* OTP blocks for 6x50 */
+#define IWN_OTP_MAX_LL_ITEMS_2x00 (4) /* OTP blocks for 2x00 */
+ const bool shadow_ram_support;
+ const bool shadow_reg_enable;
+ const bool bt_session_2;
+ const bool bt_sco_disable;
+ const bool additional_nic_config;
+ const uint32_t *regulatory_bands;
+ const bool enhanced_TX_power;
+ const uint16_t calib_need;
+ const bool support_hostap;
+ const bool no_multi_vaps;
+ uint8_t additional_gp_drv_bit;
+ enum bt_mode_enum bt_mode;
+ uint32_t plcp_err_threshold;
+};
+
+static const struct iwn_base_params iwn5000_base_params = {
+ .pll_cfg_val = IWN_ANA_PLL_INIT, /* pll_cfg_val; */
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, /* max_ll_items */
+ .shadow_ram_support = false, /* shadow_ram_support */
+ .shadow_reg_enable = false, /* shadow_reg_enable */
+ .bt_session_2 = false, /* bt_session_2 */
+ .bt_sco_disable = true, /* bt_sco_disable */
+ .additional_nic_config = false, /* additional_nic_config */
+ .regulatory_bands = iwn5000_regulatory_bands, /* regulatory_bands */
+ .enhanced_TX_power = false, /* enhanced_TX_power */
+ .calib_need =
+ ( IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ),
+ .support_hostap = false, /* support_hostap */
+ .no_multi_vaps = true, /* no_multi_vaps */
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, /* additional_gp_drv_bit */
+ .bt_mode = IWN_BT_NONE, /* bt_mode */
+ .plcp_err_threshold = IWN_PLCP_ERR_LONG_THRESHOLD,
+};
+
+/*
+ * 4965 support
+ */
+static const struct iwn_base_params iwn4965_base_params = {
+ .pll_cfg_val = 0, /* pll_cfg_val; */
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00, /* max_ll_items - ignored for 4965 */
+ .shadow_ram_support = true, /* shadow_ram_support */
+ .shadow_reg_enable = false, /* shadow_reg_enable */
+ .bt_session_2 = false, /* bt_session_2 XXX unknown? */
+ .bt_sco_disable = true, /* bt_sco_disable XXX unknown? */
+ .additional_nic_config = false, /* additional_nic_config - not for 4965 */
+ .regulatory_bands = iwn5000_regulatory_bands, /* regulatory_bands */
+ .enhanced_TX_power = false, /* enhanced_TX_power - not for 4965 */
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ),
+ .support_hostap = false, /* support_hostap - XXX should work on fixing! */
+ .no_multi_vaps = true, /* no_multi_vaps - XXX should work on fixing! */
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE, /* additional_gp_drv_bit */
+ .bt_mode = IWN_BT_SIMPLE, /* bt_mode */
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+
+static const struct iwn_base_params iwn2000_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_2x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = false,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn2030_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND
+ | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2 ),
+ .support_hostap = true,
+ .no_multi_vaps = false,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_REG_BIT_RADIO_IQ_INVERT,
+ .bt_mode = IWN_BT_NONE,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+static const struct iwn_base_params iwn2030_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_2x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = false, /* XXX check? */
+ .bt_session_2 = true,
+ .bt_sco_disable = true,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn2030_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND
+ | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSETv2 ),
+ .support_hostap = true,
+ .no_multi_vaps = false,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_REG_BIT_RADIO_IQ_INVERT,
+ .bt_mode = IWN_BT_ADVANCED,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+static const struct iwn_base_params iwn1000_base_params = {
+ .pll_cfg_val = IWN_ANA_PLL_INIT,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_1000,
+ .shadow_ram_support = false,
+ .shadow_reg_enable = false, /* XXX check? */
+ .bt_session_2 = false,
+ .bt_sco_disable = false,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn5000_regulatory_bands,
+ .enhanced_TX_power = false,
+ .calib_need =
+ ( IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND
+ ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE,
+ /* XXX 1000 - no BT */
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_EXT_LONG_THRESHOLD,
+};
+static const struct iwn_base_params iwn_6000_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = false,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE,
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+static const struct iwn_base_params iwn_6000i_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE,
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+static const struct iwn_base_params iwn_6000g2_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND
+ | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = 0,
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+static const struct iwn_base_params iwn_6050_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x50,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = true,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE,
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+static const struct iwn_base_params iwn_6150_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x50,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = true,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_6050_1X2,
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+/* IWL_DEVICE_6035 & IWL_DEVICE_6030 */
+static const struct iwn_base_params iwn_6000g2b_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND
+ | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE,
+ .bt_mode = IWN_BT_ADVANCED,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+/*
+ * 6235 series NICs.
+ */
+static const struct iwn_base_params iwn_6235_base_params = {
+ .pll_cfg_val = 0,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = true,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = true,
+ .regulatory_bands = iwn6000_regulatory_bands,
+ .enhanced_TX_power = true,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND
+ | IWN_FLG_NEED_PHY_CALIB_TEMP_OFFSET ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ /* XXX 1x2? This NIC is 2x2, right? */
+ .additional_gp_drv_bit = IWN_GP_DRIVER_6050_1X2,
+ .bt_mode = IWN_BT_ADVANCED,
+ .plcp_err_threshold = IWN_PLCP_ERR_DEFAULT_THRESHOLD,
+};
+
+static const struct iwn_base_params iwn_5x50_base_params = {
+ .pll_cfg_val = IWN_ANA_PLL_INIT,
+ .max_ll_items = IWN_OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .shadow_reg_enable = false,
+ .bt_session_2 = false,
+ .bt_sco_disable = true,
+ .additional_nic_config = false,
+ .regulatory_bands = iwn5000_regulatory_bands,
+ .enhanced_TX_power =false,
+ .calib_need =
+ (IWN_FLG_NEED_PHY_CALIB_DC
+ | IWN_FLG_NEED_PHY_CALIB_LO
+ | IWN_FLG_NEED_PHY_CALIB_TX_IQ
+ | IWN_FLG_NEED_PHY_CALIB_BASE_BAND ),
+ .support_hostap = false,
+ .no_multi_vaps = true,
+ .additional_gp_drv_bit = IWN_GP_DRIVER_NONE,
+ .bt_mode = IWN_BT_SIMPLE,
+ .plcp_err_threshold = IWN_PLCP_ERR_LONG_THRESHOLD,
+};
+
+#endif /* __IF_IWN_CHIP_CFG_H__ */
diff --git a/sys/dev/iwn/if_iwn_debug.h b/sys/dev/iwn/if_iwn_debug.h
new file mode 100644
index 0000000..2932c7e
--- /dev/null
+++ b/sys/dev/iwn/if_iwn_debug.h
@@ -0,0 +1,123 @@
+/*-
+ * Copyright (c) 2013 Cedric GROSS <c.gross@kreiz-it.fr>
+ * Copyright (c) 2011 Intel Corporation
+ * Copyright (c) 2007-2009
+ * Damien Bergamini <damien.bergamini@free.fr>
+ * Copyright (c) 2008
+ * Benjamin Close <benjsc@FreeBSD.org>
+ * Copyright (c) 2008 Sam Leffler, Errno Consulting
+ *
+ * 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __IF_IWN_DEBUG_H__
+#define __IF_IWN_DEBUG_H__
+
+#ifdef IWN_DEBUG
+enum {
+ IWN_DEBUG_XMIT = 0x00000001, /* basic xmit operation */
+ IWN_DEBUG_RECV = 0x00000002, /* basic recv operation */
+ IWN_DEBUG_STATE = 0x00000004, /* 802.11 state transitions */
+ IWN_DEBUG_TXPOW = 0x00000008, /* tx power processing */
+ IWN_DEBUG_RESET = 0x00000010, /* reset processing */
+ IWN_DEBUG_OPS = 0x00000020, /* iwn_ops processing */
+ IWN_DEBUG_BEACON = 0x00000040, /* beacon handling */
+ IWN_DEBUG_WATCHDOG = 0x00000080, /* watchdog timeout */
+ IWN_DEBUG_INTR = 0x00000100, /* ISR */
+ IWN_DEBUG_CALIBRATE = 0x00000200, /* periodic calibration */
+ IWN_DEBUG_NODE = 0x00000400, /* node management */
+ IWN_DEBUG_LED = 0x00000800, /* led management */
+ IWN_DEBUG_CMD = 0x00001000, /* cmd submission */
+ IWN_DEBUG_TXRATE = 0x00002000, /* TX rate debugging */
+ IWN_DEBUG_PWRSAVE = 0x00004000, /* Power save operations */
+ IWN_DEBUG_SCAN = 0x00008000, /* Scan related operations */
+ IWN_DEBUG_STATS = 0x00010000, /* Statistics updates */
+ IWN_DEBUG_REGISTER = 0x20000000, /* print chipset register */
+ IWN_DEBUG_TRACE = 0x40000000, /* Print begin and start driver function */
+ IWN_DEBUG_FATAL = 0x80000000, /* fatal errors */
+ IWN_DEBUG_ANY = 0xffffffff
+};
+
+#define DPRINTF(sc, m, fmt, ...) do { \
+ if (sc->sc_debug & (m)) \
+ printf(fmt, __VA_ARGS__); \
+} while (0)
+
+static const char *
+iwn_intr_str(uint8_t cmd)
+{
+ switch (cmd) {
+ /* Notifications */
+ case IWN_UC_READY: return "UC_READY";
+ case IWN_ADD_NODE_DONE: return "ADD_NODE_DONE";
+ case IWN_TX_DONE: return "TX_DONE";
+ case IWN_START_SCAN: return "START_SCAN";
+ case IWN_STOP_SCAN: return "STOP_SCAN";
+ case IWN_RX_STATISTICS: return "RX_STATS";
+ case IWN_BEACON_STATISTICS: return "BEACON_STATS";
+ case IWN_STATE_CHANGED: return "STATE_CHANGED";
+ case IWN_BEACON_MISSED: return "BEACON_MISSED";
+ case IWN_RX_PHY: return "RX_PHY";
+ case IWN_MPDU_RX_DONE: return "MPDU_RX_DONE";
+ case IWN_RX_DONE: return "RX_DONE";
+
+ /* Command Notifications */
+ case IWN_CMD_RXON: return "IWN_CMD_RXON";
+ case IWN_CMD_RXON_ASSOC: return "IWN_CMD_RXON_ASSOC";
+ case IWN_CMD_EDCA_PARAMS: return "IWN_CMD_EDCA_PARAMS";
+ case IWN_CMD_TIMING: return "IWN_CMD_TIMING";
+ case IWN_CMD_LINK_QUALITY: return "IWN_CMD_LINK_QUALITY";
+ case IWN_CMD_SET_LED: return "IWN_CMD_SET_LED";
+ case IWN5000_CMD_WIMAX_COEX: return "IWN5000_CMD_WIMAX_COEX";
+ case IWN5000_CMD_CALIB_CONFIG: return "IWN5000_CMD_CALIB_CONFIG";
+ case IWN5000_CMD_CALIB_RESULT: return "IWN5000_CMD_CALIB_RESULT";
+ case IWN5000_CMD_CALIB_COMPLETE: return "IWN5000_CMD_CALIB_COMPLETE";
+ case IWN_CMD_SET_POWER_MODE: return "IWN_CMD_SET_POWER_MODE";
+ case IWN_CMD_SCAN: return "IWN_CMD_SCAN";
+ case IWN_CMD_SCAN_RESULTS: return "IWN_CMD_SCAN_RESULTS";
+ case IWN_CMD_TXPOWER: return "IWN_CMD_TXPOWER";
+ case IWN_CMD_TXPOWER_DBM: return "IWN_CMD_TXPOWER_DBM";
+ case IWN5000_CMD_TX_ANT_CONFIG: return "IWN5000_CMD_TX_ANT_CONFIG";
+ case IWN_CMD_BT_COEX: return "IWN_CMD_BT_COEX";
+ case IWN_CMD_SET_CRITICAL_TEMP: return "IWN_CMD_SET_CRITICAL_TEMP";
+ case IWN_CMD_SET_SENSITIVITY: return "IWN_CMD_SET_SENSITIVITY";
+ case IWN_CMD_PHY_CALIB: return "IWN_CMD_PHY_CALIB";
+
+ /* Bluetooth commands */
+ case IWN_CMD_BT_COEX_PRIOTABLE: return "IWN_CMD_BT_COEX_PRIOTABLE";
+ case IWN_CMD_BT_COEX_PROT: return "IWN_CMD_BT_COEX_PROT";
+ case IWN_CMD_BT_COEX_NOTIF: return "IWN_CMD_BT_COEX_NOTIF";
+
+ /* PAN commands */
+ case IWN_CMD_WIPAN_PARAMS: return "IWN_CMD_WIPAN_PARAMS";
+ case IWN_CMD_WIPAN_RXON: return "IWN_CMD_WIPAN_RXON";
+ case IWN_CMD_WIPAN_RXON_TIMING: return "IWN_CMD_WIPAN_RXON_TIMING";
+ case IWN_CMD_WIPAN_RXON_ASSOC: return "IWN_CMD_WIPAN_RXON_ASSOC";
+ case IWN_CMD_WIPAN_QOS_PARAM: return "IWN_CMD_WIPAN_QOS_PARAM";
+ case IWN_CMD_WIPAN_WEPKEY: return "IWN_CMD_WIPAN_WEPKEY";
+ case IWN_CMD_WIPAN_P2P_CHANNEL_SWITCH:
+ return "IWN_CMD_WIPAN_P2P_CHANNEL_SWITCH";
+ case IWN_CMD_WIPAN_NOA_NOTIFICATION:
+ return "IWN_CMD_WIPAN_NOA_NOTIFICATION";
+ case IWN_CMD_WIPAN_DEACTIVATION_COMPLETE:
+ return "IWN_CMD_WIPAN_DEACTIVATION_COMPLETE";
+ }
+ return "UNKNOWN INTR NOTIF/CMD";
+}
+#else
+#define DPRINTF(sc, m, fmt, ...) do { (void) sc; } while (0)
+#endif
+
+#endif /* __IF_IWN_DEBUG_H__ */
diff --git a/sys/dev/iwn/if_iwn_devid.h b/sys/dev/iwn/if_iwn_devid.h
index 23fd0a1..dd08737 100644
--- a/sys/dev/iwn/if_iwn_devid.h
+++ b/sys/dev/iwn/if_iwn_devid.h
@@ -41,6 +41,20 @@
* DEVICE ID BLOCK
* ==========================================================================
*/
+
+/*
+ * --------------------------------------------------------------------------
+ * Device ID for 2x00 series
+ * --------------------------------------------------------------------------
+ */
+#define IWN_DID_2x00_1 0x0890
+#define IWN_DID_2x00_2 0x0891
+/* SubDevice ID */
+#define IWN_SDID_2x00_1 0x4022
+#define IWN_SDID_2x00_2 0x4222
+#define IWN_SDID_2x00_3 0x4422
+#define IWN_SDID_2x00_4 0x4822
+
/*
* --------------------------------------------------------------------------
* Device ID for 2x30 series
@@ -214,6 +228,31 @@
/*
* --------------------------------------------------------------------------
+ * Device ID for 105 Series
+ * --------------------------------------------------------------------------
+ */
+#define IWN_DID_105_1 0x0894
+#define IWN_DID_105_2 0x0895
+/* SubDevice ID */
+#define IWN_SDID_105_1 0x0022
+#define IWN_SDID_105_2 0x0222
+#define IWN_SDID_105_3 0x0422
+#define IWN_SDID_105_4 0x0822
+
+/*
+ * --------------------------------------------------------------------------
+ * Device ID for 135 Series
+ * --------------------------------------------------------------------------
+ */
+#define IWN_DID_135_1 0x0892
+#define IWN_DID_135_2 0x0893
+/* SubDevice ID */
+#define IWN_SDID_135_1 0x0062
+#define IWN_SDID_135_2 0x0262
+#define IWN_SDID_135_3 0x0462
+
+/*
+ * --------------------------------------------------------------------------
* Device ID for 5x00 Series
* --------------------------------------------------------------------------
*/
diff --git a/sys/dev/iwn/if_iwn_ioctl.h b/sys/dev/iwn/if_iwn_ioctl.h
new file mode 100644
index 0000000..1acf464
--- /dev/null
+++ b/sys/dev/iwn/if_iwn_ioctl.h
@@ -0,0 +1,25 @@
+/*-
+ * Copyright (c) 2014 Adrian Chadd <adrian@FreeBSD.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.
+ *
+ * $FreeBSD$
+ */
+#ifndef __IF_IWN_IOCTL_H__
+#define __IF_IWN_IOCTL_H__
+
+/* XXX how should I pick appropriate ioctl numbers? */
+#define SIOCGIWNSTATS _IOWR('i', 145, struct ifreq)
+#define SIOCZIWNSTATS _IOWR('i', 146, struct ifreq)
+
+#endif /* __IF_IWN_IOCTL_H__ */
diff --git a/sys/dev/iwn/if_iwnreg.h b/sys/dev/iwn/if_iwnreg.h
index e61d0fd..ed65c0b 100644
--- a/sys/dev/iwn/if_iwnreg.h
+++ b/sys/dev/iwn/if_iwnreg.h
@@ -17,6 +17,8 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#ifndef __IF_IWNREG_H__
+#define __IF_IWNREG_H__
#define IWN_CT_KILL_THRESHOLD 114 /* in Celsius */
#define IWN_CT_KILL_EXIT_THRESHOLD 95 /* in Celsius */
@@ -222,6 +224,7 @@
#define IWN_GP_DRIVER_CALIB_VER6 (1 << 2)
#define IWN_GP_DRIVER_6050_1X2 (1 << 3)
#define IWN_GP_DRIVER_REG_BIT_RADIO_IQ_INVERT (1 << 7)
+#define IWN_GP_DRIVER_NONE 0
/* Possible flags for register IWN_UCODE_GP1_CLR. */
#define IWN_UCODE_GP1_RFKILL (1 << 1)
@@ -486,6 +489,7 @@ struct iwn_tx_cmd {
#define IWN_CMD_TXPOWER_DBM 149
#define IWN_CMD_TXPOWER 151
#define IWN5000_CMD_TX_ANT_CONFIG 152
+#define IWN_CMD_TXPOWER_DBM_V1 152
#define IWN_CMD_BT_COEX 155
#define IWN_CMD_GET_STATISTICS 156
#define IWN_CMD_SET_CRITICAL_TEMP 164
@@ -882,7 +886,7 @@ struct iwn_scan_essid {
struct iwn_scan_hdr {
uint16_t len;
- uint8_t reserved1;
+ uint8_t scan_flags;
uint8_t nchan;
uint16_t quiet_time;
uint16_t quiet_threshold;
@@ -919,17 +923,53 @@ struct iwn_scan_chan {
/* Maximum size of a scan command. */
#define IWN_SCAN_MAXSZ (MCLBYTES - 4)
-#define IWN_ACTIVE_DWELL_TIME_24 (30) /* all times in msec */
-#define IWN_ACTIVE_DWELL_TIME_52 (20)
-#define IWN_ACTIVE_DWELL_FACTOR_24 (3)
-#define IWN_ACTIVE_DWELL_FACTOR_52 (2)
+/*
+ * For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
+ * sending probe req. This should be set long enough to hear probe responses
+ * from more than one AP.
+ */
+#define IWN_ACTIVE_DWELL_TIME_2GHZ (30) /* all times in msec */
+#define IWN_ACTIVE_DWELL_TIME_5GHZ (20)
+#define IWN_ACTIVE_DWELL_FACTOR_2GHZ (3)
+#define IWN_ACTIVE_DWELL_FACTOR_5GHZ (2)
-#define IWN_PASSIVE_DWELL_TIME_24 (20) /* all times in msec */
-#define IWN_PASSIVE_DWELL_TIME_52 (10)
+/*
+ * For passive scan, listen PASSIVE_DWELL_TIME (msec) on each channel.
+ * Must be set longer than active dwell time.
+ * For the most reliable scan, set > AP beacon interval (typically 100msec).
+ */
+#define IWN_PASSIVE_DWELL_TIME_2GHZ (20) /* all times in msec */
+#define IWN_PASSIVE_DWELL_TIME_5GHZ (10)
#define IWN_PASSIVE_DWELL_BASE (100)
#define IWN_CHANNEL_TUNE_TIME (5)
#define IWN_SCAN_CHAN_TIMEOUT 2
+#define IWN_MAX_SCAN_CHANNEL 50
+
+/*
+ * If active scanning is requested but a certain channel is
+ * marked passive, we can do active scanning if we detect
+ * transmissions.
+ *
+ * There is an issue with some firmware versions that triggers
+ * a sysassert on a "good CRC threshold" of zero (== disabled),
+ * on a radar channel even though this means that we should NOT
+ * send probes.
+ *
+ * The "good CRC threshold" is the number of frames that we
+ * need to receive during our dwell time on a channel before
+ * sending out probes -- setting this to a huge value will
+ * mean we never reach it, but at the same time work around
+ * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+ * here instead of IWL_GOOD_CRC_TH_DISABLED.
+ *
+ * This was fixed in later versions along with some other
+ * scan changes, and the threshold behaves as a flag in those
+ * versions.
+ */
+#define IWN_GOOD_CRC_TH_DISABLED 0
+#define IWN_GOOD_CRC_TH_DEFAULT htole16(1)
+#define IWN_GOOD_CRC_TH_NEVER htole16(0xffff)
/* Structure for command IWN_CMD_TXPOWER (4965AGN only.) */
#define IWN_RIDX_MAX 32
@@ -1102,6 +1142,12 @@ struct iwn_enhanced_sensitivity_cmd {
uint16_t reserved;
} __packed;
+/*
+ * Define maximal number of calib result send to runtime firmware
+ * PS: TEMP_OFFSET count for 2 (std and v2)
+ */
+#define IWN5000_PHY_CALIB_MAX_RESULT 8
+
/* Structures for command IWN_CMD_PHY_CALIB. */
struct iwn_phy_calib {
uint8_t code;
@@ -1221,17 +1267,91 @@ struct iwn_ucode_info {
} __packed;
/* Structures for IWN_TX_DONE notification. */
-#define IWN_TX_STATUS_MSK 0xff
-#define TX_STATUS_SUCCESS 0x01
-#define TX_STATUS_DIRECT_DONE 0x02
-
-#define IWN_TX_SUCCESS 0x00
-#define IWN_TX_FAIL 0x80 /* all failures have 0x80 set */
-#define IWN_TX_FAIL_SHORT_LIMIT 0x82 /* too many RTS retries */
-#define IWN_TX_FAIL_LONG_LIMIT 0x83 /* too many retries */
-#define IWN_TX_FAIL_FIFO_UNDERRRUN 0x84 /* tx fifo not kept running */
-#define IWN_TX_FAIL_DEST_IN_PS 0x88 /* sta found in power save */
-#define IWN_TX_FAIL_TX_LOCKED 0x90 /* waiting to see traffic */
+
+/*
+ * TX command response is sent after *agn* transmission attempts.
+ *
+ * both postpone and abort status are expected behavior from uCode. there is
+ * no special operation required from driver; except for RFKILL_FLUSH,
+ * which required tx flush host command to flush all the tx frames in queues
+ */
+#define IWN_TX_STATUS_MSK 0x000000ff
+#define IWN_TX_STATUS_DELAY_MSK 0x00000040
+#define IWN_TX_STATUS_ABORT_MSK 0x00000080
+#define IWN_TX_PACKET_MODE_MSK 0x0000ff00
+#define IWN_TX_FIFO_NUMBER_MSK 0x00070000
+#define IWN_TX_RESERVED 0x00780000
+#define IWN_TX_POWER_PA_DETECT_MSK 0x7f800000
+#define IWN_TX_ABORT_REQUIRED_MSK 0x80000000
+
+/* Success status */
+#define IWN_TX_STATUS_SUCCESS 0x01
+#define IWN_TX_STATUS_DIRECT_DONE 0x02
+
+/* postpone TX */
+#define IWN_TX_STATUS_POSTPONE_DELAY 0x40
+#define IWN_TX_STATUS_POSTPONE_FEW_BYTES 0x41
+#define IWN_TX_STATUS_POSTPONE_BT_PRIO 0x42
+#define IWN_TX_STATUS_POSTPONE_QUIET_PERIOD 0x43
+#define IWN_TX_STATUS_POSTPONE_CALC_TTAK 0x44
+
+/* Failures */
+#define IWN_TX_FAIL 0x80 /* all failures have 0x80 set */
+#define IWN_TX_STATUS_FAIL_INTERNAL_CROSSED_RETRY 0x81
+#define IWN_TX_FAIL_SHORT_LIMIT 0x82 /* too many RTS retries */
+#define IWN_TX_FAIL_LONG_LIMIT 0x83 /* too many retries */
+#define IWN_TX_FAIL_FIFO_UNDERRRUN 0x84 /* tx fifo not kept running */
+#define IWN_TX_STATUS_FAIL_DRAIN_FLOW 0x85
+#define IWN_TX_STATUS_FAIL_RFKILL_FLUSH 0x86
+#define IWN_TX_STATUS_FAIL_LIFE_EXPIRE 0x87
+#define IWN_TX_FAIL_DEST_IN_PS 0x88 /* sta found in power save */
+#define IWN_TX_STATUS_FAIL_HOST_ABORTED 0x89
+#define IWN_TX_STATUS_FAIL_BT_RETRY 0x8a
+#define IWN_TX_FAIL_STA_INVALID 0x8b /* XXX STA invalid (???) */
+#define IWN_TX_STATUS_FAIL_FRAG_DROPPED 0x8c
+#define IWN_TX_STATUS_FAIL_TID_DISABLE 0x8d
+#define IWN_TX_STATUS_FAIL_FIFO_FLUSHED 0x8e
+#define IWN_TX_STATUS_FAIL_INSUFFICIENT_CF_POLL 0x8f
+#define IWN_TX_FAIL_TX_LOCKED 0x90 /* waiting to see traffic */
+#define IWN_TX_STATUS_FAIL_NO_BEACON_ON_RADAR 0x91
+
+/*
+ * TX command response for A-MPDU packet responses.
+ *
+ * The status response is different to the non A-MPDU responses.
+ * In addition, the sequence number is treated as the sequence
+ * number of the TX command, NOT the 802.11 sequence number!
+ */
+#define IWN_AGG_TX_STATE_TRANSMITTED 0x00
+#define IWN_AGG_TX_STATE_UNDERRUN_MSK 0x01
+#define IWN_AGG_TX_STATE_FEW_BYTES_MSK 0x04
+#define IWN_AGG_TX_STATE_ABORT_MSK 0x08
+
+#define IWN_AGG_TX_STATE_LAST_SENT_TTL_MSK 0x10
+#define IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK 0x20
+
+#define IWN_AGG_TX_STATE_SCD_QUERY_MSK 0x80
+
+#define IWN_AGG_TX_STATE_TEST_BAD_CRC32_MSK 0x100
+
+#define IWN_AGG_TX_STATE_RESPONSE_MSK 0x1ff
+#define IWN_AGG_TX_STATE_DUMP_TX_MSK 0x200
+#define IWN_AGG_TX_STATE_DELAY_TX_MSK 0x400
+
+#define IWN_AGG_TX_STATUS_MSK 0x00000fff
+#define IWN_AGG_TX_TRY_MSK 0x0000f000
+
+#define IWN_AGG_TX_STATE_LAST_SENT_MSK \
+ (IWN_AGG_TX_STATE_LAST_SENT_TTL_MSK | \
+ IWN_AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK)
+
+/* # tx attempts for first frame in aggregation */
+#define IWN_AGG_TX_STATE_TRY_CNT_POS 12
+#define IWN_AGG_TX_STATE_TRY_CNT_MSK 0xf000
+
+/* Command ID and sequence number of Tx command for this frame */
+#define IWN_AGG_TX_STATE_SEQ_NUM_POS 16
+#define IWN_AGG_TX_STATE_SEQ_NUM_MSK 0xffff0000
struct iwn4965_tx_stat {
uint8_t nframes;
@@ -1358,6 +1478,12 @@ struct iwn_compressed_ba {
uint64_t bitmap;
uint16_t qid;
uint16_t ssn;
+ /* extra fields starting with iwn5000 */
+#if 0
+ uint8_t txed; /* number of frames sent */
+ uint8_t txed_2_done; /* number of frames acked */
+ uint16_t reserved1;
+#endif
} __packed;
/* Structure for IWN_START_SCAN notification. */
@@ -1463,7 +1589,7 @@ struct iwn_rx_ht_phy_stats {
uint32_t good_ampdu_crc32;
uint32_t ampdu;
uint32_t fragment;
- uint32_t reserved;
+ uint32_t unsupport_mcs;
} __packed;
struct iwn_rx_stats {
@@ -1473,6 +1599,20 @@ struct iwn_rx_stats {
struct iwn_rx_ht_phy_stats ht;
} __packed;
+struct iwn_rx_general_stats_bt {
+ struct iwn_rx_general_stats common;
+ /* additional stats for bt */
+ uint32_t num_bt_kills;
+ uint32_t reserved[2];
+} __packed;
+
+struct iwn_rx_stats_bt {
+ struct iwn_rx_phy_stats ofdm;
+ struct iwn_rx_phy_stats cck;
+ struct iwn_rx_general_stats_bt general_bt;
+ struct iwn_rx_ht_phy_stats ht;
+} __packed;
+
struct iwn_tx_stats {
uint32_t preamble;
uint32_t rx_detected;
@@ -1484,7 +1624,7 @@ struct iwn_tx_stats {
uint32_t exp_ack;
uint32_t ack;
uint32_t msdu;
- uint32_t busrt_err1;
+ uint32_t burst_err1;
uint32_t burst_err2;
uint32_t cts_collision;
uint32_t ack_collision;
@@ -1498,15 +1638,21 @@ struct iwn_tx_stats {
uint32_t underrun;
uint32_t bt_ht_kill;
uint32_t rx_ba_resp;
- uint32_t reserved[2];
+ /*
+ * 6000 series only - LSB=ant A, ant B, ant C, MSB=reserved
+ * TX power on chain in 1/2 dBm.
+ */
+ uint32_t tx_power;
+ uint32_t reserved[1];
} __packed;
struct iwn_general_stats {
- uint32_t temp;
- uint32_t temp_m;
+ uint32_t temp; /* radio temperature */
+ uint32_t temp_m; /* radio voltage */
uint32_t burst_check;
uint32_t burst;
- uint32_t reserved1[4];
+ uint32_t wait_for_silence_timeout_cnt;
+ uint32_t reserved1[3];
uint32_t sleep;
uint32_t slot_out;
uint32_t slot_idle;
@@ -1517,7 +1663,11 @@ struct iwn_general_stats {
uint32_t probe;
uint32_t reserved2[2];
uint32_t rx_enabled;
- uint32_t reserved3[3];
+ /*
+ * This is the number of times we have to re-tune
+ * in order to get out of bad PHY status.
+ */
+ uint32_t num_of_sos_states;
} __packed;
struct iwn_stats {
@@ -1525,8 +1675,30 @@ struct iwn_stats {
struct iwn_rx_stats rx;
struct iwn_tx_stats tx;
struct iwn_general_stats general;
+ uint32_t reserved1[2];
} __packed;
+struct iwn_bt_activity_stats {
+ /* Tx statistics */
+ uint32_t hi_priority_tx_req_cnt;
+ uint32_t hi_priority_tx_denied_cnt;
+ uint32_t lo_priority_tx_req_cnt;
+ uint32_t lo_priority_tx_denied_cnt;
+ /* Rx statistics */
+ uint32_t hi_priority_rx_req_cnt;
+ uint32_t hi_priority_rx_denied_cnt;
+ uint32_t lo_priority_rx_req_cnt;
+ uint32_t lo_priority_rx_denied_cnt;
+} __packed;
+
+struct iwn_stats_bt {
+ uint32_t flags;
+ struct iwn_rx_stats_bt rx_bt;
+ struct iwn_tx_stats tx;
+ struct iwn_general_stats general;
+ struct iwn_bt_activity_stats activity;
+ uint32_t reserved1[2];
+};
/* Firmware error dump. */
struct iwn_fw_dump {
@@ -1564,7 +1736,7 @@ struct iwn_fw_tlv {
#define IWN_FW_TLV_INIT_DATA 4
#define IWN_FW_TLV_BOOT_TEXT 5
#define IWN_FW_TLV_PBREQ_MAXLEN 6
-#define IWN_FW_TLV_PAN 7
+#define IWN_FW_TLV_PAN 7
#define IWN_FW_TLV_RUNT_EVTLOG_PTR 8
#define IWN_FW_TLV_RUNT_EVTLOG_SIZE 9
#define IWN_FW_TLV_RUNT_ERRLOG_PTR 10
@@ -1575,7 +1747,7 @@ struct iwn_fw_tlv {
#define IWN_FW_TLV_PHY_CALIB 15
#define IWN_FW_TLV_WOWLAN_INST 16
#define IWN_FW_TLV_WOWLAN_DATA 17
-#define IWN_FW_TLV_FLAGS 18
+#define IWN_FW_TLV_FLAGS 18
uint16_t alt;
uint32_t len;
@@ -1590,6 +1762,60 @@ struct iwn_fw_tlv {
#define IWN5000_FWSZ IWN5000_FW_TEXT_MAXSZ
/*
+ * Microcode flags TLV (18.)
+ */
+
+/**
+ * enum iwn_ucode_tlv_flag - ucode API flags
+ * @IWN_UCODE_TLV_FLAGS_PAN: This is PAN capable microcode; this previously
+ * was a separate TLV but moved here to save space.
+ * @IWN_UCODE_TLV_FLAGS_NEWSCAN: new uCode scan behaviour on hidden SSID,
+ * treats good CRC threshold as a boolean
+ * @IWN_UCODE_TLV_FLAGS_MFP: This uCode image supports MFP (802.11w).
+ * @IWN_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
+ * @IWN_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
+ * @IWN_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
+ * @IWN_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan
+ * offload profile config command.
+ * @IWN_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
+ * @IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API.
+ * @IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six
+ * (rather than two) IPv6 addresses
+ * @IWN_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
+ * @IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
+ * from the probe request template.
+ * @IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API: modified D3 API to allow keeping
+ * connection when going back to D0
+ * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL: new NS offload (small version)
+ * @IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE: new NS offload (large version)
+ * @IWN_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
+ * @IWN_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
+ * @IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD: support device wide power command
+ * containing CAM (Continuous Active Mode) indication.
+ */
+enum iwn_ucode_tlv_flag {
+ IWN_UCODE_TLV_FLAGS_PAN = (1 << 0),
+ IWN_UCODE_TLV_FLAGS_NEWSCAN = (1 << 1),
+ IWN_UCODE_TLV_FLAGS_MFP = (1 << 2),
+ IWN_UCODE_TLV_FLAGS_P2P = (1 << 3),
+ IWN_UCODE_TLV_FLAGS_DW_BC_TABLE = (1 << 4),
+ IWN_UCODE_TLV_FLAGS_NEWBT_COEX = (1 << 5),
+ IWN_UCODE_TLV_FLAGS_UAPSD = (1 << 6),
+ IWN_UCODE_TLV_FLAGS_SHORT_BL = (1 << 7),
+ IWN_UCODE_TLV_FLAGS_RX_ENERGY_API = (1 << 8),
+ IWN_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = (1 << 9),
+ IWN_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = (1 << 10),
+ IWN_UCODE_TLV_FLAGS_BF_UPDATED = (1 << 11),
+ IWN_UCODE_TLV_FLAGS_NO_BASIC_SSID = (1 << 12),
+ IWN_UCODE_TLV_FLAGS_D3_CONTINUITY_API = (1 << 14),
+ IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_SMALL = (1 << 15),
+ IWN_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE = (1 << 16),
+ IWN_UCODE_TLV_FLAGS_SCHED_SCAN = (1 << 17),
+ IWN_UCODE_TLV_FLAGS_STA_KEY_CMD = (1 << 19),
+ IWN_UCODE_TLV_FLAGS_DEVICE_PS_CMD = (1 << 20),
+};
+
+/*
* Offsets into EEPROM.
*/
#define IWN_EEPROM_MAC 0x015
@@ -1731,6 +1957,16 @@ static const uint32_t iwn1000_regulatory_bands[IWN_NBANDS] = {
IWN5000_EEPROM_NO_HT40,
};
+static const uint32_t iwn2030_regulatory_bands[IWN_NBANDS] = {
+ IWN5000_EEPROM_BAND1,
+ IWN5000_EEPROM_BAND2,
+ IWN5000_EEPROM_BAND3,
+ IWN5000_EEPROM_BAND4,
+ IWN5000_EEPROM_BAND5,
+ IWN6000_EEPROM_BAND6,
+ IWN5000_EEPROM_BAND7
+};
+
#define IWN_CHAN_BANDS_COUNT 7
#define IWN_MAX_CHAN_PER_BAND 14
static const struct iwn_chan_band {
@@ -1757,8 +1993,8 @@ static const uint8_t iwn_bss_ac_to_queue[] = {
static const uint8_t iwn_pan_ac_to_queue[] = {
5, 4, 6, 7,
};
-#define IWN1000_OTP_NBLOCKS 3
-#define IWN6000_OTP_NBLOCKS 4
+#define IWN1000_OTP_NBLOCKS 3
+#define IWN6000_OTP_NBLOCKS 4
#define IWN6050_OTP_NBLOCKS 7
/* HW rate indices. */
@@ -1891,6 +2127,7 @@ struct iwn_sensitivity_limits {
uint32_t min_energy_cck;
uint32_t energy_cck;
uint32_t energy_ofdm;
+ uint32_t barker_mrc;
};
/*
@@ -1905,7 +2142,8 @@ static const struct iwn_sensitivity_limits iwn4965_sensitivity_limits = {
200, 400,
97,
100,
- 100
+ 100,
+ 390
};
static const struct iwn_sensitivity_limits iwn5000_sensitivity_limits = {
@@ -1917,7 +2155,8 @@ static const struct iwn_sensitivity_limits iwn5000_sensitivity_limits = {
170, 400,
95,
95,
- 95
+ 95,
+ 390
};
static const struct iwn_sensitivity_limits iwn5150_sensitivity_limits = {
@@ -1929,7 +2168,8 @@ static const struct iwn_sensitivity_limits iwn5150_sensitivity_limits = {
170, 400,
95,
95,
- 95
+ 95,
+ 390,
};
static const struct iwn_sensitivity_limits iwn1000_sensitivity_limits = {
@@ -1941,7 +2181,8 @@ static const struct iwn_sensitivity_limits iwn1000_sensitivity_limits = {
170, 400,
95,
95,
- 95
+ 95,
+ 390,
};
static const struct iwn_sensitivity_limits iwn6000_sensitivity_limits = {
@@ -1953,9 +2194,24 @@ static const struct iwn_sensitivity_limits iwn6000_sensitivity_limits = {
160, 310,
97,
97,
- 100
+ 100,
+ 390
+};
+
+static const struct iwn_sensitivity_limits iwn6235_sensitivity_limits = {
+ 105, 110,
+ 192, 232,
+ 80, 145,
+ 128, 232,
+ 125, 175,
+ 160, 310,
+ 100,
+ 110,
+ 110,
+ 336
};
+
/* Get value from linux kernel 3.2.+ in Drivers/net/wireless/iwlwifi/iwl-2000.c*/
static const struct iwn_sensitivity_limits iwn2030_sensitivity_limits = {
105,110,
@@ -2052,3 +2308,5 @@ static const char * const iwn_fw_errmsg[] = {
#define IWN_BARRIER_READ_WRITE(sc) \
bus_space_barrier((sc)->sc_st, (sc)->sc_sh, 0, (sc)->sc_sz, \
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+#endif /* __IF_IWNREG_H__ */
diff --git a/sys/dev/iwn/if_iwnvar.h b/sys/dev/iwn/if_iwnvar.h
index 11a233d..b14158b 100644
--- a/sys/dev/iwn/if_iwnvar.h
+++ b/sys/dev/iwn/if_iwnvar.h
@@ -163,6 +163,7 @@ struct iwn_calib_state {
uint32_t bad_plcp_cck;
uint32_t fa_cck;
uint32_t low_fa;
+ uint32_t bad_plcp_ht;
uint8_t cck_state;
#define IWN_CCK_STATE_INIT 0
#define IWN_CCK_STATE_LOFA 1
@@ -249,6 +250,7 @@ struct iwn_softc {
#define IWN_FLAG_ENH_SENS (1 << 7)
#define IWN_FLAG_ADV_BTCOEX (1 << 8)
#define IWN_FLAG_PAN_SUPPORT (1 << 9)
+#define IWN_FLAG_BTCOEX (1 << 10)
uint8_t hw_type;
/* subdevice_id used to adjust configuration */
@@ -306,14 +308,20 @@ struct iwn_softc {
struct task sc_reinit_task;
struct task sc_radioon_task;
struct task sc_radiooff_task;
+ struct task sc_panic_task;
+ /* Taskqueue */
+ struct taskqueue *sc_tq;
+
+ /* Calibration information */
struct callout calib_to;
int calib_cnt;
struct iwn_calib_state calib;
+ int last_calib_ticks;
struct callout watchdog_to;
struct callout ct_kill_exit_to;
struct iwn_fw_info fw;
- struct iwn_calib_info calibcmd[5];
+ struct iwn_calib_info calibcmd[IWN5000_PHY_CALIB_MAX_RESULT];
uint32_t errptr;
struct iwn_rx_stat last_rx_stat;
@@ -324,6 +332,22 @@ struct iwn_softc {
int ctx;
struct ieee80211vap *ivap[IWN_NUM_RXON_CTX];
+ /* General statistics */
+ /*
+ * The statistics are reset after each channel
+ * change. So it may be zeroed after things like
+ * a background scan.
+ *
+ * So for now, this is just a cheap hack to
+ * expose the last received statistics dump
+ * via an ioctl(). Later versions of this
+ * could expose the last 'n' messages, or just
+ * provide a pipeline for the firmware responses
+ * via something like BPF.
+ */
+ struct iwn_stats last_stat;
+ int last_stat_valid;
+
uint8_t uc_scan_progress;
uint32_t rawtemp;
int temp;
@@ -358,6 +382,9 @@ struct iwn_softc {
int sc_tx_timer;
int sc_scan_timer;
+ /* Are we doing a scan? */
+ int sc_is_scanning;
+
struct ieee80211_tx_ampdu *qid2tap[IWN5000_NTXQUEUES];
int (*sc_ampdu_rx_start)(struct ieee80211_node *,
@@ -385,8 +412,11 @@ struct iwn_softc {
*/
int current_pwrsave_level;
- /* For specifique params */
- struct iwn_base_params *base_params;
+ /* For specific params */
+ const struct iwn_base_params *base_params;
+
+#define IWN_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8)
+ uint32_t ucode_rev;
};
#define IWN_LOCK_INIT(_sc) \
OpenPOWER on IntegriCloud