diff options
Diffstat (limited to 'sys/dev/iwn/if_iwn.c')
-rw-r--r-- | sys/dev/iwn/if_iwn.c | 2094 |
1 files changed, 403 insertions, 1691 deletions
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c index ab98204..806a408 100644 --- a/sys/dev/iwn/if_iwn.c +++ b/sys/dev/iwn/if_iwn.c @@ -1,10 +1,11 @@ /*- - * 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> + * 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 @@ -56,7 +57,6 @@ __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,9 +77,6 @@ __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; @@ -100,19 +97,12 @@ 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" }, @@ -129,8 +119,6 @@ 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 } }; @@ -138,7 +126,6 @@ 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 *, @@ -213,7 +200,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, int, void *); +static void iwn_ampdu_tx_done(struct iwn_softc *, 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 *); @@ -270,17 +257,14 @@ 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 int iwn_scan(struct iwn_softc *, struct ieee80211vap *, - struct ieee80211_scan_state *, struct ieee80211_channel *); +static uint8_t *ieee80211_add_ssid(uint8_t *, const uint8_t *, u_int); +static int iwn_scan(struct iwn_softc *); 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 *, @@ -308,7 +292,6 @@ 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 *, @@ -333,7 +316,6 @@ 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 *); @@ -349,6 +331,80 @@ 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), @@ -392,15 +448,6 @@ 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); @@ -468,11 +515,6 @@ 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 @@ -483,16 +525,6 @@ 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; @@ -602,16 +634,17 @@ iwn_attach(device_t dev) ic->ic_txstream = sc->ntxchains; /* - * 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. + * 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. */ - if (! iwn_is_3stream_device(sc)) { - if (ic->ic_rxstream > 2) - ic->ic_rxstream = 2; - if (ic->ic_txstream > 2) - ic->ic_txstream = 2; - } + 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 */ @@ -677,15 +710,6 @@ 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); @@ -700,13 +724,6 @@ 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__); @@ -717,488 +734,6 @@ 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) { @@ -1234,8 +769,6 @@ 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__); @@ -1276,6 +809,58 @@ 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; } @@ -1374,10 +959,6 @@ 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); @@ -1603,7 +1184,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->base_params->shadow_ram_support) { + if (sc->hw_type != IWN_HW_REV_TYPE_1000) { IWN_SETBITS(sc, IWN_DBG_LINK_PWR_MGMT, IWN_RESET_LINK_PWR_MGMT_DIS); } @@ -1616,12 +1197,11 @@ 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->base_params->shadow_ram_support) { + if (sc->hw_type == IWN_HW_REV_TYPE_1000) { /* Switch to absolute addressing mode. */ IWN_CLRBITS(sc, IWN_OTP_GP, IWN_OTP_GP_RELATIVE_ACCESS); base = prev = 0; - for (count = 0; count < sc->base_params->max_ll_items; - count++) { + for (count = 0; count < IWN1000_OTP_NBLOCKS; count++) { error = iwn_read_prom_data(sc, base, &next, 2); if (error != 0) return error; @@ -1630,7 +1210,7 @@ iwn_init_otprom(struct iwn_softc *sc) prev = base; base = le16toh(next); } - if (count == 0 || count == sc->base_params->max_ll_items) + if (count == 0 || count == IWN1000_OTP_NBLOCKS) return EIO; /* Skip "next" word. */ sc->prom_base = prev + 1; @@ -1736,12 +1316,16 @@ fail: iwn_dma_contig_free(dma); static void iwn_dma_contig_free(struct iwn_dma_info *dma) { - 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->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->tag != NULL) { bus_dma_tag_destroy(dma->tag); @@ -1875,7 +1459,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 map mbuf, error %d\n", __func__, + "%s: can't not map mbuf, error %d\n", __func__, error); goto fail; } @@ -2036,10 +1620,6 @@ 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); @@ -2188,7 +1768,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 < IWN_NBANDS - 1; i++) { + for (i = 0; i < 7; i++) { addr = iwn4965_regulatory_bands[i]; iwn_read_eeprom_channels(sc, i, addr); } @@ -2218,7 +1798,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 - 1; i++) + for (i = 0; i < IWN_NBANDS; i++) iwn4965_print_power_group(sc, i); } #endif @@ -2279,13 +1859,16 @@ iwn5000_read_eeprom(struct iwn_softc *sc) sc->eeprom_domain, 4); /* Read the list of authorized channels (20MHz ones only). */ - for (i = 0; i < IWN_NBANDS - 1; i++) { - addr = base + sc->base_params->regulatory_bands[i]; + 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]; iwn_read_eeprom_channels(sc, i, addr); } /* Read enhanced TX power information for 6000 Series. */ - if (sc->base_params->enhanced_TX_power) + if (sc->hw_type >= IWN_HW_REV_TYPE_6000) iwn_read_eeprom_enhinfo(sc); iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2); @@ -2296,14 +1879,6 @@ 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); @@ -2640,52 +2215,6 @@ 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. @@ -2699,14 +2228,19 @@ 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 (rate & IEEE80211_RATE_MCS) { + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { /* * Set the initial PLCP value to be between 0->31 for * MCS 0 -> MCS 31, then set the "I'm an MCS rate!" @@ -2733,15 +2267,15 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, } /* - * Ensure the selected rate matches the link quality - * table entries being used. + * If it's a two stream rate, enable TX on both + * antennas. + * + * XXX three stream rates? */ - if (rate > 0x8f) - plcp |= IWN_RFLAG_ANT(sc->txchainmask); - else if (rate > 0x87) - plcp |= IWN_RFLAG_ANT(iwn_get_2stream_tx_antmask(sc)); + if (rate > 0x87) + plcp |= IWN_RFLAG_ANT(txant1 | txant2); else - plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); + plcp |= IWN_RFLAG_ANT(txant1); } else { /* * Set the initial PLCP - fine for both @@ -2763,8 +2297,7 @@ iwn_rate_to_plcp(struct iwn_softc *sc, struct ieee80211_node *ni, plcp |= IWN_RFLAG_CCK; /* Set antenna configuration */ - /* XXX TODO: is this the right antenna to use for legacy? */ - plcp |= IWN_RFLAG_ANT(iwn_get_1stream_tx_antmask(sc)); + plcp |= IWN_RFLAG_ANT(txant1); } DPRINTF(sc, IWN_DEBUG_TXRATE, "%s: rate=0x%02x, plcp=0x%08x\n", @@ -2969,14 +2502,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); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + ifp->if_ierrors++; return; } /* Discard frames that are too short. */ - if (len < sizeof (struct ieee80211_frame_ack)) { + if (len < sizeof (*wh)) { DPRINTF(sc, IWN_DEBUG_RECV, "%s: frame too short: %d\n", __func__, len); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + ifp->if_ierrors++; return; } @@ -2984,7 +2517,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__); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + ifp->if_ierrors++; return; } bus_dmamap_unload(ring->data_dmat, data->map); @@ -3007,7 +2540,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); - if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); + ifp->if_ierrors++; return; } @@ -3025,10 +2558,7 @@ 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 *); - if (len >= sizeof(struct ieee80211_frame_min)) - ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); - else - ni = NULL; + ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); nf = (ni != NULL && ni->ni_vap->iv_state == IEEE80211_S_RUN && (ic->ic_flags & IEEE80211_F_SCAN) == 0) ? sc->noise : -95; @@ -3099,9 +2629,8 @@ 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 | IWN_DEBUG_XMIT, "->%s begin\n", __func__); + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); bus_dmamap_sync(sc->rxq.data_dmat, data->map, BUS_DMASYNC_POSTREAD); @@ -3131,7 +2660,6 @@ 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--; @@ -3157,32 +2685,22 @@ 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) { - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - tx_err ++; + ifp->if_oerrors++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); - tx_ok ++; + ifp->if_opackets++; ieee80211_ratectl_tx_complete(ni->ni_vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } bitmap >>= 1; } - DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, - "->%s: end; %d ok; %d err\n",__func__, tx_ok, tx_err); + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); } @@ -3210,24 +2728,25 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, switch (calib->code) { case IWN5000_PHY_CALIB_DC: - if (sc->base_params->calib_need & IWN_FLG_NEED_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) idx = 0; break; case IWN5000_PHY_CALIB_LO: - if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_LO) - idx = 1; + idx = 1; break; case IWN5000_PHY_CALIB_TX_IQ: - if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ) - idx = 2; + idx = 2; break; case IWN5000_PHY_CALIB_TX_IQ_PERIODIC: - if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_TX_IQ_PERIODIC) + if (sc->hw_type < IWN_HW_REV_TYPE_6000 && + sc->hw_type != IWN_HW_REV_TYPE_5150) idx = 3; break; case IWN5000_PHY_CALIB_BASE_BAND: - if (sc->base_params->calib_need & IWN_FLG_NEED_PHY_CALIB_BASE_BAND) - idx = 4; + idx = 4; break; } if (idx == -1) /* Ignore other results. */ @@ -3244,72 +2763,11 @@ iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc, return; } DPRINTF(sc, IWN_DEBUG_CALIBRATE, - "saving calibration result idx=%d, code=%d len=%d\n", idx, calib->code, len); + "saving calibration result code=%d len=%d\n", 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. @@ -3324,7 +2782,6 @@ 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__); @@ -3339,26 +2796,12 @@ 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 | IWN_DEBUG_STATS, - "%s: received statistics, cmd %d, len %d\n", - __func__, desc->type, le16toh(desc->len)); + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: received statistics, cmd %d\n", + __func__, desc->type); 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 (lstats->general.temp != sc->rawtemp) { + if (stats->general.temp != sc->rawtemp) { /* Convert "raw" temperature to degC. */ sc->rawtemp = stats->general.temp; temp = ops->get_temperature(sc); @@ -3373,51 +2816,25 @@ 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(&lstats->rx.general); + sc->noise = iwn_get_noise(&stats->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(lstats->rx.general.flags) != 1) { + if (le32toh(stats->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, &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); - } + iwn_collect_noise(sc, &stats->rx.general); + else if (calib->state == IWN_CALIB_STATE_RUN) + iwn_tune_sensitivity(sc, &stats->rx); 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. */ @@ -3433,18 +2850,15 @@ 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 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), + "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), 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->ackfailcnt, &stat->status); + &stat->status); } else { iwn_tx_done(sc, desc, stat->ackfailcnt, le32toh(stat->status) & 0xff); @@ -3463,12 +2877,9 @@ 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 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), + "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), le32toh(stat->status)); #ifdef notyet @@ -3479,7 +2890,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->ackfailcnt, &stat->status); + &stat->status); } else { iwn_tx_done(sc, desc, stat->ackfailcnt, le16toh(stat->status) & 0xff); @@ -3515,11 +2926,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) { - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); + ifp->if_oerrors++; ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_FAILURE, &ackfailcnt, NULL); } else { - if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); + ifp->if_opackets++; ieee80211_ratectl_tx_complete(vap, ni, IEEE80211_RATECTL_TX_SUCCESS, &ackfailcnt, NULL); } @@ -3566,19 +2977,12 @@ 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; + struct iwn_tx_ring *ring = &sc->txq[4]; struct iwn_tx_data *data; - int cmd_queue_num; - 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) + if ((desc->qid & 0xf) != 4) 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. */ @@ -3594,7 +2998,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, - int ackfailcnt, void *stat) + void *stat) { struct iwn_ops *ops = &sc->ops; struct ifnet *ifp = sc->sc_ifp; @@ -3611,60 +3015,14 @@ 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); - 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. - */ +#ifdef NOT_YET if (nframes == 1) { - if ((*status & 0xff) != 1 && (*status & 0xff) != 2) { -#ifdef NOT_YET + if ((*status & 0xff) != 1 && (*status & 0xff) != 2) 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); - } } +#endif bitmap = 0; start = idx; @@ -3703,7 +3061,6 @@ 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]; @@ -3717,7 +3074,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--; @@ -3772,12 +3129,12 @@ iwn_notif_intr(struct iwn_softc *sc) desc = mtod(data->m, struct iwn_rx_desc *); DPRINTF(sc, IWN_DEBUG_RECV, - "%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, + "%s: qid %x idx %d flags %x type %d(%s) len %d\n", + __func__, desc->qid & 0xf, desc->idx, desc->flags, desc->type, iwn_intr_str(desc->type), le16toh(desc->len)); - if (!(desc->qid & IWN_UNSOLICITED_RX_NOTIF)) /* Reply to a command. */ + if (!(desc->qid & 0x80)) /* Reply to a command. */ iwn_cmd_done(sc, desc); switch (desc->type) { @@ -3872,8 +3229,7 @@ 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 | IWN_DEBUG_STATE, - "state changed to %x\n", + DPRINTF(sc, IWN_DEBUG_INTR, "state changed to %x\n", le32toh(*status)); #endif break; @@ -3898,11 +3254,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 | IWN_DEBUG_SCAN, + DPRINTF(sc, IWN_DEBUG_STATE, "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); @@ -4054,10 +3410,8 @@ iwn_intr(void *arg) r2 = 0; /* Unused. */ } else { r1 = IWN_READ(sc, IWN_INT); - if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) { - IWN_UNLOCK(sc); + if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0) return; /* Hardware gone! */ - } r2 = IWN_READ(sc, IWN_FH_INT); } @@ -4088,8 +3442,8 @@ iwn_intr(void *arg) #endif /* Dump firmware error log and stop. */ iwn_fatal_intr(sc); - - taskqueue_enqueue(sc->sc_tq, &sc->sc_panic_task); + ifp->if_flags &= ~IFF_UP; + iwn_stop_locked(sc); goto done; } if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) || @@ -4187,115 +3541,6 @@ 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) { @@ -4316,7 +3561,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, type; + uint8_t tid, ridx, txant, type; int ac, i, totlen, error, pad, nsegs = 0, rate; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -4337,7 +3582,6 @@ 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)) { @@ -4345,27 +3589,9 @@ 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(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); - } + htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); ni->ni_txseqs[tid]++; } ring = &sc->txq[ac]; @@ -4380,13 +3606,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) { @@ -4443,18 +3669,13 @@ 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 (iwn_check_rate_needs_protection(sc, vap, rate)) { + } else if ((ic->ic_flags & IEEE80211_F_USEPROT) && + ridx >= IWN_RIDX_OFDM6) { 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. */ @@ -4501,11 +3722,13 @@ 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 = iwn_tx_rate_to_linkq_offset(sc, ni, rate); + tx->linkq = ni->ni_rates.rs_nrates - ridx - 1; 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); @@ -4528,7 +3751,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 - 1); + m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER); if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); @@ -4550,16 +3773,8 @@ 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 flags 0x%08x rate 0x%04x plcp 0x%08x\n", - __func__, - ring->qid, - ring->cur, - m->m_pkthdr.len, - nsegs, - flags, - rate, - tx->rate); + 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); /* Fill TX descriptor. */ desc->nsegs = 1; @@ -4606,9 +3821,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; @@ -4620,7 +3835,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 type; + uint8_t ridx, type, txant; DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); @@ -4636,8 +3851,16 @@ 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. */ + /* Choose a TX rate index. */ 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. */ @@ -4707,10 +3930,17 @@ 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); - tx->rate = iwn_rate_to_plcp(sc, ni, rate); + + /* 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); /* 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)); @@ -4734,7 +3964,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 - 1); + m1 = m_collapse(m, M_NOWAIT, IWN_MAX_SCATTER); if (m1 == NULL) { device_printf(sc->sc_dev, "%s: could not defrag mbuf\n", __func__); @@ -4808,7 +4038,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_XMIT | IWN_DEBUG_TRACE, "->%s begin\n", __func__); + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { ieee80211_free_node(ni); @@ -4833,13 +4063,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); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - } else - sc->sc_tx_timer = 5; + ifp->if_oerrors++; + } + sc->sc_tx_timer = 5; IWN_UNLOCK(sc); - DPRINTF(sc, IWN_DEBUG_TRACE | IWN_DEBUG_XMIT, "->%s: end\n",__func__); + DPRINTF(sc, IWN_DEBUG_TRACE, "->%s: end\n",__func__); return error; } @@ -4863,8 +4093,6 @@ 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; @@ -4880,12 +4108,11 @@ 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); - if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); - } else - sc->sc_tx_timer = 5; + ifp->if_oerrors++; + continue; + } + sc->sc_tx_timer = 5; } - - DPRINTF(sc, IWN_DEBUG_XMIT, "%s: done\n", __func__); } static void @@ -4947,18 +4174,6 @@ 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; @@ -4972,26 +4187,19 @@ 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; + struct iwn_tx_ring *ring = &sc->txq[4]; 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; @@ -5085,87 +4293,42 @@ 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; + struct ieee80211_rateset *rs = &ni->ni_rates; 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 = iwn_get_1stream_tx_antmask(sc); - linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); - - linkq.ampdu_max = 32; /* XXX negotiated? */ + linkq.antmsk_1stream = txant; + linkq.antmsk_2stream = IWN_ANT_AB; + linkq.ampdu_max = 64; 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. */ - /* - * XXX this is all very dirty! - */ - if (is_11n) + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) 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; - /* - * 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]; + if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) + rate = IEEE80211_RATE_MCS | 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)); - /* - * 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. - */ + /* Special case for dual-stream rates? */ if ((le32toh(plcp) & IWN_RFLAG_MCS) && RV(le32toh(plcp)) > 7) linkq.mimo = i + 1; @@ -5174,15 +4337,6 @@ 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__); @@ -5220,14 +4374,13 @@ iwn_add_broadcast_node(struct iwn_softc *sc, int async) memset(&linkq, 0, sizeof linkq); linkq.id = sc->broadcast_id; - linkq.antmsk_1stream = iwn_get_1stream_tx_antmask(sc); - linkq.antmsk_2stream = iwn_get_2stream_tx_antmask(sc); + linkq.antmsk_1stream = txant; + linkq.antmsk_2stream = IWN_ANT_AB; 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 @@ -5289,12 +4442,6 @@ 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); @@ -5534,7 +4681,6 @@ 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__); @@ -5546,15 +4692,8 @@ 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 | 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); + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: setting TX power\n", __func__); + return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async); } /* @@ -5754,7 +4893,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 | IWN_DEBUG_XMIT, + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: RX chains mask: theoretical=0x%x, actual=0x%x\n", __func__, sc->rxchainmask, sc->chainmask); @@ -5768,10 +4907,6 @@ 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 @@ -5879,7 +5014,7 @@ iwn5000_set_gains(struct iwn_softc *sc) cmd.gain[i - 1] |= 1 << 2; /* sign bit */ } } - DPRINTF(sc, IWN_DEBUG_CALIBRATE | IWN_DEBUG_XMIT, + DPRINTF(sc, IWN_DEBUG_CALIBRATE, "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); @@ -5929,6 +5064,10 @@ 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, @@ -5982,6 +5121,10 @@ 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, @@ -6062,7 +5205,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(sc->limits->barker_mrc); + cmd.corr_barker_mrc = htole16(390); DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: set sensitivity %d/%d/%d/%d/%d/%d/%d\n", __func__, @@ -6087,86 +5230,6 @@ 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. */ @@ -6251,73 +5314,25 @@ 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); - 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); - } - + 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); if (error != 0) return error; @@ -6372,32 +5387,13 @@ iwn_config(struct iwn_softc *sc) DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__); - 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) { + if (sc->hw_type == IWN_HW_REV_TYPE_6005) { + /* Set radio temperature sensor 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); - } - } 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); + return error; } } @@ -6413,10 +5409,9 @@ iwn_config(struct iwn_softc *sc) } /* Configure valid TX chains for >=5000 Series. */ - if (sc->hw_type != IWN_HW_REV_TYPE_4965 && - IWN_UCODE_API(sc->ucode_rev) > 1) { + if (sc->hw_type != IWN_HW_REV_TYPE_4965) { txmask = htole32(sc->txchainmask); - DPRINTF(sc, IWN_DEBUG_RESET | IWN_DEBUG_XMIT, + DPRINTF(sc, IWN_DEBUG_RESET, "%s: configuring valid TX chains 0x%x\n", __func__, txmask); error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask, sizeof txmask, 0); @@ -6429,14 +5424,10 @@ iwn_config(struct iwn_softc *sc) } /* Configure bluetooth coexistence. */ - error = 0; - - /* Configure bluetooth coexistence if needed. */ - if (sc->base_params->bt_mode == IWN_BT_ADVANCED) + if (sc->sc_flags & IWN_FLAG_ADV_BTCOEX) error = iwn_send_advanced_btcoex(sc); - if (sc->base_params->bt_mode == IWN_BT_SIMPLE) + else error = iwn_send_btcoex(sc); - if (error != 0) { device_printf(sc->sc_dev, "%s: could not configure bluetooth coexistence, error %d\n", @@ -6472,29 +5463,12 @@ 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(sc->nrxchains) | - IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains); + IWN_RXCHAIN_MIMO_COUNT(2) | + IWN_RXCHAIN_IDLE_COUNT(2); 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", @@ -6533,109 +5507,39 @@ 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)); -} - /* - * Limit the total dwell time to 85% of the beacon interval. - * - * Returns the dwell time in milliseconds. + * Add an ssid element to a frame. */ -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) +static uint8_t * +ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int 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)); + *frm++ = IEEE80211_ELEMID_SSID; + *frm++ = len; + memcpy(frm, ssid, len); + return frm + len; } static int -iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, - struct ieee80211_scan_state *ss, struct ieee80211_channel *c) +iwn_scan(struct iwn_softc *sc) { struct ifnet *ifp = sc->sc_ifp; struct ieee80211com *ic = ifp->if_l2com; - struct ieee80211_node *ni = vap->iv_bss; + struct ieee80211_scan_state *ss = ic->ic_scan; /*XXX*/ + struct ieee80211_node *ni = ss->ss_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) { @@ -6651,29 +5555,13 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, */ 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(c) && + if (IEEE80211_IS_CHAN_A(ic->ic_curchan) && 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); @@ -6687,7 +5575,7 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, tx->id = sc->broadcast_id; tx->lifetime = htole32(IWN_LIFETIME_INFINITE); - if (IEEE80211_IS_CHAN_5GHZ(c)) { + if (IEEE80211_IS_CHAN_5GHZ(ic->ic_curchan)) { /* Send probe requests at 6Mbps. */ tx->rate = htole32(0xd); rs = &ic->ic_sup_rates[IEEE80211_MODE_11A]; @@ -6706,35 +5594,12 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, 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 != 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; + 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); } - /* * Build a probe request frame. Most of the following code is a * copy & paste of what is done in net80211. @@ -6760,96 +5625,53 @@ iwn_scan(struct iwn_softc *sc, struct ieee80211vap *vap, /* Set length of probe request. */ tx->len = htole16(frm - (uint8_t *)wh); - /* - * 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; - + c = ic->ic_curchan; 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; - - /* - * 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 + if (IEEE80211_IS_CHAN_5GHZ(c) && + !(c->ic_flags & IEEE80211_CHAN_PASSIVE)) { + chan->rf_gain = 0x3b; + chan->active = htole16(24); + chan->passive = htole16(110); chan->flags |= htole32(IWN_CHAN_ACTIVE); - - /* - * 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)) + } else if (IEEE80211_IS_CHAN_5GHZ(c)) { chan->rf_gain = 0x3b; - else + 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 { + 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 %d passive %d scan_svc_time %d crc 0x%x " - "isactive=%d numssid=%d\n", __func__, + "dsp_gain 0x%x active 0x%x passive 0x%x\n", __func__, chan->chan, chan->flags, chan->rf_gain, chan->dsp_gain, - dwell_active, dwell_passive, scan_service_time, - hdr->crc_threshold, is_active, ss->ss_nssid); + chan->active, chan->passive); 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); @@ -6890,16 +5712,12 @@ iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap) sc->rxon->ofdm_mask = 0; } else { /* Assume 802.11b/g. */ - sc->rxon->cck_mask = 0x03; + sc->rxon->cck_mask = 0x0f; 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", @@ -6995,10 +5813,6 @@ 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, @@ -7397,10 +6211,10 @@ iwn5000_query_calibration(struct iwn_softc *sc) int error; memset(&cmd, 0, sizeof cmd); - cmd.ucode.once.enable = htole32(0xffffffff); - cmd.ucode.once.start = htole32(0xffffffff); - cmd.ucode.once.send = htole32(0xffffffff); - cmd.ucode.flags = htole32(0xffffffff); + cmd.ucode.once.enable = 0xffffffff; + cmd.ucode.once.start = 0xffffffff; + cmd.ucode.once.send = 0xffffffff; + cmd.ucode.flags = 0xffffffff; DPRINTF(sc, IWN_DEBUG_CALIBRATE, "%s: sending calibration query\n", __func__); error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0); @@ -7422,20 +6236,9 @@ iwn5000_send_calibration(struct iwn_softc *sc) { int idx, error; - 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; - } - + for (idx = 0; idx < 5; idx++) { + if (sc->calibcmd[idx].buf == NULL) + continue; /* No results available. */ DPRINTF(sc, IWN_DEBUG_CALIBRATE, "send calibration result idx=%d len=%d\n", idx, sc->calibcmd[idx].len); @@ -7456,7 +6259,7 @@ iwn5000_send_wimax_coex(struct iwn_softc *sc) { struct iwn5000_wimax_coex wimax; -#if 0 +#ifdef notyet if (sc->hw_type == IWN_HW_REV_TYPE_6050) { /* Enable WiMAX coexistence for combo adapters. */ wimax.flags = @@ -7512,33 +6315,6 @@ 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). @@ -7624,10 +6400,7 @@ 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. */ - 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_QCHAIN_SEL, 0xfffef); iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0); for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) { @@ -7648,20 +6421,10 @@ 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. */ - 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]); - } + 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); @@ -7906,8 +6669,6 @@ 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, @@ -7973,7 +6734,6 @@ 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 @@ -8029,7 +6789,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 = le32toh(*ptr); + tmp = htole32(*ptr); if (tmp < 253) { sc->reset_noise_gain = tmp; sc->noise_gain = tmp + 1; @@ -8040,16 +6800,8 @@ 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: - 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); + case IWN_FW_TLV_FLAGS : + sc->tlv_feature_flags = htole32(*ptr); break; case IWN_FW_TLV_PBREQ_MAXLEN: case IWN_FW_TLV_RUNT_EVTLOG_PTR: @@ -8121,8 +6873,6 @@ 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 || @@ -8187,8 +6937,9 @@ iwn_apm_init(struct iwn_softc *sc) else IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA); - if (sc->base_params->pll_cfg_val) - IWN_SETBITS(sc, IWN_ANA_PLL, sc->base_params->pll_cfg_val); + 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); /* Wait for clock stabilization before accessing prph. */ if ((error = iwn_clock_wait(sc)) != 0) @@ -8300,13 +7051,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->base_params->additional_nic_config && sc->calib_ver >= 6) { + if ((sc->hw_type == IWN_HW_REV_TYPE_6050 || + sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) { /* Indicate that ROM calibration version is >=6. */ IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6); } - if (sc->base_params->additional_gp_drv_bit) - IWN_SETBITS(sc, IWN_GP_DRIVER, - sc->base_params->additional_gp_drv_bit); + if (sc->hw_type == IWN_HW_REV_TYPE_6005) + IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2); return 0; } @@ -8441,7 +7192,7 @@ iwn_hw_init(struct iwn_softc *sc) IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL); /* Enable shadow registers. */ - if (sc->base_params->shadow_reg_enable) + if (sc->hw_type >= IWN_HW_REV_TYPE_6000) IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff); if ((error = ops->load_firmware(sc)) != 0) { @@ -8554,44 +7305,6 @@ 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; @@ -8683,7 +7396,6 @@ 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); @@ -8774,11 +7486,10 @@ 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, vap, ss, ic->ic_curchan); + error = iwn_scan(sc); IWN_UNLOCK(sc); if (error != 0) ieee80211_cancel_scan(vap); @@ -8810,6 +7521,7 @@ 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 @@ -8880,7 +7592,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 < nitems(csr_tbl); i++){ + for (i = 0; i < COUNTOF(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) |