LCOV - code coverage report
Current view: top level - dev/pci - if_iwn.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 3347 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 148 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_iwn.c,v 1.203 2018/04/28 16:05:56 phessler Exp $   */
       2             : 
       3             : /*-
       4             :  * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Driver for Intel WiFi Link 4965 and 1000/5000/6000 Series 802.11 network
      21             :  * adapters.
      22             :  */
      23             : 
      24             : #include "bpfilter.h"
      25             : 
      26             : #include <sys/param.h>
      27             : #include <sys/sockio.h>
      28             : #include <sys/mbuf.h>
      29             : #include <sys/kernel.h>
      30             : #include <sys/rwlock.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/systm.h>
      33             : #include <sys/malloc.h>
      34             : #include <sys/conf.h>
      35             : #include <sys/device.h>
      36             : #include <sys/task.h>
      37             : #include <sys/endian.h>
      38             : 
      39             : #include <machine/bus.h>
      40             : #include <machine/intr.h>
      41             : 
      42             : #include <dev/pci/pcireg.h>
      43             : #include <dev/pci/pcivar.h>
      44             : #include <dev/pci/pcidevs.h>
      45             : 
      46             : #if NBPFILTER > 0
      47             : #include <net/bpf.h>
      48             : #endif
      49             : #include <net/if.h>
      50             : #include <net/if_dl.h>
      51             : #include <net/if_media.h>
      52             : 
      53             : #include <netinet/in.h>
      54             : #include <netinet/if_ether.h>
      55             : 
      56             : #include <net80211/ieee80211_var.h>
      57             : #include <net80211/ieee80211_amrr.h>
      58             : #include <net80211/ieee80211_mira.h>
      59             : #include <net80211/ieee80211_radiotap.h>
      60             : 
      61             : #include <dev/pci/if_iwnreg.h>
      62             : #include <dev/pci/if_iwnvar.h>
      63             : 
      64             : static const struct pci_matchid iwn_devices[] = {
      65             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_4965_1 },
      66             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_4965_2 },
      67             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5100_1 },
      68             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5100_2 },
      69             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5150_1 },
      70             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5150_2 },
      71             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5300_1 },
      72             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5300_2 },
      73             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5350_1 },
      74             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_5350_2 },
      75             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1000_1 },
      76             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1000_2 },
      77             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6300_1 },
      78             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6300_2 },
      79             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6200_1 },
      80             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6200_2 },
      81             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6050_1 },
      82             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6050_2 },
      83             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6005_1 },
      84             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6005_2 },
      85             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6030_1 },
      86             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6030_2 },
      87             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1030_1 },
      88             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_1030_2 },
      89             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_100_1 },
      90             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_100_2 },
      91             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_130_1 },
      92             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_130_2 },
      93             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_1 },
      94             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_6235_2 },
      95             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2230_1 },
      96             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2230_2 },
      97             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2200_1 },
      98             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_2200_2 },
      99             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_135_1 },
     100             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_135_2 },
     101             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_105_1 },
     102             :         { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_WL_105_2 },
     103             : };
     104             : 
     105             : int             iwn_match(struct device *, void *, void *);
     106             : void            iwn_attach(struct device *, struct device *, void *);
     107             : int             iwn4965_attach(struct iwn_softc *, pci_product_id_t);
     108             : int             iwn5000_attach(struct iwn_softc *, pci_product_id_t);
     109             : #if NBPFILTER > 0
     110             : void            iwn_radiotap_attach(struct iwn_softc *);
     111             : #endif
     112             : int             iwn_detach(struct device *, int);
     113             : int             iwn_activate(struct device *, int);
     114             : void            iwn_wakeup(struct iwn_softc *);
     115             : void            iwn_init_task(void *);
     116             : int             iwn_nic_lock(struct iwn_softc *);
     117             : int             iwn_eeprom_lock(struct iwn_softc *);
     118             : int             iwn_init_otprom(struct iwn_softc *);
     119             : int             iwn_read_prom_data(struct iwn_softc *, uint32_t, void *, int);
     120             : int             iwn_dma_contig_alloc(bus_dma_tag_t, struct iwn_dma_info *,
     121             :                     void **, bus_size_t, bus_size_t);
     122             : void            iwn_dma_contig_free(struct iwn_dma_info *);
     123             : int             iwn_alloc_sched(struct iwn_softc *);
     124             : void            iwn_free_sched(struct iwn_softc *);
     125             : int             iwn_alloc_kw(struct iwn_softc *);
     126             : void            iwn_free_kw(struct iwn_softc *);
     127             : int             iwn_alloc_ict(struct iwn_softc *);
     128             : void            iwn_free_ict(struct iwn_softc *);
     129             : int             iwn_alloc_fwmem(struct iwn_softc *);
     130             : void            iwn_free_fwmem(struct iwn_softc *);
     131             : int             iwn_alloc_rx_ring(struct iwn_softc *, struct iwn_rx_ring *);
     132             : void            iwn_reset_rx_ring(struct iwn_softc *, struct iwn_rx_ring *);
     133             : void            iwn_free_rx_ring(struct iwn_softc *, struct iwn_rx_ring *);
     134             : int             iwn_alloc_tx_ring(struct iwn_softc *, struct iwn_tx_ring *,
     135             :                     int);
     136             : void            iwn_reset_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
     137             : void            iwn_free_tx_ring(struct iwn_softc *, struct iwn_tx_ring *);
     138             : void            iwn5000_ict_reset(struct iwn_softc *);
     139             : int             iwn_read_eeprom(struct iwn_softc *);
     140             : void            iwn4965_read_eeprom(struct iwn_softc *);
     141             : void            iwn4965_print_power_group(struct iwn_softc *, int);
     142             : void            iwn5000_read_eeprom(struct iwn_softc *);
     143             : void            iwn_read_eeprom_channels(struct iwn_softc *, int, uint32_t);
     144             : void            iwn_read_eeprom_enhinfo(struct iwn_softc *);
     145             : struct          ieee80211_node *iwn_node_alloc(struct ieee80211com *);
     146             : void            iwn_newassoc(struct ieee80211com *, struct ieee80211_node *,
     147             :                     int);
     148             : int             iwn_media_change(struct ifnet *);
     149             : int             iwn_newstate(struct ieee80211com *, enum ieee80211_state, int);
     150             : void            iwn_iter_func(void *, struct ieee80211_node *);
     151             : void            iwn_calib_timeout(void *);
     152             : int             iwn_ccmp_decap(struct iwn_softc *, struct mbuf *,
     153             :                     struct ieee80211_node *);
     154             : void            iwn_rx_phy(struct iwn_softc *, struct iwn_rx_desc *,
     155             :                     struct iwn_rx_data *);
     156             : void            iwn_rx_done(struct iwn_softc *, struct iwn_rx_desc *,
     157             :                     struct iwn_rx_data *);
     158             : void            iwn_rx_compressed_ba(struct iwn_softc *, struct iwn_rx_desc *,
     159             :                     struct iwn_rx_data *);
     160             : void            iwn5000_rx_calib_results(struct iwn_softc *,
     161             :                     struct iwn_rx_desc *, struct iwn_rx_data *);
     162             : void            iwn_rx_statistics(struct iwn_softc *, struct iwn_rx_desc *,
     163             :                     struct iwn_rx_data *);
     164             : void            iwn4965_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
     165             :                     struct iwn_rx_data *);
     166             : void            iwn5000_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
     167             :                     struct iwn_rx_data *);
     168             : void            iwn_tx_done(struct iwn_softc *, struct iwn_rx_desc *,
     169             :                     uint8_t, uint8_t, uint8_t, uint16_t);
     170             : void            iwn_cmd_done(struct iwn_softc *, struct iwn_rx_desc *);
     171             : void            iwn_notif_intr(struct iwn_softc *);
     172             : void            iwn_wakeup_intr(struct iwn_softc *);
     173             : void            iwn_fatal_intr(struct iwn_softc *);
     174             : int             iwn_intr(void *);
     175             : void            iwn4965_update_sched(struct iwn_softc *, int, int, uint8_t,
     176             :                     uint16_t);
     177             : void            iwn5000_update_sched(struct iwn_softc *, int, int, uint8_t,
     178             :                     uint16_t);
     179             : void            iwn5000_reset_sched(struct iwn_softc *, int, int);
     180             : int             iwn_tx(struct iwn_softc *, struct mbuf *,
     181             :                     struct ieee80211_node *);
     182             : int             iwn_rval2ridx(int);
     183             : void            iwn_start(struct ifnet *);
     184             : void            iwn_watchdog(struct ifnet *);
     185             : int             iwn_ioctl(struct ifnet *, u_long, caddr_t);
     186             : int             iwn_cmd(struct iwn_softc *, int, const void *, int, int);
     187             : int             iwn4965_add_node(struct iwn_softc *, struct iwn_node_info *,
     188             :                     int);
     189             : int             iwn5000_add_node(struct iwn_softc *, struct iwn_node_info *,
     190             :                     int);
     191             : int             iwn_set_link_quality(struct iwn_softc *,
     192             :                     struct ieee80211_node *);
     193             : int             iwn_add_broadcast_node(struct iwn_softc *, int, int);
     194             : void            iwn_updateedca(struct ieee80211com *);
     195             : void            iwn_set_led(struct iwn_softc *, uint8_t, uint8_t, uint8_t);
     196             : int             iwn_set_critical_temp(struct iwn_softc *);
     197             : int             iwn_set_timing(struct iwn_softc *, struct ieee80211_node *);
     198             : void            iwn4965_power_calibration(struct iwn_softc *, int);
     199             : int             iwn4965_set_txpower(struct iwn_softc *, int);
     200             : int             iwn5000_set_txpower(struct iwn_softc *, int);
     201             : int             iwn4965_get_rssi(const struct iwn_rx_stat *);
     202             : int             iwn5000_get_rssi(const struct iwn_rx_stat *);
     203             : int             iwn_get_noise(const struct iwn_rx_general_stats *);
     204             : int             iwn4965_get_temperature(struct iwn_softc *);
     205             : int             iwn5000_get_temperature(struct iwn_softc *);
     206             : int             iwn_init_sensitivity(struct iwn_softc *);
     207             : void            iwn_collect_noise(struct iwn_softc *,
     208             :                     const struct iwn_rx_general_stats *);
     209             : int             iwn4965_init_gains(struct iwn_softc *);
     210             : int             iwn5000_init_gains(struct iwn_softc *);
     211             : int             iwn4965_set_gains(struct iwn_softc *);
     212             : int             iwn5000_set_gains(struct iwn_softc *);
     213             : void            iwn_tune_sensitivity(struct iwn_softc *,
     214             :                     const struct iwn_rx_stats *);
     215             : int             iwn_send_sensitivity(struct iwn_softc *);
     216             : int             iwn_set_pslevel(struct iwn_softc *, int, int, int);
     217             : int             iwn_send_temperature_offset(struct iwn_softc *);
     218             : int             iwn_send_btcoex(struct iwn_softc *);
     219             : int             iwn_send_advanced_btcoex(struct iwn_softc *);
     220             : int             iwn5000_runtime_calib(struct iwn_softc *);
     221             : int             iwn_config(struct iwn_softc *);
     222             : uint16_t        iwn_get_active_dwell_time(struct iwn_softc *, uint16_t, uint8_t);
     223             : uint16_t        iwn_limit_dwell(struct iwn_softc *, uint16_t);
     224             : uint16_t        iwn_get_passive_dwell_time(struct iwn_softc *, uint16_t);
     225             : int             iwn_scan(struct iwn_softc *, uint16_t, int);
     226             : void            iwn_scan_abort(struct iwn_softc *);
     227             : int             iwn_bgscan(struct ieee80211com *);
     228             : int             iwn_auth(struct iwn_softc *, int);
     229             : int             iwn_run(struct iwn_softc *);
     230             : int             iwn_set_key(struct ieee80211com *, struct ieee80211_node *,
     231             :                     struct ieee80211_key *);
     232             : void            iwn_delete_key(struct ieee80211com *, struct ieee80211_node *,
     233             :                     struct ieee80211_key *);
     234             : void            iwn_update_htprot(struct ieee80211com *,
     235             :                     struct ieee80211_node *);
     236             : int             iwn_ampdu_rx_start(struct ieee80211com *,
     237             :                     struct ieee80211_node *, uint8_t);
     238             : void            iwn_ampdu_rx_stop(struct ieee80211com *,
     239             :                     struct ieee80211_node *, uint8_t);
     240             : int             iwn_ampdu_tx_start(struct ieee80211com *,
     241             :                     struct ieee80211_node *, uint8_t);
     242             : void            iwn_ampdu_tx_stop(struct ieee80211com *,
     243             :                     struct ieee80211_node *, uint8_t);
     244             : void            iwn4965_ampdu_tx_start(struct iwn_softc *,
     245             :                     struct ieee80211_node *, uint8_t, uint16_t);
     246             : void            iwn4965_ampdu_tx_stop(struct iwn_softc *,
     247             :                     uint8_t, uint16_t);
     248             : void            iwn5000_ampdu_tx_start(struct iwn_softc *,
     249             :                     struct ieee80211_node *, uint8_t, uint16_t);
     250             : void            iwn5000_ampdu_tx_stop(struct iwn_softc *,
     251             :                     uint8_t, uint16_t);
     252             : int             iwn5000_query_calibration(struct iwn_softc *);
     253             : int             iwn5000_send_calibration(struct iwn_softc *);
     254             : int             iwn5000_send_wimax_coex(struct iwn_softc *);
     255             : int             iwn5000_crystal_calib(struct iwn_softc *);
     256             : int             iwn6000_temp_offset_calib(struct iwn_softc *);
     257             : int             iwn2000_temp_offset_calib(struct iwn_softc *);
     258             : int             iwn4965_post_alive(struct iwn_softc *);
     259             : int             iwn5000_post_alive(struct iwn_softc *);
     260             : int             iwn4965_load_bootcode(struct iwn_softc *, const uint8_t *,
     261             :                     int);
     262             : int             iwn4965_load_firmware(struct iwn_softc *);
     263             : int             iwn5000_load_firmware_section(struct iwn_softc *, uint32_t,
     264             :                     const uint8_t *, int);
     265             : int             iwn5000_load_firmware(struct iwn_softc *);
     266             : int             iwn_read_firmware_leg(struct iwn_softc *,
     267             :                     struct iwn_fw_info *);
     268             : int             iwn_read_firmware_tlv(struct iwn_softc *,
     269             :                     struct iwn_fw_info *, uint16_t);
     270             : int             iwn_read_firmware(struct iwn_softc *);
     271             : int             iwn_clock_wait(struct iwn_softc *);
     272             : int             iwn_apm_init(struct iwn_softc *);
     273             : void            iwn_apm_stop_master(struct iwn_softc *);
     274             : void            iwn_apm_stop(struct iwn_softc *);
     275             : int             iwn4965_nic_config(struct iwn_softc *);
     276             : int             iwn5000_nic_config(struct iwn_softc *);
     277             : int             iwn_hw_prepare(struct iwn_softc *);
     278             : int             iwn_hw_init(struct iwn_softc *);
     279             : void            iwn_hw_stop(struct iwn_softc *);
     280             : int             iwn_init(struct ifnet *);
     281             : void            iwn_stop(struct ifnet *, int);
     282             : 
     283             : #ifdef IWN_DEBUG
     284             : #define DPRINTF(x)      do { if (iwn_debug > 0) printf x; } while (0)
     285             : #define DPRINTFN(n, x)  do { if (iwn_debug >= (n)) printf x; } while (0)
     286             : int iwn_debug = 1;
     287             : #else
     288             : #define DPRINTF(x)
     289             : #define DPRINTFN(n, x)
     290             : #endif
     291             : 
     292             : struct cfdriver iwn_cd = {
     293             :         NULL, "iwn", DV_IFNET
     294             : };
     295             : 
     296             : struct cfattach iwn_ca = {
     297             :         sizeof (struct iwn_softc), iwn_match, iwn_attach, iwn_detach,
     298             :         iwn_activate
     299             : };
     300             : 
     301             : int
     302           0 : iwn_match(struct device *parent, void *match, void *aux)
     303             : {
     304           0 :         return pci_matchbyid((struct pci_attach_args *)aux, iwn_devices,
     305             :             nitems(iwn_devices));
     306             : }
     307             : 
     308             : void
     309           0 : iwn_attach(struct device *parent, struct device *self, void *aux)
     310             : {
     311           0 :         struct iwn_softc *sc = (struct iwn_softc *)self;
     312           0 :         struct ieee80211com *ic = &sc->sc_ic;
     313           0 :         struct ifnet *ifp = &ic->ic_if;
     314           0 :         struct pci_attach_args *pa = aux;
     315             :         const char *intrstr;
     316           0 :         pci_intr_handle_t ih;
     317             :         pcireg_t memtype, reg;
     318             :         int i, error;
     319             : 
     320           0 :         sc->sc_pct = pa->pa_pc;
     321           0 :         sc->sc_pcitag = pa->pa_tag;
     322           0 :         sc->sc_dmat = pa->pa_dmat;
     323             : 
     324             :         /*
     325             :          * Get the offset of the PCI Express Capability Structure in PCI
     326             :          * Configuration Space.
     327             :          */
     328           0 :         error = pci_get_capability(sc->sc_pct, sc->sc_pcitag,
     329           0 :             PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL);
     330           0 :         if (error == 0) {
     331           0 :                 printf(": PCIe capability structure not found!\n");
     332           0 :                 return;
     333             :         }
     334             : 
     335             :         /* Clear device-specific "PCI retry timeout" register (41h). */
     336           0 :         reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
     337           0 :         if (reg & 0xff00)
     338           0 :                 pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
     339             : 
     340             :         /* Hardware bug workaround. */
     341           0 :         reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG);
     342           0 :         if (reg & PCI_COMMAND_INTERRUPT_DISABLE) {
     343             :                 DPRINTF(("PCIe INTx Disable set\n"));
     344           0 :                 reg &= ~PCI_COMMAND_INTERRUPT_DISABLE;
     345           0 :                 pci_conf_write(sc->sc_pct, sc->sc_pcitag,
     346             :                     PCI_COMMAND_STATUS_REG, reg);
     347           0 :         }
     348             : 
     349           0 :         memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, IWN_PCI_BAR0);
     350           0 :         error = pci_mapreg_map(pa, IWN_PCI_BAR0, memtype, 0, &sc->sc_st,
     351           0 :             &sc->sc_sh, NULL, &sc->sc_sz, 0);
     352           0 :         if (error != 0) {
     353           0 :                 printf(": can't map mem space\n");
     354           0 :                 return;
     355             :         }
     356             : 
     357             :         /* Install interrupt handler. */
     358           0 :         if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
     359           0 :                 printf(": can't map interrupt\n");
     360           0 :                 return;
     361             :         }
     362           0 :         intrstr = pci_intr_string(sc->sc_pct, ih);
     363           0 :         sc->sc_ih = pci_intr_establish(sc->sc_pct, ih, IPL_NET, iwn_intr, sc,
     364           0 :             sc->sc_dev.dv_xname);
     365           0 :         if (sc->sc_ih == NULL) {
     366           0 :                 printf(": can't establish interrupt");
     367           0 :                 if (intrstr != NULL)
     368           0 :                         printf(" at %s", intrstr);
     369           0 :                 printf("\n");
     370           0 :                 return;
     371             :         }
     372           0 :         printf(": %s", intrstr);
     373             : 
     374             :         /* Read hardware revision and attach. */
     375           0 :         sc->hw_type = (IWN_READ(sc, IWN_HW_REV) >> 4) & 0x1f;
     376           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_4965)
     377           0 :                 error = iwn4965_attach(sc, PCI_PRODUCT(pa->pa_id));
     378             :         else
     379           0 :                 error = iwn5000_attach(sc, PCI_PRODUCT(pa->pa_id));
     380           0 :         if (error != 0) {
     381           0 :                 printf(": could not attach device\n");
     382           0 :                 return;
     383             :         }
     384             : 
     385           0 :         if ((error = iwn_hw_prepare(sc)) != 0) {
     386           0 :                 printf(": hardware not ready\n");
     387           0 :                 return;
     388             :         }
     389             : 
     390             :         /* Read MAC address, channels, etc from EEPROM. */
     391           0 :         if ((error = iwn_read_eeprom(sc)) != 0) {
     392           0 :                 printf(": could not read EEPROM\n");
     393           0 :                 return;
     394             :         }
     395             : 
     396             :         /* Allocate DMA memory for firmware transfers. */
     397           0 :         if ((error = iwn_alloc_fwmem(sc)) != 0) {
     398           0 :                 printf(": could not allocate memory for firmware\n");
     399           0 :                 return;
     400             :         }
     401             : 
     402             :         /* Allocate "Keep Warm" page. */
     403           0 :         if ((error = iwn_alloc_kw(sc)) != 0) {
     404           0 :                 printf(": could not allocate keep warm page\n");
     405           0 :                 goto fail1;
     406             :         }
     407             : 
     408             :         /* Allocate ICT table for 5000 Series. */
     409           0 :         if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
     410           0 :             (error = iwn_alloc_ict(sc)) != 0) {
     411           0 :                 printf(": could not allocate ICT table\n");
     412           0 :                 goto fail2;
     413             :         }
     414             : 
     415             :         /* Allocate TX scheduler "rings". */
     416           0 :         if ((error = iwn_alloc_sched(sc)) != 0) {
     417           0 :                 printf(": could not allocate TX scheduler rings\n");
     418           0 :                 goto fail3;
     419             :         }
     420             : 
     421             :         /* Allocate TX rings (16 on 4965AGN, 20 on >=5000). */
     422           0 :         for (i = 0; i < sc->ntxqs; i++) {
     423           0 :                 if ((error = iwn_alloc_tx_ring(sc, &sc->txq[i], i)) != 0) {
     424           0 :                         printf(": could not allocate TX ring %d\n", i);
     425           0 :                         goto fail4;
     426             :                 }
     427             :         }
     428             : 
     429             :         /* Allocate RX ring. */
     430           0 :         if ((error = iwn_alloc_rx_ring(sc, &sc->rxq)) != 0) {
     431           0 :                 printf(": could not allocate RX ring\n");
     432           0 :                 goto fail4;
     433             :         }
     434             : 
     435             :         /* Clear pending interrupts. */
     436           0 :         IWN_WRITE(sc, IWN_INT, 0xffffffff);
     437             : 
     438             :         /* Count the number of available chains. */
     439           0 :         sc->ntxchains =
     440           0 :             ((sc->txchainmask >> 2) & 1) +
     441           0 :             ((sc->txchainmask >> 1) & 1) +
     442           0 :             ((sc->txchainmask >> 0) & 1);
     443           0 :         sc->nrxchains =
     444           0 :             ((sc->rxchainmask >> 2) & 1) +
     445           0 :             ((sc->rxchainmask >> 1) & 1) +
     446           0 :             ((sc->rxchainmask >> 0) & 1);
     447           0 :         printf(", MIMO %dT%dR, %.4s, address %s\n", sc->ntxchains,
     448           0 :             sc->nrxchains, sc->eeprom_domain, ether_sprintf(ic->ic_myaddr));
     449             : 
     450           0 :         ic->ic_phytype = IEEE80211_T_OFDM;   /* not only, but not used */
     451           0 :         ic->ic_opmode = IEEE80211_M_STA;     /* default to BSS mode */
     452           0 :         ic->ic_state = IEEE80211_S_INIT;
     453             : 
     454             :         /* Set device capabilities. */
     455           0 :         ic->ic_caps =
     456             :             IEEE80211_C_WEP |           /* WEP */
     457             :             IEEE80211_C_RSN |           /* WPA/RSN */
     458             :             IEEE80211_C_SCANALL |       /* device scans all channels at once */
     459             :             IEEE80211_C_SCANALLBAND |   /* driver scans all bands at once */
     460             :             IEEE80211_C_MONITOR |       /* monitor mode supported */
     461             :             IEEE80211_C_SHSLOT |        /* short slot time supported */
     462             :             IEEE80211_C_SHPREAMBLE |    /* short preamble supported */
     463             :             IEEE80211_C_PMGT;           /* power saving supported */
     464             : 
     465             :         /* No optional HT features supported for now, */
     466           0 :         ic->ic_htcaps = 0;
     467           0 :         ic->ic_htxcaps = 0;
     468           0 :         ic->ic_txbfcaps = 0;
     469           0 :         ic->ic_aselcaps = 0;
     470           0 :         ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */);
     471           0 :         if (sc->sc_flags & IWN_FLAG_HAS_11N) {
     472             :                 /* Set HT capabilities. */
     473           0 :                 ic->ic_htcaps = IEEE80211_HTCAP_SGI20;
     474             : #ifdef notyet
     475             :                 ic->ic_htcaps |=
     476             : #if IWN_RBUF_SIZE == 8192
     477             :                     IEEE80211_HTCAP_AMSDU7935 |
     478             : #endif
     479             :                     IEEE80211_HTCAP_CBW20_40 |
     480             :                     IEEE80211_HTCAP_SGI40;
     481             :                 if (sc->hw_type != IWN_HW_REV_TYPE_4965)
     482             :                         ic->ic_htcaps |= IEEE80211_HTCAP_GF;
     483             :                 if (sc->hw_type == IWN_HW_REV_TYPE_6050)
     484             :                         ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DYN;
     485             :                 else
     486             :                         ic->ic_htcaps |= IEEE80211_HTCAP_SMPS_DIS;
     487             : #endif  /* notyet */
     488           0 :         }
     489             : 
     490             :         /* Set supported legacy rates. */
     491           0 :         ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
     492           0 :         ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
     493           0 :         if (sc->sc_flags & IWN_FLAG_HAS_5GHZ) {
     494           0 :                 ic->ic_sup_rates[IEEE80211_MODE_11A] =
     495           0 :                     ieee80211_std_rateset_11a;
     496           0 :         }
     497           0 :         if (sc->sc_flags & IWN_FLAG_HAS_11N) {
     498             :                 /* Set supported HT rates. */
     499           0 :                 ic->ic_sup_mcs[0] = 0xff;            /* MCS 0-7 */
     500             : #ifdef notyet
     501             :                 if (sc->nrxchains > 1)
     502             :                         ic->ic_sup_mcs[1] = 0xff;    /* MCS 8-15 */
     503             :                 if (sc->nrxchains > 2)
     504             :                         ic->ic_sup_mcs[2] = 0xff;    /* MCS 16-23 */
     505             : #endif
     506           0 :         }
     507             : 
     508             :         /* IBSS channel undefined for now. */
     509           0 :         ic->ic_ibss_chan = &ic->ic_channels[0];
     510             : 
     511           0 :         ifp->if_softc = sc;
     512           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     513           0 :         ifp->if_ioctl = iwn_ioctl;
     514           0 :         ifp->if_start = iwn_start;
     515           0 :         ifp->if_watchdog = iwn_watchdog;
     516           0 :         memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
     517             : 
     518           0 :         if_attach(ifp);
     519           0 :         ieee80211_ifattach(ifp);
     520           0 :         ic->ic_node_alloc = iwn_node_alloc;
     521           0 :         ic->ic_bgscan_start = iwn_bgscan;
     522           0 :         ic->ic_newassoc = iwn_newassoc;
     523           0 :         ic->ic_updateedca = iwn_updateedca;
     524           0 :         ic->ic_set_key = iwn_set_key;
     525           0 :         ic->ic_delete_key = iwn_delete_key;
     526           0 :         ic->ic_update_htprot = iwn_update_htprot;
     527           0 :         ic->ic_ampdu_rx_start = iwn_ampdu_rx_start;
     528           0 :         ic->ic_ampdu_rx_stop = iwn_ampdu_rx_stop;
     529             : #ifdef notyet
     530             :         ic->ic_ampdu_tx_start = iwn_ampdu_tx_start;
     531             :         ic->ic_ampdu_tx_stop = iwn_ampdu_tx_stop;
     532             : #endif
     533             : 
     534             :         /* Override 802.11 state transition machine. */
     535           0 :         sc->sc_newstate = ic->ic_newstate;
     536           0 :         ic->ic_newstate = iwn_newstate;
     537           0 :         ieee80211_media_init(ifp, iwn_media_change, ieee80211_media_status);
     538             : 
     539           0 :         sc->amrr.amrr_min_success_threshold =  1;
     540           0 :         sc->amrr.amrr_max_success_threshold = 15;
     541             : 
     542             : #if NBPFILTER > 0
     543           0 :         iwn_radiotap_attach(sc);
     544             : #endif
     545           0 :         timeout_set(&sc->calib_to, iwn_calib_timeout, sc);
     546           0 :         rw_init(&sc->sc_rwlock, "iwnlock");
     547           0 :         task_set(&sc->init_task, iwn_init_task, sc);
     548           0 :         return;
     549             : 
     550             :         /* Free allocated memory if something failed during attachment. */
     551           0 : fail4:  while (--i >= 0)
     552           0 :                 iwn_free_tx_ring(sc, &sc->txq[i]);
     553           0 :         iwn_free_sched(sc);
     554           0 : fail3:  if (sc->ict != NULL)
     555           0 :                 iwn_free_ict(sc);
     556           0 : fail2:  iwn_free_kw(sc);
     557           0 : fail1:  iwn_free_fwmem(sc);
     558           0 : }
     559             : 
     560             : int
     561           0 : iwn4965_attach(struct iwn_softc *sc, pci_product_id_t pid)
     562             : {
     563           0 :         struct iwn_ops *ops = &sc->ops;
     564             : 
     565           0 :         ops->load_firmware = iwn4965_load_firmware;
     566           0 :         ops->read_eeprom = iwn4965_read_eeprom;
     567           0 :         ops->post_alive = iwn4965_post_alive;
     568           0 :         ops->nic_config = iwn4965_nic_config;
     569           0 :         ops->update_sched = iwn4965_update_sched;
     570           0 :         ops->get_temperature = iwn4965_get_temperature;
     571           0 :         ops->get_rssi = iwn4965_get_rssi;
     572           0 :         ops->set_txpower = iwn4965_set_txpower;
     573           0 :         ops->init_gains = iwn4965_init_gains;
     574           0 :         ops->set_gains = iwn4965_set_gains;
     575           0 :         ops->add_node = iwn4965_add_node;
     576           0 :         ops->tx_done = iwn4965_tx_done;
     577           0 :         ops->ampdu_tx_start = iwn4965_ampdu_tx_start;
     578           0 :         ops->ampdu_tx_stop = iwn4965_ampdu_tx_stop;
     579           0 :         sc->ntxqs = IWN4965_NTXQUEUES;
     580           0 :         sc->ndmachnls = IWN4965_NDMACHNLS;
     581           0 :         sc->broadcast_id = IWN4965_ID_BROADCAST;
     582           0 :         sc->rxonsz = IWN4965_RXONSZ;
     583           0 :         sc->schedsz = IWN4965_SCHEDSZ;
     584           0 :         sc->fw_text_maxsz = IWN4965_FW_TEXT_MAXSZ;
     585           0 :         sc->fw_data_maxsz = IWN4965_FW_DATA_MAXSZ;
     586           0 :         sc->fwsz = IWN4965_FWSZ;
     587           0 :         sc->sched_txfact_addr = IWN4965_SCHED_TXFACT;
     588           0 :         sc->limits = &iwn4965_sensitivity_limits;
     589           0 :         sc->fwname = "iwn-4965";
     590             :         /* Override chains masks, ROM is known to be broken. */
     591           0 :         sc->txchainmask = IWN_ANT_AB;
     592           0 :         sc->rxchainmask = IWN_ANT_ABC;
     593             : 
     594           0 :         return 0;
     595             : }
     596             : 
     597             : int
     598           0 : iwn5000_attach(struct iwn_softc *sc, pci_product_id_t pid)
     599             : {
     600           0 :         struct iwn_ops *ops = &sc->ops;
     601             : 
     602           0 :         ops->load_firmware = iwn5000_load_firmware;
     603           0 :         ops->read_eeprom = iwn5000_read_eeprom;
     604           0 :         ops->post_alive = iwn5000_post_alive;
     605           0 :         ops->nic_config = iwn5000_nic_config;
     606           0 :         ops->update_sched = iwn5000_update_sched;
     607           0 :         ops->get_temperature = iwn5000_get_temperature;
     608           0 :         ops->get_rssi = iwn5000_get_rssi;
     609           0 :         ops->set_txpower = iwn5000_set_txpower;
     610           0 :         ops->init_gains = iwn5000_init_gains;
     611           0 :         ops->set_gains = iwn5000_set_gains;
     612           0 :         ops->add_node = iwn5000_add_node;
     613           0 :         ops->tx_done = iwn5000_tx_done;
     614           0 :         ops->ampdu_tx_start = iwn5000_ampdu_tx_start;
     615           0 :         ops->ampdu_tx_stop = iwn5000_ampdu_tx_stop;
     616           0 :         sc->ntxqs = IWN5000_NTXQUEUES;
     617           0 :         sc->ndmachnls = IWN5000_NDMACHNLS;
     618           0 :         sc->broadcast_id = IWN5000_ID_BROADCAST;
     619           0 :         sc->rxonsz = IWN5000_RXONSZ;
     620           0 :         sc->schedsz = IWN5000_SCHEDSZ;
     621           0 :         sc->fw_text_maxsz = IWN5000_FW_TEXT_MAXSZ;
     622           0 :         sc->fw_data_maxsz = IWN5000_FW_DATA_MAXSZ;
     623           0 :         sc->fwsz = IWN5000_FWSZ;
     624           0 :         sc->sched_txfact_addr = IWN5000_SCHED_TXFACT;
     625             : 
     626           0 :         switch (sc->hw_type) {
     627             :         case IWN_HW_REV_TYPE_5100:
     628           0 :                 sc->limits = &iwn5000_sensitivity_limits;
     629           0 :                 sc->fwname = "iwn-5000";
     630             :                 /* Override chains masks, ROM is known to be broken. */
     631           0 :                 sc->txchainmask = IWN_ANT_B;
     632           0 :                 sc->rxchainmask = IWN_ANT_AB;
     633           0 :                 break;
     634             :         case IWN_HW_REV_TYPE_5150:
     635           0 :                 sc->limits = &iwn5150_sensitivity_limits;
     636           0 :                 sc->fwname = "iwn-5150";
     637           0 :                 break;
     638             :         case IWN_HW_REV_TYPE_5300:
     639             :         case IWN_HW_REV_TYPE_5350:
     640           0 :                 sc->limits = &iwn5000_sensitivity_limits;
     641           0 :                 sc->fwname = "iwn-5000";
     642           0 :                 break;
     643             :         case IWN_HW_REV_TYPE_1000:
     644           0 :                 sc->limits = &iwn1000_sensitivity_limits;
     645           0 :                 sc->fwname = "iwn-1000";
     646           0 :                 break;
     647             :         case IWN_HW_REV_TYPE_6000:
     648           0 :                 sc->limits = &iwn6000_sensitivity_limits;
     649           0 :                 sc->fwname = "iwn-6000";
     650           0 :                 if (pid == PCI_PRODUCT_INTEL_WL_6200_1 ||
     651           0 :                     pid == PCI_PRODUCT_INTEL_WL_6200_2) {
     652           0 :                         sc->sc_flags |= IWN_FLAG_INTERNAL_PA;
     653             :                         /* Override chains masks, ROM is known to be broken. */
     654           0 :                         sc->txchainmask = IWN_ANT_BC;
     655           0 :                         sc->rxchainmask = IWN_ANT_BC;
     656           0 :                 }
     657             :                 break;
     658             :         case IWN_HW_REV_TYPE_6050:
     659           0 :                 sc->limits = &iwn6000_sensitivity_limits;
     660           0 :                 sc->fwname = "iwn-6050";
     661           0 :                 break;
     662             :         case IWN_HW_REV_TYPE_6005:
     663           0 :                 sc->limits = &iwn6000_sensitivity_limits;
     664           0 :                 if (pid != PCI_PRODUCT_INTEL_WL_6005_1 &&
     665           0 :                     pid != PCI_PRODUCT_INTEL_WL_6005_2) {
     666           0 :                         sc->fwname = "iwn-6030";
     667           0 :                         sc->sc_flags |= IWN_FLAG_ADV_BT_COEX;
     668           0 :                 } else
     669           0 :                         sc->fwname = "iwn-6005";
     670             :                 break;
     671             :         case IWN_HW_REV_TYPE_2030:
     672           0 :                 sc->limits = &iwn2000_sensitivity_limits;
     673           0 :                 sc->fwname = "iwn-2030";
     674           0 :                 sc->sc_flags |= IWN_FLAG_ADV_BT_COEX;
     675           0 :                 break;
     676             :         case IWN_HW_REV_TYPE_2000:
     677           0 :                 sc->limits = &iwn2000_sensitivity_limits;
     678           0 :                 sc->fwname = "iwn-2000";
     679           0 :                 break;
     680             :         case IWN_HW_REV_TYPE_135:
     681           0 :                 sc->limits = &iwn2000_sensitivity_limits;
     682           0 :                 sc->fwname = "iwn-135";
     683           0 :                 sc->sc_flags |= IWN_FLAG_ADV_BT_COEX;
     684           0 :                 break;
     685             :         case IWN_HW_REV_TYPE_105:
     686           0 :                 sc->limits = &iwn2000_sensitivity_limits;
     687           0 :                 sc->fwname = "iwn-105";
     688           0 :                 break;
     689             :         default:
     690           0 :                 printf(": adapter type %d not supported\n", sc->hw_type);
     691           0 :                 return ENOTSUP;
     692             :         }
     693           0 :         return 0;
     694           0 : }
     695             : 
     696             : #if NBPFILTER > 0
     697             : /*
     698             :  * Attach the interface to 802.11 radiotap.
     699             :  */
     700             : void
     701           0 : iwn_radiotap_attach(struct iwn_softc *sc)
     702             : {
     703           0 :         bpfattach(&sc->sc_drvbpf, &sc->sc_ic.ic_if, DLT_IEEE802_11_RADIO,
     704             :             sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN);
     705             : 
     706           0 :         sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
     707           0 :         sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
     708           0 :         sc->sc_rxtap.wr_ihdr.it_present = htole32(IWN_RX_RADIOTAP_PRESENT);
     709             : 
     710           0 :         sc->sc_txtap_len = sizeof sc->sc_txtapu;
     711           0 :         sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
     712           0 :         sc->sc_txtap.wt_ihdr.it_present = htole32(IWN_TX_RADIOTAP_PRESENT);
     713           0 : }
     714             : #endif
     715             : 
     716             : int
     717           0 : iwn_detach(struct device *self, int flags)
     718             : {
     719           0 :         struct iwn_softc *sc = (struct iwn_softc *)self;
     720           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     721             :         int qid;
     722             : 
     723           0 :         timeout_del(&sc->calib_to);
     724           0 :         task_del(systq, &sc->init_task);
     725             : 
     726             :         /* Uninstall interrupt handler. */
     727           0 :         if (sc->sc_ih != NULL)
     728           0 :                 pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
     729             : 
     730             :         /* Free DMA resources. */
     731           0 :         iwn_free_rx_ring(sc, &sc->rxq);
     732           0 :         for (qid = 0; qid < sc->ntxqs; qid++)
     733           0 :                 iwn_free_tx_ring(sc, &sc->txq[qid]);
     734           0 :         iwn_free_sched(sc);
     735           0 :         iwn_free_kw(sc);
     736           0 :         if (sc->ict != NULL)
     737           0 :                 iwn_free_ict(sc);
     738           0 :         iwn_free_fwmem(sc);
     739             : 
     740           0 :         bus_space_unmap(sc->sc_st, sc->sc_sh, sc->sc_sz);
     741             : 
     742           0 :         ieee80211_ifdetach(ifp);
     743           0 :         if_detach(ifp);
     744             : 
     745           0 :         return 0;
     746             : }
     747             : 
     748             : int
     749           0 : iwn_activate(struct device *self, int act)
     750             : {
     751           0 :         struct iwn_softc *sc = (struct iwn_softc *)self;
     752           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     753             : 
     754           0 :         switch (act) {
     755             :         case DVACT_SUSPEND:
     756           0 :                 if (ifp->if_flags & IFF_RUNNING)
     757           0 :                         iwn_stop(ifp, 0);
     758             :                 break;
     759             :         case DVACT_WAKEUP:
     760           0 :                 iwn_wakeup(sc);
     761           0 :                 break;
     762             :         }
     763             : 
     764           0 :         return 0;
     765             : }
     766             : 
     767             : void
     768           0 : iwn_wakeup(struct iwn_softc *sc)
     769             : {
     770             :         pcireg_t reg;
     771             : 
     772             :         /* Clear device-specific "PCI retry timeout" register (41h). */
     773           0 :         reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
     774           0 :         if (reg & 0xff00)
     775           0 :                 pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
     776           0 :         iwn_init_task(sc);
     777           0 : }
     778             : 
     779             : void
     780           0 : iwn_init_task(void *arg1)
     781             : {
     782           0 :         struct iwn_softc *sc = arg1;
     783           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
     784             :         int s;
     785             : 
     786           0 :         rw_enter_write(&sc->sc_rwlock);
     787           0 :         s = splnet();
     788             : 
     789           0 :         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
     790           0 :                 iwn_init(ifp);
     791             : 
     792           0 :         splx(s);
     793           0 :         rw_exit_write(&sc->sc_rwlock);
     794           0 : }
     795             : 
     796             : int
     797           0 : iwn_nic_lock(struct iwn_softc *sc)
     798             : {
     799             :         int ntries;
     800             : 
     801             :         /* Request exclusive access to NIC. */
     802           0 :         IWN_SETBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_MAC_ACCESS_REQ);
     803             : 
     804             :         /* Spin until we actually get the lock. */
     805           0 :         for (ntries = 0; ntries < 1000; ntries++) {
     806           0 :                 if ((IWN_READ(sc, IWN_GP_CNTRL) &
     807           0 :                      (IWN_GP_CNTRL_MAC_ACCESS_ENA | IWN_GP_CNTRL_SLEEP)) ==
     808             :                     IWN_GP_CNTRL_MAC_ACCESS_ENA)
     809           0 :                         return 0;
     810           0 :                 DELAY(10);
     811             :         }
     812           0 :         return ETIMEDOUT;
     813           0 : }
     814             : 
     815             : static __inline void
     816           0 : iwn_nic_unlock(struct iwn_softc *sc)
     817             : {
     818           0 :         IWN_CLRBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_MAC_ACCESS_REQ);
     819           0 : }
     820             : 
     821             : static __inline uint32_t
     822           0 : iwn_prph_read(struct iwn_softc *sc, uint32_t addr)
     823             : {
     824           0 :         IWN_WRITE(sc, IWN_PRPH_RADDR, IWN_PRPH_DWORD | addr);
     825           0 :         IWN_BARRIER_READ_WRITE(sc);
     826           0 :         return IWN_READ(sc, IWN_PRPH_RDATA);
     827             : }
     828             : 
     829             : static __inline void
     830           0 : iwn_prph_write(struct iwn_softc *sc, uint32_t addr, uint32_t data)
     831             : {
     832           0 :         IWN_WRITE(sc, IWN_PRPH_WADDR, IWN_PRPH_DWORD | addr);
     833           0 :         IWN_BARRIER_WRITE(sc);
     834           0 :         IWN_WRITE(sc, IWN_PRPH_WDATA, data);
     835           0 : }
     836             : 
     837             : static __inline void
     838           0 : iwn_prph_setbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask)
     839             : {
     840           0 :         iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) | mask);
     841           0 : }
     842             : 
     843             : static __inline void
     844           0 : iwn_prph_clrbits(struct iwn_softc *sc, uint32_t addr, uint32_t mask)
     845             : {
     846           0 :         iwn_prph_write(sc, addr, iwn_prph_read(sc, addr) & ~mask);
     847           0 : }
     848             : 
     849             : static __inline void
     850           0 : iwn_prph_write_region_4(struct iwn_softc *sc, uint32_t addr,
     851             :     const uint32_t *data, int count)
     852             : {
     853           0 :         for (; count > 0; count--, data++, addr += 4)
     854           0 :                 iwn_prph_write(sc, addr, *data);
     855           0 : }
     856             : 
     857             : static __inline uint32_t
     858           0 : iwn_mem_read(struct iwn_softc *sc, uint32_t addr)
     859             : {
     860           0 :         IWN_WRITE(sc, IWN_MEM_RADDR, addr);
     861           0 :         IWN_BARRIER_READ_WRITE(sc);
     862           0 :         return IWN_READ(sc, IWN_MEM_RDATA);
     863             : }
     864             : 
     865             : static __inline void
     866           0 : iwn_mem_write(struct iwn_softc *sc, uint32_t addr, uint32_t data)
     867             : {
     868           0 :         IWN_WRITE(sc, IWN_MEM_WADDR, addr);
     869           0 :         IWN_BARRIER_WRITE(sc);
     870           0 :         IWN_WRITE(sc, IWN_MEM_WDATA, data);
     871           0 : }
     872             : 
     873             : static __inline void
     874           0 : iwn_mem_write_2(struct iwn_softc *sc, uint32_t addr, uint16_t data)
     875             : {
     876             :         uint32_t tmp;
     877             : 
     878           0 :         tmp = iwn_mem_read(sc, addr & ~3);
     879           0 :         if (addr & 3)
     880           0 :                 tmp = (tmp & 0x0000ffff) | data << 16;
     881             :         else
     882           0 :                 tmp = (tmp & 0xffff0000) | data;
     883           0 :         iwn_mem_write(sc, addr & ~3, tmp);
     884           0 : }
     885             : 
     886             : #ifdef IWN_DEBUG
     887             :  
     888             : static __inline void
     889             : iwn_mem_read_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t *data,
     890             :     int count)
     891             : {
     892             :         for (; count > 0; count--, addr += 4)
     893             :                 *data++ = iwn_mem_read(sc, addr);
     894             : }
     895             : 
     896             : #endif
     897             : 
     898             : static __inline void
     899           0 : iwn_mem_set_region_4(struct iwn_softc *sc, uint32_t addr, uint32_t val,
     900             :     int count)
     901             : {
     902           0 :         for (; count > 0; count--, addr += 4)
     903           0 :                 iwn_mem_write(sc, addr, val);
     904           0 : }
     905             : 
     906             : int
     907           0 : iwn_eeprom_lock(struct iwn_softc *sc)
     908             : {
     909             :         int i, ntries;
     910             : 
     911           0 :         for (i = 0; i < 100; i++) {
     912             :                 /* Request exclusive access to EEPROM. */
     913           0 :                 IWN_SETBITS(sc, IWN_HW_IF_CONFIG,
     914             :                     IWN_HW_IF_CONFIG_EEPROM_LOCKED);
     915             : 
     916             :                 /* Spin until we actually get the lock. */
     917           0 :                 for (ntries = 0; ntries < 100; ntries++) {
     918           0 :                         if (IWN_READ(sc, IWN_HW_IF_CONFIG) &
     919             :                             IWN_HW_IF_CONFIG_EEPROM_LOCKED)
     920           0 :                                 return 0;
     921           0 :                         DELAY(10);
     922             :                 }
     923             :         }
     924           0 :         return ETIMEDOUT;
     925           0 : }
     926             : 
     927             : static __inline void
     928           0 : iwn_eeprom_unlock(struct iwn_softc *sc)
     929             : {
     930           0 :         IWN_CLRBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_EEPROM_LOCKED);
     931           0 : }
     932             : 
     933             : /*
     934             :  * Initialize access by host to One Time Programmable ROM.
     935             :  * NB: This kind of ROM can be found on 1000 or 6000 Series only.
     936             :  */
     937             : int
     938           0 : iwn_init_otprom(struct iwn_softc *sc)
     939             : {
     940           0 :         uint16_t prev, base, next;
     941             :         int count, error;
     942             : 
     943             :         /* Wait for clock stabilization before accessing prph. */
     944           0 :         if ((error = iwn_clock_wait(sc)) != 0)
     945           0 :                 return error;
     946             : 
     947           0 :         if ((error = iwn_nic_lock(sc)) != 0)
     948           0 :                 return error;
     949           0 :         iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ);
     950           0 :         DELAY(5);
     951           0 :         iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_RESET_REQ);
     952           0 :         iwn_nic_unlock(sc);
     953             : 
     954             :         /* Set auto clock gate disable bit for HW with OTP shadow RAM. */
     955           0 :         if (sc->hw_type != IWN_HW_REV_TYPE_1000) {
     956           0 :                 IWN_SETBITS(sc, IWN_DBG_LINK_PWR_MGMT,
     957             :                     IWN_RESET_LINK_PWR_MGMT_DIS);
     958           0 :         }
     959           0 :         IWN_CLRBITS(sc, IWN_EEPROM_GP, IWN_EEPROM_GP_IF_OWNER);
     960             :         /* Clear ECC status. */
     961           0 :         IWN_SETBITS(sc, IWN_OTP_GP,
     962             :             IWN_OTP_GP_ECC_CORR_STTS | IWN_OTP_GP_ECC_UNCORR_STTS);
     963             : 
     964             :         /*
     965             :          * Find the block before last block (contains the EEPROM image)
     966             :          * for HW without OTP shadow RAM.
     967             :          */
     968           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_1000) {
     969             :                 /* Switch to absolute addressing mode. */
     970           0 :                 IWN_CLRBITS(sc, IWN_OTP_GP, IWN_OTP_GP_RELATIVE_ACCESS);
     971             :                 base = 0;
     972           0 :                 for (count = 0; count < IWN1000_OTP_NBLOCKS; count++) {
     973           0 :                         error = iwn_read_prom_data(sc, base, &next, 2);
     974           0 :                         if (error != 0)
     975           0 :                                 return error;
     976           0 :                         if (next == 0)  /* End of linked-list. */
     977             :                                 break;
     978             :                         prev = base;
     979             :                         base = letoh16(next);
     980             :                 }
     981           0 :                 if (count == 0 || count == IWN1000_OTP_NBLOCKS)
     982           0 :                         return EIO;
     983             :                 /* Skip "next" word. */
     984           0 :                 sc->prom_base = prev + 1;
     985           0 :         }
     986           0 :         return 0;
     987           0 : }
     988             : 
     989             : int
     990           0 : iwn_read_prom_data(struct iwn_softc *sc, uint32_t addr, void *data, int count)
     991             : {
     992             :         uint8_t *out = data;
     993             :         uint32_t val, tmp;
     994             :         int ntries;
     995             : 
     996           0 :         addr += sc->prom_base;
     997           0 :         for (; count > 0; count -= 2, addr++) {
     998           0 :                 IWN_WRITE(sc, IWN_EEPROM, addr << 2);
     999           0 :                 for (ntries = 0; ntries < 10; ntries++) {
    1000           0 :                         val = IWN_READ(sc, IWN_EEPROM);
    1001           0 :                         if (val & IWN_EEPROM_READ_VALID)
    1002             :                                 break;
    1003           0 :                         DELAY(5);
    1004             :                 }
    1005           0 :                 if (ntries == 10) {
    1006           0 :                         printf("%s: timeout reading ROM at 0x%x\n",
    1007           0 :                             sc->sc_dev.dv_xname, addr);
    1008           0 :                         return ETIMEDOUT;
    1009             :                 }
    1010           0 :                 if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) {
    1011             :                         /* OTPROM, check for ECC errors. */
    1012           0 :                         tmp = IWN_READ(sc, IWN_OTP_GP);
    1013           0 :                         if (tmp & IWN_OTP_GP_ECC_UNCORR_STTS) {
    1014           0 :                                 printf("%s: OTPROM ECC error at 0x%x\n",
    1015           0 :                                     sc->sc_dev.dv_xname, addr);
    1016           0 :                                 return EIO;
    1017             :                         }
    1018           0 :                         if (tmp & IWN_OTP_GP_ECC_CORR_STTS) {
    1019             :                                 /* Correctable ECC error, clear bit. */
    1020           0 :                                 IWN_SETBITS(sc, IWN_OTP_GP,
    1021             :                                     IWN_OTP_GP_ECC_CORR_STTS);
    1022           0 :                         }
    1023             :                 }
    1024           0 :                 *out++ = val >> 16;
    1025           0 :                 if (count > 1)
    1026           0 :                         *out++ = val >> 24;
    1027             :         }
    1028           0 :         return 0;
    1029           0 : }
    1030             : 
    1031             : int
    1032           0 : iwn_dma_contig_alloc(bus_dma_tag_t tag, struct iwn_dma_info *dma, void **kvap,
    1033             :     bus_size_t size, bus_size_t alignment)
    1034             : {
    1035           0 :         int nsegs, error;
    1036             : 
    1037           0 :         dma->tag = tag;
    1038           0 :         dma->size = size;
    1039             : 
    1040           0 :         error = bus_dmamap_create(tag, size, 1, size, 0, BUS_DMA_NOWAIT,
    1041             :             &dma->map);
    1042           0 :         if (error != 0)
    1043             :                 goto fail;
    1044             : 
    1045           0 :         error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs,
    1046             :             BUS_DMA_NOWAIT | BUS_DMA_ZERO);
    1047           0 :         if (error != 0)
    1048             :                 goto fail;
    1049             : 
    1050           0 :         error = bus_dmamem_map(tag, &dma->seg, 1, size, &dma->vaddr,
    1051             :             BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
    1052           0 :         if (error != 0)
    1053             :                 goto fail;
    1054             : 
    1055           0 :         error = bus_dmamap_load_raw(tag, dma->map, &dma->seg, 1, size,
    1056             :             BUS_DMA_NOWAIT);
    1057           0 :         if (error != 0)
    1058             :                 goto fail;
    1059             : 
    1060           0 :         bus_dmamap_sync(tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE);
    1061             : 
    1062           0 :         dma->paddr = dma->map->dm_segs[0].ds_addr;
    1063           0 :         if (kvap != NULL)
    1064           0 :                 *kvap = dma->vaddr;
    1065             : 
    1066           0 :         return 0;
    1067             : 
    1068           0 : fail:   iwn_dma_contig_free(dma);
    1069           0 :         return error;
    1070           0 : }
    1071             : 
    1072             : void
    1073           0 : iwn_dma_contig_free(struct iwn_dma_info *dma)
    1074             : {
    1075           0 :         if (dma->map != NULL) {
    1076           0 :                 if (dma->vaddr != NULL) {
    1077           0 :                         bus_dmamap_sync(dma->tag, dma->map, 0, dma->size,
    1078             :                             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    1079           0 :                         bus_dmamap_unload(dma->tag, dma->map);
    1080           0 :                         bus_dmamem_unmap(dma->tag, dma->vaddr, dma->size);
    1081           0 :                         bus_dmamem_free(dma->tag, &dma->seg, 1);
    1082           0 :                         dma->vaddr = NULL;
    1083           0 :                 }
    1084           0 :                 bus_dmamap_destroy(dma->tag, dma->map);
    1085           0 :                 dma->map = NULL;
    1086           0 :         }
    1087           0 : }
    1088             : 
    1089             : int
    1090           0 : iwn_alloc_sched(struct iwn_softc *sc)
    1091             : {
    1092             :         /* TX scheduler rings must be aligned on a 1KB boundary. */
    1093           0 :         return iwn_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma,
    1094           0 :             (void **)&sc->sched, sc->schedsz, 1024);
    1095             : }
    1096             : 
    1097             : void
    1098           0 : iwn_free_sched(struct iwn_softc *sc)
    1099             : {
    1100           0 :         iwn_dma_contig_free(&sc->sched_dma);
    1101           0 : }
    1102             : 
    1103             : int
    1104           0 : iwn_alloc_kw(struct iwn_softc *sc)
    1105             : {
    1106             :         /* "Keep Warm" page must be aligned on a 4KB boundary. */
    1107           0 :         return iwn_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, NULL, 4096,
    1108             :             4096);
    1109             : }
    1110             : 
    1111             : void
    1112           0 : iwn_free_kw(struct iwn_softc *sc)
    1113             : {
    1114           0 :         iwn_dma_contig_free(&sc->kw_dma);
    1115           0 : }
    1116             : 
    1117             : int
    1118           0 : iwn_alloc_ict(struct iwn_softc *sc)
    1119             : {
    1120             :         /* ICT table must be aligned on a 4KB boundary. */
    1121           0 :         return iwn_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma,
    1122           0 :             (void **)&sc->ict, IWN_ICT_SIZE, 4096);
    1123             : }
    1124             : 
    1125             : void
    1126           0 : iwn_free_ict(struct iwn_softc *sc)
    1127             : {
    1128           0 :         iwn_dma_contig_free(&sc->ict_dma);
    1129           0 : }
    1130             : 
    1131             : int
    1132           0 : iwn_alloc_fwmem(struct iwn_softc *sc)
    1133             : {
    1134             :         /* Must be aligned on a 16-byte boundary. */
    1135           0 :         return iwn_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma, NULL,
    1136           0 :             sc->fwsz, 16);
    1137             : }
    1138             : 
    1139             : void
    1140           0 : iwn_free_fwmem(struct iwn_softc *sc)
    1141             : {
    1142           0 :         iwn_dma_contig_free(&sc->fw_dma);
    1143           0 : }
    1144             : 
    1145             : int
    1146           0 : iwn_alloc_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring)
    1147             : {
    1148             :         bus_size_t size;
    1149             :         int i, error;
    1150             : 
    1151           0 :         ring->cur = 0;
    1152             : 
    1153             :         /* Allocate RX descriptors (256-byte aligned). */
    1154             :         size = IWN_RX_RING_COUNT * sizeof (uint32_t);
    1155           0 :         error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma,
    1156           0 :             (void **)&ring->desc, size, 256);
    1157           0 :         if (error != 0) {
    1158           0 :                 printf("%s: could not allocate RX ring DMA memory\n",
    1159           0 :                     sc->sc_dev.dv_xname);
    1160           0 :                 goto fail;
    1161             :         }
    1162             : 
    1163             :         /* Allocate RX status area (16-byte aligned). */
    1164           0 :         error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma,
    1165           0 :             (void **)&ring->stat, sizeof (struct iwn_rx_status), 16);
    1166           0 :         if (error != 0) {
    1167           0 :                 printf("%s: could not allocate RX status DMA memory\n",
    1168           0 :                     sc->sc_dev.dv_xname);
    1169           0 :                 goto fail;
    1170             :         }
    1171             : 
    1172             :         /*
    1173             :          * Allocate and map RX buffers.
    1174             :          */
    1175           0 :         for (i = 0; i < IWN_RX_RING_COUNT; i++) {
    1176           0 :                 struct iwn_rx_data *data = &ring->data[i];
    1177             : 
    1178           0 :                 error = bus_dmamap_create(sc->sc_dmat, IWN_RBUF_SIZE, 1,
    1179             :                     IWN_RBUF_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
    1180             :                     &data->map);
    1181           0 :                 if (error != 0) {
    1182           0 :                         printf("%s: could not create RX buf DMA map\n",
    1183           0 :                             sc->sc_dev.dv_xname);
    1184           0 :                         goto fail;
    1185             :                 }
    1186             : 
    1187           0 :                 data->m = MCLGETI(NULL, M_DONTWAIT, NULL, IWN_RBUF_SIZE);
    1188           0 :                 if (data->m == NULL) {
    1189           0 :                         printf("%s: could not allocate RX mbuf\n",
    1190           0 :                             sc->sc_dev.dv_xname);
    1191             :                         error = ENOBUFS;
    1192           0 :                         goto fail;
    1193             :                 }
    1194             : 
    1195           0 :                 error = bus_dmamap_load(sc->sc_dmat, data->map,
    1196             :                     mtod(data->m, void *), IWN_RBUF_SIZE, NULL,
    1197             :                     BUS_DMA_NOWAIT | BUS_DMA_READ);
    1198           0 :                 if (error != 0) {
    1199           0 :                         printf("%s: can't map mbuf (error %d)\n",
    1200           0 :                             sc->sc_dev.dv_xname, error);
    1201           0 :                         goto fail;
    1202             :                 }
    1203             : 
    1204             :                 /* Set physical address of RX buffer (256-byte aligned). */
    1205           0 :                 ring->desc[i] = htole32(data->map->dm_segs[0].ds_addr >> 8);
    1206           0 :         }
    1207             : 
    1208           0 :         bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0, size,
    1209             :             BUS_DMASYNC_PREWRITE);
    1210             : 
    1211           0 :         return 0;
    1212             : 
    1213           0 : fail:   iwn_free_rx_ring(sc, ring);
    1214           0 :         return error;
    1215           0 : }
    1216             : 
    1217             : void
    1218           0 : iwn_reset_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring)
    1219             : {
    1220             :         int ntries;
    1221             : 
    1222           0 :         if (iwn_nic_lock(sc) == 0) {
    1223           0 :                 IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0);
    1224           0 :                 for (ntries = 0; ntries < 1000; ntries++) {
    1225           0 :                         if (IWN_READ(sc, IWN_FH_RX_STATUS) &
    1226             :                             IWN_FH_RX_STATUS_IDLE)
    1227             :                                 break;
    1228           0 :                         DELAY(10);
    1229             :                 }
    1230           0 :                 iwn_nic_unlock(sc);
    1231           0 :         }
    1232           0 :         ring->cur = 0;
    1233           0 :         sc->last_rx_valid = 0;
    1234           0 : }
    1235             : 
    1236             : void
    1237           0 : iwn_free_rx_ring(struct iwn_softc *sc, struct iwn_rx_ring *ring)
    1238             : {
    1239             :         int i;
    1240             : 
    1241           0 :         iwn_dma_contig_free(&ring->desc_dma);
    1242           0 :         iwn_dma_contig_free(&ring->stat_dma);
    1243             : 
    1244           0 :         for (i = 0; i < IWN_RX_RING_COUNT; i++) {
    1245           0 :                 struct iwn_rx_data *data = &ring->data[i];
    1246             : 
    1247           0 :                 if (data->m != NULL) {
    1248           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, 0,
    1249             :                             data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1250           0 :                         bus_dmamap_unload(sc->sc_dmat, data->map);
    1251           0 :                         m_freem(data->m);
    1252           0 :                 }
    1253           0 :                 if (data->map != NULL)
    1254           0 :                         bus_dmamap_destroy(sc->sc_dmat, data->map);
    1255             :         }
    1256           0 : }
    1257             : 
    1258             : int
    1259           0 : iwn_alloc_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring, int qid)
    1260             : {
    1261             :         bus_addr_t paddr;
    1262             :         bus_size_t size;
    1263             :         int i, error;
    1264             : 
    1265           0 :         ring->qid = qid;
    1266           0 :         ring->queued = 0;
    1267           0 :         ring->cur = 0;
    1268             : 
    1269             :         /* Allocate TX descriptors (256-byte aligned). */
    1270             :         size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_desc);
    1271           0 :         error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma,
    1272           0 :             (void **)&ring->desc, size, 256);
    1273           0 :         if (error != 0) {
    1274           0 :                 printf("%s: could not allocate TX ring DMA memory\n",
    1275           0 :                     sc->sc_dev.dv_xname);
    1276           0 :                 goto fail;
    1277             :         }
    1278             :         /*
    1279             :          * We only use rings 0 through 4 (4 EDCA + cmd) so there is no need
    1280             :          * to allocate commands space for other rings.
    1281             :          * XXX Do we really need to allocate descriptors for other rings?
    1282             :          */
    1283           0 :         if (qid > 4)
    1284           0 :                 return 0;
    1285             : 
    1286             :         size = IWN_TX_RING_COUNT * sizeof (struct iwn_tx_cmd);
    1287           0 :         error = iwn_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma,
    1288           0 :             (void **)&ring->cmd, size, 4);
    1289           0 :         if (error != 0) {
    1290           0 :                 printf("%s: could not allocate TX cmd DMA memory\n",
    1291           0 :                     sc->sc_dev.dv_xname);
    1292           0 :                 goto fail;
    1293             :         }
    1294             : 
    1295           0 :         paddr = ring->cmd_dma.paddr;
    1296           0 :         for (i = 0; i < IWN_TX_RING_COUNT; i++) {
    1297           0 :                 struct iwn_tx_data *data = &ring->data[i];
    1298             : 
    1299           0 :                 data->cmd_paddr = paddr;
    1300           0 :                 data->scratch_paddr = paddr + 12;
    1301           0 :                 paddr += sizeof (struct iwn_tx_cmd);
    1302             : 
    1303           0 :                 error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
    1304             :                     IWN_MAX_SCATTER - 1, MCLBYTES, 0, BUS_DMA_NOWAIT,
    1305             :                     &data->map);
    1306           0 :                 if (error != 0) {
    1307           0 :                         printf("%s: could not create TX buf DMA map\n",
    1308           0 :                             sc->sc_dev.dv_xname);
    1309           0 :                         goto fail;
    1310             :                 }
    1311           0 :         }
    1312           0 :         return 0;
    1313             : 
    1314           0 : fail:   iwn_free_tx_ring(sc, ring);
    1315           0 :         return error;
    1316           0 : }
    1317             : 
    1318             : void
    1319           0 : iwn_reset_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring)
    1320             : {
    1321             :         int i;
    1322             : 
    1323           0 :         for (i = 0; i < IWN_TX_RING_COUNT; i++) {
    1324           0 :                 struct iwn_tx_data *data = &ring->data[i];
    1325             : 
    1326           0 :                 if (data->m != NULL) {
    1327           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, 0,
    1328             :                             data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
    1329           0 :                         bus_dmamap_unload(sc->sc_dmat, data->map);
    1330           0 :                         m_freem(data->m);
    1331           0 :                         data->m = NULL;
    1332           0 :                 }
    1333             :         }
    1334             :         /* Clear TX descriptors. */
    1335           0 :         memset(ring->desc, 0, ring->desc_dma.size);
    1336           0 :         bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0,
    1337             :             ring->desc_dma.size, BUS_DMASYNC_PREWRITE);
    1338           0 :         sc->qfullmsk &= ~(1 << ring->qid);
    1339           0 :         ring->queued = 0;
    1340           0 :         ring->cur = 0;
    1341           0 : }
    1342             : 
    1343             : void
    1344           0 : iwn_free_tx_ring(struct iwn_softc *sc, struct iwn_tx_ring *ring)
    1345             : {
    1346             :         int i;
    1347             : 
    1348           0 :         iwn_dma_contig_free(&ring->desc_dma);
    1349           0 :         iwn_dma_contig_free(&ring->cmd_dma);
    1350             : 
    1351           0 :         for (i = 0; i < IWN_TX_RING_COUNT; i++) {
    1352           0 :                 struct iwn_tx_data *data = &ring->data[i];
    1353             : 
    1354           0 :                 if (data->m != NULL) {
    1355           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, 0,
    1356             :                             data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
    1357           0 :                         bus_dmamap_unload(sc->sc_dmat, data->map);
    1358           0 :                         m_freem(data->m);
    1359           0 :                 }
    1360           0 :                 if (data->map != NULL)
    1361           0 :                         bus_dmamap_destroy(sc->sc_dmat, data->map);
    1362             :         }
    1363           0 : }
    1364             : 
    1365             : void
    1366           0 : iwn5000_ict_reset(struct iwn_softc *sc)
    1367             : {
    1368             :         /* Disable interrupts. */
    1369           0 :         IWN_WRITE(sc, IWN_INT_MASK, 0);
    1370             : 
    1371             :         /* Reset ICT table. */
    1372           0 :         memset(sc->ict, 0, IWN_ICT_SIZE);
    1373           0 :         sc->ict_cur = 0;
    1374             : 
    1375             :         /* Set physical address of ICT table (4KB aligned). */
    1376             :         DPRINTF(("enabling ICT\n"));
    1377           0 :         IWN_WRITE(sc, IWN_DRAM_INT_TBL, IWN_DRAM_INT_TBL_ENABLE |
    1378             :             IWN_DRAM_INT_TBL_WRAP_CHECK | sc->ict_dma.paddr >> 12);
    1379             : 
    1380             :         /* Enable periodic RX interrupt. */
    1381           0 :         sc->int_mask |= IWN_INT_RX_PERIODIC;
    1382             :         /* Switch to ICT interrupt mode in driver. */
    1383           0 :         sc->sc_flags |= IWN_FLAG_USE_ICT;
    1384             : 
    1385             :         /* Re-enable interrupts. */
    1386           0 :         IWN_WRITE(sc, IWN_INT, 0xffffffff);
    1387           0 :         IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
    1388           0 : }
    1389             : 
    1390             : int
    1391           0 : iwn_read_eeprom(struct iwn_softc *sc)
    1392             : {
    1393           0 :         struct iwn_ops *ops = &sc->ops;
    1394           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1395           0 :         uint16_t val;
    1396             :         int error;
    1397             : 
    1398             :         /* Check whether adapter has an EEPROM or an OTPROM. */
    1399           0 :         if (sc->hw_type >= IWN_HW_REV_TYPE_1000 &&
    1400           0 :             (IWN_READ(sc, IWN_OTP_GP) & IWN_OTP_GP_DEV_SEL_OTP))
    1401           0 :                 sc->sc_flags |= IWN_FLAG_HAS_OTPROM;
    1402             :         DPRINTF(("%s found\n", (sc->sc_flags & IWN_FLAG_HAS_OTPROM) ?
    1403             :             "OTPROM" : "EEPROM"));
    1404             : 
    1405             :         /* Adapter has to be powered on for EEPROM access to work. */
    1406           0 :         if ((error = iwn_apm_init(sc)) != 0) {
    1407           0 :                 printf("%s: could not power ON adapter\n",
    1408           0 :                     sc->sc_dev.dv_xname);
    1409           0 :                 return error;
    1410             :         }
    1411             : 
    1412           0 :         if ((IWN_READ(sc, IWN_EEPROM_GP) & 0x7) == 0) {
    1413           0 :                 printf("%s: bad ROM signature\n", sc->sc_dev.dv_xname);
    1414           0 :                 return EIO;
    1415             :         }
    1416           0 :         if ((error = iwn_eeprom_lock(sc)) != 0) {
    1417           0 :                 printf("%s: could not lock ROM (error=%d)\n",
    1418           0 :                     sc->sc_dev.dv_xname, error);
    1419           0 :                 return error;
    1420             :         }
    1421           0 :         if (sc->sc_flags & IWN_FLAG_HAS_OTPROM) {
    1422           0 :                 if ((error = iwn_init_otprom(sc)) != 0) {
    1423           0 :                         printf("%s: could not initialize OTPROM\n",
    1424           0 :                             sc->sc_dev.dv_xname);
    1425           0 :                         return error;
    1426             :                 }
    1427             :         }
    1428             : 
    1429           0 :         iwn_read_prom_data(sc, IWN_EEPROM_SKU_CAP, &val, 2);
    1430             :         DPRINTF(("SKU capabilities=0x%04x\n", letoh16(val)));
    1431             :         /* Check if HT support is bonded out. */
    1432           0 :         if (val & htole16(IWN_EEPROM_SKU_CAP_11N))
    1433           0 :                 sc->sc_flags |= IWN_FLAG_HAS_11N;
    1434             : 
    1435           0 :         iwn_read_prom_data(sc, IWN_EEPROM_RFCFG, &val, 2);
    1436           0 :         sc->rfcfg = letoh16(val);
    1437             :         DPRINTF(("radio config=0x%04x\n", sc->rfcfg));
    1438             :         /* Read Tx/Rx chains from ROM unless it's known to be broken. */
    1439           0 :         if (sc->txchainmask == 0)
    1440           0 :                 sc->txchainmask = IWN_RFCFG_TXANTMSK(sc->rfcfg);
    1441           0 :         if (sc->rxchainmask == 0)
    1442           0 :                 sc->rxchainmask = IWN_RFCFG_RXANTMSK(sc->rfcfg);
    1443             : 
    1444             :         /* Read MAC address. */
    1445           0 :         iwn_read_prom_data(sc, IWN_EEPROM_MAC, ic->ic_myaddr, 6);
    1446             : 
    1447             :         /* Read adapter-specific information from EEPROM. */
    1448           0 :         ops->read_eeprom(sc);
    1449             : 
    1450           0 :         iwn_apm_stop(sc);       /* Power OFF adapter. */
    1451             : 
    1452           0 :         iwn_eeprom_unlock(sc);
    1453           0 :         return 0;
    1454           0 : }
    1455             : 
    1456             : void
    1457           0 : iwn4965_read_eeprom(struct iwn_softc *sc)
    1458             : {
    1459             :         uint32_t addr;
    1460           0 :         uint16_t val;
    1461             :         int i;
    1462             : 
    1463             :         /* Read regulatory domain (4 ASCII characters). */
    1464           0 :         iwn_read_prom_data(sc, IWN4965_EEPROM_DOMAIN, sc->eeprom_domain, 4);
    1465             : 
    1466             :         /* Read the list of authorized channels (20MHz ones only). */
    1467           0 :         for (i = 0; i < 5; i++) {
    1468           0 :                 addr = iwn4965_regulatory_bands[i];
    1469           0 :                 iwn_read_eeprom_channels(sc, i, addr);
    1470             :         }
    1471             : 
    1472             :         /* Read maximum allowed TX power for 2GHz and 5GHz bands. */
    1473           0 :         iwn_read_prom_data(sc, IWN4965_EEPROM_MAXPOW, &val, 2);
    1474           0 :         sc->maxpwr2GHz = val & 0xff;
    1475           0 :         sc->maxpwr5GHz = val >> 8;
    1476             :         /* Check that EEPROM values are within valid range. */
    1477           0 :         if (sc->maxpwr5GHz < 20 || sc->maxpwr5GHz > 50)
    1478           0 :                 sc->maxpwr5GHz = 38;
    1479           0 :         if (sc->maxpwr2GHz < 20 || sc->maxpwr2GHz > 50)
    1480           0 :                 sc->maxpwr2GHz = 38;
    1481             :         DPRINTF(("maxpwr 2GHz=%d 5GHz=%d\n", sc->maxpwr2GHz, sc->maxpwr5GHz));
    1482             : 
    1483             :         /* Read samples for each TX power group. */
    1484           0 :         iwn_read_prom_data(sc, IWN4965_EEPROM_BANDS, sc->bands,
    1485             :             sizeof sc->bands);
    1486             : 
    1487             :         /* Read voltage at which samples were taken. */
    1488           0 :         iwn_read_prom_data(sc, IWN4965_EEPROM_VOLTAGE, &val, 2);
    1489           0 :         sc->eeprom_voltage = (int16_t)letoh16(val);
    1490             :         DPRINTF(("voltage=%d (in 0.3V)\n", sc->eeprom_voltage));
    1491             : 
    1492             : #ifdef IWN_DEBUG
    1493             :         /* Print samples. */
    1494             :         if (iwn_debug > 0) {
    1495             :                 for (i = 0; i < IWN_NBANDS; i++)
    1496             :                         iwn4965_print_power_group(sc, i);
    1497             :         }
    1498             : #endif
    1499           0 : }
    1500             : 
    1501             : #ifdef IWN_DEBUG
    1502             : void
    1503             : iwn4965_print_power_group(struct iwn_softc *sc, int i)
    1504             : {
    1505             :         struct iwn4965_eeprom_band *band = &sc->bands[i];
    1506             :         struct iwn4965_eeprom_chan_samples *chans = band->chans;
    1507             :         int j, c;
    1508             : 
    1509             :         printf("===band %d===\n", i);
    1510             :         printf("chan lo=%d, chan hi=%d\n", band->lo, band->hi);
    1511             :         printf("chan1 num=%d\n", chans[0].num);
    1512             :         for (c = 0; c < 2; c++) {
    1513             :                 for (j = 0; j < IWN_NSAMPLES; j++) {
    1514             :                         printf("chain %d, sample %d: temp=%d gain=%d "
    1515             :                             "power=%d pa_det=%d\n", c, j,
    1516             :                             chans[0].samples[c][j].temp,
    1517             :                             chans[0].samples[c][j].gain,
    1518             :                             chans[0].samples[c][j].power,
    1519             :                             chans[0].samples[c][j].pa_det);
    1520             :                 }
    1521             :         }
    1522             :         printf("chan2 num=%d\n", chans[1].num);
    1523             :         for (c = 0; c < 2; c++) {
    1524             :                 for (j = 0; j < IWN_NSAMPLES; j++) {
    1525             :                         printf("chain %d, sample %d: temp=%d gain=%d "
    1526             :                             "power=%d pa_det=%d\n", c, j,
    1527             :                             chans[1].samples[c][j].temp,
    1528             :                             chans[1].samples[c][j].gain,
    1529             :                             chans[1].samples[c][j].power,
    1530             :                             chans[1].samples[c][j].pa_det);
    1531             :                 }
    1532             :         }
    1533             : }
    1534             : #endif
    1535             : 
    1536             : void
    1537           0 : iwn5000_read_eeprom(struct iwn_softc *sc)
    1538             : {
    1539           0 :         struct iwn5000_eeprom_calib_hdr hdr;
    1540             :         int32_t volt;
    1541             :         uint32_t base, addr;
    1542           0 :         uint16_t val;
    1543             :         int i;
    1544             : 
    1545             :         /* Read regulatory domain (4 ASCII characters). */
    1546           0 :         iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2);
    1547           0 :         base = letoh16(val);
    1548           0 :         iwn_read_prom_data(sc, base + IWN5000_EEPROM_DOMAIN,
    1549           0 :             sc->eeprom_domain, 4);
    1550             : 
    1551             :         /* Read the list of authorized channels (20MHz ones only). */
    1552           0 :         for (i = 0; i < 5; i++) {
    1553           0 :                 addr = base + iwn5000_regulatory_bands[i];
    1554           0 :                 iwn_read_eeprom_channels(sc, i, addr);
    1555             :         }
    1556             : 
    1557             :         /* Read enhanced TX power information for 6000 Series. */
    1558           0 :         if (sc->hw_type >= IWN_HW_REV_TYPE_6000)
    1559           0 :                 iwn_read_eeprom_enhinfo(sc);
    1560             : 
    1561           0 :         iwn_read_prom_data(sc, IWN5000_EEPROM_CAL, &val, 2);
    1562           0 :         base = letoh16(val);
    1563           0 :         iwn_read_prom_data(sc, base, &hdr, sizeof hdr);
    1564             :         DPRINTF(("calib version=%u pa type=%u voltage=%u\n",
    1565             :             hdr.version, hdr.pa_type, letoh16(hdr.volt)));
    1566           0 :         sc->calib_ver = hdr.version;
    1567             : 
    1568           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_2030 ||
    1569           0 :             sc->hw_type == IWN_HW_REV_TYPE_2000 ||
    1570           0 :             sc->hw_type == IWN_HW_REV_TYPE_135 ||
    1571           0 :             sc->hw_type == IWN_HW_REV_TYPE_105) {
    1572           0 :                 sc->eeprom_voltage = letoh16(hdr.volt);
    1573           0 :                 iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
    1574           0 :                 sc->eeprom_temp = letoh16(val);
    1575           0 :                 iwn_read_prom_data(sc, base + IWN2000_EEPROM_RAWTEMP, &val, 2);
    1576           0 :                 sc->eeprom_rawtemp = letoh16(val);
    1577           0 :         }
    1578             : 
    1579           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
    1580             :                 /* Compute temperature offset. */
    1581           0 :                 iwn_read_prom_data(sc, base + IWN5000_EEPROM_TEMP, &val, 2);
    1582           0 :                 sc->eeprom_temp = letoh16(val);
    1583           0 :                 iwn_read_prom_data(sc, base + IWN5000_EEPROM_VOLT, &val, 2);
    1584           0 :                 volt = letoh16(val);
    1585           0 :                 sc->temp_off = sc->eeprom_temp - (volt / -5);
    1586             :                 DPRINTF(("temp=%d volt=%d offset=%dK\n",
    1587             :                     sc->eeprom_temp, volt, sc->temp_off));
    1588           0 :         } else {
    1589             :                 /* Read crystal calibration. */
    1590           0 :                 iwn_read_prom_data(sc, base + IWN5000_EEPROM_CRYSTAL,
    1591           0 :                     &sc->eeprom_crystal, sizeof (uint32_t));
    1592             :                 DPRINTF(("crystal calibration 0x%08x\n",
    1593             :                     letoh32(sc->eeprom_crystal)));
    1594             :         }
    1595           0 : }
    1596             : 
    1597             : void
    1598           0 : iwn_read_eeprom_channels(struct iwn_softc *sc, int n, uint32_t addr)
    1599             : {
    1600           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1601           0 :         const struct iwn_chan_band *band = &iwn_bands[n];
    1602           0 :         struct iwn_eeprom_chan channels[IWN_MAX_CHAN_PER_BAND];
    1603             :         uint8_t chan;
    1604             :         int i;
    1605             : 
    1606           0 :         iwn_read_prom_data(sc, addr, channels,
    1607           0 :             band->nchan * sizeof (struct iwn_eeprom_chan));
    1608             : 
    1609           0 :         for (i = 0; i < band->nchan; i++) {
    1610           0 :                 if (!(channels[i].flags & IWN_EEPROM_CHAN_VALID))
    1611             :                         continue;
    1612             : 
    1613           0 :                 chan = band->chan[i];
    1614             : 
    1615           0 :                 if (n == 0) {   /* 2GHz band */
    1616           0 :                         ic->ic_channels[chan].ic_freq =
    1617           0 :                             ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
    1618           0 :                         ic->ic_channels[chan].ic_flags =
    1619             :                             IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
    1620             :                             IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
    1621             : 
    1622           0 :                 } else {        /* 5GHz band */
    1623             :                         /*
    1624             :                          * Some adapters support channels 7, 8, 11 and 12
    1625             :                          * both in the 2GHz and 4.9GHz bands.
    1626             :                          * Because of limitations in our net80211 layer,
    1627             :                          * we don't support them in the 4.9GHz band.
    1628             :                          */
    1629           0 :                         if (chan <= 14)
    1630             :                                 continue;
    1631             : 
    1632           0 :                         ic->ic_channels[chan].ic_freq =
    1633           0 :                             ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
    1634           0 :                         ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_A;
    1635             :                         /* We have at least one valid 5GHz channel. */
    1636           0 :                         sc->sc_flags |= IWN_FLAG_HAS_5GHZ;
    1637             :                 }
    1638             : 
    1639             :                 /* Is active scan allowed on this channel? */
    1640           0 :                 if (!(channels[i].flags & IWN_EEPROM_CHAN_ACTIVE)) {
    1641           0 :                         ic->ic_channels[chan].ic_flags |=
    1642             :                             IEEE80211_CHAN_PASSIVE;
    1643           0 :                 }
    1644             : 
    1645             :                 /* Save maximum allowed TX power for this channel. */
    1646           0 :                 sc->maxpwr[chan] = channels[i].maxpwr;
    1647             : 
    1648           0 :                 if (sc->sc_flags & IWN_FLAG_HAS_11N)
    1649           0 :                         ic->ic_channels[chan].ic_flags |= IEEE80211_CHAN_HT;
    1650             : 
    1651             :                 DPRINTF(("adding chan %d flags=0x%x maxpwr=%d\n",
    1652             :                     chan, channels[i].flags, sc->maxpwr[chan]));
    1653             :         }
    1654           0 : }
    1655             : 
    1656             : void
    1657           0 : iwn_read_eeprom_enhinfo(struct iwn_softc *sc)
    1658             : {
    1659           0 :         struct iwn_eeprom_enhinfo enhinfo[35];
    1660           0 :         uint16_t val, base;
    1661             :         int8_t maxpwr;
    1662             :         int i;
    1663             : 
    1664           0 :         iwn_read_prom_data(sc, IWN5000_EEPROM_REG, &val, 2);
    1665           0 :         base = letoh16(val);
    1666           0 :         iwn_read_prom_data(sc, base + IWN6000_EEPROM_ENHINFO,
    1667           0 :             enhinfo, sizeof enhinfo);
    1668             : 
    1669           0 :         memset(sc->enh_maxpwr, 0, sizeof sc->enh_maxpwr);
    1670           0 :         for (i = 0; i < nitems(enhinfo); i++) {
    1671           0 :                 if (enhinfo[i].chan == 0 || enhinfo[i].reserved != 0)
    1672             :                         continue;       /* Skip invalid entries. */
    1673             : 
    1674             :                 maxpwr = 0;
    1675           0 :                 if (sc->txchainmask & IWN_ANT_A)
    1676           0 :                         maxpwr = MAX(maxpwr, enhinfo[i].chain[0]);
    1677           0 :                 if (sc->txchainmask & IWN_ANT_B)
    1678           0 :                         maxpwr = MAX(maxpwr, enhinfo[i].chain[1]);
    1679           0 :                 if (sc->txchainmask & IWN_ANT_C)
    1680           0 :                         maxpwr = MAX(maxpwr, enhinfo[i].chain[2]);
    1681           0 :                 if (sc->ntxchains == 2)
    1682           0 :                         maxpwr = MAX(maxpwr, enhinfo[i].mimo2);
    1683           0 :                 else if (sc->ntxchains == 3)
    1684           0 :                         maxpwr = MAX(maxpwr, enhinfo[i].mimo3);
    1685           0 :                 maxpwr /= 2;    /* Convert half-dBm to dBm. */
    1686             : 
    1687             :                 DPRINTF(("enhinfo %d, maxpwr=%d\n", i, maxpwr));
    1688           0 :                 sc->enh_maxpwr[i] = maxpwr;
    1689           0 :         }
    1690           0 : }
    1691             : 
    1692             : struct ieee80211_node *
    1693           0 : iwn_node_alloc(struct ieee80211com *ic)
    1694             : {
    1695           0 :         return malloc(sizeof (struct iwn_node), M_DEVBUF, M_NOWAIT | M_ZERO);
    1696             : }
    1697             : 
    1698             : void
    1699           0 : iwn_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni, int isnew)
    1700             : {
    1701           0 :         struct iwn_softc *sc = ic->ic_if.if_softc;
    1702           0 :         struct iwn_node *wn = (void *)ni;
    1703             :         uint8_t rate;
    1704             :         int ridx, i;
    1705             : 
    1706           0 :         if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
    1707           0 :                 ieee80211_amrr_node_init(&sc->amrr, &wn->amn);
    1708             : 
    1709             :         /* Start at lowest available bit-rate, AMRR/MiRA will raise. */
    1710           0 :         ni->ni_txrate = 0;
    1711           0 :         ni->ni_txmcs = 0;
    1712             : 
    1713           0 :         for (i = 0; i < ni->ni_rates.rs_nrates; i++) {
    1714           0 :                 rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
    1715             :                 /* Map 802.11 rate to HW rate index. */
    1716           0 :                 for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) {
    1717           0 :                         if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID &&
    1718           0 :                             iwn_rates[ridx].rate == rate)
    1719             :                                 break;
    1720             :                 }
    1721           0 :                 wn->ridx[i] = ridx;
    1722             :         }
    1723           0 : }
    1724             : 
    1725             : int
    1726           0 : iwn_media_change(struct ifnet *ifp)
    1727             : {
    1728           0 :         struct iwn_softc *sc = ifp->if_softc;
    1729           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1730             :         uint8_t rate, ridx;
    1731             :         int error;
    1732             : 
    1733           0 :         error = ieee80211_media_change(ifp);
    1734           0 :         if (error != ENETRESET)
    1735           0 :                 return error;
    1736             : 
    1737           0 :         if (ic->ic_fixed_mcs != -1)
    1738           0 :                 sc->fixed_ridx = iwn_mcs2ridx[ic->ic_fixed_mcs];
    1739           0 :         if (ic->ic_fixed_rate != -1) {
    1740           0 :                 rate = ic->ic_sup_rates[ic->ic_curmode].
    1741           0 :                     rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
    1742             :                 /* Map 802.11 rate to HW rate index. */
    1743           0 :                 for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++)
    1744           0 :                         if (iwn_rates[ridx].plcp != IWN_PLCP_INVALID &&
    1745           0 :                             iwn_rates[ridx].rate == rate)
    1746             :                                 break;
    1747           0 :                 sc->fixed_ridx = ridx;
    1748           0 :         }
    1749             : 
    1750           0 :         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
    1751             :             (IFF_UP | IFF_RUNNING)) {
    1752           0 :                 iwn_stop(ifp, 0);
    1753           0 :                 error = iwn_init(ifp);
    1754           0 :         }
    1755           0 :         return error;
    1756           0 : }
    1757             : 
    1758             : int
    1759           0 : iwn_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
    1760             : {
    1761           0 :         struct ifnet *ifp = &ic->ic_if;
    1762           0 :         struct iwn_softc *sc = ifp->if_softc;
    1763           0 :         struct ieee80211_node *ni = ic->ic_bss;
    1764           0 :         struct iwn_node *wn = (void *)ni;
    1765             :         int error;
    1766             : 
    1767           0 :         if (ic->ic_state == IEEE80211_S_RUN) {
    1768           0 :                 ieee80211_mira_cancel_timeouts(&wn->mn);
    1769           0 :                 timeout_del(&sc->calib_to);
    1770           0 :                 sc->calib.state = IWN_CALIB_STATE_INIT;
    1771           0 :                 if (sc->sc_flags & IWN_FLAG_BGSCAN)
    1772           0 :                         iwn_scan_abort(sc);
    1773             :         }
    1774             : 
    1775           0 :         if (ic->ic_state == IEEE80211_S_SCAN) {
    1776           0 :                 if (nstate == IEEE80211_S_SCAN) {
    1777           0 :                         if (sc->sc_flags & IWN_FLAG_SCANNING)
    1778           0 :                                 return 0;
    1779             :                 } else
    1780           0 :                         sc->sc_flags &= ~IWN_FLAG_SCANNING;
    1781             :                 /* Turn LED off when leaving scan state. */
    1782           0 :                 iwn_set_led(sc, IWN_LED_LINK, 1, 0);
    1783           0 :         }
    1784             : 
    1785           0 :         if (ic->ic_state >= IEEE80211_S_ASSOC &&
    1786           0 :             nstate <= IEEE80211_S_ASSOC) {
    1787             :                 /* Reset state to handle re- and disassociations. */
    1788           0 :                 sc->rxon.associd = 0;
    1789           0 :                 sc->rxon.filter &= ~htole32(IWN_FILTER_BSS);
    1790           0 :                 sc->calib.state = IWN_CALIB_STATE_INIT;
    1791           0 :                 error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1);
    1792           0 :                 if (error != 0)
    1793           0 :                         printf("%s: RXON command failed\n",
    1794           0 :                             sc->sc_dev.dv_xname);
    1795             :         }                
    1796             : 
    1797           0 :         switch (nstate) {
    1798             :         case IEEE80211_S_SCAN:
    1799             :                 /* Make the link LED blink while we're scanning. */
    1800           0 :                 iwn_set_led(sc, IWN_LED_LINK, 10, 10);
    1801             : 
    1802           0 :                 if ((error = iwn_scan(sc, IEEE80211_CHAN_2GHZ, 0)) != 0) {
    1803           0 :                         printf("%s: could not initiate scan\n",
    1804           0 :                             sc->sc_dev.dv_xname);
    1805           0 :                         return error;
    1806             :                 }
    1807           0 :                 if (ifp->if_flags & IFF_DEBUG)
    1808           0 :                         printf("%s: %s -> %s\n", ifp->if_xname,
    1809           0 :                             ieee80211_state_name[ic->ic_state],
    1810           0 :                             ieee80211_state_name[nstate]);
    1811           0 :                 if ((sc->sc_flags & IWN_FLAG_BGSCAN) == 0) {
    1812           0 :                         ieee80211_set_link_state(ic, LINK_STATE_DOWN);
    1813           0 :                         ieee80211_free_allnodes(ic, 1);
    1814           0 :                 }
    1815           0 :                 ic->ic_state = nstate;
    1816           0 :                 return 0;
    1817             : 
    1818             :         case IEEE80211_S_ASSOC:
    1819           0 :                 if (ic->ic_state != IEEE80211_S_RUN)
    1820             :                         break;
    1821             :                 /* FALLTHROUGH */
    1822             :         case IEEE80211_S_AUTH:
    1823           0 :                 if ((error = iwn_auth(sc, arg)) != 0) {
    1824           0 :                         printf("%s: could not move to auth state\n",
    1825           0 :                             sc->sc_dev.dv_xname);
    1826           0 :                         return error;
    1827             :                 }
    1828             :                 break;
    1829             : 
    1830             :         case IEEE80211_S_RUN:
    1831           0 :                 if ((error = iwn_run(sc)) != 0) {
    1832           0 :                         printf("%s: could not move to run state\n",
    1833           0 :                             sc->sc_dev.dv_xname);
    1834           0 :                         return error;
    1835             :                 }
    1836             :                 break;
    1837             : 
    1838             :         case IEEE80211_S_INIT:
    1839           0 :                 sc->calib.state = IWN_CALIB_STATE_INIT;
    1840           0 :                 break;
    1841             :         }
    1842             : 
    1843           0 :         return sc->sc_newstate(ic, nstate, arg);
    1844           0 : }
    1845             : 
    1846             : void
    1847           0 : iwn_iter_func(void *arg, struct ieee80211_node *ni)
    1848             : {
    1849           0 :         struct iwn_softc *sc = arg;
    1850           0 :         struct iwn_node *wn = (void *)ni;
    1851             : 
    1852           0 :         if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
    1853           0 :                 ieee80211_amrr_choose(&sc->amrr, ni, &wn->amn);
    1854           0 : }
    1855             : 
    1856             : void
    1857           0 : iwn_calib_timeout(void *arg)
    1858             : {
    1859           0 :         struct iwn_softc *sc = arg;
    1860           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1861             :         int s;
    1862             : 
    1863           0 :         s = splnet();
    1864           0 :         if (ic->ic_fixed_rate == -1) {
    1865           0 :                 if (ic->ic_opmode == IEEE80211_M_STA)
    1866           0 :                         iwn_iter_func(sc, ic->ic_bss);
    1867             :                 else
    1868           0 :                         ieee80211_iterate_nodes(ic, iwn_iter_func, sc);
    1869             :         }
    1870             :         /* Force automatic TX power calibration every 60 secs. */
    1871           0 :         if (++sc->calib_cnt >= 120) {
    1872           0 :                 uint32_t flags = 0;
    1873             : 
    1874             :                 DPRINTFN(2, ("sending request for statistics\n"));
    1875           0 :                 (void)iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags,
    1876             :                     sizeof flags, 1);
    1877           0 :                 sc->calib_cnt = 0;
    1878           0 :         }
    1879           0 :         splx(s);
    1880             : 
    1881             :         /* Automatic rate control triggered every 500ms. */
    1882           0 :         timeout_add_msec(&sc->calib_to, 500);
    1883           0 : }
    1884             : 
    1885             : int
    1886           0 : iwn_ccmp_decap(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
    1887             : {
    1888           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1889           0 :         struct ieee80211_key *k = &ni->ni_pairwise_key;
    1890             :         struct ieee80211_frame *wh;
    1891             :         struct ieee80211_rx_ba *ba;
    1892             :         uint64_t pn, *prsc;
    1893             :         uint8_t *ivp;
    1894             :         uint8_t tid;
    1895             :         int hdrlen, hasqos;
    1896             : 
    1897           0 :         wh = mtod(m, struct ieee80211_frame *);
    1898           0 :         hdrlen = ieee80211_get_hdrlen(wh);
    1899           0 :         ivp = (uint8_t *)wh + hdrlen;
    1900             : 
    1901             :         /* Check that ExtIV bit is be set. */
    1902           0 :         if (!(ivp[3] & IEEE80211_WEP_EXTIV)) {
    1903             :                 DPRINTF(("CCMP decap ExtIV not set\n"));
    1904           0 :                 return 1;
    1905             :         }
    1906           0 :         hasqos = ieee80211_has_qos(wh);
    1907           0 :         tid = hasqos ? ieee80211_get_qos(wh) & IEEE80211_QOS_TID : 0;
    1908           0 :         ba = hasqos ? &ni->ni_rx_ba[tid] : NULL;
    1909           0 :         prsc = &k->k_rsc[tid];
    1910             : 
    1911             :         /* Extract the 48-bit PN from the CCMP header. */
    1912           0 :         pn = (uint64_t)ivp[0]       |
    1913           0 :              (uint64_t)ivp[1] <<  8 |
    1914           0 :              (uint64_t)ivp[4] << 16 |
    1915           0 :              (uint64_t)ivp[5] << 24 |
    1916           0 :              (uint64_t)ivp[6] << 32 |
    1917           0 :              (uint64_t)ivp[7] << 40;
    1918           0 :         if (pn <= *prsc) {
    1919           0 :                 if (hasqos && ba->ba_state == IEEE80211_BA_AGREED) {
    1920             :                         /*
    1921             :                          * This is an A-MPDU subframe.
    1922             :                          * Such frames may be received out of order due to
    1923             :                          * legitimate retransmissions of failed subframes
    1924             :                          * in previous A-MPDUs. Duplicates will be handled
    1925             :                          * in ieee80211_input() as part of A-MPDU reordering.
    1926             :                          */
    1927           0 :                 } else if (ieee80211_has_seq(wh)) {
    1928             :                         /*
    1929             :                          * Not necessarily a replayed frame since we did not
    1930             :                          * check the sequence number of the 802.11 header yet.
    1931             :                          */
    1932             :                         int nrxseq, orxseq;
    1933             : 
    1934           0 :                         nrxseq = letoh16(*(u_int16_t *)wh->i_seq) >>
    1935             :                             IEEE80211_SEQ_SEQ_SHIFT;
    1936           0 :                         if (hasqos)
    1937           0 :                                 orxseq = ni->ni_qos_rxseqs[tid];
    1938             :                         else
    1939           0 :                                 orxseq = ni->ni_rxseq;
    1940           0 :                         if (nrxseq < orxseq) {
    1941             :                                 DPRINTF(("CCMP replayed (n=%d < o=%d)\n",
    1942             :                                     nrxseq, orxseq));
    1943           0 :                                 ic->ic_stats.is_ccmp_replays++;
    1944           0 :                                 return 1;
    1945             :                         }
    1946           0 :                 } else {
    1947             :                         DPRINTF(("CCMP replayed\n"));
    1948           0 :                         ic->ic_stats.is_ccmp_replays++;
    1949           0 :                         return 1;
    1950             :                 }
    1951             :         }
    1952             :         /* Update last seen packet number. */
    1953           0 :         *prsc = pn;
    1954             : 
    1955             :         /* Clear Protected bit and strip IV. */
    1956           0 :         wh->i_fc[1] &= ~IEEE80211_FC1_PROTECTED;
    1957           0 :         memmove(mtod(m, caddr_t) + IEEE80211_CCMP_HDRLEN, wh, hdrlen);
    1958           0 :         m_adj(m, IEEE80211_CCMP_HDRLEN);
    1959             :         /* Strip MIC. */
    1960           0 :         m_adj(m, -IEEE80211_CCMP_MICLEN);
    1961           0 :         return 0;
    1962           0 : }
    1963             : 
    1964             : /*
    1965             :  * Process an RX_PHY firmware notification.  This is usually immediately
    1966             :  * followed by an MPDU_RX_DONE notification.
    1967             :  */
    1968             : void
    1969           0 : iwn_rx_phy(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    1970             :     struct iwn_rx_data *data)
    1971             : {
    1972           0 :         struct iwn_rx_stat *stat = (struct iwn_rx_stat *)(desc + 1);
    1973             : 
    1974             :         DPRINTFN(2, ("received PHY stats\n"));
    1975           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    1976             :             sizeof (*stat), BUS_DMASYNC_POSTREAD);
    1977             : 
    1978             :         /* Save RX statistics, they will be used on MPDU_RX_DONE. */
    1979           0 :         memcpy(&sc->last_rx_stat, stat, sizeof (*stat));
    1980           0 :         sc->last_rx_valid = IWN_LAST_RX_VALID;
    1981             :         /*
    1982             :          * The firmware does not send separate RX_PHY
    1983             :          * notifications for A-MPDU subframes.
    1984             :          */
    1985           0 :         if (stat->flags & htole16(IWN_STAT_FLAG_AGG))
    1986           0 :                 sc->last_rx_valid |= IWN_LAST_RX_AMPDU;
    1987           0 : }
    1988             : 
    1989             : /*
    1990             :  * Process an RX_DONE (4965AGN only) or MPDU_RX_DONE firmware notification.
    1991             :  * Each MPDU_RX_DONE notification must be preceded by an RX_PHY one.
    1992             :  */
    1993             : void
    1994           0 : iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    1995             :     struct iwn_rx_data *data)
    1996             : {
    1997           0 :         struct iwn_ops *ops = &sc->ops;
    1998           0 :         struct ieee80211com *ic = &sc->sc_ic;
    1999           0 :         struct ifnet *ifp = &ic->ic_if;
    2000           0 :         struct iwn_rx_ring *ring = &sc->rxq;
    2001             :         struct ieee80211_frame *wh;
    2002           0 :         struct ieee80211_rxinfo rxi;
    2003             :         struct ieee80211_node *ni;
    2004             :         struct ieee80211_channel *bss_chan = NULL;
    2005             :         struct mbuf *m, *m1;
    2006             :         struct iwn_rx_stat *stat;
    2007             :         caddr_t head;
    2008             :         uint32_t flags;
    2009             :         int error, len, rssi;
    2010             :         uint16_t chan;
    2011             : 
    2012           0 :         if (desc->type == IWN_MPDU_RX_DONE) {
    2013             :                 /* Check for prior RX_PHY notification. */
    2014           0 :                 if (!sc->last_rx_valid) {
    2015             :                         DPRINTF(("missing RX_PHY\n"));
    2016           0 :                         return;
    2017             :                 }
    2018           0 :                 sc->last_rx_valid &= ~IWN_LAST_RX_VALID;
    2019           0 :                 stat = &sc->last_rx_stat;
    2020           0 :                 if ((sc->last_rx_valid & IWN_LAST_RX_AMPDU) &&
    2021           0 :                     (stat->flags & htole16(IWN_STAT_FLAG_AGG)) == 0) {
    2022             :                         DPRINTF(("missing RX_PHY (expecting A-MPDU)\n"));
    2023           0 :                         return;
    2024             :                 }
    2025           0 :                 if ((sc->last_rx_valid & IWN_LAST_RX_AMPDU) == 0 &&
    2026           0 :                     (stat->flags & htole16(IWN_STAT_FLAG_AGG))) {
    2027             :                         DPRINTF(("missing RX_PHY (unexpected A-MPDU)\n"));
    2028           0 :                         return;
    2029             :                 }
    2030             :         } else
    2031           0 :                 stat = (struct iwn_rx_stat *)(desc + 1);
    2032             : 
    2033           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWN_RBUF_SIZE,
    2034             :             BUS_DMASYNC_POSTREAD);
    2035             : 
    2036           0 :         if (stat->cfg_phy_len > IWN_STAT_MAXLEN) {
    2037           0 :                 printf("%s: invalid RX statistic header\n",
    2038           0 :                     sc->sc_dev.dv_xname);
    2039           0 :                 return;
    2040             :         }
    2041           0 :         if (desc->type == IWN_MPDU_RX_DONE) {
    2042           0 :                 struct iwn_rx_mpdu *mpdu = (struct iwn_rx_mpdu *)(desc + 1);
    2043           0 :                 head = (caddr_t)(mpdu + 1);
    2044           0 :                 len = letoh16(mpdu->len);
    2045           0 :         } else {
    2046           0 :                 head = (caddr_t)(stat + 1) + stat->cfg_phy_len;
    2047           0 :                 len = letoh16(stat->len);
    2048             :         }
    2049             : 
    2050           0 :         flags = letoh32(*(uint32_t *)(head + len));
    2051             : 
    2052             :         /* Discard frames with a bad FCS early. */
    2053           0 :         if ((flags & IWN_RX_NOERROR) != IWN_RX_NOERROR) {
    2054             :                 DPRINTFN(2, ("RX flags error %x\n", flags));
    2055           0 :                 ifp->if_ierrors++;
    2056           0 :                 return;
    2057             :         }
    2058             :         /* Discard frames that are too short. */
    2059           0 :         if (ic->ic_opmode == IEEE80211_M_MONITOR) {
    2060             :                 /* Allow control frames in monitor mode. */
    2061           0 :                 if (len < sizeof (struct ieee80211_frame_cts)) {
    2062             :                         DPRINTF(("frame too short: %d\n", len));
    2063           0 :                         ic->ic_stats.is_rx_tooshort++;
    2064           0 :                         ifp->if_ierrors++;
    2065           0 :                         return;
    2066             :                 }
    2067           0 :         } else if (len < sizeof (*wh)) {
    2068             :                 DPRINTF(("frame too short: %d\n", len));
    2069           0 :                 ic->ic_stats.is_rx_tooshort++;
    2070           0 :                 ifp->if_ierrors++;
    2071           0 :                 return;
    2072             :         }
    2073             : 
    2074           0 :         m1 = MCLGETI(NULL, M_DONTWAIT, NULL, IWN_RBUF_SIZE);
    2075           0 :         if (m1 == NULL) {
    2076           0 :                 ic->ic_stats.is_rx_nombuf++;
    2077           0 :                 ifp->if_ierrors++;
    2078           0 :                 return;
    2079             :         }
    2080           0 :         bus_dmamap_unload(sc->sc_dmat, data->map);
    2081             : 
    2082           0 :         error = bus_dmamap_load(sc->sc_dmat, data->map, mtod(m1, void *),
    2083             :             IWN_RBUF_SIZE, NULL, BUS_DMA_NOWAIT | BUS_DMA_READ);
    2084           0 :         if (error != 0) {
    2085           0 :                 m_freem(m1);
    2086             : 
    2087             :                 /* Try to reload the old mbuf. */
    2088           0 :                 error = bus_dmamap_load(sc->sc_dmat, data->map,
    2089             :                     mtod(data->m, void *), IWN_RBUF_SIZE, NULL,
    2090             :                     BUS_DMA_NOWAIT | BUS_DMA_READ);
    2091           0 :                 if (error != 0) {
    2092           0 :                         panic("%s: could not load old RX mbuf",
    2093           0 :                             sc->sc_dev.dv_xname);
    2094             :                 }
    2095             :                 /* Physical address may have changed. */
    2096           0 :                 ring->desc[ring->cur] =
    2097           0 :                     htole32(data->map->dm_segs[0].ds_addr >> 8);
    2098           0 :                 bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
    2099             :                     ring->cur * sizeof (uint32_t), sizeof (uint32_t),
    2100             :                     BUS_DMASYNC_PREWRITE);
    2101           0 :                 ifp->if_ierrors++;
    2102           0 :                 return;
    2103             :         }
    2104             : 
    2105           0 :         m = data->m;
    2106           0 :         data->m = m1;
    2107             :         /* Update RX descriptor. */
    2108           0 :         ring->desc[ring->cur] = htole32(data->map->dm_segs[0].ds_addr >> 8);
    2109           0 :         bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
    2110             :             ring->cur * sizeof (uint32_t), sizeof (uint32_t),
    2111             :             BUS_DMASYNC_PREWRITE);
    2112             : 
    2113             :         /* Finalize mbuf. */
    2114           0 :         m->m_data = head;
    2115           0 :         m->m_pkthdr.len = m->m_len = len;
    2116             : 
    2117             :         /* 
    2118             :          * Grab a reference to the source node. Note that control frames are
    2119             :          * shorter than struct ieee80211_frame but ieee80211_find_rxnode()
    2120             :          * is being careful about control frames.
    2121             :          */
    2122           0 :         wh = mtod(m, struct ieee80211_frame *);
    2123           0 :         if (len < sizeof (*wh) &&
    2124           0 :            (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
    2125           0 :                 ic->ic_stats.is_rx_tooshort++;
    2126           0 :                 ifp->if_ierrors++;
    2127           0 :                 m_freem(m);
    2128           0 :                 return;
    2129             :         }
    2130           0 :         ni = ieee80211_find_rxnode(ic, wh);
    2131             : 
    2132           0 :         rxi.rxi_flags = 0;
    2133           0 :         if (((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL)
    2134           0 :             && (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) &&
    2135           0 :             !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
    2136           0 :             (ni->ni_flags & IEEE80211_NODE_RXPROT) &&
    2137           0 :             ni->ni_pairwise_key.k_cipher == IEEE80211_CIPHER_CCMP) {
    2138           0 :                 if ((flags & IWN_RX_CIPHER_MASK) != IWN_RX_CIPHER_CCMP) {
    2139           0 :                         ic->ic_stats.is_ccmp_dec_errs++;
    2140           0 :                         ifp->if_ierrors++;
    2141           0 :                         m_freem(m);
    2142           0 :                         return;
    2143             :                 }
    2144             :                 /* Check whether decryption was successful or not. */
    2145           0 :                 if ((desc->type == IWN_MPDU_RX_DONE &&
    2146           0 :                      (flags & (IWN_RX_MPDU_DEC | IWN_RX_MPDU_MIC_OK)) !=
    2147           0 :                       (IWN_RX_MPDU_DEC | IWN_RX_MPDU_MIC_OK)) ||
    2148           0 :                     (desc->type != IWN_MPDU_RX_DONE &&
    2149           0 :                      (flags & IWN_RX_DECRYPT_MASK) != IWN_RX_DECRYPT_OK)) {
    2150             :                         DPRINTF(("CCMP decryption failed 0x%x\n", flags));
    2151           0 :                         ic->ic_stats.is_ccmp_dec_errs++;
    2152           0 :                         ifp->if_ierrors++;
    2153           0 :                         m_freem(m);
    2154           0 :                         return;
    2155             :                 }
    2156           0 :                 if (iwn_ccmp_decap(sc, m, ni) != 0) {
    2157           0 :                         ifp->if_ierrors++;
    2158           0 :                         m_freem(m);
    2159           0 :                         return;
    2160             :                 }
    2161           0 :                 rxi.rxi_flags |= IEEE80211_RXI_HWDEC;
    2162           0 :         }
    2163             : 
    2164           0 :         rssi = ops->get_rssi(stat);
    2165             : 
    2166           0 :         chan = stat->chan;
    2167           0 :         if (chan > IEEE80211_CHAN_MAX)
    2168             :                 chan = IEEE80211_CHAN_MAX;
    2169             : 
    2170           0 :         if (ni == ic->ic_bss) {
    2171           0 :                 bss_chan = ni->ni_chan;
    2172             :                 /* Fix current channel. */
    2173           0 :                 ni->ni_chan = &ic->ic_channels[chan];
    2174           0 :         }
    2175             : 
    2176             : #if NBPFILTER > 0
    2177           0 :         if (sc->sc_drvbpf != NULL) {
    2178           0 :                 struct mbuf mb;
    2179           0 :                 struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap;
    2180             :                 uint16_t chan_flags;
    2181             : 
    2182           0 :                 tap->wr_flags = 0;
    2183           0 :                 if (stat->flags & htole16(IWN_STAT_FLAG_SHPREAMBLE))
    2184           0 :                         tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
    2185           0 :                 tap->wr_chan_freq = htole16(ic->ic_channels[chan].ic_freq);
    2186           0 :                 chan_flags = ic->ic_channels[chan].ic_flags;
    2187           0 :                 if (ic->ic_curmode != IEEE80211_MODE_11N)
    2188           0 :                         chan_flags &= ~IEEE80211_CHAN_HT;
    2189           0 :                 tap->wr_chan_flags = htole16(chan_flags);
    2190           0 :                 tap->wr_dbm_antsignal = (int8_t)rssi;
    2191           0 :                 tap->wr_dbm_antnoise = (int8_t)sc->noise;
    2192           0 :                 tap->wr_tsft = stat->tstamp;
    2193           0 :                 if (stat->rflags & IWN_RFLAG_MCS) {
    2194           0 :                         tap->wr_rate = (0x80 | stat->rate); /* HT MCS index */
    2195           0 :                 } else {
    2196           0 :                         switch (stat->rate) {
    2197             :                         /* CCK rates. */
    2198           0 :                         case  10: tap->wr_rate =   2; break;
    2199           0 :                         case  20: tap->wr_rate =   4; break;
    2200           0 :                         case  55: tap->wr_rate =  11; break;
    2201           0 :                         case 110: tap->wr_rate =  22; break;
    2202             :                         /* OFDM rates. */
    2203           0 :                         case 0xd: tap->wr_rate =  12; break;
    2204           0 :                         case 0xf: tap->wr_rate =  18; break;
    2205           0 :                         case 0x5: tap->wr_rate =  24; break;
    2206           0 :                         case 0x7: tap->wr_rate =  36; break;
    2207           0 :                         case 0x9: tap->wr_rate =  48; break;
    2208           0 :                         case 0xb: tap->wr_rate =  72; break;
    2209           0 :                         case 0x1: tap->wr_rate =  96; break;
    2210           0 :                         case 0x3: tap->wr_rate = 108; break;
    2211             :                         /* Unknown rate: should not happen. */
    2212           0 :                         default:  tap->wr_rate =  0;
    2213           0 :                         }
    2214             :                 }
    2215             : 
    2216           0 :                 mb.m_data = (caddr_t)tap;
    2217           0 :                 mb.m_len = sc->sc_rxtap_len;
    2218           0 :                 mb.m_next = m;
    2219           0 :                 mb.m_nextpkt = NULL;
    2220           0 :                 mb.m_type = 0;
    2221           0 :                 mb.m_flags = 0;
    2222           0 :                 bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_IN);
    2223           0 :         }
    2224             : #endif
    2225             : 
    2226             :         /* Send the frame to the 802.11 layer. */
    2227           0 :         rxi.rxi_rssi = rssi;
    2228           0 :         rxi.rxi_tstamp = 0;     /* unused */
    2229           0 :         ieee80211_input(ifp, m, ni, &rxi);
    2230             : 
    2231             :         /* Restore BSS channel. */
    2232           0 :         if (ni == ic->ic_bss)
    2233           0 :                 ni->ni_chan = bss_chan;
    2234             : 
    2235             :         /* Node is no longer needed. */
    2236           0 :         ieee80211_release_node(ic, ni);
    2237           0 : }
    2238             : 
    2239             : /* Process an incoming Compressed BlockAck. */
    2240             : void
    2241           0 : iwn_rx_compressed_ba(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    2242             :     struct iwn_rx_data *data)
    2243             : {
    2244           0 :         struct iwn_compressed_ba *ba = (struct iwn_compressed_ba *)(desc + 1);
    2245             :         struct iwn_tx_ring *txq;
    2246             : 
    2247           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), sizeof (*ba),
    2248             :             BUS_DMASYNC_POSTREAD);
    2249             : 
    2250           0 :         txq = &sc->txq[letoh16(ba->qid)];
    2251             :         /* XXX TBD */
    2252           0 : }
    2253             : 
    2254             : /*
    2255             :  * Process a CALIBRATION_RESULT notification sent by the initialization
    2256             :  * firmware on response to a CMD_CALIB_CONFIG command (5000 only).
    2257             :  */
    2258             : void
    2259           0 : iwn5000_rx_calib_results(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    2260             :     struct iwn_rx_data *data)
    2261             : {
    2262           0 :         struct iwn_phy_calib *calib = (struct iwn_phy_calib *)(desc + 1);
    2263             :         int len, idx = -1;
    2264             : 
    2265             :         /* Runtime firmware should not send such a notification. */
    2266           0 :         if (sc->sc_flags & IWN_FLAG_CALIB_DONE)
    2267           0 :                 return;
    2268             : 
    2269           0 :         len = (letoh32(desc->len) & 0x3fff) - 4;
    2270           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc), len,
    2271             :             BUS_DMASYNC_POSTREAD);
    2272             : 
    2273           0 :         switch (calib->code) {
    2274             :         case IWN5000_PHY_CALIB_DC:
    2275           0 :                 if (sc->hw_type == IWN_HW_REV_TYPE_5150 ||
    2276           0 :                     sc->hw_type == IWN_HW_REV_TYPE_2030 ||
    2277           0 :                     sc->hw_type == IWN_HW_REV_TYPE_2000 ||
    2278           0 :                     sc->hw_type == IWN_HW_REV_TYPE_135 ||
    2279           0 :                     sc->hw_type == IWN_HW_REV_TYPE_105)
    2280           0 :                         idx = 0;
    2281             :                 break;
    2282             :         case IWN5000_PHY_CALIB_LO:
    2283             :                 idx = 1;
    2284           0 :                 break;
    2285             :         case IWN5000_PHY_CALIB_TX_IQ:
    2286             :                 idx = 2;
    2287           0 :                 break;
    2288             :         case IWN5000_PHY_CALIB_TX_IQ_PERIODIC:
    2289           0 :                 if (sc->hw_type < IWN_HW_REV_TYPE_6000 &&
    2290           0 :                     sc->hw_type != IWN_HW_REV_TYPE_5150)
    2291           0 :                         idx = 3;
    2292             :                 break;
    2293             :         case IWN5000_PHY_CALIB_BASE_BAND:
    2294             :                 idx = 4;
    2295           0 :                 break;
    2296             :         }
    2297           0 :         if (idx == -1)  /* Ignore other results. */
    2298           0 :                 return;
    2299             : 
    2300             :         /* Save calibration result. */
    2301           0 :         if (sc->calibcmd[idx].buf != NULL)
    2302           0 :                 free(sc->calibcmd[idx].buf, M_DEVBUF, 0);
    2303           0 :         sc->calibcmd[idx].buf = malloc(len, M_DEVBUF, M_NOWAIT);
    2304           0 :         if (sc->calibcmd[idx].buf == NULL) {
    2305             :                 DPRINTF(("not enough memory for calibration result %d\n",
    2306             :                     calib->code));
    2307           0 :                 return;
    2308             :         }
    2309             :         DPRINTF(("saving calibration result code=%d len=%d\n",
    2310             :             calib->code, len));
    2311           0 :         sc->calibcmd[idx].len = len;
    2312           0 :         memcpy(sc->calibcmd[idx].buf, calib, len);
    2313           0 : }
    2314             : 
    2315             : /*
    2316             :  * Process an RX_STATISTICS or BEACON_STATISTICS firmware notification.
    2317             :  * The latter is sent by the firmware after each received beacon.
    2318             :  */
    2319             : void
    2320           0 : iwn_rx_statistics(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    2321             :     struct iwn_rx_data *data)
    2322             : {
    2323           0 :         struct iwn_ops *ops = &sc->ops;
    2324           0 :         struct ieee80211com *ic = &sc->sc_ic;
    2325           0 :         struct iwn_calib_state *calib = &sc->calib;
    2326           0 :         struct iwn_stats *stats = (struct iwn_stats *)(desc + 1);
    2327             :         int temp;
    2328             : 
    2329             :         /* Ignore statistics received during a scan. */
    2330           0 :         if (ic->ic_state != IEEE80211_S_RUN)
    2331           0 :                 return;
    2332             : 
    2333           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2334             :             sizeof (*stats), BUS_DMASYNC_POSTREAD);
    2335             : 
    2336             :         DPRINTFN(3, ("received statistics (cmd=%d)\n", desc->type));
    2337           0 :         sc->calib_cnt = 0;   /* Reset TX power calibration timeout. */
    2338             : 
    2339             :         /* Test if temperature has changed. */
    2340           0 :         if (stats->general.temp != sc->rawtemp) {
    2341             :                 /* Convert "raw" temperature to degC. */
    2342           0 :                 sc->rawtemp = stats->general.temp;
    2343           0 :                 temp = ops->get_temperature(sc);
    2344             :                 DPRINTFN(2, ("temperature=%dC\n", temp));
    2345             : 
    2346             :                 /* Update TX power if need be (4965AGN only). */
    2347           0 :                 if (sc->hw_type == IWN_HW_REV_TYPE_4965)
    2348           0 :                         iwn4965_power_calibration(sc, temp);
    2349             :         }
    2350             : 
    2351           0 :         if (desc->type != IWN_BEACON_STATISTICS)
    2352           0 :                 return; /* Reply to a statistics request. */
    2353             : 
    2354           0 :         sc->noise = iwn_get_noise(&stats->rx.general);
    2355             : 
    2356             :         /* Test that RSSI and noise are present in stats report. */
    2357           0 :         if (letoh32(stats->rx.general.flags) != 1) {
    2358             :                 DPRINTF(("received statistics without RSSI\n"));
    2359           0 :                 return;
    2360             :         }
    2361             : 
    2362             :         /*
    2363             :          * XXX Differential gain calibration makes the 6005 firmware
    2364             :          * crap out, so skip it for now.  This effectively disables
    2365             :          * sensitivity tuning as well.
    2366             :          */
    2367           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_6005)
    2368           0 :                 return;
    2369             : 
    2370           0 :         if (calib->state == IWN_CALIB_STATE_ASSOC)
    2371           0 :                 iwn_collect_noise(sc, &stats->rx.general);
    2372           0 :         else if (calib->state == IWN_CALIB_STATE_RUN)
    2373           0 :                 iwn_tune_sensitivity(sc, &stats->rx);
    2374           0 : }
    2375             : 
    2376             : /*
    2377             :  * Process a TX_DONE firmware notification.  Unfortunately, the 4965AGN
    2378             :  * and 5000 adapters have different incompatible TX status formats.
    2379             :  */
    2380             : void
    2381           0 : iwn4965_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    2382             :     struct iwn_rx_data *data)
    2383             : {
    2384           0 :         struct iwn4965_tx_stat *stat = (struct iwn4965_tx_stat *)(desc + 1);
    2385           0 :         struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
    2386           0 :         struct iwn_tx_data *txdata = &ring->data[desc->idx];
    2387             :         /* XXX 4965 does not report byte count */
    2388           0 :         uint16_t len = txdata->totlen + IEEE80211_CRC_LEN;
    2389             : 
    2390           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2391             :             sizeof (*stat), BUS_DMASYNC_POSTREAD);
    2392           0 :         iwn_tx_done(sc, desc, stat->nframes, stat->ackfailcnt,
    2393           0 :             letoh32(stat->status) & 0xff, len);
    2394           0 : }
    2395             : 
    2396             : void
    2397           0 : iwn5000_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc,
    2398             :     struct iwn_rx_data *data)
    2399             : {
    2400           0 :         struct iwn5000_tx_stat *stat = (struct iwn5000_tx_stat *)(desc + 1);
    2401             : 
    2402             : #ifdef notyet
    2403             :         /* Reset TX scheduler slot. */
    2404             :         iwn5000_reset_sched(sc, desc->qid & 0xf, desc->idx);
    2405             : #endif
    2406             : 
    2407           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2408             :             sizeof (*stat), BUS_DMASYNC_POSTREAD);
    2409           0 :         iwn_tx_done(sc, desc, stat->nframes, stat->ackfailcnt,
    2410           0 :             letoh16(stat->status) & 0xff, letoh16(stat->len));
    2411           0 : }
    2412             : 
    2413             : /*
    2414             :  * Adapter-independent backend for TX_DONE firmware notifications.
    2415             :  */
    2416             : void
    2417           0 : iwn_tx_done(struct iwn_softc *sc, struct iwn_rx_desc *desc, uint8_t nframes,
    2418             :     uint8_t ackfailcnt, uint8_t status, uint16_t len)
    2419             : {
    2420           0 :         struct ieee80211com *ic = &sc->sc_ic;
    2421           0 :         struct ifnet *ifp = &ic->ic_if;
    2422           0 :         struct iwn_tx_ring *ring = &sc->txq[desc->qid & 0xf];
    2423           0 :         struct iwn_tx_data *data = &ring->data[desc->idx];
    2424           0 :         struct iwn_node *wn = (void *)data->ni;
    2425           0 :         int txfail = (status != 1 && status != 2);
    2426             : 
    2427           0 :         KASSERT(nframes == 1); /* We don't support aggregation yet. */
    2428             : 
    2429             :         /* Update rate control statistics. */
    2430           0 :         if (data->ni->ni_flags & IEEE80211_NODE_HT) {
    2431           0 :                 wn->mn.frames += nframes;
    2432           0 :                 wn->mn.ampdu_size = len;
    2433           0 :                 wn->mn.agglen = nframes; 
    2434           0 :                 if (ackfailcnt > 0)
    2435           0 :                         wn->mn.retries += ackfailcnt;
    2436           0 :                 if (txfail)
    2437           0 :                         wn->mn.txfail += nframes;
    2438           0 :                 if (ic->ic_state == IEEE80211_S_RUN)
    2439           0 :                         ieee80211_mira_choose(&wn->mn, ic, data->ni);
    2440             :         } else {
    2441           0 :                 wn->amn.amn_txcnt++;
    2442           0 :                 if (ackfailcnt > 0)
    2443           0 :                         wn->amn.amn_retrycnt++;
    2444             :         }
    2445           0 :         if (txfail) {
    2446             :                 DPRINTF(("%s: status=0x%x\n", __func__, status));
    2447           0 :                 ifp->if_oerrors++;
    2448           0 :         }
    2449             : 
    2450             :         /* Unmap and free mbuf. */
    2451           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
    2452             :             BUS_DMASYNC_POSTWRITE);
    2453           0 :         bus_dmamap_unload(sc->sc_dmat, data->map);
    2454           0 :         m_freem(data->m);
    2455           0 :         data->m = NULL;
    2456           0 :         ieee80211_release_node(ic, data->ni);
    2457           0 :         data->ni = NULL;
    2458             : 
    2459           0 :         sc->sc_tx_timer = 0;
    2460           0 :         if (--ring->queued < IWN_TX_RING_LOMARK) {
    2461           0 :                 sc->qfullmsk &= ~(1 << ring->qid);
    2462           0 :                 if (sc->qfullmsk == 0 && ifq_is_oactive(&ifp->if_snd)) {
    2463           0 :                         ifq_clr_oactive(&ifp->if_snd);
    2464           0 :                         (*ifp->if_start)(ifp);
    2465           0 :                 }
    2466             :         }
    2467           0 : }
    2468             : 
    2469             : /*
    2470             :  * Process a "command done" firmware notification.  This is where we wakeup
    2471             :  * processes waiting for a synchronous command completion.
    2472             :  */
    2473             : void
    2474           0 : iwn_cmd_done(struct iwn_softc *sc, struct iwn_rx_desc *desc)
    2475             : {
    2476           0 :         struct iwn_tx_ring *ring = &sc->txq[4];
    2477             :         struct iwn_tx_data *data;
    2478             : 
    2479           0 :         if ((desc->qid & 0xf) != 4)
    2480           0 :                 return; /* Not a command ack. */
    2481             : 
    2482           0 :         data = &ring->data[desc->idx];
    2483             : 
    2484             :         /* If the command was mapped in an mbuf, free it. */
    2485           0 :         if (data->m != NULL) {
    2486           0 :                 bus_dmamap_sync(sc->sc_dmat, data->map, 0,
    2487             :                     data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
    2488           0 :                 bus_dmamap_unload(sc->sc_dmat, data->map);
    2489           0 :                 m_freem(data->m);
    2490           0 :                 data->m = NULL;
    2491           0 :         }
    2492           0 :         wakeup(&ring->desc[desc->idx]);
    2493           0 : }
    2494             : 
    2495             : /*
    2496             :  * Process an INT_FH_RX or INT_SW_RX interrupt.
    2497             :  */
    2498             : void
    2499           0 : iwn_notif_intr(struct iwn_softc *sc)
    2500             : {
    2501           0 :         struct iwn_ops *ops = &sc->ops;
    2502           0 :         struct ieee80211com *ic = &sc->sc_ic;
    2503           0 :         struct ifnet *ifp = &ic->ic_if;
    2504             :         uint16_t hw;
    2505             : 
    2506           0 :         bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
    2507             :             0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
    2508             : 
    2509           0 :         hw = letoh16(sc->rxq.stat->closed_count) & 0xfff;
    2510           0 :         while (sc->rxq.cur != hw) {
    2511           0 :                 struct iwn_rx_data *data = &sc->rxq.data[sc->rxq.cur];
    2512             :                 struct iwn_rx_desc *desc;
    2513             : 
    2514           0 :                 bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof (*desc),
    2515             :                     BUS_DMASYNC_POSTREAD);
    2516           0 :                 desc = mtod(data->m, struct iwn_rx_desc *);
    2517             : 
    2518             :                 DPRINTFN(4, ("notification qid=%d idx=%d flags=%x type=%d\n",
    2519             :                     desc->qid & 0xf, desc->idx, desc->flags, desc->type));
    2520             : 
    2521           0 :                 if (!(desc->qid & 0x80)) /* Reply to a command. */
    2522           0 :                         iwn_cmd_done(sc, desc);
    2523             : 
    2524           0 :                 switch (desc->type) {
    2525             :                 case IWN_RX_PHY:
    2526           0 :                         iwn_rx_phy(sc, desc, data);
    2527           0 :                         break;
    2528             : 
    2529             :                 case IWN_RX_DONE:               /* 4965AGN only. */
    2530             :                 case IWN_MPDU_RX_DONE:
    2531             :                         /* An 802.11 frame has been received. */
    2532           0 :                         iwn_rx_done(sc, desc, data);
    2533           0 :                         break;
    2534             :                 case IWN_RX_COMPRESSED_BA:
    2535             :                         /* A Compressed BlockAck has been received. */
    2536           0 :                         iwn_rx_compressed_ba(sc, desc, data);
    2537           0 :                         break;
    2538             :                 case IWN_TX_DONE:
    2539             :                         /* An 802.11 frame has been transmitted. */
    2540           0 :                         ops->tx_done(sc, desc, data);
    2541           0 :                         break;
    2542             : 
    2543             :                 case IWN_RX_STATISTICS:
    2544             :                 case IWN_BEACON_STATISTICS:
    2545           0 :                         iwn_rx_statistics(sc, desc, data);
    2546           0 :                         break;
    2547             : 
    2548             :                 case IWN_BEACON_MISSED:
    2549             :                 {
    2550             :                         struct iwn_beacon_missed *miss =
    2551           0 :                             (struct iwn_beacon_missed *)(desc + 1);
    2552             :                         uint32_t missed;
    2553             : 
    2554           0 :                         if ((ic->ic_opmode != IEEE80211_M_STA) ||
    2555           0 :                             (ic->ic_state != IEEE80211_S_RUN))
    2556           0 :                                 break;
    2557             : 
    2558           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2559             :                             sizeof (*miss), BUS_DMASYNC_POSTREAD);
    2560           0 :                         missed = letoh32(miss->consecutive);
    2561             : 
    2562             :                         /*
    2563             :                          * If more than 5 consecutive beacons are missed,
    2564             :                          * reinitialize the sensitivity state machine.
    2565             :                          */
    2566           0 :                         if (missed > 5)
    2567           0 :                                 (void)iwn_init_sensitivity(sc);
    2568             : 
    2569             :                         /*
    2570             :                          * Rather than go directly to scan state, try to send a
    2571             :                          * directed probe request first. If that fails then the
    2572             :                          * state machine will drop us into scanning after timing
    2573             :                          * out waiting for a probe response.
    2574             :                          */
    2575           0 :                         if (missed > ic->ic_bmissthres && !ic->ic_mgt_timer)
    2576           0 :                                 IEEE80211_SEND_MGMT(ic, ic->ic_bss,
    2577             :                                     IEEE80211_FC0_SUBTYPE_PROBE_REQ, 0);
    2578           0 :                         break;
    2579             :                 }
    2580             :                 case IWN_UC_READY:
    2581             :                 {
    2582             :                         struct iwn_ucode_info *uc =
    2583           0 :                             (struct iwn_ucode_info *)(desc + 1);
    2584             : 
    2585             :                         /* The microcontroller is ready. */
    2586           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2587             :                             sizeof (*uc), BUS_DMASYNC_POSTREAD);
    2588             :                         DPRINTF(("microcode alive notification version=%d.%d "
    2589             :                             "subtype=%x alive=%x\n", uc->major, uc->minor,
    2590             :                             uc->subtype, letoh32(uc->valid)));
    2591             : 
    2592           0 :                         if (letoh32(uc->valid) != 1) {
    2593           0 :                                 printf("%s: microcontroller initialization "
    2594           0 :                                     "failed\n", sc->sc_dev.dv_xname);
    2595           0 :                                 break;
    2596             :                         }
    2597           0 :                         if (uc->subtype == IWN_UCODE_INIT) {
    2598             :                                 /* Save microcontroller report. */
    2599           0 :                                 memcpy(&sc->ucode_info, uc, sizeof (*uc));
    2600           0 :                         }
    2601             :                         /* Save the address of the error log in SRAM. */
    2602           0 :                         sc->errptr = letoh32(uc->errptr);
    2603           0 :                         break;
    2604             :                 }
    2605             :                 case IWN_STATE_CHANGED:
    2606             :                 {
    2607           0 :                         uint32_t *status = (uint32_t *)(desc + 1);
    2608             : 
    2609             :                         /* Enabled/disabled notification. */
    2610           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2611             :                             sizeof (*status), BUS_DMASYNC_POSTREAD);
    2612             :                         DPRINTF(("state changed to %x\n", letoh32(*status)));
    2613             : 
    2614           0 :                         if (letoh32(*status) & 1) {
    2615             :                                 /* The radio button has to be pushed. */
    2616           0 :                                 printf("%s: Radio transmitter is off\n",
    2617           0 :                                     sc->sc_dev.dv_xname);
    2618             :                                 /* Turn the interface down. */
    2619           0 :                                 iwn_stop(ifp, 1);
    2620           0 :                                 return; /* No further processing. */
    2621             :                         }
    2622           0 :                         break;
    2623             :                 }
    2624             :                 case IWN_START_SCAN:
    2625             :                 {
    2626             :                         struct iwn_start_scan *scan =
    2627           0 :                             (struct iwn_start_scan *)(desc + 1);
    2628             : 
    2629           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2630             :                             sizeof (*scan), BUS_DMASYNC_POSTREAD);
    2631             :                         DPRINTFN(2, ("scanning channel %d status %x\n",
    2632             :                             scan->chan, letoh32(scan->status)));
    2633             : 
    2634           0 :                         if (sc->sc_flags & IWN_FLAG_BGSCAN)
    2635           0 :                                 break;
    2636             : 
    2637             :                         /* Fix current channel. */
    2638           0 :                         ic->ic_bss->ni_chan = &ic->ic_channels[scan->chan];
    2639           0 :                         break;
    2640             :                 }
    2641             :                 case IWN_STOP_SCAN:
    2642             :                 {
    2643             :                         struct iwn_stop_scan *scan =
    2644           0 :                             (struct iwn_stop_scan *)(desc + 1);
    2645             : 
    2646           0 :                         bus_dmamap_sync(sc->sc_dmat, data->map, sizeof (*desc),
    2647             :                             sizeof (*scan), BUS_DMASYNC_POSTREAD);
    2648             :                         DPRINTF(("scan finished nchan=%d status=%d chan=%d\n",
    2649             :                             scan->nchan, scan->status, scan->chan));
    2650             : 
    2651           0 :                         if (scan->status == 1 && scan->chan <= 14 &&
    2652           0 :                             (sc->sc_flags & IWN_FLAG_HAS_5GHZ)) {
    2653             :                                 int error;
    2654             :                                 /*
    2655             :                                  * We just finished scanning 2GHz channels,
    2656             :                                  * start scanning 5GHz ones.
    2657             :                                  */
    2658           0 :                                 error = iwn_scan(sc, IEEE80211_CHAN_5GHZ,
    2659           0 :                                     (sc->sc_flags & IWN_FLAG_BGSCAN) ? 1 : 0);
    2660           0 :                                 if (error == 0)
    2661           0 :                                         break;
    2662           0 :                         }
    2663           0 :                         sc->sc_flags &= ~IWN_FLAG_SCANNING;
    2664           0 :                         sc->sc_flags &= ~IWN_FLAG_BGSCAN;
    2665           0 :                         ieee80211_end_scan(ifp);
    2666           0 :                         break;
    2667             :                 }
    2668             :                 case IWN5000_CALIBRATION_RESULT:
    2669           0 :                         iwn5000_rx_calib_results(sc, desc, data);
    2670           0 :                         break;
    2671             : 
    2672             :                 case IWN5000_CALIBRATION_DONE:
    2673           0 :                         sc->sc_flags |= IWN_FLAG_CALIB_DONE;
    2674           0 :                         wakeup(sc);
    2675           0 :                         break;
    2676             :                 }
    2677             : 
    2678           0 :                 sc->rxq.cur = (sc->rxq.cur + 1) % IWN_RX_RING_COUNT;
    2679           0 :         }
    2680             : 
    2681             :         /* Tell the firmware what we have processed. */
    2682           0 :         hw = (hw == 0) ? IWN_RX_RING_COUNT - 1 : hw - 1;
    2683           0 :         IWN_WRITE(sc, IWN_FH_RX_WPTR, hw & ~7);
    2684           0 : }
    2685             : 
    2686             : /*
    2687             :  * Process an INT_WAKEUP interrupt raised when the microcontroller wakes up
    2688             :  * from power-down sleep mode.
    2689             :  */
    2690             : void
    2691           0 : iwn_wakeup_intr(struct iwn_softc *sc)
    2692             : {
    2693             :         int qid;
    2694             : 
    2695             :         DPRINTF(("ucode wakeup from power-down sleep\n"));
    2696             : 
    2697             :         /* Wakeup RX and TX rings. */
    2698           0 :         IWN_WRITE(sc, IWN_FH_RX_WPTR, sc->rxq.cur & ~7);
    2699           0 :         for (qid = 0; qid < sc->ntxqs; qid++) {
    2700           0 :                 struct iwn_tx_ring *ring = &sc->txq[qid];
    2701           0 :                 IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | ring->cur);
    2702             :         }
    2703           0 : }
    2704             : 
    2705             : #ifdef IWN_DEBUG
    2706             : /*
    2707             :  * Dump the error log of the firmware when a firmware panic occurs.  Although
    2708             :  * we can't debug the firmware because it is neither open source nor free, it
    2709             :  * can help us to identify certain classes of problems.
    2710             :  */
    2711             : void
    2712             : iwn_fatal_intr(struct iwn_softc *sc)
    2713             : {
    2714             :         struct iwn_fw_dump dump;
    2715             :         int i;
    2716             : 
    2717             :         /* Check that the error log address is valid. */
    2718             :         if (sc->errptr < IWN_FW_DATA_BASE ||
    2719             :             sc->errptr + sizeof (dump) >
    2720             :             IWN_FW_DATA_BASE + sc->fw_data_maxsz) {
    2721             :                 printf("%s: bad firmware error log address 0x%08x\n",
    2722             :                     sc->sc_dev.dv_xname, sc->errptr);
    2723             :                 return;
    2724             :         }
    2725             :         if (iwn_nic_lock(sc) != 0) {
    2726             :                 printf("%s: could not read firmware error log\n",
    2727             :                     sc->sc_dev.dv_xname);
    2728             :                 return;
    2729             :         }
    2730             :         /* Read firmware error log from SRAM. */
    2731             :         iwn_mem_read_region_4(sc, sc->errptr, (uint32_t *)&dump,
    2732             :             sizeof (dump) / sizeof (uint32_t));
    2733             :         iwn_nic_unlock(sc);
    2734             : 
    2735             :         if (dump.valid == 0) {
    2736             :                 printf("%s: firmware error log is empty\n",
    2737             :                     sc->sc_dev.dv_xname);
    2738             :                 return;
    2739             :         }
    2740             :         printf("firmware error log:\n");
    2741             :         printf("  error type      = \"%s\" (0x%08X)\n",
    2742             :             (dump.id < nitems(iwn_fw_errmsg)) ?
    2743             :                 iwn_fw_errmsg[dump.id] : "UNKNOWN",
    2744             :             dump.id);
    2745             :         printf("  program counter = 0x%08X\n", dump.pc);
    2746             :         printf("  source line     = 0x%08X\n", dump.src_line);
    2747             :         printf("  error data      = 0x%08X%08X\n",
    2748             :             dump.error_data[0], dump.error_data[1]);
    2749             :         printf("  branch link     = 0x%08X%08X\n",
    2750             :             dump.branch_link[0], dump.branch_link[1]);
    2751             :         printf("  interrupt link  = 0x%08X%08X\n",
    2752             :             dump.interrupt_link[0], dump.interrupt_link[1]);
    2753             :         printf("  time            = %u\n", dump.time[0]);
    2754             : 
    2755             :         /* Dump driver status (TX and RX rings) while we're here. */
    2756             :         printf("driver status:\n");
    2757             :         for (i = 0; i < sc->ntxqs; i++) {
    2758             :                 struct iwn_tx_ring *ring = &sc->txq[i];
    2759             :                 printf("  tx ring %2d: qid=%-2d cur=%-3d queued=%-3d\n",
    2760             :                     i, ring->qid, ring->cur, ring->queued);
    2761             :         }
    2762             :         printf("  rx ring: cur=%d\n", sc->rxq.cur);
    2763             :         printf("  802.11 state %d\n", sc->sc_ic.ic_state);
    2764             : }
    2765             : #endif
    2766             : 
    2767             : int
    2768           0 : iwn_intr(void *arg)
    2769             : {
    2770           0 :         struct iwn_softc *sc = arg;
    2771           0 :         struct ifnet *ifp = &sc->sc_ic.ic_if;
    2772             :         uint32_t r1, r2, tmp;
    2773             : 
    2774             :         /* Disable interrupts. */
    2775           0 :         IWN_WRITE(sc, IWN_INT_MASK, 0);
    2776             : 
    2777             :         /* Read interrupts from ICT (fast) or from registers (slow). */
    2778           0 :         if (sc->sc_flags & IWN_FLAG_USE_ICT) {
    2779             :                 tmp = 0;
    2780           0 :                 while (sc->ict[sc->ict_cur] != 0) {
    2781           0 :                         tmp |= sc->ict[sc->ict_cur];
    2782           0 :                         sc->ict[sc->ict_cur] = 0; /* Acknowledge. */
    2783           0 :                         sc->ict_cur = (sc->ict_cur + 1) % IWN_ICT_COUNT;
    2784             :                 }
    2785             :                 tmp = letoh32(tmp);
    2786           0 :                 if (tmp == 0xffffffff)  /* Shouldn't happen. */
    2787           0 :                         tmp = 0;
    2788           0 :                 else if (tmp & 0xc0000)     /* Workaround a HW bug. */
    2789           0 :                         tmp |= 0x8000;
    2790           0 :                 r1 = (tmp & 0xff00) << 16 | (tmp & 0xff);
    2791             :                 r2 = 0; /* Unused. */
    2792           0 :         } else {
    2793           0 :                 r1 = IWN_READ(sc, IWN_INT);
    2794           0 :                 if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
    2795           0 :                         return 0;       /* Hardware gone! */
    2796           0 :                 r2 = IWN_READ(sc, IWN_FH_INT);
    2797             :         }
    2798           0 :         if (r1 == 0 && r2 == 0) {
    2799           0 :                 if (ifp->if_flags & IFF_UP)
    2800           0 :                         IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
    2801           0 :                 return 0;       /* Interrupt not for us. */
    2802             :         }
    2803             : 
    2804             :         /* Acknowledge interrupts. */
    2805           0 :         IWN_WRITE(sc, IWN_INT, r1);
    2806           0 :         if (!(sc->sc_flags & IWN_FLAG_USE_ICT))
    2807           0 :                 IWN_WRITE(sc, IWN_FH_INT, r2);
    2808             : 
    2809           0 :         if (r1 & IWN_INT_RF_TOGGLED) {
    2810           0 :                 tmp = IWN_READ(sc, IWN_GP_CNTRL);
    2811           0 :                 printf("%s: RF switch: radio %s\n", sc->sc_dev.dv_xname,
    2812           0 :                     (tmp & IWN_GP_CNTRL_RFKILL) ? "enabled" : "disabled");
    2813           0 :         }
    2814           0 :         if (r1 & IWN_INT_CT_REACHED) {
    2815           0 :                 printf("%s: critical temperature reached!\n",
    2816           0 :                     sc->sc_dev.dv_xname);
    2817           0 :         }
    2818           0 :         if (r1 & (IWN_INT_SW_ERR | IWN_INT_HW_ERR)) {
    2819           0 :                 printf("%s: fatal firmware error\n", sc->sc_dev.dv_xname);
    2820             : 
    2821             :                 /* Force a complete recalibration on next init. */
    2822           0 :                 sc->sc_flags &= ~IWN_FLAG_CALIB_DONE;
    2823             : 
    2824             :                 /* Dump firmware error log and stop. */
    2825             : #ifdef IWN_DEBUG
    2826             :                 iwn_fatal_intr(sc);
    2827             : #endif
    2828           0 :                 iwn_stop(ifp, 1);
    2829           0 :                 task_add(systq, &sc->init_task);
    2830           0 :                 return 1;
    2831             :         }
    2832           0 :         if ((r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX | IWN_INT_RX_PERIODIC)) ||
    2833           0 :             (r2 & IWN_FH_INT_RX)) {
    2834           0 :                 if (sc->sc_flags & IWN_FLAG_USE_ICT) {
    2835           0 :                         if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX))
    2836           0 :                                 IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_RX);
    2837           0 :                         IWN_WRITE_1(sc, IWN_INT_PERIODIC,
    2838             :                             IWN_INT_PERIODIC_DIS);
    2839           0 :                         iwn_notif_intr(sc);
    2840           0 :                         if (r1 & (IWN_INT_FH_RX | IWN_INT_SW_RX)) {
    2841           0 :                                 IWN_WRITE_1(sc, IWN_INT_PERIODIC,
    2842             :                                     IWN_INT_PERIODIC_ENA);
    2843           0 :                         }
    2844             :                 } else
    2845           0 :                         iwn_notif_intr(sc);
    2846             :         }
    2847             : 
    2848           0 :         if ((r1 & IWN_INT_FH_TX) || (r2 & IWN_FH_INT_TX)) {
    2849           0 :                 if (sc->sc_flags & IWN_FLAG_USE_ICT)
    2850           0 :                         IWN_WRITE(sc, IWN_FH_INT, IWN_FH_INT_TX);
    2851           0 :                 wakeup(sc);     /* FH DMA transfer completed. */
    2852           0 :         }
    2853             : 
    2854           0 :         if (r1 & IWN_INT_ALIVE)
    2855           0 :                 wakeup(sc);     /* Firmware is alive. */
    2856             : 
    2857           0 :         if (r1 & IWN_INT_WAKEUP)
    2858           0 :                 iwn_wakeup_intr(sc);
    2859             : 
    2860             :         /* Re-enable interrupts. */
    2861           0 :         if (ifp->if_flags & IFF_UP)
    2862           0 :                 IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
    2863             : 
    2864           0 :         return 1;
    2865           0 : }
    2866             : 
    2867             : /*
    2868             :  * Update TX scheduler ring when transmitting an 802.11 frame (4965AGN and
    2869             :  * 5000 adapters use a slightly different format).
    2870             :  */
    2871             : void
    2872           0 : iwn4965_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id,
    2873             :     uint16_t len)
    2874             : {
    2875           0 :         uint16_t *w = &sc->sched[qid * IWN4965_SCHED_COUNT + idx];
    2876             : 
    2877           0 :         *w = htole16(len + 8);
    2878           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
    2879             :             (caddr_t)w - sc->sched_dma.vaddr, sizeof (uint16_t),
    2880             :             BUS_DMASYNC_PREWRITE);
    2881           0 :         if (idx < IWN_SCHED_WINSZ) {
    2882           0 :                 *(w + IWN_TX_RING_COUNT) = *w;
    2883           0 :                 bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
    2884             :                     (caddr_t)(w + IWN_TX_RING_COUNT) - sc->sched_dma.vaddr,
    2885             :                     sizeof (uint16_t), BUS_DMASYNC_PREWRITE);
    2886           0 :         }
    2887           0 : }
    2888             : 
    2889             : void
    2890           0 : iwn5000_update_sched(struct iwn_softc *sc, int qid, int idx, uint8_t id,
    2891             :     uint16_t len)
    2892             : {
    2893           0 :         uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx];
    2894             : 
    2895           0 :         *w = htole16(id << 12 | (len + 8));
    2896           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
    2897             :             (caddr_t)w - sc->sched_dma.vaddr, sizeof (uint16_t),
    2898             :             BUS_DMASYNC_PREWRITE);
    2899           0 :         if (idx < IWN_SCHED_WINSZ) {
    2900           0 :                 *(w + IWN_TX_RING_COUNT) = *w;
    2901           0 :                 bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
    2902             :                     (caddr_t)(w + IWN_TX_RING_COUNT) - sc->sched_dma.vaddr,
    2903             :                     sizeof (uint16_t), BUS_DMASYNC_PREWRITE);
    2904           0 :         }
    2905           0 : }
    2906             : 
    2907             : void
    2908           0 : iwn5000_reset_sched(struct iwn_softc *sc, int qid, int idx)
    2909             : {
    2910           0 :         uint16_t *w = &sc->sched[qid * IWN5000_SCHED_COUNT + idx];
    2911             : 
    2912           0 :         *w = (*w & htole16(0xf000)) | htole16(1);
    2913           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
    2914             :             (caddr_t)w - sc->sched_dma.vaddr, sizeof (uint16_t),
    2915             :             BUS_DMASYNC_PREWRITE);
    2916           0 :         if (idx < IWN_SCHED_WINSZ) {
    2917           0 :                 *(w + IWN_TX_RING_COUNT) = *w;
    2918           0 :                 bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
    2919             :                     (caddr_t)(w + IWN_TX_RING_COUNT) - sc->sched_dma.vaddr,
    2920             :                     sizeof (uint16_t), BUS_DMASYNC_PREWRITE);
    2921           0 :         }
    2922           0 : }
    2923             : 
    2924             : int
    2925           0 : iwn_rval2ridx(int rval)
    2926             : {
    2927             :         int ridx;
    2928             : 
    2929           0 :         for (ridx = 0; ridx < nitems(iwn_rates); ridx++) {
    2930           0 :                 if (rval == iwn_rates[ridx].rate)
    2931             :                         break;
    2932             :         }
    2933             : 
    2934           0 :         return ridx;
    2935             : }
    2936             : 
    2937             : int
    2938           0 : iwn_tx(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni)
    2939             : {
    2940           0 :         struct ieee80211com *ic = &sc->sc_ic;
    2941           0 :         struct iwn_node *wn = (void *)ni;
    2942             :         struct iwn_tx_ring *ring;
    2943             :         struct iwn_tx_desc *desc;
    2944             :         struct iwn_tx_data *data;
    2945             :         struct iwn_tx_cmd *cmd;
    2946             :         struct iwn_cmd_data *tx;
    2947             :         const struct iwn_rate *rinfo;
    2948             :         struct ieee80211_frame *wh;
    2949             :         struct ieee80211_key *k = NULL;
    2950             :         enum ieee80211_edca_ac ac;
    2951             :         uint32_t flags;
    2952             :         uint16_t qos;
    2953             :         u_int hdrlen;
    2954             :         bus_dma_segment_t *seg;
    2955             :         uint8_t *ivp, tid, ridx, txant, type;
    2956             :         int i, totlen, hasqos, error, pad;
    2957             : 
    2958           0 :         wh = mtod(m, struct ieee80211_frame *);
    2959           0 :         hdrlen = ieee80211_get_hdrlen(wh);
    2960           0 :         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
    2961             : 
    2962             :         /* Select EDCA Access Category and TX ring for this frame. */
    2963           0 :         if ((hasqos = ieee80211_has_qos(wh))) {
    2964           0 :                 qos = ieee80211_get_qos(wh);
    2965           0 :                 tid = qos & IEEE80211_QOS_TID;
    2966           0 :                 ac = ieee80211_up_to_ac(ic, tid);
    2967           0 :         } else {
    2968             :                 qos = 0;
    2969             :                 tid = 0;
    2970             :                 ac = EDCA_AC_BE;
    2971             :         }
    2972             : 
    2973           0 :         ring = &sc->txq[ac];
    2974           0 :         desc = &ring->desc[ring->cur];
    2975           0 :         data = &ring->data[ring->cur];
    2976             : 
    2977             :         /* Choose a TX rate index. */
    2978           0 :         if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
    2979           0 :             type != IEEE80211_FC0_TYPE_DATA)
    2980           0 :                 ridx = iwn_rval2ridx(ieee80211_min_basic_rate(ic));
    2981           0 :         else if (ic->ic_fixed_mcs != -1)
    2982           0 :                 ridx = sc->fixed_ridx;
    2983           0 :         else if (ic->ic_fixed_rate != -1)
    2984           0 :                 ridx = sc->fixed_ridx;
    2985             :         else {
    2986           0 :                 if (ni->ni_flags & IEEE80211_NODE_HT)
    2987           0 :                         ridx = iwn_mcs2ridx[ni->ni_txmcs];
    2988             :                 else
    2989           0 :                         ridx = wn->ridx[ni->ni_txrate];
    2990             :         }       
    2991           0 :         rinfo = &iwn_rates[ridx];
    2992             : #if NBPFILTER > 0
    2993           0 :         if (sc->sc_drvbpf != NULL) {
    2994           0 :                 struct mbuf mb;
    2995           0 :                 struct iwn_tx_radiotap_header *tap = &sc->sc_txtap;
    2996             :                 uint16_t chan_flags;
    2997             : 
    2998           0 :                 tap->wt_flags = 0;
    2999           0 :                 tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
    3000           0 :                 chan_flags = ni->ni_chan->ic_flags;
    3001           0 :                 if (ic->ic_curmode != IEEE80211_MODE_11N)
    3002           0 :                         chan_flags &= ~IEEE80211_CHAN_HT;
    3003           0 :                 tap->wt_chan_flags = htole16(chan_flags);
    3004           0 :                 if ((ni->ni_flags & IEEE80211_NODE_HT) &&
    3005           0 :                     !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
    3006           0 :                     type == IEEE80211_FC0_TYPE_DATA) {
    3007           0 :                         tap->wt_rate = (0x80 | ni->ni_txmcs);
    3008           0 :                 } else
    3009           0 :                         tap->wt_rate = rinfo->rate;
    3010           0 :                 tap->wt_hwqueue = ac;
    3011           0 :                 if ((ic->ic_flags & IEEE80211_F_WEPON) &&
    3012           0 :                     (wh->i_fc[1] & IEEE80211_FC1_PROTECTED))
    3013           0 :                         tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
    3014             : 
    3015           0 :                 mb.m_data = (caddr_t)tap;
    3016           0 :                 mb.m_len = sc->sc_txtap_len;
    3017           0 :                 mb.m_next = m;
    3018           0 :                 mb.m_nextpkt = NULL;
    3019           0 :                 mb.m_type = 0;
    3020           0 :                 mb.m_flags = 0;
    3021           0 :                 bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
    3022           0 :         }
    3023             : #endif
    3024             : 
    3025           0 :         totlen = m->m_pkthdr.len;
    3026             : 
    3027             :         /* Encrypt the frame if need be. */
    3028           0 :         if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
    3029             :                 /* Retrieve key for TX. */
    3030           0 :                 k = ieee80211_get_txkey(ic, wh, ni);
    3031           0 :                 if (k->k_cipher != IEEE80211_CIPHER_CCMP) {
    3032             :                         /* Do software encryption. */
    3033           0 :                         if ((m = ieee80211_encrypt(ic, m, k)) == NULL)
    3034           0 :                                 return ENOBUFS;
    3035             :                         /* 802.11 header may have moved. */
    3036           0 :                         wh = mtod(m, struct ieee80211_frame *);
    3037           0 :                         totlen = m->m_pkthdr.len;
    3038             : 
    3039           0 :                 } else  /* HW appends CCMP MIC. */
    3040           0 :                         totlen += IEEE80211_CCMP_HDRLEN;
    3041             :         }
    3042             : 
    3043           0 :         data->totlen = totlen;
    3044             : 
    3045             :         /* Prepare TX firmware command. */
    3046           0 :         cmd = &ring->cmd[ring->cur];
    3047           0 :         cmd->code = IWN_CMD_TX_DATA;
    3048           0 :         cmd->flags = 0;
    3049           0 :         cmd->qid = ring->qid;
    3050           0 :         cmd->idx = ring->cur;
    3051             : 
    3052           0 :         tx = (struct iwn_cmd_data *)cmd->data;
    3053             :         /* NB: No need to clear tx, all fields are reinitialized here. */
    3054           0 :         tx->scratch = 0;     /* clear "scratch" area */
    3055             : 
    3056             :         flags = 0;
    3057           0 :         if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
    3058             :                 /* Unicast frame, check if an ACK is expected. */
    3059           0 :                 if (!hasqos || (qos & IEEE80211_QOS_ACK_POLICY_MASK) !=
    3060             :                     IEEE80211_QOS_ACK_POLICY_NOACK)
    3061           0 :                         flags |= IWN_TX_NEED_ACK;
    3062             :         }
    3063           0 :         if ((wh->i_fc[0] &
    3064           0 :             (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) ==
    3065             :             (IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR))
    3066           0 :                 flags |= IWN_TX_IMM_BA;         /* Cannot happen yet. */
    3067             : 
    3068           0 :         if (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG)
    3069           0 :                 flags |= IWN_TX_MORE_FRAG;      /* Cannot happen yet. */
    3070             : 
    3071             :         /* Check if frame must be protected using RTS/CTS or CTS-to-self. */
    3072           0 :         if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
    3073             :                 /* NB: Group frames are sent using CCK in 802.11b/g/n (2GHz). */
    3074           0 :                 if (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold) {
    3075           0 :                         flags |= IWN_TX_NEED_RTS;
    3076           0 :                 } else if ((ic->ic_flags & IEEE80211_F_USEPROT) &&
    3077           0 :                     ridx >= IWN_RIDX_OFDM6) {
    3078           0 :                         if (ic->ic_protmode == IEEE80211_PROT_CTSONLY)
    3079           0 :                                 flags |= IWN_TX_NEED_CTS;
    3080           0 :                         else if (ic->ic_protmode == IEEE80211_PROT_RTSCTS)
    3081           0 :                                 flags |= IWN_TX_NEED_RTS;
    3082             :                 }
    3083             : 
    3084           0 :                 if (flags & (IWN_TX_NEED_RTS | IWN_TX_NEED_CTS)) {
    3085           0 :                         if (sc->hw_type != IWN_HW_REV_TYPE_4965) {
    3086             :                                 /* 5000 autoselects RTS/CTS or CTS-to-self. */
    3087           0 :                                 flags &= ~(IWN_TX_NEED_RTS | IWN_TX_NEED_CTS);
    3088           0 :                                 flags |= IWN_TX_NEED_PROTECTION;
    3089           0 :                         } else
    3090           0 :                                 flags |= IWN_TX_FULL_TXOP;
    3091             :                 }
    3092             :         }
    3093             : 
    3094           0 :         if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
    3095           0 :             type != IEEE80211_FC0_TYPE_DATA)
    3096           0 :                 tx->id = sc->broadcast_id;
    3097             :         else
    3098           0 :                 tx->id = wn->id;
    3099             : 
    3100           0 :         if (type == IEEE80211_FC0_TYPE_MGT) {
    3101           0 :                 uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
    3102             : 
    3103             : #ifndef IEEE80211_STA_ONLY
    3104             :                 /* Tell HW to set timestamp in probe responses. */
    3105           0 :                 if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
    3106           0 :                         flags |= IWN_TX_INSERT_TSTAMP;
    3107             : #endif
    3108           0 :                 if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ ||
    3109           0 :                     subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
    3110           0 :                         tx->timeout = htole16(3);
    3111             :                 else
    3112           0 :                         tx->timeout = htole16(2);
    3113           0 :         } else
    3114           0 :                 tx->timeout = htole16(0);
    3115             : 
    3116           0 :         if (hdrlen & 3) {
    3117             :                 /* First segment length must be a multiple of 4. */
    3118           0 :                 flags |= IWN_TX_NEED_PADDING;
    3119           0 :                 pad = 4 - (hdrlen & 3);
    3120           0 :         } else
    3121             :                 pad = 0;
    3122             : 
    3123           0 :         tx->len = htole16(totlen);
    3124           0 :         tx->tid = tid;
    3125           0 :         tx->rts_ntries = 60;
    3126           0 :         tx->data_ntries = 15;
    3127           0 :         tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
    3128             : 
    3129           0 :         if ((ni->ni_flags & IEEE80211_NODE_HT) &&
    3130           0 :             tx->id != sc->broadcast_id)
    3131           0 :                 tx->plcp = rinfo->ht_plcp;
    3132             :         else
    3133           0 :                 tx->plcp = rinfo->plcp;
    3134             : 
    3135           0 :         if ((ni->ni_flags & IEEE80211_NODE_HT) &&
    3136           0 :             tx->id != sc->broadcast_id) {
    3137           0 :                 tx->rflags = rinfo->ht_flags;
    3138           0 :                 if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20)
    3139           0 :                         tx->rflags |= IWN_RFLAG_SGI;
    3140             :         }
    3141             :         else
    3142           0 :                 tx->rflags = rinfo->flags;
    3143           0 :         if (tx->id == sc->broadcast_id) {
    3144             :                 /* Group or management frame. */
    3145           0 :                 tx->linkq = 0;
    3146             :                 /* XXX Alternate between antenna A and B? */
    3147           0 :                 txant = IWN_LSB(sc->txchainmask);
    3148           0 :                 tx->rflags |= IWN_RFLAG_ANT(txant);
    3149           0 :         } else {
    3150           0 :                 if (ni->ni_flags & IEEE80211_NODE_HT)
    3151           0 :                         tx->linkq = 7 - ni->ni_txmcs; /* XXX revisit for MIMO */
    3152             :                 else
    3153           0 :                         tx->linkq = ni->ni_rates.rs_nrates - ni->ni_txrate - 1;
    3154           0 :                 flags |= IWN_TX_LINKQ;  /* enable MRR */
    3155             :         }
    3156             :         /* Set physical address of "scratch area". */
    3157           0 :         tx->loaddr = htole32(IWN_LOADDR(data->scratch_paddr));
    3158           0 :         tx->hiaddr = IWN_HIADDR(data->scratch_paddr);
    3159             : 
    3160             :         /* Copy 802.11 header in TX command. */
    3161           0 :         memcpy((uint8_t *)(tx + 1), wh, hdrlen);
    3162             : 
    3163           0 :         if (k != NULL && k->k_cipher == IEEE80211_CIPHER_CCMP) {
    3164             :                 /* Trim 802.11 header and prepend CCMP IV. */
    3165           0 :                 m_adj(m, hdrlen - IEEE80211_CCMP_HDRLEN);
    3166           0 :                 ivp = mtod(m, uint8_t *);
    3167           0 :                 k->k_tsc++;
    3168           0 :                 ivp[0] = k->k_tsc;
    3169           0 :                 ivp[1] = k->k_tsc >> 8;
    3170           0 :                 ivp[2] = 0;
    3171           0 :                 ivp[3] = k->k_id << 6 | IEEE80211_WEP_EXTIV;
    3172           0 :                 ivp[4] = k->k_tsc >> 16;
    3173           0 :                 ivp[5] = k->k_tsc >> 24;
    3174           0 :                 ivp[6] = k->k_tsc >> 32;
    3175           0 :                 ivp[7] = k->k_tsc >> 40;
    3176             : 
    3177           0 :                 tx->security = IWN_CIPHER_CCMP;
    3178             :                 /* XXX flags |= IWN_TX_AMPDU_CCMP; */
    3179           0 :                 memcpy(tx->key, k->k_key, k->k_len);
    3180             : 
    3181             :                 /* TX scheduler includes CCMP MIC len w/5000 Series. */
    3182           0 :                 if (sc->hw_type != IWN_HW_REV_TYPE_4965)
    3183           0 :                         totlen += IEEE80211_CCMP_MICLEN;
    3184             :         } else {
    3185             :                 /* Trim 802.11 header. */
    3186           0 :                 m_adj(m, hdrlen);
    3187           0 :                 tx->security = 0;
    3188             :         }
    3189           0 :         tx->flags = htole32(flags);
    3190             : 
    3191           0 :         error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
    3192             :             BUS_DMA_NOWAIT | BUS_DMA_WRITE);
    3193           0 :         if (error != 0 && error != EFBIG) {
    3194           0 :                 printf("%s: can't map mbuf (error %d)\n",
    3195           0 :                     sc->sc_dev.dv_xname, error);
    3196           0 :                 m_freem(m);
    3197           0 :                 return error;
    3198             :         }
    3199           0 :         if (error != 0) {
    3200             :                 /* Too many DMA segments, linearize mbuf. */
    3201           0 :                 if (m_defrag(m, M_DONTWAIT)) {
    3202           0 :                         m_freem(m);
    3203           0 :                         return ENOBUFS;
    3204             :                 }
    3205           0 :                 error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
    3206             :                     BUS_DMA_NOWAIT | BUS_DMA_WRITE);
    3207           0 :                 if (error != 0) {
    3208           0 :                         printf("%s: can't map mbuf (error %d)\n",
    3209           0 :                             sc->sc_dev.dv_xname, error);
    3210           0 :                         m_freem(m);
    3211           0 :                         return error;
    3212             :                 }
    3213             :         }
    3214             : 
    3215           0 :         data->m = m;
    3216           0 :         data->ni = ni;
    3217             : 
    3218             :         DPRINTFN(4, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n",
    3219             :             ring->qid, ring->cur, m->m_pkthdr.len, data->map->dm_nsegs));
    3220             : 
    3221             :         /* Fill TX descriptor. */
    3222           0 :         desc->nsegs = 1 + data->map->dm_nsegs;
    3223             :         /* First DMA segment is used by the TX command. */
    3224           0 :         desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr));
    3225           0 :         desc->segs[0].len  = htole16(IWN_HIADDR(data->cmd_paddr) |
    3226             :             (4 + sizeof (*tx) + hdrlen + pad) << 4);
    3227             :         /* Other DMA segments are for data payload. */
    3228           0 :         seg = data->map->dm_segs;
    3229           0 :         for (i = 1; i <= data->map->dm_nsegs; i++) {
    3230           0 :                 desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr));
    3231           0 :                 desc->segs[i].len  = htole16(IWN_HIADDR(seg->ds_addr) |
    3232             :                     seg->ds_len << 4);
    3233           0 :                 seg++;
    3234             :         }
    3235             : 
    3236           0 :         bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
    3237             :             BUS_DMASYNC_PREWRITE);
    3238           0 :         bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
    3239             :             (caddr_t)cmd - ring->cmd_dma.vaddr, sizeof (*cmd),
    3240             :             BUS_DMASYNC_PREWRITE);
    3241           0 :         bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
    3242             :             (caddr_t)desc - ring->desc_dma.vaddr, sizeof (*desc),
    3243             :             BUS_DMASYNC_PREWRITE);
    3244             : 
    3245             : #ifdef notyet
    3246             :         /* Update TX scheduler. */
    3247             :         ops->update_sched(sc, ring->qid, ring->cur, tx->id, totlen);
    3248             : #endif
    3249             : 
    3250             :         /* Kick TX ring. */
    3251           0 :         ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
    3252           0 :         IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
    3253             : 
    3254             :         /* Mark TX ring as full if we reach a certain threshold. */
    3255           0 :         if (++ring->queued > IWN_TX_RING_HIMARK)
    3256           0 :                 sc->qfullmsk |= 1 << ring->qid;
    3257             : 
    3258           0 :         return 0;
    3259           0 : }
    3260             : 
    3261             : void
    3262           0 : iwn_start(struct ifnet *ifp)
    3263             : {
    3264           0 :         struct iwn_softc *sc = ifp->if_softc;
    3265           0 :         struct ieee80211com *ic = &sc->sc_ic;
    3266           0 :         struct ieee80211_node *ni;
    3267             :         struct mbuf *m;
    3268             : 
    3269           0 :         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
    3270           0 :                 return;
    3271             : 
    3272           0 :         for (;;) {
    3273           0 :                 if (sc->qfullmsk != 0) {
    3274           0 :                         ifq_set_oactive(&ifp->if_snd);
    3275           0 :                         break;
    3276             :                 }
    3277             :                 /* Send pending management frames first. */
    3278           0 :                 m = mq_dequeue(&ic->ic_mgtq);
    3279           0 :                 if (m != NULL) {
    3280           0 :                         ni = m->m_pkthdr.ph_cookie;
    3281           0 :                         goto sendit;
    3282             :                 }
    3283           0 :                 if (ic->ic_state != IEEE80211_S_RUN ||
    3284           0 :                     (ic->ic_xflags & IEEE80211_F_TX_MGMT_ONLY))
    3285             :                         break;
    3286             : 
    3287             :                 /* Encapsulate and send data frames. */
    3288           0 :                 IFQ_DEQUEUE(&ifp->if_snd, m);
    3289           0 :                 if (m == NULL)
    3290             :                         break;
    3291             : #if NBPFILTER > 0
    3292           0 :                 if (ifp->if_bpf != NULL)
    3293           0 :                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
    3294             : #endif
    3295           0 :                 if ((m = ieee80211_encap(ifp, m, &ni)) == NULL)
    3296           0 :                         continue;
    3297             : sendit:
    3298             : #if NBPFILTER > 0
    3299           0 :                 if (ic->ic_rawbpf != NULL)
    3300           0 :                         bpf_mtap(ic->ic_rawbpf, m, BPF_DIRECTION_OUT);
    3301             : #endif
    3302           0 :                 if (iwn_tx(sc, m, ni) != 0) {
    3303           0 :                         ieee80211_release_node(ic, ni);
    3304           0 :                         ifp->if_oerrors++;
    3305           0 :                         continue;
    3306             :                 }
    3307             : 
    3308           0 :                 sc->sc_tx_timer = 5;
    3309           0 :                 ifp->if_timer = 1;
    3310             :         }
    3311           0 : }
    3312             : 
    3313             : void
    3314           0 : iwn_watchdog(struct ifnet *ifp)
    3315             : {
    3316           0 :         struct iwn_softc *sc = ifp->if_softc;
    3317             : 
    3318           0 :         ifp->if_timer = 0;
    3319             : 
    3320           0 :         if (sc->sc_tx_timer > 0) {
    3321           0 :                 if (--sc->sc_tx_timer == 0) {
    3322           0 :                         printf("%s: device timeout\n", sc->sc_dev.dv_xname);
    3323           0 :                         iwn_stop(ifp, 1);
    3324           0 :                         ifp->if_oerrors++;
    3325           0 :                         return;
    3326             :                 }
    3327           0 :                 ifp->if_timer = 1;
    3328           0 :         }
    3329             : 
    3330           0 :         ieee80211_watchdog(ifp);
    3331           0 : }
    3332             : 
    3333             : int
    3334           0 : iwn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
    3335             : {
    3336           0 :         struct iwn_softc *sc = ifp->if_softc;
    3337           0 :         struct ieee80211com *ic = &sc->sc_ic;
    3338             :         int s, error = 0;
    3339             : 
    3340           0 :         error = rw_enter(&sc->sc_rwlock, RW_WRITE | RW_INTR);
    3341           0 :         if (error)
    3342           0 :                 return error;
    3343           0 :         s = splnet();
    3344             : 
    3345           0 :         switch (cmd) {
    3346             :         case SIOCSIFADDR:
    3347           0 :                 ifp->if_flags |= IFF_UP;
    3348             :                 /* FALLTHROUGH */
    3349             :         case SIOCSIFFLAGS:
    3350           0 :                 if (ifp->if_flags & IFF_UP) {
    3351           0 :                         if (!(ifp->if_flags & IFF_RUNNING))
    3352           0 :                                 error = iwn_init(ifp);
    3353             :                 } else {
    3354           0 :                         if (ifp->if_flags & IFF_RUNNING)
    3355           0 :                                 iwn_stop(ifp, 1);
    3356             :                 }
    3357             :                 break;
    3358             : 
    3359             :         case SIOCS80211POWER:
    3360           0 :                 error = ieee80211_ioctl(ifp, cmd, data);
    3361           0 :                 if (error != ENETRESET)
    3362             :                         break;
    3363           0 :                 if (ic->ic_state == IEEE80211_S_RUN &&
    3364           0 :                     sc->calib.state == IWN_CALIB_STATE_RUN) {
    3365           0 :                         if (ic->ic_flags & IEEE80211_F_PMGTON)
    3366           0 :                                 error = iwn_set_pslevel(sc, 0, 3, 0);
    3367             :                         else    /* back to CAM */
    3368           0 :                                 error = iwn_set_pslevel(sc, 0, 0, 0);
    3369             :                 } else {
    3370             :                         /* Defer until transition to IWN_CALIB_STATE_RUN. */
    3371             :                         error = 0;
    3372             :                 }
    3373             :                 break;
    3374             : 
    3375             :         default:
    3376           0 :                 error = ieee80211_ioctl(ifp, cmd, data);
    3377           0 :         }
    3378             : 
    3379           0 :         if (error == ENETRESET) {
    3380             :                 error = 0;
    3381           0 :                 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
    3382             :                     (IFF_UP | IFF_RUNNING)) {
    3383           0 :                         iwn_stop(ifp, 0);
    3384           0 :                         error = iwn_init(ifp);
    3385           0 :                 }
    3386             :         }
    3387             : 
    3388           0 :         splx(s);
    3389           0 :         rw_exit_write(&sc->sc_rwlock);
    3390           0 :         return error;
    3391           0 : }
    3392             : 
    3393             : /*
    3394             :  * Send a command to the firmware.
    3395             :  */
    3396             : int
    3397           0 : iwn_cmd(struct iwn_softc *sc, int code, const void *buf, int size, int async)
    3398             : {
    3399           0 :         struct iwn_tx_ring *ring = &sc->txq[4];
    3400             :         struct iwn_tx_desc *desc;
    3401             :         struct iwn_tx_data *data;
    3402             :         struct iwn_tx_cmd *cmd;
    3403             :         struct mbuf *m;
    3404             :         bus_addr_t paddr;
    3405             :         int totlen, error;
    3406             : 
    3407           0 :         desc = &ring->desc[ring->cur];
    3408           0 :         data = &ring->data[ring->cur];
    3409           0 :         totlen = 4 + size;
    3410             : 
    3411           0 :         if (size > sizeof cmd->data) {
    3412             :                 /* Command is too large to fit in a descriptor. */
    3413           0 :                 if (totlen > MCLBYTES)
    3414           0 :                         return EINVAL;
    3415           0 :                 MGETHDR(m, M_DONTWAIT, MT_DATA);
    3416           0 :                 if (m == NULL)
    3417           0 :                         return ENOMEM;
    3418           0 :                 if (totlen > MHLEN) {
    3419           0 :                         MCLGET(m, M_DONTWAIT);
    3420           0 :                         if (!(m->m_flags & M_EXT)) {
    3421           0 :                                 m_freem(m);
    3422           0 :                                 return ENOMEM;
    3423             :                         }
    3424             :                 }
    3425           0 :                 cmd = mtod(m, struct iwn_tx_cmd *);
    3426           0 :                 error = bus_dmamap_load(sc->sc_dmat, data->map, cmd, totlen,
    3427             :                     NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
    3428           0 :                 if (error != 0) {
    3429           0 :                         m_freem(m);
    3430           0 :                         return error;
    3431             :                 }
    3432           0 :                 data->m = m;
    3433           0 :                 paddr = data->map->dm_segs[0].ds_addr;
    3434           0 :         } else {
    3435           0 :                 cmd = &ring->cmd[ring->cur];
    3436           0 :                 paddr = data->cmd_paddr;
    3437             :         }
    3438             : 
    3439           0 :         cmd->code = code;
    3440           0 :         cmd->flags = 0;
    3441           0 :         cmd->qid = ring->qid;
    3442           0 :         cmd->idx = ring->cur;
    3443           0 :         memcpy(cmd->data, buf, size);
    3444             : 
    3445           0 :         desc->nsegs = 1;
    3446           0 :         desc->segs[0].addr = htole32(IWN_LOADDR(paddr));
    3447           0 :         desc->segs[0].len  = htole16(IWN_HIADDR(paddr) | totlen << 4);
    3448             : 
    3449           0 :         if (size > sizeof cmd->data) {
    3450           0 :                 bus_dmamap_sync(sc->sc_dmat, data->map, 0, totlen,
    3451             :                     BUS_DMASYNC_PREWRITE);
    3452           0 :         } else {
    3453           0 :                 bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
    3454             :                     (caddr_t)cmd - ring->cmd_dma.vaddr, totlen,
    3455             :                     BUS_DMASYNC_PREWRITE);
    3456             :         }
    3457           0 :         bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
    3458             :             (caddr_t)desc - ring->desc_dma.vaddr, sizeof (*desc),
    3459             :             BUS_DMASYNC_PREWRITE);
    3460             : 
    3461             : #ifdef notyet
    3462             :         /* Update TX scheduler. */
    3463             :         ops->update_sched(sc, ring->qid, ring->cur, 0, 0);
    3464             : #endif
    3465             : 
    3466             :         /* Kick command ring. */
    3467           0 :         ring->cur = (ring->cur + 1) % IWN_TX_RING_COUNT;
    3468           0 :         IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
    3469             : 
    3470           0 :         return async ? 0 : tsleep(desc, PCATCH, "iwncmd", hz);
    3471           0 : }
    3472             : 
    3473             : int
    3474           0 : iwn4965_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async)
    3475             : {
    3476           0 :         struct iwn4965_node_info hnode;
    3477             :         caddr_t src, dst;
    3478             : 
    3479             :         /*
    3480             :          * We use the node structure for 5000 Series internally (it is
    3481             :          * a superset of the one for 4965AGN). We thus copy the common
    3482             :          * fields before sending the command.
    3483             :          */
    3484           0 :         src = (caddr_t)node;
    3485             :         dst = (caddr_t)&hnode;
    3486           0 :         memcpy(dst, src, 48);
    3487             :         /* Skip TSC, RX MIC and TX MIC fields from ``src''. */
    3488           0 :         memcpy(dst + 48, src + 72, 20);
    3489           0 :         return iwn_cmd(sc, IWN_CMD_ADD_NODE, &hnode, sizeof hnode, async);
    3490           0 : }
    3491             : 
    3492             : int
    3493           0 : iwn5000_add_node(struct iwn_softc *sc, struct iwn_node_info *node, int async)
    3494             : {
    3495             :         /* Direct mapping. */
    3496           0 :         return iwn_cmd(sc, IWN_CMD_ADD_NODE, node, sizeof (*node), async);
    3497             : }
    3498             : 
    3499             : int
    3500           0 : iwn_set_link_quality(struct iwn_softc *sc, struct ieee80211_node *ni)
    3501             : {
    3502           0 :         struct ieee80211com *ic = &sc->sc_ic;
    3503           0 :         struct iwn_node *wn = (void *)ni;
    3504           0 :         struct ieee80211_rateset *rs = &ni->ni_rates;
    3505           0 :         struct iwn_cmd_link_quality linkq;
    3506             :         const struct iwn_rate *rinfo;
    3507             :         uint8_t txant;
    3508             :         int i, txrate;
    3509             : 
    3510             :         /* Use the first valid TX antenna. */
    3511           0 :         txant = IWN_LSB(sc->txchainmask);
    3512             : 
    3513           0 :         memset(&linkq, 0, sizeof linkq);
    3514           0 :         linkq.id = wn->id;
    3515           0 :         linkq.antmsk_1stream = txant;
    3516           0 :         linkq.antmsk_2stream = IWN_ANT_AB;
    3517           0 :         linkq.ampdu_max = IWN_AMPDU_MAX;
    3518           0 :         linkq.ampdu_threshold = 3;
    3519           0 :         linkq.ampdu_limit = htole16(4000);      /* 4ms */
    3520             : 
    3521           0 :         if (ni->ni_flags & IEEE80211_NODE_HT) {
    3522             :                 /* Fill LQ table with MCS 7 - 0 (XXX revisit for MIMO) */
    3523             :                 i = 0;
    3524           0 :                 for (txrate = 7; txrate >= 0; txrate--) {
    3525           0 :                         rinfo = &iwn_rates[iwn_mcs2ridx[txrate]];
    3526           0 :                         linkq.retry[i].plcp = rinfo->ht_plcp;
    3527           0 :                         linkq.retry[i].rflags = rinfo->ht_flags;
    3528             : 
    3529           0 :                         if (ni->ni_htcaps & IEEE80211_HTCAP_SGI20)
    3530           0 :                                 linkq.retry[i].rflags |= IWN_RFLAG_SGI;
    3531             : 
    3532             :                         /* XXX set correct ant mask for MIMO rates here */
    3533           0 :                         linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
    3534             : 
    3535           0 :                         if (++i >= IWN_MAX_TX_RETRIES)
    3536             :                                 break;
    3537             :                 }
    3538             : 
    3539             :                 /* Fill the rest with the lowest basic rate. */
    3540           0 :                 rinfo = &iwn_rates[iwn_rval2ridx(ieee80211_min_basic_rate(ic))];
    3541           0 :                 while (i < IWN_MAX_TX_RETRIES) {
    3542           0 :                         linkq.retry[i].plcp = rinfo->plcp;
    3543           0 :                         linkq.retry[i].rflags = rinfo->flags;
    3544           0 :                         linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
    3545           0 :                         i++;
    3546             :                 }
    3547             :         } else {
    3548             :                 /* Start at highest available bit-rate. */
    3549           0 :                 txrate = rs->rs_nrates - 1;
    3550           0 :                 for (i = 0; i < IWN_MAX_TX_RETRIES; i++) {
    3551           0 :                         rinfo = &iwn_rates[wn->ridx[txrate]];
    3552           0 :                         linkq.retry[i].plcp = rinfo->plcp;
    3553           0 :                         linkq.retry[i].rflags = rinfo->flags;
    3554           0 :                         linkq.retry[i].rflags |= IWN_RFLAG_ANT(txant);
    3555             :                         /* Next retry at immediate lower bit-rate. */
    3556           0 :                         if (txrate > 0)
    3557           0 :                                 txrate--;
    3558             :                 }
    3559             :         }
    3560             : 
    3561           0 :         return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, 1);
    3562           0 : }
    3563             : 
    3564             : /*
    3565             :  * Broadcast node is used to send group-addressed and management frames.
    3566             :  */
    3567             : int
    3568           0 : iwn_add_broadcast_node(struct iwn_softc *sc, int async, int ridx)
    3569             : {
    3570           0 :         struct iwn_ops *ops = &sc->ops;
    3571           0 :         struct iwn_node_info node;
    3572           0 :         struct iwn_cmd_link_quality linkq;
    3573             :         const struct iwn_rate *rinfo;
    3574             :         uint8_t txant;
    3575             :         int i, error;
    3576             : 
    3577           0 :         memset(&node, 0, sizeof node);
    3578           0 :         IEEE80211_ADDR_COPY(node.macaddr, etherbroadcastaddr);
    3579           0 :         node.id = sc->broadcast_id;
    3580             :         DPRINTF(("adding broadcast node\n"));
    3581           0 :         if ((error = ops->add_node(sc, &node, async)) != 0)
    3582           0 :                 return error;
    3583             : 
    3584             :         /* Use the first valid TX antenna. */
    3585           0 :         txant = IWN_LSB(sc->txchainmask);
    3586             : 
    3587           0 :         memset(&linkq, 0, sizeof linkq);
    3588           0 :         linkq.id = sc->broadcast_id;
    3589           0 :         linkq.antmsk_1stream = txant;
    3590           0 :         linkq.antmsk_2stream = IWN_ANT_AB;
    3591           0 :         linkq.ampdu_max = IWN_AMPDU_MAX_NO_AGG;
    3592           0 :         linkq.ampdu_threshold = 3;
    3593           0 :         linkq.ampdu_limit = htole16(4000);      /* 4ms */
    3594             : 
    3595             :         /* Use lowest mandatory bit-rate. */
    3596           0 :         rinfo = &iwn_rates[ridx];
    3597           0 :         linkq.retry[0].plcp = rinfo->plcp;
    3598           0 :         linkq.retry[0].rflags = rinfo->flags;
    3599           0 :         linkq.retry[0].rflags |= IWN_RFLAG_ANT(txant);
    3600             :         /* Use same bit-rate for all TX retries. */
    3601           0 :         for (i = 1; i < IWN_MAX_TX_RETRIES; i++) {
    3602           0 :                 linkq.retry[i].plcp = linkq.retry[0].plcp;
    3603           0 :                 linkq.retry[i].rflags = linkq.retry[0].rflags;
    3604             :         }
    3605           0 :         return iwn_cmd(sc, IWN_CMD_LINK_QUALITY, &linkq, sizeof linkq, async);
    3606           0 : }
    3607             : 
    3608             : void
    3609           0 : iwn_updateedca(struct ieee80211com *ic)
    3610             : {
    3611             : #define IWN_EXP2(x)     ((1 << (x)) - 1)  /* CWmin = 2^ECWmin - 1 */
    3612           0 :         struct iwn_softc *sc = ic->ic_softc;
    3613           0 :         struct iwn_edca_params cmd;
    3614             :         int aci;
    3615             : 
    3616           0 :         memset(&cmd, 0, sizeof cmd);
    3617           0 :         cmd.flags = htole32(IWN_EDCA_UPDATE);
    3618           0 :         for (aci = 0; aci < EDCA_NUM_AC; aci++) {
    3619             :                 const struct ieee80211_edca_ac_params *ac =
    3620           0 :                     &ic->ic_edca_ac[aci];
    3621           0 :                 cmd.ac[aci].aifsn = ac->ac_aifsn;
    3622           0 :                 cmd.ac[aci].cwmin = htole16(IWN_EXP2(ac->ac_ecwmin));
    3623           0 :                 cmd.ac[aci].cwmax = htole16(IWN_EXP2(ac->ac_ecwmax));
    3624           0 :                 cmd.ac[aci].txoplimit =
    3625           0 :                     htole16(IEEE80211_TXOP_TO_US(ac->ac_txoplimit));
    3626             :         }
    3627           0 :         (void)iwn_cmd(sc, IWN_CMD_EDCA_PARAMS, &cmd, sizeof cmd, 1);
    3628             : #undef IWN_EXP2
    3629           0 : }
    3630             : 
    3631             : void
    3632           0 : iwn_set_led(struct iwn_softc *sc, uint8_t which, uint8_t off, uint8_t on)
    3633             : {
    3634           0 :         struct iwn_cmd_led led;
    3635             : 
    3636             :         /* Clear microcode LED ownership. */
    3637           0 :         IWN_CLRBITS(sc, IWN_LED, IWN_LED_BSM_CTRL);
    3638             : 
    3639           0 :         led.which = which;
    3640           0 :         led.unit = htole32(10000);      /* on/off in unit of 100ms */
    3641           0 :         led.off = off;
    3642           0 :         led.on = on;
    3643           0 :         (void)iwn_cmd(sc, IWN_CMD_SET_LED, &led, sizeof led, 1);
    3644           0 : }
    3645             : 
    3646             : /*
    3647             :  * Set the critical temperature at which the firmware will stop the radio
    3648             :  * and notify us.
    3649             :  */
    3650             : int
    3651           0 : iwn_set_critical_temp(struct iwn_softc *sc)
    3652             : {
    3653           0 :         struct iwn_critical_temp crit;
    3654             :         int32_t temp;
    3655             : 
    3656           0 :         IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_CTEMP_STOP_RF);
    3657             : 
    3658           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_5150)
    3659           0 :                 temp = (IWN_CTOK(110) - sc->temp_off) * -5;
    3660           0 :         else if (sc->hw_type == IWN_HW_REV_TYPE_4965)
    3661           0 :                 temp = IWN_CTOK(110);
    3662             :         else
    3663             :                 temp = 110;
    3664           0 :         memset(&crit, 0, sizeof crit);
    3665           0 :         crit.tempR = htole32(temp);
    3666             :         DPRINTF(("setting critical temperature to %d\n", temp));
    3667           0 :         return iwn_cmd(sc, IWN_CMD_SET_CRITICAL_TEMP, &crit, sizeof crit, 0);
    3668           0 : }
    3669             : 
    3670             : int
    3671           0 : iwn_set_timing(struct iwn_softc *sc, struct ieee80211_node *ni)
    3672             : {
    3673           0 :         struct iwn_cmd_timing cmd;
    3674             :         uint64_t val, mod;
    3675             : 
    3676           0 :         memset(&cmd, 0, sizeof cmd);
    3677           0 :         memcpy(&cmd.tstamp, ni->ni_tstamp, sizeof (uint64_t));
    3678           0 :         cmd.bintval = htole16(ni->ni_intval);
    3679           0 :         cmd.lintval = htole16(10);
    3680             : 
    3681             :         /* Compute remaining time until next beacon. */
    3682           0 :         val = (uint64_t)ni->ni_intval * IEEE80211_DUR_TU;
    3683           0 :         mod = letoh64(cmd.tstamp) % val;
    3684           0 :         cmd.binitval = htole32((uint32_t)(val - mod));
    3685             : 
    3686             :         DPRINTF(("timing bintval=%u, tstamp=%llu, init=%u\n",
    3687             :             ni->ni_intval, letoh64(cmd.tstamp), (uint32_t)(val - mod)));
    3688             : 
    3689           0 :         return iwn_cmd(sc, IWN_CMD_TIMING, &cmd, sizeof cmd, 1);
    3690           0 : }
    3691             : 
    3692             : void
    3693           0 : iwn4965_power_calibration(struct iwn_softc *sc, int temp)
    3694             : {
    3695             :         /* Adjust TX power if need be (delta >= 3 degC). */
    3696             :         DPRINTF(("temperature %d->%d\n", sc->temp, temp));
    3697           0 :         if (abs(temp - sc->temp) >= 3) {
    3698             :                 /* Record temperature of last calibration. */
    3699           0 :                 sc->temp = temp;
    3700           0 :                 (void)iwn4965_set_txpower(sc, 1);
    3701           0 :         }
    3702           0 : }
    3703             : 
    3704             : /*
    3705             :  * Set TX power for current channel (each rate has its own power settings).
    3706             :  * This function takes into account the regulatory information from EEPROM,
    3707             :  * the current temperature and the current voltage.
    3708             :  */
    3709             : int
    3710           0 : iwn4965_set_txpower(struct iwn_softc *sc, int async)
    3711             : {
    3712             : /* Fixed-point arithmetic division using a n-bit fractional part. */
    3713             : #define fdivround(a, b, n)      \
    3714             :         ((((1 << n) * (a)) / (b) + (1 << n) / 2) / (1 << n))
    3715             : /* Linear interpolation. */
    3716             : #define interpolate(x, x1, y1, x2, y2, n)       \
    3717             :         ((y1) + fdivround(((int)(x) - (x1)) * ((y2) - (y1)), (x2) - (x1), n))
    3718             : 
    3719             :         static const int tdiv[IWN_NATTEN_GROUPS] = { 9, 8, 8, 8, 6 };
    3720           0 :         struct ieee80211com *ic = &sc->sc_ic;
    3721           0 :         struct iwn_ucode_info *uc = &sc->ucode_info;
    3722             :         struct ieee80211_channel *ch;
    3723           0 :         struct iwn4965_cmd_txpower cmd;
    3724             :         struct iwn4965_eeprom_chan_samples *chans;
    3725             :         const uint8_t *rf_gain, *dsp_gain;
    3726             :         int32_t vdiff, tdiff;
    3727             :         int i, c, grp, maxpwr;
    3728             :         uint8_t chan;
    3729             : 
    3730             :         /* Retrieve current channel from last RXON. */
    3731           0 :         chan = sc->rxon.chan;
    3732             :         DPRINTF(("setting TX power for channel %d\n", chan));
    3733           0 :         ch = &ic->ic_channels[chan];
    3734             : 
    3735           0 :         memset(&cmd, 0, sizeof cmd);
    3736           0 :         cmd.band = IEEE80211_IS_CHAN_5GHZ(ch) ? 0 : 1;
    3737           0 :         cmd.chan = chan;
    3738             : 
    3739           0 :         if (IEEE80211_IS_CHAN_5GHZ(ch)) {
    3740           0 :                 maxpwr   = sc->maxpwr5GHz;
    3741             :                 rf_gain  = iwn4965_rf_gain_5ghz;
    3742             :                 dsp_gain = iwn4965_dsp_gain_5ghz;
    3743           0 :         } else {
    3744           0 :                 maxpwr   = sc->maxpwr2GHz;
    3745             :                 rf_gain  = iwn4965_rf_gain_2ghz;
    3746             :                 dsp_gain = iwn4965_dsp_gain_2ghz;
    3747             :         }
    3748             : 
    3749             :         /* Compute voltage compensation. */
    3750           0 :         vdiff = ((int32_t)letoh32(uc->volt) - sc->eeprom_voltage) / 7;
    3751           0 :         if (vdiff > 0)
    3752           0 :                 vdiff *= 2;
    3753           0 :         if (abs(vdiff) > 2)
    3754           0 :                 vdiff = 0;
    3755             :         DPRINTF(("voltage compensation=%d (UCODE=%d, EEPROM=%d)\n",
    3756             :             vdiff, letoh32(uc->volt), sc->eeprom_voltage));
    3757             : 
    3758             :         /* Get channel attenuation group. */
    3759           0 :         if (chan <= 20)              /* 1-20 */
    3760           0 :                 grp = 4;
    3761           0 :         else if (chan <= 43) /* 34-43 */
    3762           0 :                 grp = 0;
    3763           0 :         else if (chan <= 70) /* 44-70 */
    3764           0 :                 grp = 1;
    3765           0 :         else if (chan <= 124)        /* 71-124 */
    3766           0 :                 grp = 2;
    3767             :         else                    /* 125-200 */
    3768             :                 grp = 3;
    3769             :         DPRINTF(("chan %d, attenuation group=%d\n", chan, grp));
    3770             : 
    3771             :         /* Get channel sub-band. */
    3772           0 :         for (i = 0; i < IWN_NBANDS; i++)
    3773           0 :                 if (sc->bands[i].lo != 0 &&
    3774           0 :                     sc->bands[i].lo <= chan && chan <= sc->bands[i].hi)
    3775             :                         break;
    3776           0 :         if (i == IWN_NBANDS)    /* Can't happen in real-life. */
    3777           0 :                 return EINVAL;
    3778           0 :         chans = sc->bands[i].chans;
    3779             :         DPRINTF(("chan %d sub-band=%d\n", chan, i));
    3780             : 
    3781           0 :         for (c = 0; c < 2; c++) {
    3782             :                 uint8_t power, gain, temp;
    3783             :                 int maxchpwr, pwr, ridx, idx;
    3784             : 
    3785           0 :                 power = interpolate(chan,
    3786             :                     chans[0].num, chans[0].samples[c][1].power,
    3787             :                     chans[1].num, chans[1].samples[c][1].power, 1);
    3788           0 :                 gain  = interpolate(chan,
    3789             :                     chans[0].num, chans[0].samples[c][1].gain,
    3790             :                     chans[1].num, chans[1].samples[c][1].gain, 1);
    3791           0 :                 temp  = interpolate(chan,
    3792             :                     chans[0].num, chans[0].samples[c][1].temp,
    3793             :                     chans[1].num, chans[1].samples[c][1].temp, 1);
    3794             :                 DPRINTF(("TX chain %d: power=%d gain=%d temp=%d\n",
    3795             :                     c, power, gain, temp));
    3796             : 
    3797             :                 /* Compute temperature compensation. */
    3798           0 :                 tdiff = ((sc->temp - temp) * 2) / tdiv[grp];
    3799             :                 DPRINTF(("temperature compensation=%d (current=%d, "
    3800             :                     "EEPROM=%d)\n", tdiff, sc->temp, temp));
    3801             : 
    3802           0 :                 for (ridx = 0; ridx <= IWN_RIDX_MAX; ridx++) {
    3803             :                         /* Convert dBm to half-dBm. */
    3804           0 :                         maxchpwr = sc->maxpwr[chan] * 2;
    3805             : #ifdef notyet
    3806             :                         if (ridx > iwn_mcs2ridx[7] && ridx < iwn_mcs2ridx[16])
    3807             :                                 maxchpwr -= 6;  /* MIMO 2T: -3dB */
    3808             : #endif
    3809             : 
    3810             :                         pwr = maxpwr;
    3811             : 
    3812             :                         /* Adjust TX power based on rate. */
    3813           0 :                         if ((ridx % 8) == 5)
    3814           0 :                                 pwr -= 15;      /* OFDM48: -7.5dB */
    3815           0 :                         else if ((ridx % 8) == 6)
    3816           0 :                                 pwr -= 17;      /* OFDM54: -8.5dB */
    3817           0 :                         else if ((ridx % 8) == 7)
    3818           0 :                                 pwr -= 20;      /* OFDM60: -10dB */
    3819             :                         else
    3820           0 :                                 pwr -= 10;      /* Others: -5dB */
    3821             : 
    3822             :                         /* Do not exceed channel max TX power. */
    3823           0 :                         if (pwr > maxchpwr)
    3824           0 :                                 pwr = maxchpwr;
    3825             : 
    3826           0 :                         idx = gain - (pwr - power) - tdiff - vdiff;
    3827           0 :                         if (ridx > iwn_mcs2ridx[7]) /* MIMO */
    3828           0 :                                 idx += (int32_t)letoh32(uc->atten[grp][c]);
    3829             : 
    3830           0 :                         if (cmd.band == 0)
    3831           0 :                                 idx += 9;       /* 5GHz */
    3832           0 :                         if (ridx == IWN_RIDX_MAX)
    3833           0 :                                 idx += 5;       /* CCK */
    3834             : 
    3835             :                         /* Make sure idx stays in a valid range. */
    3836           0 :                         if (idx < 0)
    3837           0 :                                 idx = 0;
    3838           0 :                         else if (idx > IWN4965_MAX_PWR_INDEX)
    3839           0 :                                 idx = IWN4965_MAX_PWR_INDEX;
    3840             : 
    3841             :                         DPRINTF(("TX chain %d, rate idx %d: power=%d\n",
    3842             :                             c, ridx, idx));
    3843           0 :                         cmd.power[ridx].rf_gain[c] = rf_gain[idx];
    3844           0 :                         cmd.power[ridx].dsp_gain[c] = dsp_gain[idx];
    3845             :                 }
    3846             :         }
    3847             : 
    3848             :         DPRINTF(("setting TX power for chan %d\n", chan));
    3849           0 :         return iwn_cmd(sc, IWN_CMD_TXPOWER, &cmd, sizeof cmd, async);
    3850             : 
    3851             : #undef interpolate
    3852             : #undef fdivround
    3853           0 : }
    3854             : 
    3855             : int
    3856           0 : iwn5000_set_txpower(struct iwn_softc *sc, int async)
    3857             : {
    3858           0 :         struct iwn5000_cmd_txpower cmd;
    3859             : 
    3860             :         /*
    3861             :          * TX power calibration is handled automatically by the firmware
    3862             :          * for 5000 Series.
    3863             :          */
    3864           0 :         memset(&cmd, 0, sizeof cmd);
    3865           0 :         cmd.global_limit = 2 * IWN5000_TXPOWER_MAX_DBM; /* 16 dBm */
    3866           0 :         cmd.flags = IWN5000_TXPOWER_NO_CLOSED;
    3867           0 :         cmd.srv_limit = IWN5000_TXPOWER_AUTO;
    3868             :         DPRINTF(("setting TX power\n"));
    3869           0 :         return iwn_cmd(sc, IWN_CMD_TXPOWER_DBM, &cmd, sizeof cmd, async);
    3870           0 : }
    3871             : 
    3872             : /*
    3873             :  * Retrieve the maximum RSSI (in dBm) among receivers.
    3874             :  */
    3875             : int
    3876           0 : iwn4965_get_rssi(const struct iwn_rx_stat *stat)
    3877             : {
    3878           0 :         struct iwn4965_rx_phystat *phy = (void *)stat->phybuf;
    3879             :         uint8_t mask, agc;
    3880             :         int rssi;
    3881             : 
    3882           0 :         mask = (letoh16(phy->antenna) >> 4) & IWN_ANT_ABC;
    3883           0 :         agc  = (letoh16(phy->agc) >> 7) & 0x7f;
    3884             : 
    3885             :         rssi = 0;
    3886           0 :         if (mask & IWN_ANT_A)
    3887           0 :                 rssi = MAX(rssi, phy->rssi[0]);
    3888           0 :         if (mask & IWN_ANT_B)
    3889           0 :                 rssi = MAX(rssi, phy->rssi[2]);
    3890           0 :         if (mask & IWN_ANT_C)
    3891           0 :                 rssi = MAX(rssi, phy->rssi[4]);
    3892             : 
    3893           0 :         return rssi - agc - IWN_RSSI_TO_DBM;
    3894             : }
    3895             : 
    3896             : int
    3897           0 : iwn5000_get_rssi(const struct iwn_rx_stat *stat)
    3898             : {
    3899           0 :         struct iwn5000_rx_phystat *phy = (void *)stat->phybuf;
    3900             :         uint8_t agc;
    3901             :         int rssi;
    3902             : 
    3903           0 :         agc = (letoh32(phy->agc) >> 9) & 0x7f;
    3904             : 
    3905           0 :         rssi = MAX(letoh16(phy->rssi[0]) & 0xff,
    3906             :                    letoh16(phy->rssi[1]) & 0xff);
    3907           0 :         rssi = MAX(letoh16(phy->rssi[2]) & 0xff, rssi);
    3908             : 
    3909           0 :         return rssi - agc - IWN_RSSI_TO_DBM;
    3910             : }
    3911             : 
    3912             : /*
    3913             :  * Retrieve the average noise (in dBm) among receivers.
    3914             :  */
    3915             : int
    3916           0 : iwn_get_noise(const struct iwn_rx_general_stats *stats)
    3917             : {
    3918             :         int i, total, nbant, noise;
    3919             : 
    3920             :         total = nbant = 0;
    3921           0 :         for (i = 0; i < 3; i++) {
    3922           0 :                 if ((noise = letoh32(stats->noise[i]) & 0xff) == 0)
    3923             :                         continue;
    3924           0 :                 total += noise;
    3925           0 :                 nbant++;
    3926           0 :         }
    3927             :         /* There should be at least one antenna but check anyway. */
    3928           0 :         return (nbant == 0) ? -127 : (total / nbant) - 107;
    3929             : }
    3930             : 
    3931             : /*
    3932             :  * Compute temperature (in degC) from last received statistics.
    3933             :  */
    3934             : int
    3935           0 : iwn4965_get_temperature(struct iwn_softc *sc)
    3936             : {
    3937           0 :         struct iwn_ucode_info *uc = &sc->ucode_info;
    3938             :         int32_t r1, r2, r3, r4, temp;
    3939             : 
    3940           0 :         r1 = letoh32(uc->temp[0].chan20MHz);
    3941           0 :         r2 = letoh32(uc->temp[1].chan20MHz);
    3942           0 :         r3 = letoh32(uc->temp[2].chan20MHz);
    3943           0 :         r4 = letoh32(sc->rawtemp);
    3944             : 
    3945           0 :         if (r1 == r3)   /* Prevents division by 0 (should not happen). */
    3946           0 :                 return 0;
    3947             : 
    3948             :         /* Sign-extend 23-bit R4 value to 32-bit. */
    3949           0 :         r4 = ((r4 & 0xffffff) ^ 0x800000) - 0x800000;
    3950             :         /* Compute temperature in Kelvin. */
    3951           0 :         temp = (259 * (r4 - r2)) / (r3 - r1);
    3952           0 :         temp = (temp * 97) / 100 + 8;
    3953             : 
    3954             :         DPRINTF(("temperature %dK/%dC\n", temp, IWN_KTOC(temp)));
    3955           0 :         return IWN_KTOC(temp);
    3956           0 : }
    3957             : 
    3958             : int
    3959           0 : iwn5000_get_temperature(struct iwn_softc *sc)
    3960             : {
    3961             :         int32_t temp;
    3962             : 
    3963             :         /*
    3964             :          * Temperature is not used by the driver for 5000 Series because
    3965             :          * TX power calibration is handled by firmware.
    3966             :          */
    3967           0 :         temp = letoh32(sc->rawtemp);
    3968           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_5150) {
    3969           0 :                 temp = (temp / -5) + sc->temp_off;
    3970           0 :                 temp = IWN_KTOC(temp);
    3971           0 :         }
    3972           0 :         return temp;
    3973             : }
    3974             : 
    3975             : /*
    3976             :  * Initialize sensitivity calibration state machine.
    3977             :  */
    3978             : int
    3979           0 : iwn_init_sensitivity(struct iwn_softc *sc)
    3980             : {
    3981           0 :         struct iwn_ops *ops = &sc->ops;
    3982           0 :         struct iwn_calib_state *calib = &sc->calib;
    3983           0 :         uint32_t flags;
    3984             :         int error;
    3985             : 
    3986             :         /* Reset calibration state machine. */
    3987           0 :         memset(calib, 0, sizeof (*calib));
    3988           0 :         calib->state = IWN_CALIB_STATE_INIT;
    3989           0 :         calib->cck_state = IWN_CCK_STATE_HIFA;
    3990             :         /* Set initial correlation values. */
    3991           0 :         calib->ofdm_x1     = sc->limits->min_ofdm_x1;
    3992           0 :         calib->ofdm_mrc_x1 = sc->limits->min_ofdm_mrc_x1;
    3993           0 :         calib->ofdm_x4     = sc->limits->min_ofdm_x4;
    3994           0 :         calib->ofdm_mrc_x4 = sc->limits->min_ofdm_mrc_x4;
    3995           0 :         calib->cck_x4      = 125;
    3996           0 :         calib->cck_mrc_x4  = sc->limits->min_cck_mrc_x4;
    3997           0 :         calib->energy_cck  = sc->limits->energy_cck;
    3998             : 
    3999             :         /* Write initial sensitivity. */
    4000           0 :         if ((error = iwn_send_sensitivity(sc)) != 0)
    4001           0 :                 return error;
    4002             : 
    4003             :         /* Write initial gains. */
    4004           0 :         if ((error = ops->init_gains(sc)) != 0)
    4005           0 :                 return error;
    4006             : 
    4007             :         /* Request statistics at each beacon interval. */
    4008           0 :         flags = 0;
    4009             :         DPRINTFN(2, ("sending request for statistics\n"));
    4010           0 :         return iwn_cmd(sc, IWN_CMD_GET_STATISTICS, &flags, sizeof flags, 1);
    4011           0 : }
    4012             : 
    4013             : /*
    4014             :  * Collect noise and RSSI statistics for the first 20 beacons received
    4015             :  * after association and use them to determine connected antennas and
    4016             :  * to set differential gains.
    4017             :  */
    4018             : void
    4019           0 : iwn_collect_noise(struct iwn_softc *sc,
    4020             :     const struct iwn_rx_general_stats *stats)
    4021             : {
    4022           0 :         struct iwn_ops *ops = &sc->ops;
    4023           0 :         struct iwn_calib_state *calib = &sc->calib;
    4024             :         uint32_t val;
    4025             :         int i;
    4026             : 
    4027             :         /* Accumulate RSSI and noise for all 3 antennas. */
    4028           0 :         for (i = 0; i < 3; i++) {
    4029           0 :                 calib->rssi[i] += letoh32(stats->rssi[i]) & 0xff;
    4030           0 :                 calib->noise[i] += letoh32(stats->noise[i]) & 0xff;
    4031             :         }
    4032             :         /* NB: We update differential gains only once after 20 beacons. */
    4033           0 :         if (++calib->nbeacons < 20)
    4034           0 :                 return;
    4035             : 
    4036             :         /* Determine highest average RSSI. */
    4037           0 :         val = MAX(calib->rssi[0], calib->rssi[1]);
    4038           0 :         val = MAX(calib->rssi[2], val);
    4039             : 
    4040             :         /* Determine which antennas are connected. */
    4041           0 :         sc->chainmask = sc->rxchainmask;
    4042           0 :         for (i = 0; i < 3; i++)
    4043           0 :                 if (val - calib->rssi[i] > 15 * 20)
    4044           0 :                         sc->chainmask &= ~(1 << i);
    4045             :         DPRINTF(("RX chains mask: theoretical=0x%x, actual=0x%x\n",
    4046             :             sc->rxchainmask, sc->chainmask));
    4047             : 
    4048             :         /* If none of the TX antennas are connected, keep at least one. */
    4049           0 :         if ((sc->chainmask & sc->txchainmask) == 0)
    4050           0 :                 sc->chainmask |= IWN_LSB(sc->txchainmask);
    4051             : 
    4052           0 :         (void)ops->set_gains(sc);
    4053           0 :         calib->state = IWN_CALIB_STATE_RUN;
    4054             : 
    4055             : #ifdef notyet
    4056             :         /* XXX Disable RX chains with no antennas connected. */
    4057             :         sc->rxon.rxchain = htole16(IWN_RXCHAIN_SEL(sc->chainmask));
    4058             :         (void)iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1);
    4059             : #endif
    4060             : 
    4061             :         /* Enable power-saving mode if requested by user. */
    4062           0 :         if (sc->sc_ic.ic_flags & IEEE80211_F_PMGTON)
    4063           0 :                 (void)iwn_set_pslevel(sc, 0, 3, 1);
    4064           0 : }
    4065             : 
    4066             : int
    4067           0 : iwn4965_init_gains(struct iwn_softc *sc)
    4068             : {
    4069           0 :         struct iwn_phy_calib_gain cmd;
    4070             : 
    4071           0 :         memset(&cmd, 0, sizeof cmd);
    4072           0 :         cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN;
    4073             :         /* Differential gains initially set to 0 for all 3 antennas. */
    4074             :         DPRINTF(("setting initial differential gains\n"));
    4075           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
    4076           0 : }
    4077             : 
    4078             : int
    4079           0 : iwn5000_init_gains(struct iwn_softc *sc)
    4080             : {
    4081           0 :         struct iwn_phy_calib cmd;
    4082             : 
    4083           0 :         memset(&cmd, 0, sizeof cmd);
    4084           0 :         cmd.code = sc->reset_noise_gain;
    4085           0 :         cmd.ngroups = 1;
    4086           0 :         cmd.isvalid = 1;
    4087             :         DPRINTF(("setting initial differential gains\n"));
    4088           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
    4089           0 : }
    4090             : 
    4091             : int
    4092           0 : iwn4965_set_gains(struct iwn_softc *sc)
    4093             : {
    4094           0 :         struct iwn_calib_state *calib = &sc->calib;
    4095           0 :         struct iwn_phy_calib_gain cmd;
    4096             :         int i, delta, noise;
    4097             : 
    4098             :         /* Get minimal noise among connected antennas. */
    4099             :         noise = INT_MAX;        /* NB: There's at least one antenna. */
    4100           0 :         for (i = 0; i < 3; i++)
    4101           0 :                 if (sc->chainmask & (1 << i))
    4102           0 :                         noise = MIN(calib->noise[i], noise);
    4103             : 
    4104           0 :         memset(&cmd, 0, sizeof cmd);
    4105           0 :         cmd.code = IWN4965_PHY_CALIB_DIFF_GAIN;
    4106             :         /* Set differential gains for connected antennas. */
    4107           0 :         for (i = 0; i < 3; i++) {
    4108           0 :                 if (sc->chainmask & (1 << i)) {
    4109             :                         /* Compute attenuation (in unit of 1.5dB). */
    4110           0 :                         delta = (noise - (int32_t)calib->noise[i]) / 30;
    4111             :                         /* NB: delta <= 0 */
    4112             :                         /* Limit to [-4.5dB,0]. */
    4113           0 :                         cmd.gain[i] = MIN(abs(delta), 3);
    4114           0 :                         if (delta < 0)
    4115           0 :                                 cmd.gain[i] |= 1 << 2;    /* sign bit */
    4116             :                 }
    4117             :         }
    4118             :         DPRINTF(("setting differential gains Ant A/B/C: %x/%x/%x (%x)\n",
    4119             :             cmd.gain[0], cmd.gain[1], cmd.gain[2], sc->chainmask));
    4120           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
    4121           0 : }
    4122             : 
    4123             : int
    4124           0 : iwn5000_set_gains(struct iwn_softc *sc)
    4125             : {
    4126           0 :         struct iwn_calib_state *calib = &sc->calib;
    4127           0 :         struct iwn_phy_calib_gain cmd;
    4128             :         int i, ant, div, delta;
    4129             : 
    4130             :         /* We collected 20 beacons and !=6050 need a 1.5 factor. */
    4131           0 :         div = (sc->hw_type == IWN_HW_REV_TYPE_6050) ? 20 : 30;
    4132             : 
    4133           0 :         memset(&cmd, 0, sizeof cmd);
    4134           0 :         cmd.code = sc->noise_gain;
    4135           0 :         cmd.ngroups = 1;
    4136           0 :         cmd.isvalid = 1;
    4137             :         /* Get first available RX antenna as referential. */
    4138           0 :         ant = IWN_LSB(sc->rxchainmask);
    4139             :         /* Set differential gains for other antennas. */
    4140           0 :         for (i = ant + 1; i < 3; i++) {
    4141           0 :                 if (sc->chainmask & (1 << i)) {
    4142             :                         /* The delta is relative to antenna "ant". */
    4143           0 :                         delta = ((int32_t)calib->noise[ant] -
    4144           0 :                             (int32_t)calib->noise[i]) / div;
    4145             :                         /* Limit to [-4.5dB,+4.5dB]. */
    4146           0 :                         cmd.gain[i - 1] = MIN(abs(delta), 3);
    4147           0 :                         if (delta < 0)
    4148           0 :                                 cmd.gain[i - 1] |= 1 << 2;        /* sign bit */
    4149             :                 }
    4150             :         }
    4151             :         DPRINTF(("setting differential gains: %x/%x (%x)\n",
    4152             :             cmd.gain[0], cmd.gain[1], sc->chainmask));
    4153           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 1);
    4154           0 : }
    4155             : 
    4156             : /*
    4157             :  * Tune RF RX sensitivity based on the number of false alarms detected
    4158             :  * during the last beacon period.
    4159             :  */
    4160             : void
    4161           0 : iwn_tune_sensitivity(struct iwn_softc *sc, const struct iwn_rx_stats *stats)
    4162             : {
    4163             : #define inc(val, inc, max)                      \
    4164             :         if ((val) < (max)) {                 \
    4165             :                 if ((val) < (max) - (inc))   \
    4166             :                         (val) += (inc);         \
    4167             :                 else                            \
    4168             :                         (val) = (max);          \
    4169             :                 needs_update = 1;               \
    4170             :         }
    4171             : #define dec(val, dec, min)                      \
    4172             :         if ((val) > (min)) {                 \
    4173             :                 if ((val) > (min) + (dec))   \
    4174             :                         (val) -= (dec);         \
    4175             :                 else                            \
    4176             :                         (val) = (min);          \
    4177             :                 needs_update = 1;               \
    4178             :         }
    4179             : 
    4180           0 :         const struct iwn_sensitivity_limits *limits = sc->limits;
    4181           0 :         struct iwn_calib_state *calib = &sc->calib;
    4182             :         uint32_t val, rxena, fa;
    4183           0 :         uint32_t energy[3], energy_min;
    4184           0 :         uint8_t noise[3], noise_ref;
    4185             :         int i, needs_update = 0;
    4186             : 
    4187             :         /* Check that we've been enabled long enough. */
    4188           0 :         if ((rxena = letoh32(stats->general.load)) == 0)
    4189           0 :                 return;
    4190             : 
    4191             :         /* Compute number of false alarms since last call for OFDM. */
    4192           0 :         fa  = letoh32(stats->ofdm.bad_plcp) - calib->bad_plcp_ofdm;
    4193           0 :         fa += letoh32(stats->ofdm.fa) - calib->fa_ofdm;
    4194           0 :         fa *= 200 * IEEE80211_DUR_TU;   /* 200TU */
    4195             : 
    4196             :         /* Save counters values for next call. */
    4197           0 :         calib->bad_plcp_ofdm = letoh32(stats->ofdm.bad_plcp);
    4198           0 :         calib->fa_ofdm = letoh32(stats->ofdm.fa);
    4199             : 
    4200           0 :         if (fa > 50 * rxena) {
    4201             :                 /* High false alarm count, decrease sensitivity. */
    4202             :                 DPRINTFN(2, ("OFDM high false alarm count: %u\n", fa));
    4203           0 :                 inc(calib->ofdm_x1,     1, limits->max_ofdm_x1);
    4204           0 :                 inc(calib->ofdm_mrc_x1, 1, limits->max_ofdm_mrc_x1);
    4205           0 :                 inc(calib->ofdm_x4,     1, limits->max_ofdm_x4);
    4206           0 :                 inc(calib->ofdm_mrc_x4, 1, limits->max_ofdm_mrc_x4);
    4207             : 
    4208           0 :         } else if (fa < 5 * rxena) {
    4209             :                 /* Low false alarm count, increase sensitivity. */
    4210             :                 DPRINTFN(2, ("OFDM low false alarm count: %u\n", fa));
    4211           0 :                 dec(calib->ofdm_x1,     1, limits->min_ofdm_x1);
    4212           0 :                 dec(calib->ofdm_mrc_x1, 1, limits->min_ofdm_mrc_x1);
    4213           0 :                 dec(calib->ofdm_x4,     1, limits->min_ofdm_x4);
    4214           0 :                 dec(calib->ofdm_mrc_x4, 1, limits->min_ofdm_mrc_x4);
    4215             :         }
    4216             : 
    4217             :         /* Compute maximum noise among 3 receivers. */
    4218           0 :         for (i = 0; i < 3; i++)
    4219           0 :                 noise[i] = (letoh32(stats->general.noise[i]) >> 8) & 0xff;
    4220           0 :         val = MAX(noise[0], noise[1]);
    4221           0 :         val = MAX(noise[2], val);
    4222             :         /* Insert it into our samples table. */
    4223           0 :         calib->noise_samples[calib->cur_noise_sample] = val;
    4224           0 :         calib->cur_noise_sample = (calib->cur_noise_sample + 1) % 20;
    4225             : 
    4226             :         /* Compute maximum noise among last 20 samples. */
    4227           0 :         noise_ref = calib->noise_samples[0];
    4228           0 :         for (i = 1; i < 20; i++)
    4229           0 :                 noise_ref = MAX(noise_ref, calib->noise_samples[i]);
    4230             : 
    4231             :         /* Compute maximum energy among 3 receivers. */
    4232           0 :         for (i = 0; i < 3; i++)
    4233           0 :                 energy[i] = letoh32(stats->general.energy[i]);
    4234           0 :         val = MIN(energy[0], energy[1]);
    4235           0 :         val = MIN(energy[2], val);
    4236             :         /* Insert it into our samples table. */
    4237           0 :         calib->energy_samples[calib->cur_energy_sample] = val;
    4238           0 :         calib->cur_energy_sample = (calib->cur_energy_sample + 1) % 10;
    4239             : 
    4240             :         /* Compute minimum energy among last 10 samples. */
    4241           0 :         energy_min = calib->energy_samples[0];
    4242           0 :         for (i = 1; i < 10; i++)
    4243           0 :                 energy_min = MAX(energy_min, calib->energy_samples[i]);
    4244           0 :         energy_min += 6;
    4245             : 
    4246             :         /* Compute number of false alarms since last call for CCK. */
    4247           0 :         fa  = letoh32(stats->cck.bad_plcp) - calib->bad_plcp_cck;
    4248           0 :         fa += letoh32(stats->cck.fa) - calib->fa_cck;
    4249           0 :         fa *= 200 * IEEE80211_DUR_TU;   /* 200TU */
    4250             : 
    4251             :         /* Save counters values for next call. */
    4252           0 :         calib->bad_plcp_cck = letoh32(stats->cck.bad_plcp);
    4253           0 :         calib->fa_cck = letoh32(stats->cck.fa);
    4254             : 
    4255           0 :         if (fa > 50 * rxena) {
    4256             :                 /* High false alarm count, decrease sensitivity. */
    4257             :                 DPRINTFN(2, ("CCK high false alarm count: %u\n", fa));
    4258           0 :                 calib->cck_state = IWN_CCK_STATE_HIFA;
    4259           0 :                 calib->low_fa = 0;
    4260             : 
    4261           0 :                 if (calib->cck_x4 > 160) {
    4262           0 :                         calib->noise_ref = noise_ref;
    4263           0 :                         if (calib->energy_cck > 2)
    4264           0 :                                 dec(calib->energy_cck, 2, energy_min);
    4265             :                 }
    4266           0 :                 if (calib->cck_x4 < 160) {
    4267           0 :                         calib->cck_x4 = 161;
    4268             :                         needs_update = 1;
    4269           0 :                 } else
    4270           0 :                         inc(calib->cck_x4, 3, limits->max_cck_x4);
    4271             : 
    4272           0 :                 inc(calib->cck_mrc_x4, 3, limits->max_cck_mrc_x4);
    4273             : 
    4274           0 :         } else if (fa < 5 * rxena) {
    4275             :                 /* Low false alarm count, increase sensitivity. */
    4276             :                 DPRINTFN(2, ("CCK low false alarm count: %u\n", fa));
    4277           0 :                 calib->cck_state = IWN_CCK_STATE_LOFA;
    4278           0 :                 calib->low_fa++;
    4279             : 
    4280           0 :                 if (calib->cck_state != IWN_CCK_STATE_INIT &&
    4281           0 :                     (((int32_t)calib->noise_ref - (int32_t)noise_ref) > 2 ||
    4282           0 :                      calib->low_fa > 100)) {
    4283           0 :                         inc(calib->energy_cck, 2, limits->min_energy_cck);
    4284           0 :                         dec(calib->cck_x4,     3, limits->min_cck_x4);
    4285           0 :                         dec(calib->cck_mrc_x4, 3, limits->min_cck_mrc_x4);
    4286             :                 }
    4287             :         } else {
    4288             :                 /* Not worth to increase or decrease sensitivity. */
    4289             :                 DPRINTFN(2, ("CCK normal false alarm count: %u\n", fa));
    4290           0 :                 calib->low_fa = 0;
    4291           0 :                 calib->noise_ref = noise_ref;
    4292             : 
    4293           0 :                 if (calib->cck_state == IWN_CCK_STATE_HIFA) {
    4294             :                         /* Previous interval had many false alarms. */
    4295           0 :                         dec(calib->energy_cck, 8, energy_min);
    4296             :                 }
    4297           0 :                 calib->cck_state = IWN_CCK_STATE_INIT;
    4298             :         }
    4299             : 
    4300           0 :         if (needs_update)
    4301           0 :                 (void)iwn_send_sensitivity(sc);
    4302             : #undef dec
    4303             : #undef inc
    4304           0 : }
    4305             : 
    4306             : int
    4307           0 : iwn_send_sensitivity(struct iwn_softc *sc)
    4308             : {
    4309           0 :         struct iwn_calib_state *calib = &sc->calib;
    4310           0 :         struct iwn_enhanced_sensitivity_cmd cmd;
    4311             :         int len;
    4312             : 
    4313           0 :         memset(&cmd, 0, sizeof cmd);
    4314             :         len = sizeof (struct iwn_sensitivity_cmd);
    4315           0 :         cmd.which = IWN_SENSITIVITY_WORKTBL;
    4316             :         /* OFDM modulation. */
    4317           0 :         cmd.corr_ofdm_x1       = htole16(calib->ofdm_x1);
    4318           0 :         cmd.corr_ofdm_mrc_x1   = htole16(calib->ofdm_mrc_x1);
    4319           0 :         cmd.corr_ofdm_x4       = htole16(calib->ofdm_x4);
    4320           0 :         cmd.corr_ofdm_mrc_x4   = htole16(calib->ofdm_mrc_x4);
    4321           0 :         cmd.energy_ofdm        = htole16(sc->limits->energy_ofdm);
    4322           0 :         cmd.energy_ofdm_th     = htole16(62);
    4323             :         /* CCK modulation. */
    4324           0 :         cmd.corr_cck_x4        = htole16(calib->cck_x4);
    4325           0 :         cmd.corr_cck_mrc_x4    = htole16(calib->cck_mrc_x4);
    4326           0 :         cmd.energy_cck         = htole16(calib->energy_cck);
    4327             :         /* Barker modulation: use default values. */
    4328           0 :         cmd.corr_barker        = htole16(190);
    4329           0 :         cmd.corr_barker_mrc    = htole16(390);
    4330           0 :         if (!(sc->sc_flags & IWN_FLAG_ENH_SENS))
    4331             :                 goto send;
    4332             :         /* Enhanced sensitivity settings. */
    4333             :         len = sizeof (struct iwn_enhanced_sensitivity_cmd);
    4334           0 :         cmd.ofdm_det_slope_mrc = htole16(668);
    4335           0 :         cmd.ofdm_det_icept_mrc = htole16(4);
    4336           0 :         cmd.ofdm_det_slope     = htole16(486);
    4337           0 :         cmd.ofdm_det_icept     = htole16(37);
    4338           0 :         cmd.cck_det_slope_mrc  = htole16(853);
    4339           0 :         cmd.cck_det_icept_mrc  = htole16(4);
    4340           0 :         cmd.cck_det_slope      = htole16(476);
    4341           0 :         cmd.cck_det_icept      = htole16(99);
    4342             : send:
    4343           0 :         return iwn_cmd(sc, IWN_CMD_SET_SENSITIVITY, &cmd, len, 1);
    4344           0 : }
    4345             : 
    4346             : /*
    4347             :  * Set STA mode power saving level (between 0 and 5).
    4348             :  * Level 0 is CAM (Continuously Aware Mode), 5 is for maximum power saving.
    4349             :  */
    4350             : int
    4351           0 : iwn_set_pslevel(struct iwn_softc *sc, int dtim, int level, int async)
    4352             : {
    4353           0 :         struct iwn_pmgt_cmd cmd;
    4354             :         const struct iwn_pmgt *pmgt;
    4355             :         uint32_t max, skip_dtim;
    4356             :         pcireg_t reg;
    4357             :         int i;
    4358             : 
    4359             :         /* Select which PS parameters to use. */
    4360           0 :         if (dtim <= 2)
    4361           0 :                 pmgt = &iwn_pmgt[0][level];
    4362           0 :         else if (dtim <= 10)
    4363           0 :                 pmgt = &iwn_pmgt[1][level];
    4364             :         else
    4365           0 :                 pmgt = &iwn_pmgt[2][level];
    4366             : 
    4367           0 :         memset(&cmd, 0, sizeof cmd);
    4368           0 :         if (level != 0) /* not CAM */
    4369           0 :                 cmd.flags |= htole16(IWN_PS_ALLOW_SLEEP);
    4370           0 :         if (level == 5)
    4371           0 :                 cmd.flags |= htole16(IWN_PS_FAST_PD);
    4372             :         /* Retrieve PCIe Active State Power Management (ASPM). */
    4373           0 :         reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag,
    4374           0 :             sc->sc_cap_off + PCI_PCIE_LCSR);
    4375           0 :         if (!(reg & PCI_PCIE_LCSR_ASPM_L0S))        /* L0s Entry disabled. */
    4376           0 :                 cmd.flags |= htole16(IWN_PS_PCI_PMGT);
    4377           0 :         cmd.rxtimeout = htole32(pmgt->rxtimeout * 1024);
    4378           0 :         cmd.txtimeout = htole32(pmgt->txtimeout * 1024);
    4379             : 
    4380           0 :         if (dtim == 0) {
    4381             :                 dtim = 1;
    4382             :                 skip_dtim = 0;
    4383           0 :         } else
    4384           0 :                 skip_dtim = pmgt->skip_dtim;
    4385           0 :         if (skip_dtim != 0) {
    4386           0 :                 cmd.flags |= htole16(IWN_PS_SLEEP_OVER_DTIM);
    4387           0 :                 max = pmgt->intval[4];
    4388           0 :                 if (max == (uint32_t)-1)
    4389           0 :                         max = dtim * (skip_dtim + 1);
    4390           0 :                 else if (max > dtim)
    4391           0 :                         max = (max / dtim) * dtim;
    4392             :         } else
    4393             :                 max = dtim;
    4394           0 :         for (i = 0; i < 5; i++)
    4395           0 :                 cmd.intval[i] = htole32(MIN(max, pmgt->intval[i]));
    4396             : 
    4397             :         DPRINTF(("setting power saving level to %d\n", level));
    4398           0 :         return iwn_cmd(sc, IWN_CMD_SET_POWER_MODE, &cmd, sizeof cmd, async);
    4399           0 : }
    4400             : 
    4401             : int
    4402           0 : iwn_send_btcoex(struct iwn_softc *sc)
    4403             : {
    4404           0 :         struct iwn_bluetooth cmd;
    4405             : 
    4406           0 :         memset(&cmd, 0, sizeof cmd);
    4407           0 :         cmd.flags = IWN_BT_COEX_CHAN_ANN | IWN_BT_COEX_BT_PRIO;
    4408           0 :         cmd.lead_time = IWN_BT_LEAD_TIME_DEF;
    4409           0 :         cmd.max_kill = IWN_BT_MAX_KILL_DEF;
    4410             :         DPRINTF(("configuring bluetooth coexistence\n"));
    4411           0 :         return iwn_cmd(sc, IWN_CMD_BT_COEX, &cmd, sizeof(cmd), 0);
    4412           0 : }
    4413             : 
    4414             : int
    4415           0 : iwn_send_advanced_btcoex(struct iwn_softc *sc)
    4416             : {
    4417             :         static const uint32_t btcoex_3wire[12] = {
    4418             :                 0xaaaaaaaa, 0xaaaaaaaa, 0xaeaaaaaa, 0xaaaaaaaa,
    4419             :                 0xcc00ff28, 0x0000aaaa, 0xcc00aaaa, 0x0000aaaa,
    4420             :                 0xc0004000, 0x00004000, 0xf0005000, 0xf0005000,
    4421             :         };
    4422           0 :         struct iwn_btcoex_priotable btprio;
    4423           0 :         struct iwn_btcoex_prot btprot;
    4424             :         int error, i;
    4425             : 
    4426           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_2030 ||
    4427           0 :             sc->hw_type == IWN_HW_REV_TYPE_135) {
    4428           0 :                 struct iwn2000_btcoex_config btconfig;
    4429             : 
    4430           0 :                 memset(&btconfig, 0, sizeof btconfig);
    4431           0 :                 btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION |
    4432             :                     (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) |
    4433             :                     IWN_BT_SYNC_2_BT_DISABLE;
    4434           0 :                 btconfig.max_kill = 5;
    4435           0 :                 btconfig.bt3_t7_timer = 1;
    4436           0 :                 btconfig.kill_ack = htole32(0xffff0000);
    4437           0 :                 btconfig.kill_cts = htole32(0xffff0000);
    4438           0 :                 btconfig.sample_time = 2;
    4439           0 :                 btconfig.bt3_t2_timer = 0xc;
    4440           0 :                 for (i = 0; i < 12; i++)
    4441           0 :                         btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
    4442           0 :                 btconfig.valid = htole16(0xff);
    4443           0 :                 btconfig.prio_boost = htole32(0xf0);
    4444             :                 DPRINTF(("configuring advanced bluetooth coexistence\n"));
    4445           0 :                 error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
    4446             :                     sizeof(btconfig), 1);
    4447           0 :                 if (error != 0)
    4448           0 :                         return (error);
    4449           0 :         } else {
    4450           0 :                 struct iwn6000_btcoex_config btconfig;
    4451             : 
    4452           0 :                 memset(&btconfig, 0, sizeof btconfig);
    4453           0 :                 btconfig.flags = IWN_BT_COEX6000_CHAN_INHIBITION |
    4454             :                     (IWN_BT_COEX6000_MODE_3W << IWN_BT_COEX6000_MODE_SHIFT) |
    4455             :                     IWN_BT_SYNC_2_BT_DISABLE;
    4456           0 :                 btconfig.max_kill = 5;
    4457           0 :                 btconfig.bt3_t7_timer = 1;
    4458           0 :                 btconfig.kill_ack = htole32(0xffff0000);
    4459           0 :                 btconfig.kill_cts = htole32(0xffff0000);
    4460           0 :                 btconfig.sample_time = 2;
    4461           0 :                 btconfig.bt3_t2_timer = 0xc;
    4462           0 :                 for (i = 0; i < 12; i++)
    4463           0 :                         btconfig.lookup_table[i] = htole32(btcoex_3wire[i]);
    4464           0 :                 btconfig.valid = htole16(0xff);
    4465           0 :                 btconfig.prio_boost = 0xf0;
    4466             :                 DPRINTF(("configuring advanced bluetooth coexistence\n"));
    4467           0 :                 error = iwn_cmd(sc, IWN_CMD_BT_COEX, &btconfig,
    4468             :                     sizeof(btconfig), 1);
    4469           0 :                 if (error != 0)
    4470           0 :                         return (error);
    4471           0 :         }
    4472             : 
    4473           0 :         memset(&btprio, 0, sizeof btprio);
    4474           0 :         btprio.calib_init1 = 0x6;
    4475           0 :         btprio.calib_init2 = 0x7;
    4476           0 :         btprio.calib_periodic_low1 = 0x2;
    4477           0 :         btprio.calib_periodic_low2 = 0x3;
    4478           0 :         btprio.calib_periodic_high1 = 0x4;
    4479           0 :         btprio.calib_periodic_high2 = 0x5;
    4480           0 :         btprio.dtim = 0x6;
    4481           0 :         btprio.scan52 = 0x8;
    4482           0 :         btprio.scan24 = 0xa;
    4483           0 :         error = iwn_cmd(sc, IWN_CMD_BT_COEX_PRIOTABLE, &btprio, sizeof(btprio),
    4484             :             1);
    4485           0 :         if (error != 0)
    4486           0 :                 return (error);
    4487             : 
    4488             :         /* Force BT state machine change */
    4489           0 :         memset(&btprot, 0, sizeof btprot);
    4490           0 :         btprot.open = 1;
    4491           0 :         btprot.type = 1;
    4492           0 :         error = iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1);
    4493           0 :         if (error != 0)
    4494           0 :                 return (error);
    4495             : 
    4496           0 :         btprot.open = 0;
    4497           0 :         return (iwn_cmd(sc, IWN_CMD_BT_COEX_PROT, &btprot, sizeof(btprot), 1));
    4498           0 : }
    4499             : 
    4500             : int
    4501           0 : iwn5000_runtime_calib(struct iwn_softc *sc)
    4502             : {
    4503           0 :         struct iwn5000_calib_config cmd;
    4504             : 
    4505           0 :         memset(&cmd, 0, sizeof cmd);
    4506           0 :         cmd.ucode.once.enable = 0xffffffff;
    4507           0 :         cmd.ucode.once.start = IWN5000_CALIB_DC;
    4508             :         DPRINTF(("configuring runtime calibration\n"));
    4509           0 :         return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0);
    4510           0 : }
    4511             : 
    4512             : int
    4513           0 : iwn_config(struct iwn_softc *sc)
    4514             : {
    4515           0 :         struct iwn_ops *ops = &sc->ops;
    4516           0 :         struct ieee80211com *ic = &sc->sc_ic;
    4517           0 :         struct ifnet *ifp = &ic->ic_if;
    4518           0 :         uint32_t txmask;
    4519             :         uint16_t rxchain;
    4520             :         int error, ridx;
    4521             : 
    4522             :         /* Set radio temperature sensor offset. */
    4523           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_6005) {
    4524           0 :                 error = iwn6000_temp_offset_calib(sc);
    4525           0 :                 if (error != 0) {
    4526           0 :                         printf("%s: could not set temperature offset\n",
    4527           0 :                             sc->sc_dev.dv_xname);
    4528           0 :                         return error;
    4529             :                 }
    4530             :         }
    4531             : 
    4532           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_2030 ||
    4533           0 :             sc->hw_type == IWN_HW_REV_TYPE_2000 ||
    4534           0 :             sc->hw_type == IWN_HW_REV_TYPE_135 ||
    4535           0 :             sc->hw_type == IWN_HW_REV_TYPE_105) {
    4536           0 :                 error = iwn2000_temp_offset_calib(sc);
    4537           0 :                 if (error != 0) {
    4538           0 :                         printf("%s: could not set temperature offset\n",
    4539           0 :                             sc->sc_dev.dv_xname);
    4540           0 :                         return error;
    4541             :                 }
    4542             :         }
    4543             : 
    4544           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_6050 ||
    4545           0 :             sc->hw_type == IWN_HW_REV_TYPE_6005) {
    4546             :                 /* Configure runtime DC calibration. */
    4547           0 :                 error = iwn5000_runtime_calib(sc);
    4548           0 :                 if (error != 0) {
    4549           0 :                         printf("%s: could not configure runtime calibration\n",
    4550           0 :                             sc->sc_dev.dv_xname);
    4551           0 :                         return error;
    4552             :                 }
    4553             :         }
    4554             : 
    4555             :         /* Configure valid TX chains for >=5000 Series. */
    4556           0 :         if (sc->hw_type != IWN_HW_REV_TYPE_4965) {
    4557           0 :                 txmask = htole32(sc->txchainmask);
    4558             :                 DPRINTF(("configuring valid TX chains 0x%x\n", txmask));
    4559           0 :                 error = iwn_cmd(sc, IWN5000_CMD_TX_ANT_CONFIG, &txmask,
    4560             :                     sizeof txmask, 0);
    4561           0 :                 if (error != 0) {
    4562           0 :                         printf("%s: could not configure valid TX chains\n",
    4563           0 :                             sc->sc_dev.dv_xname);
    4564           0 :                         return error;
    4565             :                 }
    4566             :         }
    4567             : 
    4568             :         /* Configure bluetooth coexistence. */
    4569           0 :         if (sc->sc_flags & IWN_FLAG_ADV_BT_COEX)
    4570           0 :                 error = iwn_send_advanced_btcoex(sc);
    4571             :         else
    4572           0 :                 error = iwn_send_btcoex(sc);
    4573           0 :         if (error != 0) {
    4574           0 :                 printf("%s: could not configure bluetooth coexistence\n",
    4575           0 :                     sc->sc_dev.dv_xname);
    4576           0 :                 return error;
    4577             :         }
    4578             : 
    4579             :         /* Set mode, channel, RX filter and enable RX. */
    4580           0 :         memset(&sc->rxon, 0, sizeof (struct iwn_rxon));
    4581           0 :         IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
    4582           0 :         IEEE80211_ADDR_COPY(sc->rxon.myaddr, ic->ic_myaddr);
    4583           0 :         IEEE80211_ADDR_COPY(sc->rxon.wlap, ic->ic_myaddr);
    4584           0 :         sc->rxon.chan = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
    4585           0 :         sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
    4586           0 :         if (IEEE80211_IS_CHAN_2GHZ(ic->ic_ibss_chan)) {
    4587           0 :                 sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
    4588           0 :                 if (ic->ic_flags & IEEE80211_F_USEPROT)
    4589           0 :                         sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT);
    4590             :                 DPRINTF(("%s: 2ghz prot 0x%x\n", __func__,
    4591             :                     le32toh(sc->rxon.flags)));
    4592             :         }
    4593           0 :         switch (ic->ic_opmode) {
    4594             :         case IEEE80211_M_STA:
    4595           0 :                 sc->rxon.mode = IWN_MODE_STA;
    4596           0 :                 sc->rxon.filter = htole32(IWN_FILTER_MULTICAST);
    4597           0 :                 break;
    4598             :         case IEEE80211_M_MONITOR:
    4599           0 :                 sc->rxon.mode = IWN_MODE_MONITOR;
    4600           0 :                 sc->rxon.filter = htole32(IWN_FILTER_MULTICAST |
    4601             :                     IWN_FILTER_CTL | IWN_FILTER_PROMISC);
    4602           0 :                 break;
    4603             :         default:
    4604             :                 /* Should not get there. */
    4605             :                 break;
    4606             :         }
    4607           0 :         sc->rxon.cck_mask  = 0x0f;   /* not yet negotiated */
    4608           0 :         sc->rxon.ofdm_mask = 0xff;   /* not yet negotiated */
    4609           0 :         sc->rxon.ht_single_mask = 0xff;
    4610           0 :         sc->rxon.ht_dual_mask = 0xff;
    4611           0 :         sc->rxon.ht_triple_mask = 0xff;
    4612             :         rxchain =
    4613           0 :             IWN_RXCHAIN_VALID(sc->rxchainmask) |
    4614           0 :             IWN_RXCHAIN_MIMO_COUNT(sc->nrxchains) |
    4615           0 :             IWN_RXCHAIN_IDLE_COUNT(sc->nrxchains);
    4616           0 :         if (ic->ic_opmode == IEEE80211_M_MONITOR) {
    4617           0 :                 rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask);
    4618           0 :                 rxchain |= IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask);
    4619           0 :                 rxchain |= (IWN_RXCHAIN_DRIVER_FORCE | IWN_RXCHAIN_MIMO_FORCE);
    4620           0 :         }
    4621           0 :         sc->rxon.rxchain = htole16(rxchain);
    4622             :         DPRINTF(("setting configuration\n"));
    4623             :         DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x rxchain %x\n",
    4624             :             __func__, sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
    4625             :             sc->rxon.ofdm_mask, sc->rxon.rxchain));
    4626           0 :         error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 0);
    4627           0 :         if (error != 0) {
    4628           0 :                 printf("%s: RXON command failed\n", sc->sc_dev.dv_xname);
    4629           0 :                 return error;
    4630             :         }
    4631             : 
    4632           0 :         ridx = (sc->sc_ic.ic_curmode == IEEE80211_MODE_11A) ?
    4633             :             IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
    4634           0 :         if ((error = iwn_add_broadcast_node(sc, 0, ridx)) != 0) {
    4635           0 :                 printf("%s: could not add broadcast node\n",
    4636           0 :                     sc->sc_dev.dv_xname);
    4637           0 :                 return error;
    4638             :         }
    4639             : 
    4640             :         /* Configuration has changed, set TX power accordingly. */
    4641           0 :         if ((error = ops->set_txpower(sc, 0)) != 0) {
    4642           0 :                 printf("%s: could not set TX power\n", sc->sc_dev.dv_xname);
    4643           0 :                 return error;
    4644             :         }
    4645             : 
    4646           0 :         if ((error = iwn_set_critical_temp(sc)) != 0) {
    4647           0 :                 printf("%s: could not set critical temperature\n",
    4648           0 :                     sc->sc_dev.dv_xname);
    4649           0 :                 return error;
    4650             :         }
    4651             : 
    4652             :         /* Set power saving level to CAM during initialization. */
    4653           0 :         if ((error = iwn_set_pslevel(sc, 0, 0, 0)) != 0) {
    4654           0 :                 printf("%s: could not set power saving level\n",
    4655           0 :                     sc->sc_dev.dv_xname);
    4656           0 :                 return error;
    4657             :         }
    4658           0 :         return 0;
    4659           0 : }
    4660             : 
    4661             : uint16_t
    4662           0 : iwn_get_active_dwell_time(struct iwn_softc *sc,
    4663             :     uint16_t flags, uint8_t n_probes)
    4664             : {
    4665             :         /* No channel? Default to 2GHz settings */
    4666           0 :         if (flags & IEEE80211_CHAN_2GHZ) {
    4667           0 :                 return (IWN_ACTIVE_DWELL_TIME_2GHZ +
    4668           0 :                 IWN_ACTIVE_DWELL_FACTOR_2GHZ * (n_probes + 1));
    4669             :         }
    4670             : 
    4671             :         /* 5GHz dwell time */
    4672           0 :         return (IWN_ACTIVE_DWELL_TIME_5GHZ +
    4673           0 :             IWN_ACTIVE_DWELL_FACTOR_5GHZ * (n_probes + 1));
    4674           0 : }
    4675             : 
    4676             : /*
    4677             :  * Limit the total dwell time to 85% of the beacon interval.
    4678             :  *
    4679             :  * Returns the dwell time in milliseconds.
    4680             :  */
    4681             : uint16_t
    4682           0 : iwn_limit_dwell(struct iwn_softc *sc, uint16_t dwell_time)
    4683             : {
    4684           0 :         struct ieee80211com *ic = &sc->sc_ic;
    4685           0 :         struct ieee80211_node *ni = ic->ic_bss;
    4686             :         int bintval = 0;
    4687             : 
    4688             :         /* bintval is in TU (1.024mS) */
    4689           0 :         if (ni != NULL)
    4690           0 :                 bintval = ni->ni_intval;
    4691             : 
    4692             :         /*
    4693             :          * If it's non-zero, we should calculate the minimum of
    4694             :          * it and the DWELL_BASE.
    4695             :          *
    4696             :          * XXX Yes, the math should take into account that bintval
    4697             :          * is 1.024mS, not 1mS..
    4698             :          */
    4699           0 :         if (ic->ic_state == IEEE80211_S_RUN && bintval > 0)
    4700           0 :                 return (MIN(IWN_PASSIVE_DWELL_BASE, ((bintval * 85) / 100)));
    4701             : 
    4702             :         /* No association context? Default */
    4703           0 :         return (IWN_PASSIVE_DWELL_BASE);
    4704           0 : }
    4705             : 
    4706             : uint16_t
    4707           0 : iwn_get_passive_dwell_time(struct iwn_softc *sc, uint16_t flags)
    4708             : {
    4709             :         uint16_t passive;
    4710           0 :         if (flags & IEEE80211_CHAN_2GHZ) {
    4711             :                 passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_2GHZ;
    4712           0 :         } else {
    4713             :                 passive = IWN_PASSIVE_DWELL_BASE + IWN_PASSIVE_DWELL_TIME_5GHZ;
    4714             :         }
    4715             : 
    4716             :         /* Clamp to the beacon interval if we're associated */
    4717           0 :         return (iwn_limit_dwell(sc, passive));
    4718             : }
    4719             : 
    4720             : int
    4721           0 : iwn_scan(struct iwn_softc *sc, uint16_t flags, int bgscan)
    4722             : {
    4723           0 :         struct ieee80211com *ic = &sc->sc_ic;
    4724             :         struct iwn_scan_hdr *hdr;
    4725             :         struct iwn_cmd_data *tx;
    4726             :         struct iwn_scan_essid *essid;
    4727             :         struct iwn_scan_chan *chan;
    4728             :         struct ieee80211_frame *wh;
    4729             :         struct ieee80211_rateset *rs;
    4730             :         struct ieee80211_channel *c;
    4731           0 :         struct ifnet *ifp = &ic->ic_if;
    4732             :         uint8_t *buf, *frm;
    4733             :         uint16_t rxchain, dwell_active, dwell_passive;
    4734             :         uint8_t txant;
    4735             :         int buflen, error, is_active;
    4736             : 
    4737           0 :         buf = malloc(IWN_SCAN_MAXSZ, M_DEVBUF, M_NOWAIT | M_ZERO);
    4738           0 :         if (buf == NULL) {
    4739           0 :                 printf("%s: could not allocate buffer for scan command\n",
    4740           0 :                     sc->sc_dev.dv_xname);
    4741           0 :                 return ENOMEM;
    4742             :         }
    4743           0 :         hdr = (struct iwn_scan_hdr *)buf;
    4744             :         /*
    4745             :          * Move to the next channel if no frames are received within 10ms
    4746             :          * after sending the probe request.
    4747             :          */
    4748           0 :         hdr->quiet_time = htole16(10);               /* timeout in milliseconds */
    4749           0 :         hdr->quiet_threshold = htole16(1);   /* min # of packets */
    4750             : 
    4751           0 :         if (bgscan) {
    4752             :                 int bintval;
    4753             : 
    4754             :                 /* Set maximum off-channel time. */
    4755           0 :                 hdr->max_out = htole32(200 * 1024);
    4756             : 
    4757             :                 /* Configure scan pauses which service on-channel traffic. */
    4758           0 :                 bintval = ic->ic_bss->ni_intval ? ic->ic_bss->ni_intval : 100;
    4759           0 :                 hdr->pause_scan = htole32(((100 / bintval) << 22) |
    4760             :                     ((100 % bintval) * 1024));
    4761           0 :         }
    4762             : 
    4763             :         /* Select antennas for scanning. */
    4764             :         rxchain =
    4765           0 :             IWN_RXCHAIN_VALID(sc->rxchainmask) |
    4766           0 :             IWN_RXCHAIN_FORCE_MIMO_SEL(sc->rxchainmask) |
    4767             :             IWN_RXCHAIN_DRIVER_FORCE;
    4768           0 :         if ((flags & IEEE80211_CHAN_5GHZ) &&
    4769           0 :             sc->hw_type == IWN_HW_REV_TYPE_4965) {
    4770             :                 /* 
    4771             :                  * On 4965 ant A and C must be avoided in 5GHz because of a
    4772             :                  * HW bug which causes very weak RSSI values being reported.
    4773             :                  */
    4774           0 :                 rxchain |= IWN_RXCHAIN_FORCE_SEL(IWN_ANT_B);
    4775           0 :         } else  /* Use all available RX antennas. */
    4776           0 :                 rxchain |= IWN_RXCHAIN_FORCE_SEL(sc->rxchainmask);
    4777           0 :         hdr->rxchain = htole16(rxchain);
    4778           0 :         hdr->filter = htole32(IWN_FILTER_MULTICAST | IWN_FILTER_BEACON);
    4779             : 
    4780           0 :         tx = (struct iwn_cmd_data *)(hdr + 1);
    4781           0 :         tx->flags = htole32(IWN_TX_AUTO_SEQ);
    4782           0 :         tx->id = sc->broadcast_id;
    4783           0 :         tx->lifetime = htole32(IWN_LIFETIME_INFINITE);
    4784             : 
    4785           0 :         if (flags & IEEE80211_CHAN_5GHZ) {
    4786             :                 /* Send probe requests at 6Mbps. */
    4787           0 :                 tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp;
    4788           0 :                 rs = &ic->ic_sup_rates[IEEE80211_MODE_11A];
    4789           0 :         } else {
    4790           0 :                 hdr->flags = htole32(IWN_RXON_24GHZ | IWN_RXON_AUTO);
    4791           0 :                 if (bgscan && sc->hw_type == IWN_HW_REV_TYPE_4965 &&
    4792           0 :                     sc->rxon.chan > 14) {
    4793             :                         /* 
    4794             :                          * 4965 firmware can crash when sending probe requests
    4795             :                          * with CCK rates while associated to a 5GHz AP.
    4796             :                          * Send probe requests at 6Mbps OFDM as a workaround.
    4797             :                          */
    4798           0 :                         tx->plcp = iwn_rates[IWN_RIDX_OFDM6].plcp;
    4799           0 :                 } else {
    4800             :                         /* Send probe requests at 1Mbps. */
    4801           0 :                         tx->plcp = iwn_rates[IWN_RIDX_CCK1].plcp;
    4802           0 :                         tx->rflags = IWN_RFLAG_CCK;
    4803             :                 }
    4804           0 :                 rs = &ic->ic_sup_rates[IEEE80211_MODE_11G];
    4805             :         }
    4806             :         /* Use the first valid TX antenna. */
    4807           0 :         txant = IWN_LSB(sc->txchainmask);
    4808           0 :         tx->rflags |= IWN_RFLAG_ANT(txant);
    4809             : 
    4810             :         /*
    4811             :          * Only do active scanning if we're announcing a probe request
    4812             :          * for a given SSID (or more, if we ever add it to the driver.)
    4813             :          */
    4814             :         is_active = 0;
    4815             : 
    4816             :         /*
    4817             :          * If we're scanning for a specific SSID, add it to the command.
    4818             :          */
    4819           0 :         essid = (struct iwn_scan_essid *)(tx + 1);
    4820           0 :         if (ic->ic_des_esslen != 0) {
    4821           0 :                 essid[0].id = IEEE80211_ELEMID_SSID;
    4822           0 :                 essid[0].len = ic->ic_des_esslen;
    4823           0 :                 memcpy(essid[0].data, ic->ic_des_essid, ic->ic_des_esslen);
    4824             : 
    4825             :                 is_active = 1;
    4826           0 :         }
    4827             :         /*
    4828             :          * Build a probe request frame.  Most of the following code is a
    4829             :          * copy & paste of what is done in net80211.
    4830             :          */
    4831           0 :         wh = (struct ieee80211_frame *)(essid + 20);
    4832           0 :         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
    4833             :             IEEE80211_FC0_SUBTYPE_PROBE_REQ;
    4834           0 :         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
    4835           0 :         IEEE80211_ADDR_COPY(ic->ic_myaddr, LLADDR(ifp->if_sadl));
    4836           0 :         IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
    4837           0 :         IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
    4838           0 :         IEEE80211_ADDR_COPY(wh->i_addr3, etherbroadcastaddr);
    4839           0 :         *(uint16_t *)&wh->i_dur[0] = 0;  /* filled by HW */
    4840           0 :         *(uint16_t *)&wh->i_seq[0] = 0;  /* filled by HW */
    4841             : 
    4842           0 :         frm = (uint8_t *)(wh + 1);
    4843           0 :         frm = ieee80211_add_ssid(frm, NULL, 0);
    4844           0 :         frm = ieee80211_add_rates(frm, rs);
    4845           0 :         if (rs->rs_nrates > IEEE80211_RATE_SIZE)
    4846           0 :                 frm = ieee80211_add_xrates(frm, rs);
    4847           0 :         if (ic->ic_flags & IEEE80211_F_HTON)
    4848           0 :                 frm = ieee80211_add_htcaps(frm, ic);
    4849             : 
    4850             :         /* Set length of probe request. */
    4851           0 :         tx->len = htole16(frm - (uint8_t *)wh);
    4852             : 
    4853             :         /*
    4854             :          * If active scanning is requested but a certain channel is
    4855             :          * marked passive, we can do active scanning if we detect
    4856             :          * transmissions.
    4857             :          *
    4858             :          * There is an issue with some firmware versions that triggers
    4859             :          * a sysassert on a "good CRC threshold" of zero (== disabled),
    4860             :          * on a radar channel even though this means that we should NOT
    4861             :          * send probes.
    4862             :          *
    4863             :          * The "good CRC threshold" is the number of frames that we
    4864             :          * need to receive during our dwell time on a channel before
    4865             :          * sending out probes -- setting this to a huge value will
    4866             :          * mean we never reach it, but at the same time work around
    4867             :          * the aforementioned issue. Thus use IWN_GOOD_CRC_TH_NEVER
    4868             :          * here instead of IWN_GOOD_CRC_TH_DISABLED.
    4869             :          *
    4870             :          * This was fixed in later versions along with some other
    4871             :          * scan changes, and the threshold behaves as a flag in those
    4872             :          * versions.
    4873             :          */
    4874             : 
    4875             :         /*
    4876             :          * If we're doing active scanning, set the crc_threshold
    4877             :          * to a suitable value.  This is different to active veruss
    4878             :          * passive scanning depending upon the channel flags; the
    4879             :          * firmware will obey that particular check for us.
    4880             :          */
    4881           0 :         if (sc->tlv_feature_flags & IWN_UCODE_TLV_FLAGS_NEWSCAN)
    4882           0 :                 hdr->crc_threshold = is_active ?
    4883             :                     IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_DISABLED;
    4884             :         else
    4885           0 :                 hdr->crc_threshold = is_active ?
    4886             :                     IWN_GOOD_CRC_TH_DEFAULT : IWN_GOOD_CRC_TH_NEVER;
    4887             : 
    4888           0 :         chan = (struct iwn_scan_chan *)frm;
    4889           0 :         for (c  = &ic->ic_channels[1];
    4890           0 :              c <= &ic->ic_channels[IEEE80211_CHAN_MAX]; c++) {
    4891           0 :                 if ((c->ic_flags & flags) != flags)
    4892             :                         continue;
    4893             : 
    4894           0 :                 chan->chan = htole16(ieee80211_chan2ieee(ic, c));
    4895             :                 DPRINTFN(2, ("adding channel %d\n", chan->chan));
    4896           0 :                 chan->flags = 0;
    4897           0 :                 if (ic->ic_des_esslen != 0)
    4898           0 :                         chan->flags |= htole32(IWN_CHAN_NPBREQS(1));
    4899             : 
    4900           0 :                 if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
    4901           0 :                         chan->flags |= htole32(IWN_CHAN_PASSIVE);
    4902             :                 else
    4903           0 :                         chan->flags |= htole32(IWN_CHAN_ACTIVE);
    4904             : 
    4905             :                 /*
    4906             :                  * Calculate the active/passive dwell times.
    4907             :                  */
    4908             : 
    4909           0 :                 dwell_active = iwn_get_active_dwell_time(sc, flags, is_active);
    4910           0 :                 dwell_passive = iwn_get_passive_dwell_time(sc, flags);
    4911             : 
    4912             :                 /* Make sure they're valid */
    4913           0 :                 if (dwell_passive <= dwell_active)
    4914           0 :                         dwell_passive = dwell_active + 1;
    4915             : 
    4916           0 :                 chan->active = htole16(dwell_active);
    4917           0 :                 chan->passive = htole16(dwell_passive);
    4918             : 
    4919           0 :                 chan->dsp_gain = 0x6e;
    4920           0 :                 if (IEEE80211_IS_CHAN_5GHZ(c)) {
    4921           0 :                         chan->rf_gain = 0x3b;
    4922           0 :                 } else {
    4923           0 :                         chan->rf_gain = 0x28;
    4924             :                 }
    4925           0 :                 hdr->nchan++;
    4926           0 :                 chan++;
    4927           0 :         }
    4928             : 
    4929           0 :         buflen = (uint8_t *)chan - buf;
    4930           0 :         hdr->len = htole16(buflen);
    4931             : 
    4932             :         DPRINTF(("sending scan command nchan=%d\n", hdr->nchan));
    4933           0 :         error = iwn_cmd(sc, IWN_CMD_SCAN, buf, buflen, 1);
    4934           0 :         if (error == 0) {
    4935           0 :                 sc->sc_flags |= IWN_FLAG_SCANNING;
    4936           0 :                 if (bgscan)
    4937           0 :                         sc->sc_flags |= IWN_FLAG_BGSCAN;
    4938             :         }
    4939           0 :         free(buf, M_DEVBUF, IWN_SCAN_MAXSZ);
    4940           0 :         return error;
    4941           0 : }
    4942             : 
    4943             : void
    4944           0 : iwn_scan_abort(struct iwn_softc *sc)
    4945             : {
    4946           0 :         iwn_cmd(sc, IWN_CMD_SCAN_ABORT, NULL, 0, 1);
    4947             : 
    4948             :         /* XXX Cannot wait for status response in interrupt context. */
    4949           0 :         DELAY(100);
    4950             : 
    4951           0 :         sc->sc_flags &= ~IWN_FLAG_SCANNING;
    4952           0 :         sc->sc_flags &= ~IWN_FLAG_BGSCAN;
    4953           0 : }
    4954             : 
    4955             : int
    4956           0 : iwn_bgscan(struct ieee80211com *ic) 
    4957             : {
    4958           0 :         struct iwn_softc *sc = ic->ic_softc;
    4959             :         int error; 
    4960             : 
    4961           0 :         if (sc->sc_flags & IWN_FLAG_SCANNING)
    4962           0 :                 return 0;
    4963             : 
    4964           0 :         error = iwn_scan(sc, IEEE80211_CHAN_2GHZ, 1);
    4965           0 :         if (error)
    4966           0 :                 printf("%s: could not initiate background scan\n",
    4967           0 :                     sc->sc_dev.dv_xname);
    4968           0 :         return error;
    4969           0 : }
    4970             : 
    4971             : int
    4972           0 : iwn_auth(struct iwn_softc *sc, int arg)
    4973             : {
    4974           0 :         struct iwn_ops *ops = &sc->ops;
    4975           0 :         struct ieee80211com *ic = &sc->sc_ic;
    4976           0 :         struct ieee80211_node *ni = ic->ic_bss;
    4977             :         int error, ridx;
    4978             :         int bss_switch = 
    4979           0 :             (!IEEE80211_ADDR_EQ(sc->bss_node_addr, etheranyaddr) &&
    4980           0 :             !IEEE80211_ADDR_EQ(sc->bss_node_addr, ni->ni_macaddr));
    4981             : 
    4982             :         /* Update adapter configuration. */
    4983           0 :         IEEE80211_ADDR_COPY(sc->rxon.bssid, ni->ni_bssid);
    4984           0 :         sc->rxon.chan = ieee80211_chan2ieee(ic, ni->ni_chan);
    4985           0 :         sc->rxon.flags = htole32(IWN_RXON_TSF | IWN_RXON_CTS_TO_SELF);
    4986           0 :         if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
    4987           0 :                 sc->rxon.flags |= htole32(IWN_RXON_AUTO | IWN_RXON_24GHZ);
    4988           0 :                 if (ic->ic_flags & IEEE80211_F_USEPROT)
    4989           0 :                         sc->rxon.flags |= htole32(IWN_RXON_TGG_PROT);
    4990             :                 DPRINTF(("%s: 2ghz prot 0x%x\n", __func__,
    4991             :                     le32toh(sc->rxon.flags)));
    4992             :         }
    4993           0 :         if (ic->ic_flags & IEEE80211_F_SHSLOT)
    4994           0 :                 sc->rxon.flags |= htole32(IWN_RXON_SHSLOT);
    4995             :         else
    4996           0 :                 sc->rxon.flags &= ~htole32(IWN_RXON_SHSLOT);
    4997           0 :         if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
    4998           0 :                 sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE);
    4999             :         else
    5000           0 :                 sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE);
    5001           0 :         switch (ic->ic_curmode) {
    5002             :         case IEEE80211_MODE_11A:
    5003           0 :                 sc->rxon.cck_mask  = 0;
    5004           0 :                 sc->rxon.ofdm_mask = 0x15;
    5005           0 :                 break;
    5006             :         case IEEE80211_MODE_11B:
    5007           0 :                 sc->rxon.cck_mask  = 0x03;
    5008           0 :                 sc->rxon.ofdm_mask = 0;
    5009           0 :                 break;
    5010             :         default:        /* Assume 802.11b/g/n. */
    5011           0 :                 sc->rxon.cck_mask  = 0x0f;
    5012           0 :                 sc->rxon.ofdm_mask = 0x15;
    5013           0 :         }
    5014             :         DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__,
    5015             :             sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
    5016             :             sc->rxon.ofdm_mask));
    5017           0 :         error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1);
    5018           0 :         if (error != 0) {
    5019           0 :                 printf("%s: RXON command failed\n", sc->sc_dev.dv_xname);
    5020           0 :                 return error;
    5021             :         }
    5022             : 
    5023             :         /* Configuration has changed, set TX power accordingly. */
    5024           0 :         if ((error = ops->set_txpower(sc, 1)) != 0) {
    5025           0 :                 printf("%s: could not set TX power\n", sc->sc_dev.dv_xname);
    5026           0 :                 return error;
    5027             :         }
    5028             :         /*
    5029             :          * Reconfiguring RXON clears the firmware nodes table so we must
    5030             :          * add the broadcast node again.
    5031             :          */
    5032           0 :         ridx = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ?
    5033             :             IWN_RIDX_OFDM6 : IWN_RIDX_CCK1;
    5034           0 :         if ((error = iwn_add_broadcast_node(sc, 1, ridx)) != 0) {
    5035           0 :                 printf("%s: could not add broadcast node\n",
    5036           0 :                     sc->sc_dev.dv_xname);
    5037           0 :                 return error;
    5038             :         }
    5039             : 
    5040             :         /* 
    5041             :          * Make sure the firmware gets to see a beacon before we send
    5042             :          * the auth request. Otherwise the Tx attempt can fail due to
    5043             :          * the firmware's built-in regulatory domain enforcement.
    5044             :          * Delaying here for every incoming deauth frame can result in a DoS.
    5045             :          * Don't delay if we're here because of an incoming frame (arg != -1)
    5046             :          * or if we're already waiting for a response (ic_mgt_timer != 0).
    5047             :          * If we are switching APs after a background scan then net80211 has
    5048             :          * just faked the reception of a deauth frame from our old AP, so it
    5049             :          * is safe to delay in that case.
    5050             :          */
    5051           0 :         if ((arg == -1 || bss_switch) && ic->ic_mgt_timer == 0)
    5052           0 :                 DELAY(ni->ni_intval * 3 * IEEE80211_DUR_TU);
    5053             : 
    5054             :         /* We can now clear the cached address of our previous AP. */
    5055           0 :         memset(sc->bss_node_addr, 0, sizeof(sc->bss_node_addr));
    5056             : 
    5057           0 :         return 0;
    5058           0 : }
    5059             : 
    5060             : int
    5061           0 : iwn_run(struct iwn_softc *sc)
    5062             : {
    5063           0 :         struct iwn_ops *ops = &sc->ops;
    5064           0 :         struct ieee80211com *ic = &sc->sc_ic;
    5065           0 :         struct ieee80211_node *ni = ic->ic_bss;
    5066           0 :         struct iwn_node *wn = (void *)ni;
    5067           0 :         struct iwn_node_info node;
    5068             :         int error;
    5069             : 
    5070           0 :         if (ic->ic_opmode == IEEE80211_M_MONITOR) {
    5071             :                 /* Link LED blinks while monitoring. */
    5072           0 :                 iwn_set_led(sc, IWN_LED_LINK, 50, 50);
    5073           0 :                 return 0;
    5074             :         }
    5075           0 :         if ((error = iwn_set_timing(sc, ni)) != 0) {
    5076           0 :                 printf("%s: could not set timing\n", sc->sc_dev.dv_xname);
    5077           0 :                 return error;
    5078             :         }
    5079             : 
    5080             :         /* Update adapter configuration. */
    5081           0 :         sc->rxon.associd = htole16(IEEE80211_AID(ni->ni_associd));
    5082             :         /* Short preamble and slot time are negotiated when associating. */
    5083           0 :         sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE | IWN_RXON_SHSLOT);
    5084           0 :         if (ic->ic_flags & IEEE80211_F_SHSLOT)
    5085           0 :                 sc->rxon.flags |= htole32(IWN_RXON_SHSLOT);
    5086           0 :         if (ic->ic_flags & IEEE80211_F_SHPREAMBLE)
    5087           0 :                 sc->rxon.flags |= htole32(IWN_RXON_SHPREAMBLE);
    5088           0 :         sc->rxon.filter |= htole32(IWN_FILTER_BSS);
    5089             : 
    5090             :         /* HT is negotiated when associating. */
    5091           0 :         if (ni->ni_flags & IEEE80211_NODE_HT) {
    5092             :                 enum ieee80211_htprot htprot =
    5093           0 :                     (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK);
    5094             :                 DPRINTF(("%s: htprot = %d\n", __func__, htprot));
    5095           0 :                 sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot));
    5096           0 :         } else
    5097           0 :                 sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3));
    5098             : 
    5099           0 :         if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) {
    5100             :                 /* 11a or 11n 5GHz */
    5101           0 :                 sc->rxon.cck_mask  = 0;
    5102           0 :                 sc->rxon.ofdm_mask = 0x15;
    5103           0 :         } else if (ni->ni_flags & IEEE80211_NODE_HT) {
    5104             :                 /* 11n 2GHz */
    5105           0 :                 sc->rxon.cck_mask  = 0x0f;
    5106           0 :                 sc->rxon.ofdm_mask = 0x15;
    5107           0 :         } else {
    5108           0 :                 if (ni->ni_rates.rs_nrates == 4) {
    5109             :                         /* 11b */
    5110           0 :                         sc->rxon.cck_mask  = 0x03;
    5111           0 :                         sc->rxon.ofdm_mask = 0;
    5112           0 :                 } else {
    5113             :                         /* assume 11g */
    5114           0 :                         sc->rxon.cck_mask  = 0x0f;
    5115           0 :                         sc->rxon.ofdm_mask = 0x15;
    5116             :                 }
    5117             :         }
    5118             :         DPRINTF(("%s: rxon chan %d flags %x cck %x ofdm %x\n", __func__,
    5119             :             sc->rxon.chan, le32toh(sc->rxon.flags), sc->rxon.cck_mask,
    5120             :             sc->rxon.ofdm_mask));
    5121           0 :         error = iwn_cmd(sc, IWN_CMD_RXON, &sc->rxon, sc->rxonsz, 1);
    5122           0 :         if (error != 0) {
    5123           0 :                 printf("%s: could not update configuration\n",
    5124           0 :                     sc->sc_dev.dv_xname);
    5125           0 :                 return error;
    5126             :         }
    5127             : 
    5128             :         /* Configuration has changed, set TX power accordingly. */
    5129           0 :         if ((error = ops->set_txpower(sc, 1)) != 0) {
    5130           0 :                 printf("%s: could not set TX power\n", sc->sc_dev.dv_xname);
    5131           0 :                 return error;
    5132             :         }
    5133             : 
    5134             :         /* Fake a join to initialize the TX rate. */
    5135           0 :         ((struct iwn_node *)ni)->id = IWN_ID_BSS;
    5136           0 :         iwn_newassoc(ic, ni, 1);
    5137             : 
    5138             :         /* Add BSS node. */
    5139           0 :         memset(&node, 0, sizeof node);
    5140           0 :         IEEE80211_ADDR_COPY(node.macaddr, ni->ni_macaddr);
    5141           0 :         node.id = IWN_ID_BSS;
    5142           0 :         if (ni->ni_flags & IEEE80211_NODE_HT) {
    5143           0 :                 node.htmask = (IWN_AMDPU_SIZE_FACTOR_MASK |
    5144             :                     IWN_AMDPU_DENSITY_MASK);
    5145           0 :                 node.htflags = htole32(
    5146             :                     IWN_AMDPU_SIZE_FACTOR(
    5147             :                         (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_LE)) |
    5148             :                     IWN_AMDPU_DENSITY(
    5149             :                         (ic->ic_ampdu_params & IEEE80211_AMPDU_PARAM_SS) >> 2));
    5150           0 :         }
    5151             :         DPRINTF(("adding BSS node\n"));
    5152           0 :         error = ops->add_node(sc, &node, 1);
    5153           0 :         if (error != 0) {
    5154           0 :                 printf("%s: could not add BSS node\n", sc->sc_dev.dv_xname);
    5155           0 :                 return error;
    5156             :         }
    5157             : 
    5158             :         /* Cache address of AP in case it changes after a background scan. */
    5159           0 :         IEEE80211_ADDR_COPY(sc->bss_node_addr, ni->ni_macaddr);
    5160             : 
    5161             :         DPRINTF(("setting link quality for node %d\n", node.id));
    5162           0 :         if ((error = iwn_set_link_quality(sc, ni)) != 0) {
    5163           0 :                 printf("%s: could not setup link quality for node %d\n",
    5164           0 :                     sc->sc_dev.dv_xname, node.id);
    5165           0 :                 return error;
    5166             :         }
    5167             : 
    5168           0 :         if ((error = iwn_init_sensitivity(sc)) != 0) {
    5169           0 :                 printf("%s: could not set sensitivity\n",
    5170           0 :                     sc->sc_dev.dv_xname);
    5171           0 :                 return error;
    5172             :         }
    5173             :         /* Start periodic calibration timer. */
    5174           0 :         sc->calib.state = IWN_CALIB_STATE_ASSOC;
    5175           0 :         sc->calib_cnt = 0;
    5176           0 :         timeout_add_msec(&sc->calib_to, 500);
    5177             : 
    5178           0 :         ieee80211_mira_node_init(&wn->mn);
    5179             : 
    5180             :         /* Link LED always on while associated. */
    5181           0 :         iwn_set_led(sc, IWN_LED_LINK, 0, 1);
    5182           0 :         return 0;
    5183           0 : }
    5184             : 
    5185             : /*
    5186             :  * We support CCMP hardware encryption/decryption of unicast frames only.
    5187             :  * HW support for TKIP really sucks.  We should let TKIP die anyway.
    5188             :  */
    5189             : int
    5190           0 : iwn_set_key(struct ieee80211com *ic, struct ieee80211_node *ni,
    5191             :     struct ieee80211_key *k)
    5192             : {
    5193           0 :         struct iwn_softc *sc = ic->ic_softc;
    5194           0 :         struct iwn_ops *ops = &sc->ops;
    5195           0 :         struct iwn_node *wn = (void *)ni;
    5196           0 :         struct iwn_node_info node;
    5197             :         uint16_t kflags;
    5198             : 
    5199           0 :         if ((k->k_flags & IEEE80211_KEY_GROUP) ||
    5200           0 :             k->k_cipher != IEEE80211_CIPHER_CCMP)
    5201           0 :                 return ieee80211_set_key(ic, ni, k);
    5202             : 
    5203           0 :         kflags = IWN_KFLAG_CCMP | IWN_KFLAG_MAP | IWN_KFLAG_KID(k->k_id);
    5204           0 :         if (k->k_flags & IEEE80211_KEY_GROUP)
    5205           0 :                 kflags |= IWN_KFLAG_GROUP;
    5206             : 
    5207           0 :         memset(&node, 0, sizeof node);
    5208           0 :         node.id = (k->k_flags & IEEE80211_KEY_GROUP) ?
    5209           0 :             sc->broadcast_id : wn->id;
    5210           0 :         node.control = IWN_NODE_UPDATE;
    5211           0 :         node.flags = IWN_FLAG_SET_KEY;
    5212           0 :         node.kflags = htole16(kflags);
    5213           0 :         node.kid = k->k_id;
    5214           0 :         memcpy(node.key, k->k_key, k->k_len);
    5215             :         DPRINTF(("set key id=%d for node %d\n", k->k_id, node.id));
    5216           0 :         return ops->add_node(sc, &node, 1);
    5217           0 : }
    5218             : 
    5219             : void
    5220           0 : iwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni,
    5221             :     struct ieee80211_key *k)
    5222             : {
    5223           0 :         struct iwn_softc *sc = ic->ic_softc;
    5224           0 :         struct iwn_ops *ops = &sc->ops;
    5225           0 :         struct iwn_node *wn = (void *)ni;
    5226           0 :         struct iwn_node_info node;
    5227             : 
    5228           0 :         if ((k->k_flags & IEEE80211_KEY_GROUP) ||
    5229           0 :             k->k_cipher != IEEE80211_CIPHER_CCMP) {
    5230             :                 /* See comment about other ciphers above. */
    5231           0 :                 ieee80211_delete_key(ic, ni, k);
    5232           0 :                 return;
    5233             :         }
    5234           0 :         if (ic->ic_state != IEEE80211_S_RUN)
    5235           0 :                 return; /* Nothing to do. */
    5236           0 :         memset(&node, 0, sizeof node);
    5237           0 :         node.id = (k->k_flags & IEEE80211_KEY_GROUP) ?
    5238           0 :             sc->broadcast_id : wn->id;
    5239           0 :         node.control = IWN_NODE_UPDATE;
    5240           0 :         node.flags = IWN_FLAG_SET_KEY;
    5241           0 :         node.kflags = htole16(IWN_KFLAG_INVALID);
    5242           0 :         node.kid = 0xff;
    5243             :         DPRINTF(("delete keys for node %d\n", node.id));
    5244           0 :         (void)ops->add_node(sc, &node, 1);
    5245           0 : }
    5246             : 
    5247             : /*
    5248             :  * This function is called by upper layer when HT protection settings in
    5249             :  * beacons have changed.
    5250             :  */
    5251             : void
    5252           0 : iwn_update_htprot(struct ieee80211com *ic, struct ieee80211_node *ni)
    5253             : {
    5254           0 :         struct iwn_softc *sc = ic->ic_softc;
    5255           0 :         struct iwn_ops *ops = &sc->ops;
    5256             :         enum ieee80211_htprot htprot;
    5257           0 :         struct iwn_rxon_assoc rxon_assoc;
    5258             :         int s, error;
    5259             : 
    5260             :         /* Update HT protection mode setting. */
    5261           0 :         htprot = (ni->ni_htop1 & IEEE80211_HTOP1_PROT_MASK) >>
    5262             :             IEEE80211_HTOP1_PROT_SHIFT;
    5263           0 :         sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3));
    5264           0 :         sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot));
    5265             : 
    5266             :         /* Update RXON config. */
    5267           0 :         memset(&rxon_assoc, 0, sizeof(rxon_assoc));
    5268           0 :         rxon_assoc.flags = sc->rxon.flags;
    5269           0 :         rxon_assoc.filter = sc->rxon.filter;
    5270           0 :         rxon_assoc.ofdm_mask = sc->rxon.ofdm_mask;
    5271           0 :         rxon_assoc.cck_mask = sc->rxon.cck_mask;
    5272           0 :         rxon_assoc.ht_single_mask = sc->rxon.ht_single_mask;
    5273           0 :         rxon_assoc.ht_dual_mask = sc->rxon.ht_dual_mask;
    5274           0 :         rxon_assoc.ht_triple_mask = sc->rxon.ht_triple_mask;
    5275           0 :         rxon_assoc.rxchain = sc->rxon.rxchain;
    5276           0 :         rxon_assoc.acquisition = sc->rxon.acquisition;
    5277             : 
    5278           0 :         s = splnet();
    5279             : 
    5280           0 :         error = iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &rxon_assoc,
    5281             :             sizeof(rxon_assoc), 1);
    5282           0 :         if (error != 0)
    5283           0 :                 printf("%s: RXON_ASSOC command failed\n", sc->sc_dev.dv_xname);
    5284             : 
    5285           0 :         DELAY(100);
    5286             : 
    5287             :         /* All RXONs wipe the firmware's txpower table. Restore it. */
    5288           0 :         error = ops->set_txpower(sc, 1);
    5289           0 :         if (error != 0)
    5290           0 :                 printf("%s: could not set TX power\n", sc->sc_dev.dv_xname);
    5291             : 
    5292           0 :         DELAY(100);
    5293             : 
    5294             :         /* Restore power saving level */
    5295           0 :         if (ic->ic_flags & IEEE80211_F_PMGTON)
    5296           0 :                 error = iwn_set_pslevel(sc, 0, 3, 1);
    5297             :         else
    5298           0 :                 error = iwn_set_pslevel(sc, 0, 0, 1);
    5299           0 :         if (error != 0)
    5300           0 :                 printf("%s: could not set PS level\n", sc->sc_dev.dv_xname);
    5301             : 
    5302           0 :         splx(s);
    5303           0 : }
    5304             : 
    5305             : /*
    5306             :  * This function is called by upper layer when an ADDBA request is received
    5307             :  * from another STA and before the ADDBA response is sent.
    5308             :  */
    5309             : int
    5310           0 : iwn_ampdu_rx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
    5311             :     uint8_t tid)
    5312             : {
    5313           0 :         struct ieee80211_rx_ba *ba = &ni->ni_rx_ba[tid];
    5314           0 :         struct iwn_softc *sc = ic->ic_softc;
    5315           0 :         struct iwn_ops *ops = &sc->ops;
    5316           0 :         struct iwn_node *wn = (void *)ni;
    5317           0 :         struct iwn_node_info node;
    5318             : 
    5319           0 :         memset(&node, 0, sizeof node);
    5320           0 :         node.id = wn->id;
    5321           0 :         node.control = IWN_NODE_UPDATE;
    5322           0 :         node.flags = IWN_FLAG_SET_ADDBA;
    5323           0 :         node.addba_tid = tid;
    5324           0 :         node.addba_ssn = htole16(ba->ba_winstart);
    5325             :         DPRINTF(("ADDBA RA=%d TID=%d SSN=%d\n", wn->id, tid,
    5326             :             ba->ba_winstart));
    5327             :         /* XXX async command, so firmware may still fail to add BA agreement */
    5328           0 :         return ops->add_node(sc, &node, 1);
    5329           0 : }
    5330             : 
    5331             : /*
    5332             :  * This function is called by upper layer on teardown of an HT-immediate
    5333             :  * Block Ack agreement (eg. uppon receipt of a DELBA frame).
    5334             :  */
    5335             : void
    5336           0 : iwn_ampdu_rx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
    5337             :     uint8_t tid)
    5338             : {
    5339           0 :         struct iwn_softc *sc = ic->ic_softc;
    5340           0 :         struct iwn_ops *ops = &sc->ops;
    5341           0 :         struct iwn_node *wn = (void *)ni;
    5342           0 :         struct iwn_node_info node;
    5343             : 
    5344           0 :         memset(&node, 0, sizeof node);
    5345           0 :         node.id = wn->id;
    5346           0 :         node.control = IWN_NODE_UPDATE;
    5347           0 :         node.flags = IWN_FLAG_SET_DELBA;
    5348           0 :         node.delba_tid = tid;
    5349             :         DPRINTF(("DELBA RA=%d TID=%d\n", wn->id, tid));
    5350           0 :         (void)ops->add_node(sc, &node, 1);
    5351           0 : }
    5352             : 
    5353             : /*
    5354             :  * This function is called by upper layer when an ADDBA response is received
    5355             :  * from another STA.
    5356             :  */
    5357             : int
    5358           0 : iwn_ampdu_tx_start(struct ieee80211com *ic, struct ieee80211_node *ni,
    5359             :     uint8_t tid)
    5360             : {
    5361           0 :         struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
    5362           0 :         struct iwn_softc *sc = ic->ic_softc;
    5363           0 :         struct iwn_ops *ops = &sc->ops;
    5364           0 :         struct iwn_node *wn = (void *)ni;
    5365           0 :         struct iwn_node_info node;
    5366             :         int error;
    5367             : 
    5368             :         /* Enable TX for the specified RA/TID. */
    5369           0 :         wn->disable_tid &= ~(1 << tid);
    5370           0 :         memset(&node, 0, sizeof node);
    5371           0 :         node.id = wn->id;
    5372           0 :         node.control = IWN_NODE_UPDATE;
    5373           0 :         node.flags = IWN_FLAG_SET_DISABLE_TID;
    5374           0 :         node.disable_tid = htole16(wn->disable_tid);
    5375           0 :         error = ops->add_node(sc, &node, 1);
    5376           0 :         if (error != 0)
    5377           0 :                 return error;
    5378             : 
    5379           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5380           0 :                 return error;
    5381           0 :         ops->ampdu_tx_start(sc, ni, tid, ba->ba_winstart);
    5382           0 :         iwn_nic_unlock(sc);
    5383           0 :         return 0;
    5384           0 : }
    5385             : 
    5386             : void
    5387           0 : iwn_ampdu_tx_stop(struct ieee80211com *ic, struct ieee80211_node *ni,
    5388             :     uint8_t tid)
    5389             : {
    5390           0 :         struct ieee80211_tx_ba *ba = &ni->ni_tx_ba[tid];
    5391           0 :         struct iwn_softc *sc = ic->ic_softc;
    5392           0 :         struct iwn_ops *ops = &sc->ops;
    5393             : 
    5394           0 :         if (iwn_nic_lock(sc) != 0)
    5395           0 :                 return;
    5396           0 :         ops->ampdu_tx_stop(sc, tid, ba->ba_winstart);
    5397           0 :         iwn_nic_unlock(sc);
    5398           0 : }
    5399             : 
    5400             : void
    5401           0 : iwn4965_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
    5402             :     uint8_t tid, uint16_t ssn)
    5403             : {
    5404           0 :         struct iwn_node *wn = (void *)ni;
    5405           0 :         int qid = 7 + tid;
    5406             : 
    5407             :         /* Stop TX scheduler while we're changing its configuration. */
    5408           0 :         iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
    5409             :             IWN4965_TXQ_STATUS_CHGACT);
    5410             : 
    5411             :         /* Assign RA/TID translation to the queue. */
    5412           0 :         iwn_mem_write_2(sc, sc->sched_base + IWN4965_SCHED_TRANS_TBL(qid),
    5413           0 :             wn->id << 4 | tid);
    5414             : 
    5415             :         /* Enable chain-building mode for the queue. */
    5416           0 :         iwn_prph_setbits(sc, IWN4965_SCHED_QCHAIN_SEL, 1 << qid);
    5417             : 
    5418             :         /* Set starting sequence number from the ADDBA request. */
    5419           0 :         IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff));
    5420           0 :         iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn);
    5421             : 
    5422             :         /* Set scheduler window size. */
    5423           0 :         iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid),
    5424             :             IWN_SCHED_WINSZ);
    5425             :         /* Set scheduler frame limit. */
    5426           0 :         iwn_mem_write(sc, sc->sched_base + IWN4965_SCHED_QUEUE_OFFSET(qid) + 4,
    5427             :             IWN_SCHED_LIMIT << 16);
    5428             : 
    5429             :         /* Enable interrupts for the queue. */
    5430           0 :         iwn_prph_setbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid);
    5431             : 
    5432             :         /* Mark the queue as active. */
    5433           0 :         iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
    5434           0 :             IWN4965_TXQ_STATUS_ACTIVE | IWN4965_TXQ_STATUS_AGGR_ENA |
    5435           0 :             iwn_tid2fifo[tid] << 1);
    5436           0 : }
    5437             : 
    5438             : void
    5439           0 : iwn4965_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
    5440             : {
    5441           0 :         int qid = 7 + tid;
    5442             : 
    5443             :         /* Stop TX scheduler while we're changing its configuration. */
    5444           0 :         iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
    5445             :             IWN4965_TXQ_STATUS_CHGACT);
    5446             : 
    5447             :         /* Set starting sequence number from the ADDBA request. */
    5448           0 :         IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff));
    5449           0 :         iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), ssn);
    5450             : 
    5451             :         /* Disable interrupts for the queue. */
    5452           0 :         iwn_prph_clrbits(sc, IWN4965_SCHED_INTR_MASK, 1 << qid);
    5453             : 
    5454             :         /* Mark the queue as inactive. */
    5455           0 :         iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
    5456           0 :             IWN4965_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid] << 1);
    5457           0 : }
    5458             : 
    5459             : void
    5460           0 : iwn5000_ampdu_tx_start(struct iwn_softc *sc, struct ieee80211_node *ni,
    5461             :     uint8_t tid, uint16_t ssn)
    5462             : {
    5463           0 :         struct iwn_node *wn = (void *)ni;
    5464           0 :         int qid = 10 + tid;
    5465             : 
    5466             :         /* Stop TX scheduler while we're changing its configuration. */
    5467           0 :         iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
    5468             :             IWN5000_TXQ_STATUS_CHGACT);
    5469             : 
    5470             :         /* Assign RA/TID translation to the queue. */
    5471           0 :         iwn_mem_write_2(sc, sc->sched_base + IWN5000_SCHED_TRANS_TBL(qid),
    5472           0 :             wn->id << 4 | tid);
    5473             : 
    5474             :         /* Enable chain-building mode for the queue. */
    5475           0 :         iwn_prph_setbits(sc, IWN5000_SCHED_QCHAIN_SEL, 1 << qid);
    5476             : 
    5477             :         /* Enable aggregation for the queue. */
    5478           0 :         iwn_prph_setbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid);
    5479             : 
    5480             :         /* Set starting sequence number from the ADDBA request. */
    5481           0 :         IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff));
    5482           0 :         iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn);
    5483             : 
    5484             :         /* Set scheduler window size and frame limit. */
    5485           0 :         iwn_mem_write(sc, sc->sched_base + IWN5000_SCHED_QUEUE_OFFSET(qid) + 4,
    5486             :             IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ);
    5487             : 
    5488             :         /* Enable interrupts for the queue. */
    5489           0 :         iwn_prph_setbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid);
    5490             : 
    5491             :         /* Mark the queue as active. */
    5492           0 :         iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
    5493           0 :             IWN5000_TXQ_STATUS_ACTIVE | iwn_tid2fifo[tid]);
    5494           0 : }
    5495             : 
    5496             : void
    5497           0 : iwn5000_ampdu_tx_stop(struct iwn_softc *sc, uint8_t tid, uint16_t ssn)
    5498             : {
    5499           0 :         int qid = 10 + tid;
    5500             : 
    5501             :         /* Stop TX scheduler while we're changing its configuration. */
    5502           0 :         iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
    5503             :             IWN5000_TXQ_STATUS_CHGACT);
    5504             : 
    5505             :         /* Disable aggregation for the queue. */
    5506           0 :         iwn_prph_clrbits(sc, IWN5000_SCHED_AGGR_SEL, 1 << qid);
    5507             : 
    5508             :         /* Set starting sequence number from the ADDBA request. */
    5509           0 :         IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | (ssn & 0xff));
    5510           0 :         iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), ssn);
    5511             : 
    5512             :         /* Disable interrupts for the queue. */
    5513           0 :         iwn_prph_clrbits(sc, IWN5000_SCHED_INTR_MASK, 1 << qid);
    5514             : 
    5515             :         /* Mark the queue as inactive. */
    5516           0 :         iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
    5517           0 :             IWN5000_TXQ_STATUS_INACTIVE | iwn_tid2fifo[tid]);
    5518           0 : }
    5519             : 
    5520             : /*
    5521             :  * Query calibration tables from the initialization firmware.  We do this
    5522             :  * only once at first boot.  Called from a process context.
    5523             :  */
    5524             : int
    5525           0 : iwn5000_query_calibration(struct iwn_softc *sc)
    5526             : {
    5527           0 :         struct iwn5000_calib_config cmd;
    5528             :         int error;
    5529             : 
    5530           0 :         memset(&cmd, 0, sizeof cmd);
    5531           0 :         cmd.ucode.once.enable = 0xffffffff;
    5532           0 :         cmd.ucode.once.start  = 0xffffffff;
    5533           0 :         cmd.ucode.once.send   = 0xffffffff;
    5534           0 :         cmd.ucode.flags       = 0xffffffff;
    5535             :         DPRINTF(("sending calibration query\n"));
    5536           0 :         error = iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof cmd, 0);
    5537           0 :         if (error != 0)
    5538           0 :                 return error;
    5539             : 
    5540             :         /* Wait at most two seconds for calibration to complete. */
    5541           0 :         if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE))
    5542           0 :                 error = tsleep(sc, PCATCH, "iwncal", 2 * hz);
    5543           0 :         return error;
    5544           0 : }
    5545             : 
    5546             : /*
    5547             :  * Send calibration results to the runtime firmware.  These results were
    5548             :  * obtained on first boot from the initialization firmware.
    5549             :  */
    5550             : int
    5551           0 : iwn5000_send_calibration(struct iwn_softc *sc)
    5552             : {
    5553             :         int idx, error;
    5554             : 
    5555           0 :         for (idx = 0; idx < 5; idx++) {
    5556           0 :                 if (sc->calibcmd[idx].buf == NULL)
    5557             :                         continue;       /* No results available. */
    5558             :                 DPRINTF(("send calibration result idx=%d len=%d\n",
    5559             :                     idx, sc->calibcmd[idx].len));
    5560           0 :                 error = iwn_cmd(sc, IWN_CMD_PHY_CALIB, sc->calibcmd[idx].buf,
    5561           0 :                     sc->calibcmd[idx].len, 0);
    5562           0 :                 if (error != 0) {
    5563           0 :                         printf("%s: could not send calibration result\n",
    5564           0 :                             sc->sc_dev.dv_xname);
    5565           0 :                         return error;
    5566             :                 }
    5567             :         }
    5568           0 :         return 0;
    5569           0 : }
    5570             : 
    5571             : int
    5572           0 : iwn5000_send_wimax_coex(struct iwn_softc *sc)
    5573             : {
    5574           0 :         struct iwn5000_wimax_coex wimax;
    5575             : 
    5576             : #ifdef notyet
    5577             :         if (sc->hw_type == IWN_HW_REV_TYPE_6050) {
    5578             :                 /* Enable WiMAX coexistence for combo adapters. */
    5579             :                 wimax.flags =
    5580             :                     IWN_WIMAX_COEX_ASSOC_WA_UNMASK |
    5581             :                     IWN_WIMAX_COEX_UNASSOC_WA_UNMASK |
    5582             :                     IWN_WIMAX_COEX_STA_TABLE_VALID |
    5583             :                     IWN_WIMAX_COEX_ENABLE;
    5584             :                 memcpy(wimax.events, iwn6050_wimax_events,
    5585             :                     sizeof iwn6050_wimax_events);
    5586             :         } else
    5587             : #endif
    5588             :         {
    5589             :                 /* Disable WiMAX coexistence. */
    5590           0 :                 wimax.flags = 0;
    5591           0 :                 memset(wimax.events, 0, sizeof wimax.events);
    5592             :         }
    5593             :         DPRINTF(("Configuring WiMAX coexistence\n"));
    5594           0 :         return iwn_cmd(sc, IWN5000_CMD_WIMAX_COEX, &wimax, sizeof wimax, 0);
    5595           0 : }
    5596             : 
    5597             : int
    5598           0 : iwn5000_crystal_calib(struct iwn_softc *sc)
    5599             : {
    5600           0 :         struct iwn5000_phy_calib_crystal cmd;
    5601             : 
    5602           0 :         memset(&cmd, 0, sizeof cmd);
    5603           0 :         cmd.code = IWN5000_PHY_CALIB_CRYSTAL;
    5604           0 :         cmd.ngroups = 1;
    5605           0 :         cmd.isvalid = 1;
    5606           0 :         cmd.cap_pin[0] = letoh32(sc->eeprom_crystal) & 0xff;
    5607           0 :         cmd.cap_pin[1] = (letoh32(sc->eeprom_crystal) >> 16) & 0xff;
    5608             :         DPRINTF(("sending crystal calibration %d, %d\n",
    5609             :             cmd.cap_pin[0], cmd.cap_pin[1]));
    5610           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
    5611           0 : }
    5612             : 
    5613             : int
    5614           0 : iwn6000_temp_offset_calib(struct iwn_softc *sc)
    5615             : {
    5616           0 :         struct iwn6000_phy_calib_temp_offset cmd;
    5617             : 
    5618           0 :         memset(&cmd, 0, sizeof cmd);
    5619           0 :         cmd.code = IWN6000_PHY_CALIB_TEMP_OFFSET;
    5620           0 :         cmd.ngroups = 1;
    5621           0 :         cmd.isvalid = 1;
    5622           0 :         if (sc->eeprom_temp != 0)
    5623           0 :                 cmd.offset = htole16(sc->eeprom_temp);
    5624             :         else
    5625           0 :                 cmd.offset = htole16(IWN_DEFAULT_TEMP_OFFSET);
    5626             :         DPRINTF(("setting radio sensor offset to %d\n", letoh16(cmd.offset)));
    5627           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
    5628           0 : }
    5629             : 
    5630             : int
    5631           0 : iwn2000_temp_offset_calib(struct iwn_softc *sc)
    5632             : {
    5633           0 :         struct iwn2000_phy_calib_temp_offset cmd;
    5634             : 
    5635           0 :         memset(&cmd, 0, sizeof cmd);
    5636           0 :         cmd.code = IWN2000_PHY_CALIB_TEMP_OFFSET;
    5637           0 :         cmd.ngroups = 1;
    5638           0 :         cmd.isvalid = 1;
    5639           0 :         if (sc->eeprom_rawtemp != 0) {
    5640           0 :                 cmd.offset_low = htole16(sc->eeprom_rawtemp);
    5641           0 :                 cmd.offset_high = htole16(sc->eeprom_temp);
    5642           0 :         } else {
    5643           0 :                 cmd.offset_low = htole16(IWN_DEFAULT_TEMP_OFFSET);
    5644           0 :                 cmd.offset_high = htole16(IWN_DEFAULT_TEMP_OFFSET);
    5645             :         }
    5646           0 :         cmd.burnt_voltage_ref = htole16(sc->eeprom_voltage);
    5647             :         DPRINTF(("setting radio sensor offset to %d:%d, voltage to %d\n",
    5648             :             letoh16(cmd.offset_low), letoh16(cmd.offset_high),
    5649             :             letoh16(cmd.burnt_voltage_ref)));
    5650           0 :         return iwn_cmd(sc, IWN_CMD_PHY_CALIB, &cmd, sizeof cmd, 0);
    5651           0 : }
    5652             : 
    5653             : /*
    5654             :  * This function is called after the runtime firmware notifies us of its
    5655             :  * readiness (called in a process context).
    5656             :  */
    5657             : int
    5658           0 : iwn4965_post_alive(struct iwn_softc *sc)
    5659             : {
    5660             :         int error, qid;
    5661             : 
    5662           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5663           0 :                 return error;
    5664             : 
    5665             :         /* Clear TX scheduler state in SRAM. */
    5666           0 :         sc->sched_base = iwn_prph_read(sc, IWN_SCHED_SRAM_ADDR);
    5667           0 :         iwn_mem_set_region_4(sc, sc->sched_base + IWN4965_SCHED_CTX_OFF, 0,
    5668             :             IWN4965_SCHED_CTX_LEN / sizeof (uint32_t));
    5669             : 
    5670             :         /* Set physical address of TX scheduler rings (1KB aligned). */
    5671           0 :         iwn_prph_write(sc, IWN4965_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10);
    5672             : 
    5673           0 :         IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY);
    5674             : 
    5675             :         /* Disable chain mode for all our 16 queues. */
    5676           0 :         iwn_prph_write(sc, IWN4965_SCHED_QCHAIN_SEL, 0);
    5677             : 
    5678           0 :         for (qid = 0; qid < IWN4965_NTXQUEUES; qid++) {
    5679           0 :                 iwn_prph_write(sc, IWN4965_SCHED_QUEUE_RDPTR(qid), 0);
    5680           0 :                 IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | 0);
    5681             : 
    5682             :                 /* Set scheduler window size. */
    5683           0 :                 iwn_mem_write(sc, sc->sched_base +
    5684           0 :                     IWN4965_SCHED_QUEUE_OFFSET(qid), IWN_SCHED_WINSZ);
    5685             :                 /* Set scheduler frame limit. */
    5686           0 :                 iwn_mem_write(sc, sc->sched_base +
    5687           0 :                     IWN4965_SCHED_QUEUE_OFFSET(qid) + 4,
    5688             :                     IWN_SCHED_LIMIT << 16);
    5689             :         }
    5690             : 
    5691             :         /* Enable interrupts for all our 16 queues. */
    5692           0 :         iwn_prph_write(sc, IWN4965_SCHED_INTR_MASK, 0xffff);
    5693             :         /* Identify TX FIFO rings (0-7). */
    5694           0 :         iwn_prph_write(sc, IWN4965_SCHED_TXFACT, 0xff);
    5695             : 
    5696             :         /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
    5697           0 :         for (qid = 0; qid < 7; qid++) {
    5698             :                 static uint8_t qid2fifo[] = { 3, 2, 1, 0, 4, 5, 6 };
    5699           0 :                 iwn_prph_write(sc, IWN4965_SCHED_QUEUE_STATUS(qid),
    5700           0 :                     IWN4965_TXQ_STATUS_ACTIVE | qid2fifo[qid] << 1);
    5701             :         }
    5702           0 :         iwn_nic_unlock(sc);
    5703           0 :         return 0;
    5704           0 : }
    5705             : 
    5706             : /*
    5707             :  * This function is called after the initialization or runtime firmware
    5708             :  * notifies us of its readiness (called in a process context).
    5709             :  */
    5710             : int
    5711           0 : iwn5000_post_alive(struct iwn_softc *sc)
    5712             : {
    5713             :         int error, qid;
    5714             : 
    5715             :         /* Switch to using ICT interrupt mode. */
    5716           0 :         iwn5000_ict_reset(sc);
    5717             : 
    5718           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5719           0 :                 return error;
    5720             : 
    5721             :         /* Clear TX scheduler state in SRAM. */
    5722           0 :         sc->sched_base = iwn_prph_read(sc, IWN_SCHED_SRAM_ADDR);
    5723           0 :         iwn_mem_set_region_4(sc, sc->sched_base + IWN5000_SCHED_CTX_OFF, 0,
    5724             :             IWN5000_SCHED_CTX_LEN / sizeof (uint32_t));
    5725             : 
    5726             :         /* Set physical address of TX scheduler rings (1KB aligned). */
    5727           0 :         iwn_prph_write(sc, IWN5000_SCHED_DRAM_ADDR, sc->sched_dma.paddr >> 10);
    5728             : 
    5729           0 :         IWN_SETBITS(sc, IWN_FH_TX_CHICKEN, IWN_FH_TX_CHICKEN_SCHED_RETRY);
    5730             : 
    5731             :         /* Enable chain mode for all queues, except command queue. */
    5732           0 :         iwn_prph_write(sc, IWN5000_SCHED_QCHAIN_SEL, 0xfffef);
    5733           0 :         iwn_prph_write(sc, IWN5000_SCHED_AGGR_SEL, 0);
    5734             : 
    5735           0 :         for (qid = 0; qid < IWN5000_NTXQUEUES; qid++) {
    5736           0 :                 iwn_prph_write(sc, IWN5000_SCHED_QUEUE_RDPTR(qid), 0);
    5737           0 :                 IWN_WRITE(sc, IWN_HBUS_TARG_WRPTR, qid << 8 | 0);
    5738             : 
    5739           0 :                 iwn_mem_write(sc, sc->sched_base +
    5740           0 :                     IWN5000_SCHED_QUEUE_OFFSET(qid), 0);
    5741             :                 /* Set scheduler window size and frame limit. */
    5742           0 :                 iwn_mem_write(sc, sc->sched_base +
    5743           0 :                     IWN5000_SCHED_QUEUE_OFFSET(qid) + 4,
    5744             :                     IWN_SCHED_LIMIT << 16 | IWN_SCHED_WINSZ);
    5745             :         }
    5746             : 
    5747             :         /* Enable interrupts for all our 20 queues. */
    5748           0 :         iwn_prph_write(sc, IWN5000_SCHED_INTR_MASK, 0xfffff);
    5749             :         /* Identify TX FIFO rings (0-7). */
    5750           0 :         iwn_prph_write(sc, IWN5000_SCHED_TXFACT, 0xff);
    5751             : 
    5752             :         /* Mark TX rings (4 EDCA + cmd + 2 HCCA) as active. */
    5753           0 :         for (qid = 0; qid < 7; qid++) {
    5754             :                 static uint8_t qid2fifo[] = { 3, 2, 1, 0, 7, 5, 6 };
    5755           0 :                 iwn_prph_write(sc, IWN5000_SCHED_QUEUE_STATUS(qid),
    5756           0 :                     IWN5000_TXQ_STATUS_ACTIVE | qid2fifo[qid]);
    5757             :         }
    5758           0 :         iwn_nic_unlock(sc);
    5759             : 
    5760             :         /* Configure WiMAX coexistence for combo adapters. */
    5761           0 :         error = iwn5000_send_wimax_coex(sc);
    5762           0 :         if (error != 0) {
    5763           0 :                 printf("%s: could not configure WiMAX coexistence\n",
    5764           0 :                     sc->sc_dev.dv_xname);
    5765           0 :                 return error;
    5766             :         }
    5767           0 :         if (sc->hw_type != IWN_HW_REV_TYPE_5150) {
    5768             :                 /* Perform crystal calibration. */
    5769           0 :                 error = iwn5000_crystal_calib(sc);
    5770           0 :                 if (error != 0) {
    5771           0 :                         printf("%s: crystal calibration failed\n",
    5772           0 :                             sc->sc_dev.dv_xname);
    5773           0 :                         return error;
    5774             :                 }
    5775             :         }
    5776           0 :         if (!(sc->sc_flags & IWN_FLAG_CALIB_DONE)) {
    5777             :                 /* Query calibration from the initialization firmware. */
    5778           0 :                 if ((error = iwn5000_query_calibration(sc)) != 0) {
    5779           0 :                         printf("%s: could not query calibration\n",
    5780           0 :                             sc->sc_dev.dv_xname);
    5781           0 :                         return error;
    5782             :                 }
    5783             :                 /*
    5784             :                  * We have the calibration results now, reboot with the
    5785             :                  * runtime firmware (call ourselves recursively!)
    5786             :                  */
    5787           0 :                 iwn_hw_stop(sc);
    5788           0 :                 error = iwn_hw_init(sc);
    5789           0 :         } else {
    5790             :                 /* Send calibration results to runtime firmware. */
    5791           0 :                 error = iwn5000_send_calibration(sc);
    5792             :         }
    5793           0 :         return error;
    5794           0 : }
    5795             : 
    5796             : /*
    5797             :  * The firmware boot code is small and is intended to be copied directly into
    5798             :  * the NIC internal memory (no DMA transfer).
    5799             :  */
    5800             : int
    5801           0 : iwn4965_load_bootcode(struct iwn_softc *sc, const uint8_t *ucode, int size)
    5802             : {
    5803             :         int error, ntries;
    5804             : 
    5805           0 :         size /= sizeof (uint32_t);
    5806             : 
    5807           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5808           0 :                 return error;
    5809             : 
    5810             :         /* Copy microcode image into NIC memory. */
    5811           0 :         iwn_prph_write_region_4(sc, IWN_BSM_SRAM_BASE,
    5812           0 :             (const uint32_t *)ucode, size);
    5813             : 
    5814           0 :         iwn_prph_write(sc, IWN_BSM_WR_MEM_SRC, 0);
    5815           0 :         iwn_prph_write(sc, IWN_BSM_WR_MEM_DST, IWN_FW_TEXT_BASE);
    5816           0 :         iwn_prph_write(sc, IWN_BSM_WR_DWCOUNT, size);
    5817             : 
    5818             :         /* Start boot load now. */
    5819           0 :         iwn_prph_write(sc, IWN_BSM_WR_CTRL, IWN_BSM_WR_CTRL_START);
    5820             : 
    5821             :         /* Wait for transfer to complete. */
    5822           0 :         for (ntries = 0; ntries < 1000; ntries++) {
    5823           0 :                 if (!(iwn_prph_read(sc, IWN_BSM_WR_CTRL) &
    5824             :                     IWN_BSM_WR_CTRL_START))
    5825             :                         break;
    5826           0 :                 DELAY(10);
    5827             :         }
    5828           0 :         if (ntries == 1000) {
    5829           0 :                 printf("%s: could not load boot firmware\n",
    5830           0 :                     sc->sc_dev.dv_xname);
    5831           0 :                 iwn_nic_unlock(sc);
    5832           0 :                 return ETIMEDOUT;
    5833             :         }
    5834             : 
    5835             :         /* Enable boot after power up. */
    5836           0 :         iwn_prph_write(sc, IWN_BSM_WR_CTRL, IWN_BSM_WR_CTRL_START_EN);
    5837             : 
    5838           0 :         iwn_nic_unlock(sc);
    5839           0 :         return 0;
    5840           0 : }
    5841             : 
    5842             : int
    5843           0 : iwn4965_load_firmware(struct iwn_softc *sc)
    5844             : {
    5845           0 :         struct iwn_fw_info *fw = &sc->fw;
    5846           0 :         struct iwn_dma_info *dma = &sc->fw_dma;
    5847             :         int error;
    5848             : 
    5849             :         /* Copy initialization sections into pre-allocated DMA-safe memory. */
    5850           0 :         memcpy(dma->vaddr, fw->init.data, fw->init.datasz);
    5851           0 :         bus_dmamap_sync(sc->sc_dmat, dma->map, 0, fw->init.datasz,
    5852             :             BUS_DMASYNC_PREWRITE);
    5853           0 :         memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ,
    5854             :             fw->init.text, fw->init.textsz);
    5855           0 :         bus_dmamap_sync(sc->sc_dmat, dma->map, IWN4965_FW_DATA_MAXSZ,
    5856             :             fw->init.textsz, BUS_DMASYNC_PREWRITE);
    5857             : 
    5858             :         /* Tell adapter where to find initialization sections. */
    5859           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5860           0 :                 return error;
    5861           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4);
    5862           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->init.datasz);
    5863           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR,
    5864           0 :             (dma->paddr + IWN4965_FW_DATA_MAXSZ) >> 4);
    5865           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_SIZE, fw->init.textsz);
    5866           0 :         iwn_nic_unlock(sc);
    5867             : 
    5868             :         /* Load firmware boot code. */
    5869           0 :         error = iwn4965_load_bootcode(sc, fw->boot.text, fw->boot.textsz);
    5870           0 :         if (error != 0) {
    5871           0 :                 printf("%s: could not load boot firmware\n",
    5872           0 :                     sc->sc_dev.dv_xname);
    5873           0 :                 return error;
    5874             :         }
    5875             :         /* Now press "execute". */
    5876           0 :         IWN_WRITE(sc, IWN_RESET, 0);
    5877             : 
    5878             :         /* Wait at most one second for first alive notification. */
    5879           0 :         if ((error = tsleep(sc, PCATCH, "iwninit", hz)) != 0) {
    5880           0 :                 printf("%s: timeout waiting for adapter to initialize\n",
    5881           0 :                     sc->sc_dev.dv_xname);
    5882           0 :                 return error;
    5883             :         }
    5884             : 
    5885             :         /* Retrieve current temperature for initial TX power calibration. */
    5886           0 :         sc->rawtemp = sc->ucode_info.temp[3].chan20MHz;
    5887           0 :         sc->temp = iwn4965_get_temperature(sc);
    5888             : 
    5889             :         /* Copy runtime sections into pre-allocated DMA-safe memory. */
    5890           0 :         memcpy(dma->vaddr, fw->main.data, fw->main.datasz);
    5891           0 :         bus_dmamap_sync(sc->sc_dmat, dma->map, 0, fw->main.datasz,
    5892             :             BUS_DMASYNC_PREWRITE);
    5893           0 :         memcpy(dma->vaddr + IWN4965_FW_DATA_MAXSZ,
    5894             :             fw->main.text, fw->main.textsz);
    5895           0 :         bus_dmamap_sync(sc->sc_dmat, dma->map, IWN4965_FW_DATA_MAXSZ,
    5896             :             fw->main.textsz, BUS_DMASYNC_PREWRITE);
    5897             : 
    5898             :         /* Tell adapter where to find runtime sections. */
    5899           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5900           0 :                 return error;
    5901           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_DATA_ADDR, dma->paddr >> 4);
    5902           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_DATA_SIZE, fw->main.datasz);
    5903           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_ADDR,
    5904           0 :             (dma->paddr + IWN4965_FW_DATA_MAXSZ) >> 4);
    5905           0 :         iwn_prph_write(sc, IWN_BSM_DRAM_TEXT_SIZE,
    5906           0 :             IWN_FW_UPDATED | fw->main.textsz);
    5907           0 :         iwn_nic_unlock(sc);
    5908             : 
    5909           0 :         return 0;
    5910           0 : }
    5911             : 
    5912             : int
    5913           0 : iwn5000_load_firmware_section(struct iwn_softc *sc, uint32_t dst,
    5914             :     const uint8_t *section, int size)
    5915             : {
    5916           0 :         struct iwn_dma_info *dma = &sc->fw_dma;
    5917             :         int error;
    5918             : 
    5919             :         /* Copy firmware section into pre-allocated DMA-safe memory. */
    5920           0 :         memcpy(dma->vaddr, section, size);
    5921           0 :         bus_dmamap_sync(sc->sc_dmat, dma->map, 0, size, BUS_DMASYNC_PREWRITE);
    5922             : 
    5923           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    5924           0 :                 return error;
    5925             : 
    5926           0 :         IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL),
    5927             :             IWN_FH_TX_CONFIG_DMA_PAUSE);
    5928             : 
    5929           0 :         IWN_WRITE(sc, IWN_FH_SRAM_ADDR(IWN_SRVC_DMACHNL), dst);
    5930           0 :         IWN_WRITE(sc, IWN_FH_TFBD_CTRL0(IWN_SRVC_DMACHNL),
    5931             :             IWN_LOADDR(dma->paddr));
    5932           0 :         IWN_WRITE(sc, IWN_FH_TFBD_CTRL1(IWN_SRVC_DMACHNL),
    5933             :             IWN_HIADDR(dma->paddr) << 28 | size);
    5934           0 :         IWN_WRITE(sc, IWN_FH_TXBUF_STATUS(IWN_SRVC_DMACHNL),
    5935             :             IWN_FH_TXBUF_STATUS_TBNUM(1) |
    5936             :             IWN_FH_TXBUF_STATUS_TBIDX(1) |
    5937             :             IWN_FH_TXBUF_STATUS_TFBD_VALID);
    5938             : 
    5939             :         /* Kick Flow Handler to start DMA transfer. */
    5940           0 :         IWN_WRITE(sc, IWN_FH_TX_CONFIG(IWN_SRVC_DMACHNL),
    5941             :             IWN_FH_TX_CONFIG_DMA_ENA | IWN_FH_TX_CONFIG_CIRQ_HOST_ENDTFD);
    5942             : 
    5943           0 :         iwn_nic_unlock(sc);
    5944             : 
    5945             :         /* Wait at most five seconds for FH DMA transfer to complete. */
    5946           0 :         return tsleep(sc, PCATCH, "iwninit", 5 * hz);
    5947           0 : }
    5948             : 
    5949             : int
    5950           0 : iwn5000_load_firmware(struct iwn_softc *sc)
    5951             : {
    5952             :         struct iwn_fw_part *fw;
    5953             :         int error;
    5954             : 
    5955             :         /* Load the initialization firmware on first boot only. */
    5956           0 :         fw = (sc->sc_flags & IWN_FLAG_CALIB_DONE) ?
    5957           0 :             &sc->fw.main : &sc->fw.init;
    5958             : 
    5959           0 :         error = iwn5000_load_firmware_section(sc, IWN_FW_TEXT_BASE,
    5960           0 :             fw->text, fw->textsz);
    5961           0 :         if (error != 0) {
    5962           0 :                 printf("%s: could not load firmware %s section\n",
    5963           0 :                     sc->sc_dev.dv_xname, ".text");
    5964           0 :                 return error;
    5965             :         }
    5966           0 :         error = iwn5000_load_firmware_section(sc, IWN_FW_DATA_BASE,
    5967           0 :             fw->data, fw->datasz);
    5968           0 :         if (error != 0) {
    5969           0 :                 printf("%s: could not load firmware %s section\n",
    5970           0 :                     sc->sc_dev.dv_xname, ".data");
    5971           0 :                 return error;
    5972             :         }
    5973             : 
    5974             :         /* Now press "execute". */
    5975           0 :         IWN_WRITE(sc, IWN_RESET, 0);
    5976           0 :         return 0;
    5977           0 : }
    5978             : 
    5979             : /*
    5980             :  * Extract text and data sections from a legacy firmware image.
    5981             :  */
    5982             : int
    5983           0 : iwn_read_firmware_leg(struct iwn_softc *sc, struct iwn_fw_info *fw)
    5984             : {
    5985             :         const uint32_t *ptr;
    5986             :         size_t hdrlen = 24;
    5987             :         uint32_t rev;
    5988             : 
    5989           0 :         ptr = (const uint32_t *)fw->data;
    5990           0 :         rev = letoh32(*ptr++);
    5991             : 
    5992             :         /* Check firmware API version. */
    5993           0 :         if (IWN_FW_API(rev) <= 1) {
    5994           0 :                 printf("%s: bad firmware, need API version >=2\n",
    5995           0 :                     sc->sc_dev.dv_xname);
    5996           0 :                 return EINVAL;
    5997             :         }
    5998           0 :         if (IWN_FW_API(rev) >= 3) {
    5999             :                 /* Skip build number (version 2 header). */
    6000             :                 hdrlen += 4;
    6001           0 :                 ptr++;
    6002           0 :         }
    6003           0 :         if (fw->size < hdrlen) {
    6004           0 :                 printf("%s: firmware too short: %zu bytes\n",
    6005           0 :                     sc->sc_dev.dv_xname, fw->size);
    6006           0 :                 return EINVAL;
    6007             :         }
    6008           0 :         fw->main.textsz = letoh32(*ptr++);
    6009           0 :         fw->main.datasz = letoh32(*ptr++);
    6010           0 :         fw->init.textsz = letoh32(*ptr++);
    6011           0 :         fw->init.datasz = letoh32(*ptr++);
    6012           0 :         fw->boot.textsz = letoh32(*ptr++);
    6013             : 
    6014             :         /* Check that all firmware sections fit. */
    6015           0 :         if (fw->size < hdrlen + fw->main.textsz + fw->main.datasz +
    6016           0 :             fw->init.textsz + fw->init.datasz + fw->boot.textsz) {
    6017           0 :                 printf("%s: firmware too short: %zu bytes\n",
    6018           0 :                     sc->sc_dev.dv_xname, fw->size);
    6019           0 :                 return EINVAL;
    6020             :         }
    6021             : 
    6022             :         /* Get pointers to firmware sections. */
    6023           0 :         fw->main.text = (const uint8_t *)ptr;
    6024           0 :         fw->main.data = fw->main.text + fw->main.textsz;
    6025           0 :         fw->init.text = fw->main.data + fw->main.datasz;
    6026           0 :         fw->init.data = fw->init.text + fw->init.textsz;
    6027           0 :         fw->boot.text = fw->init.data + fw->init.datasz;
    6028           0 :         return 0;
    6029           0 : }
    6030             : 
    6031             : /*
    6032             :  * Extract text and data sections from a TLV firmware image.
    6033             :  */
    6034             : int
    6035           0 : iwn_read_firmware_tlv(struct iwn_softc *sc, struct iwn_fw_info *fw,
    6036             :     uint16_t alt)
    6037             : {
    6038             :         const struct iwn_fw_tlv_hdr *hdr;
    6039             :         const struct iwn_fw_tlv *tlv;
    6040             :         const uint8_t *ptr, *end;
    6041             :         uint64_t altmask;
    6042             :         uint32_t len;
    6043             : 
    6044           0 :         if (fw->size < sizeof (*hdr)) {
    6045           0 :                 printf("%s: firmware too short: %zu bytes\n",
    6046           0 :                     sc->sc_dev.dv_xname, fw->size);
    6047           0 :                 return EINVAL;
    6048             :         }
    6049           0 :         hdr = (const struct iwn_fw_tlv_hdr *)fw->data;
    6050           0 :         if (hdr->signature != htole32(IWN_FW_SIGNATURE)) {
    6051           0 :                 printf("%s: bad firmware signature 0x%08x\n",
    6052           0 :                     sc->sc_dev.dv_xname, letoh32(hdr->signature));
    6053           0 :                 return EINVAL;
    6054             :         }
    6055             :         DPRINTF(("FW: \"%.64s\", build 0x%x\n", hdr->descr,
    6056             :             letoh32(hdr->build)));
    6057             : 
    6058             :         /*
    6059             :          * Select the closest supported alternative that is less than
    6060             :          * or equal to the specified one.
    6061             :          */
    6062           0 :         altmask = letoh64(hdr->altmask);
    6063           0 :         while (alt > 0 && !(altmask & (1ULL << alt)))
    6064           0 :                 alt--;  /* Downgrade. */
    6065             :         DPRINTF(("using alternative %d\n", alt));
    6066             : 
    6067           0 :         ptr = (const uint8_t *)(hdr + 1);
    6068           0 :         end = (const uint8_t *)(fw->data + fw->size);
    6069             : 
    6070             :         /* Parse type-length-value fields. */
    6071           0 :         while (ptr + sizeof (*tlv) <= end) {
    6072           0 :                 tlv = (const struct iwn_fw_tlv *)ptr;
    6073           0 :                 len = letoh32(tlv->len);
    6074             : 
    6075             :                 ptr += sizeof (*tlv);
    6076           0 :                 if (ptr + len > end) {
    6077           0 :                         printf("%s: firmware too short: %zu bytes\n",
    6078           0 :                             sc->sc_dev.dv_xname, fw->size);
    6079           0 :                         return EINVAL;
    6080             :                 }
    6081             :                 /* Skip other alternatives. */
    6082           0 :                 if (tlv->alt != 0 && tlv->alt != htole16(alt))
    6083             :                         goto next;
    6084             : 
    6085           0 :                 switch (letoh16(tlv->type)) {
    6086             :                 case IWN_FW_TLV_MAIN_TEXT:
    6087           0 :                         fw->main.text = ptr;
    6088           0 :                         fw->main.textsz = len;
    6089           0 :                         break;
    6090             :                 case IWN_FW_TLV_MAIN_DATA:
    6091           0 :                         fw->main.data = ptr;
    6092           0 :                         fw->main.datasz = len;
    6093           0 :                         break;
    6094             :                 case IWN_FW_TLV_INIT_TEXT:
    6095           0 :                         fw->init.text = ptr;
    6096           0 :                         fw->init.textsz = len;
    6097           0 :                         break;
    6098             :                 case IWN_FW_TLV_INIT_DATA:
    6099           0 :                         fw->init.data = ptr;
    6100           0 :                         fw->init.datasz = len;
    6101           0 :                         break;
    6102             :                 case IWN_FW_TLV_BOOT_TEXT:
    6103           0 :                         fw->boot.text = ptr;
    6104           0 :                         fw->boot.textsz = len;
    6105           0 :                         break;
    6106             :                 case IWN_FW_TLV_ENH_SENS:
    6107           0 :                         if (len !=  0) {
    6108           0 :                                 printf("%s: TLV type %d has invalid size %u\n",
    6109           0 :                                     sc->sc_dev.dv_xname, letoh16(tlv->type),
    6110             :                                     len);
    6111           0 :                                 goto next;
    6112             :                         }
    6113           0 :                         sc->sc_flags |= IWN_FLAG_ENH_SENS;
    6114           0 :                         break;
    6115             :                 case IWN_FW_TLV_PHY_CALIB:
    6116           0 :                         if (len != sizeof(uint32_t)) {
    6117           0 :                                 printf("%s: TLV type %d has invalid size %u\n",
    6118           0 :                                     sc->sc_dev.dv_xname, letoh16(tlv->type),
    6119             :                                     len);
    6120           0 :                                 goto next;
    6121             :                         }
    6122           0 :                         if (letoh32(*ptr) <= IWN5000_PHY_CALIB_MAX) {
    6123           0 :                                 sc->reset_noise_gain = letoh32(*ptr);
    6124           0 :                                 sc->noise_gain = letoh32(*ptr) + 1;
    6125           0 :                         }
    6126             :                         break;
    6127             :                 case IWN_FW_TLV_FLAGS:
    6128           0 :                         if (len < sizeof(uint32_t))
    6129             :                                 break;
    6130           0 :                         if (len % sizeof(uint32_t))
    6131             :                                 break;
    6132           0 :                         sc->tlv_feature_flags = letoh32(*ptr);
    6133             :                         DPRINTF(("feature: 0x%08x\n", sc->tlv_feature_flags));
    6134           0 :                         break;
    6135             :                 default:
    6136             :                         DPRINTF(("TLV type %d not handled\n",
    6137             :                             letoh16(tlv->type)));
    6138             :                         break;
    6139             :                 }
    6140             :  next:          /* TLV fields are 32-bit aligned. */
    6141           0 :                 ptr += (len + 3) & ~3;
    6142             :         }
    6143           0 :         return 0;
    6144           0 : }
    6145             : 
    6146             : int
    6147           0 : iwn_read_firmware(struct iwn_softc *sc)
    6148             : {
    6149           0 :         struct iwn_fw_info *fw = &sc->fw;
    6150             :         int error;
    6151             : 
    6152             :         /*
    6153             :          * Some PHY calibration commands are firmware-dependent; these
    6154             :          * are the default values that will be overridden if
    6155             :          * necessary.
    6156             :          */
    6157           0 :         sc->reset_noise_gain = IWN5000_PHY_CALIB_RESET_NOISE_GAIN;
    6158           0 :         sc->noise_gain = IWN5000_PHY_CALIB_NOISE_GAIN;
    6159             : 
    6160           0 :         memset(fw, 0, sizeof (*fw));
    6161             : 
    6162             :         /* Read firmware image from filesystem. */
    6163           0 :         if ((error = loadfirmware(sc->fwname, &fw->data, &fw->size)) != 0) {
    6164           0 :                 printf("%s: could not read firmware %s (error %d)\n",
    6165           0 :                     sc->sc_dev.dv_xname, sc->fwname, error);
    6166           0 :                 return error;
    6167             :         }
    6168           0 :         if (fw->size < sizeof (uint32_t)) {
    6169           0 :                 printf("%s: firmware too short: %zu bytes\n",
    6170           0 :                     sc->sc_dev.dv_xname, fw->size);
    6171           0 :                 free(fw->data, M_DEVBUF, fw->size);
    6172           0 :                 return EINVAL;
    6173             :         }
    6174             : 
    6175             :         /* Retrieve text and data sections. */
    6176           0 :         if (*(const uint32_t *)fw->data != 0)        /* Legacy image. */
    6177           0 :                 error = iwn_read_firmware_leg(sc, fw);
    6178             :         else
    6179           0 :                 error = iwn_read_firmware_tlv(sc, fw, 1);
    6180           0 :         if (error != 0) {
    6181           0 :                 printf("%s: could not read firmware sections\n",
    6182           0 :                     sc->sc_dev.dv_xname);
    6183           0 :                 free(fw->data, M_DEVBUF, fw->size);
    6184           0 :                 return error;
    6185             :         }
    6186             : 
    6187             :         /* Make sure text and data sections fit in hardware memory. */
    6188           0 :         if (fw->main.textsz > sc->fw_text_maxsz ||
    6189           0 :             fw->main.datasz > sc->fw_data_maxsz ||
    6190           0 :             fw->init.textsz > sc->fw_text_maxsz ||
    6191           0 :             fw->init.datasz > sc->fw_data_maxsz ||
    6192           0 :             fw->boot.textsz > IWN_FW_BOOT_TEXT_MAXSZ ||
    6193           0 :             (fw->boot.textsz & 3) != 0) {
    6194           0 :                 printf("%s: firmware sections too large\n",
    6195           0 :                     sc->sc_dev.dv_xname);
    6196           0 :                 free(fw->data, M_DEVBUF, fw->size);
    6197           0 :                 return EINVAL;
    6198             :         }
    6199             : 
    6200             :         /* We can proceed with loading the firmware. */
    6201           0 :         return 0;
    6202           0 : }
    6203             : 
    6204             : int
    6205           0 : iwn_clock_wait(struct iwn_softc *sc)
    6206             : {
    6207             :         int ntries;
    6208             : 
    6209             :         /* Set "initialization complete" bit. */
    6210           0 :         IWN_SETBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_INIT_DONE);
    6211             : 
    6212             :         /* Wait for clock stabilization. */
    6213           0 :         for (ntries = 0; ntries < 2500; ntries++) {
    6214           0 :                 if (IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_MAC_CLOCK_READY)
    6215           0 :                         return 0;
    6216           0 :                 DELAY(10);
    6217             :         }
    6218           0 :         printf("%s: timeout waiting for clock stabilization\n",
    6219           0 :             sc->sc_dev.dv_xname);
    6220           0 :         return ETIMEDOUT;
    6221           0 : }
    6222             : 
    6223             : int
    6224           0 : iwn_apm_init(struct iwn_softc *sc)
    6225             : {
    6226             :         pcireg_t reg;
    6227             :         int error;
    6228             : 
    6229             :         /* Disable L0s exit timer (NMI bug workaround). */
    6230           0 :         IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_DIS_L0S_TIMER);
    6231             :         /* Don't wait for ICH L0s (ICH bug workaround). */
    6232           0 :         IWN_SETBITS(sc, IWN_GIO_CHICKEN, IWN_GIO_CHICKEN_L1A_NO_L0S_RX);
    6233             : 
    6234             :         /* Set FH wait threshold to max (HW bug under stress workaround). */
    6235           0 :         IWN_SETBITS(sc, IWN_DBG_HPET_MEM, 0xffff0000);
    6236             : 
    6237             :         /* Enable HAP INTA to move adapter from L1a to L0s. */
    6238           0 :         IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_HAP_WAKE_L1A);
    6239             : 
    6240             :         /* Retrieve PCIe Active State Power Management (ASPM). */
    6241           0 :         reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag,
    6242           0 :             sc->sc_cap_off + PCI_PCIE_LCSR);
    6243             :         /* Workaround for HW instability in PCIe L0->L0s->L1 transition. */
    6244           0 :         if (reg & PCI_PCIE_LCSR_ASPM_L1)    /* L1 Entry enabled. */
    6245           0 :                 IWN_SETBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA);
    6246             :         else
    6247           0 :                 IWN_CLRBITS(sc, IWN_GIO, IWN_GIO_L0S_ENA);
    6248             : 
    6249           0 :         if (sc->hw_type != IWN_HW_REV_TYPE_4965 &&
    6250           0 :             sc->hw_type <= IWN_HW_REV_TYPE_1000)
    6251           0 :                 IWN_SETBITS(sc, IWN_ANA_PLL, IWN_ANA_PLL_INIT);
    6252             : 
    6253             :         /* Wait for clock stabilization before accessing prph. */
    6254           0 :         if ((error = iwn_clock_wait(sc)) != 0)
    6255           0 :                 return error;
    6256             : 
    6257           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    6258           0 :                 return error;
    6259           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_4965) {
    6260             :                 /* Enable DMA and BSM (Bootstrap State Machine). */
    6261           0 :                 iwn_prph_write(sc, IWN_APMG_CLK_EN,
    6262             :                     IWN_APMG_CLK_CTRL_DMA_CLK_RQT |
    6263             :                     IWN_APMG_CLK_CTRL_BSM_CLK_RQT);
    6264           0 :         } else {
    6265             :                 /* Enable DMA. */
    6266           0 :                 iwn_prph_write(sc, IWN_APMG_CLK_EN,
    6267             :                     IWN_APMG_CLK_CTRL_DMA_CLK_RQT);
    6268             :         }
    6269           0 :         DELAY(20);
    6270             :         /* Disable L1-Active. */
    6271           0 :         iwn_prph_setbits(sc, IWN_APMG_PCI_STT, IWN_APMG_PCI_STT_L1A_DIS);
    6272           0 :         iwn_nic_unlock(sc);
    6273             : 
    6274           0 :         return 0;
    6275           0 : }
    6276             : 
    6277             : void
    6278           0 : iwn_apm_stop_master(struct iwn_softc *sc)
    6279             : {
    6280             :         int ntries;
    6281             : 
    6282             :         /* Stop busmaster DMA activity. */
    6283           0 :         IWN_SETBITS(sc, IWN_RESET, IWN_RESET_STOP_MASTER);
    6284           0 :         for (ntries = 0; ntries < 100; ntries++) {
    6285           0 :                 if (IWN_READ(sc, IWN_RESET) & IWN_RESET_MASTER_DISABLED)
    6286           0 :                         return;
    6287           0 :                 DELAY(10);
    6288             :         }
    6289           0 :         printf("%s: timeout waiting for master\n", sc->sc_dev.dv_xname);
    6290           0 : }
    6291             : 
    6292             : void
    6293           0 : iwn_apm_stop(struct iwn_softc *sc)
    6294             : {
    6295           0 :         iwn_apm_stop_master(sc);
    6296             : 
    6297             :         /* Reset the entire device. */
    6298           0 :         IWN_SETBITS(sc, IWN_RESET, IWN_RESET_SW);
    6299           0 :         DELAY(10);
    6300             :         /* Clear "initialization complete" bit. */
    6301           0 :         IWN_CLRBITS(sc, IWN_GP_CNTRL, IWN_GP_CNTRL_INIT_DONE);
    6302           0 : }
    6303             : 
    6304             : int
    6305           0 : iwn4965_nic_config(struct iwn_softc *sc)
    6306             : {
    6307           0 :         if (IWN_RFCFG_TYPE(sc->rfcfg) == 1) {
    6308             :                 /*
    6309             :                  * I don't believe this to be correct but this is what the
    6310             :                  * vendor driver is doing. Probably the bits should not be
    6311             :                  * shifted in IWN_RFCFG_*.
    6312             :                  */
    6313           0 :                 IWN_SETBITS(sc, IWN_HW_IF_CONFIG,
    6314             :                     IWN_RFCFG_TYPE(sc->rfcfg) |
    6315             :                     IWN_RFCFG_STEP(sc->rfcfg) |
    6316             :                     IWN_RFCFG_DASH(sc->rfcfg));
    6317           0 :         }
    6318           0 :         IWN_SETBITS(sc, IWN_HW_IF_CONFIG,
    6319             :             IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI);
    6320           0 :         return 0;
    6321             : }
    6322             : 
    6323             : int
    6324           0 : iwn5000_nic_config(struct iwn_softc *sc)
    6325             : {
    6326             :         uint32_t tmp;
    6327             :         int error;
    6328             : 
    6329           0 :         if (IWN_RFCFG_TYPE(sc->rfcfg) < 3) {
    6330           0 :                 IWN_SETBITS(sc, IWN_HW_IF_CONFIG,
    6331             :                     IWN_RFCFG_TYPE(sc->rfcfg) |
    6332             :                     IWN_RFCFG_STEP(sc->rfcfg) |
    6333             :                     IWN_RFCFG_DASH(sc->rfcfg));
    6334           0 :         }
    6335           0 :         IWN_SETBITS(sc, IWN_HW_IF_CONFIG,
    6336             :             IWN_HW_IF_CONFIG_RADIO_SI | IWN_HW_IF_CONFIG_MAC_SI);
    6337             : 
    6338           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    6339           0 :                 return error;
    6340           0 :         iwn_prph_setbits(sc, IWN_APMG_PS, IWN_APMG_PS_EARLY_PWROFF_DIS);
    6341             : 
    6342           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_1000) {
    6343             :                 /*
    6344             :                  * Select first Switching Voltage Regulator (1.32V) to
    6345             :                  * solve a stability issue related to noisy DC2DC line
    6346             :                  * in the silicon of 1000 Series.
    6347             :                  */
    6348           0 :                 tmp = iwn_prph_read(sc, IWN_APMG_DIGITAL_SVR);
    6349           0 :                 tmp &= ~IWN_APMG_DIGITAL_SVR_VOLTAGE_MASK;
    6350           0 :                 tmp |= IWN_APMG_DIGITAL_SVR_VOLTAGE_1_32;
    6351           0 :                 iwn_prph_write(sc, IWN_APMG_DIGITAL_SVR, tmp);
    6352           0 :         }
    6353           0 :         iwn_nic_unlock(sc);
    6354             : 
    6355           0 :         if (sc->sc_flags & IWN_FLAG_INTERNAL_PA) {
    6356             :                 /* Use internal power amplifier only. */
    6357           0 :                 IWN_WRITE(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_2X2_IPA);
    6358           0 :         }
    6359           0 :         if ((sc->hw_type == IWN_HW_REV_TYPE_6050 ||
    6360           0 :              sc->hw_type == IWN_HW_REV_TYPE_6005) && sc->calib_ver >= 6) {
    6361             :                 /* Indicate that ROM calibration version is >=6. */
    6362           0 :                 IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_CALIB_VER6);
    6363           0 :         }
    6364           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_6005)
    6365           0 :                 IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_6050_1X2);
    6366           0 :         if (sc->hw_type == IWN_HW_REV_TYPE_2030 ||
    6367           0 :             sc->hw_type == IWN_HW_REV_TYPE_2000 ||
    6368           0 :             sc->hw_type == IWN_HW_REV_TYPE_135 ||
    6369           0 :             sc->hw_type == IWN_HW_REV_TYPE_105)
    6370           0 :                 IWN_SETBITS(sc, IWN_GP_DRIVER, IWN_GP_DRIVER_RADIO_IQ_INVERT);
    6371           0 :         return 0;
    6372           0 : }
    6373             : 
    6374             : /*
    6375             :  * Take NIC ownership over Intel Active Management Technology (AMT).
    6376             :  */
    6377             : int
    6378           0 : iwn_hw_prepare(struct iwn_softc *sc)
    6379             : {
    6380             :         int ntries;
    6381             : 
    6382             :         /* Check if hardware is ready. */
    6383           0 :         IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_NIC_READY);
    6384           0 :         for (ntries = 0; ntries < 5; ntries++) {
    6385           0 :                 if (IWN_READ(sc, IWN_HW_IF_CONFIG) &
    6386             :                     IWN_HW_IF_CONFIG_NIC_READY)
    6387           0 :                         return 0;
    6388           0 :                 DELAY(10);
    6389             :         }
    6390             : 
    6391             :         /* Hardware not ready, force into ready state. */
    6392           0 :         IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_PREPARE);
    6393           0 :         for (ntries = 0; ntries < 15000; ntries++) {
    6394           0 :                 if (!(IWN_READ(sc, IWN_HW_IF_CONFIG) &
    6395             :                     IWN_HW_IF_CONFIG_PREPARE_DONE))
    6396             :                         break;
    6397           0 :                 DELAY(10);
    6398             :         }
    6399           0 :         if (ntries == 15000)
    6400           0 :                 return ETIMEDOUT;
    6401             : 
    6402             :         /* Hardware should be ready now. */
    6403           0 :         IWN_SETBITS(sc, IWN_HW_IF_CONFIG, IWN_HW_IF_CONFIG_NIC_READY);
    6404           0 :         for (ntries = 0; ntries < 5; ntries++) {
    6405           0 :                 if (IWN_READ(sc, IWN_HW_IF_CONFIG) &
    6406             :                     IWN_HW_IF_CONFIG_NIC_READY)
    6407           0 :                         return 0;
    6408           0 :                 DELAY(10);
    6409             :         }
    6410           0 :         return ETIMEDOUT;
    6411           0 : }
    6412             : 
    6413             : int
    6414           0 : iwn_hw_init(struct iwn_softc *sc)
    6415             : {
    6416           0 :         struct iwn_ops *ops = &sc->ops;
    6417             :         int error, chnl, qid;
    6418             : 
    6419             :         /* Clear pending interrupts. */
    6420           0 :         IWN_WRITE(sc, IWN_INT, 0xffffffff);
    6421             : 
    6422           0 :         if ((error = iwn_apm_init(sc)) != 0) {
    6423           0 :                 printf("%s: could not power on adapter\n",
    6424           0 :                     sc->sc_dev.dv_xname);
    6425           0 :                 return error;
    6426             :         }
    6427             : 
    6428             :         /* Select VMAIN power source. */
    6429           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    6430           0 :                 return error;
    6431           0 :         iwn_prph_clrbits(sc, IWN_APMG_PS, IWN_APMG_PS_PWR_SRC_MASK);
    6432           0 :         iwn_nic_unlock(sc);
    6433             : 
    6434             :         /* Perform adapter-specific initialization. */
    6435           0 :         if ((error = ops->nic_config(sc)) != 0)
    6436           0 :                 return error;
    6437             : 
    6438             :         /* Initialize RX ring. */
    6439           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    6440           0 :                 return error;
    6441           0 :         IWN_WRITE(sc, IWN_FH_RX_CONFIG, 0);
    6442           0 :         IWN_WRITE(sc, IWN_FH_RX_WPTR, 0);
    6443             :         /* Set physical address of RX ring (256-byte aligned). */
    6444           0 :         IWN_WRITE(sc, IWN_FH_RX_BASE, sc->rxq.desc_dma.paddr >> 8);
    6445             :         /* Set physical address of RX status (16-byte aligned). */
    6446           0 :         IWN_WRITE(sc, IWN_FH_STATUS_WPTR, sc->rxq.stat_dma.paddr >> 4);
    6447             :         /* Enable RX. */
    6448           0 :         IWN_WRITE(sc, IWN_FH_RX_CONFIG,
    6449             :             IWN_FH_RX_CONFIG_ENA           |
    6450             :             IWN_FH_RX_CONFIG_IGN_RXF_EMPTY |    /* HW bug workaround */
    6451             :             IWN_FH_RX_CONFIG_IRQ_DST_HOST  |
    6452             :             IWN_FH_RX_CONFIG_SINGLE_FRAME  |
    6453             :             IWN_FH_RX_CONFIG_RB_TIMEOUT(0x11) | /* about 1/2 msec */
    6454             :             IWN_FH_RX_CONFIG_NRBD(IWN_RX_RING_COUNT_LOG));
    6455           0 :         iwn_nic_unlock(sc);
    6456           0 :         IWN_WRITE(sc, IWN_FH_RX_WPTR, (IWN_RX_RING_COUNT - 1) & ~7);
    6457             : 
    6458           0 :         if ((error = iwn_nic_lock(sc)) != 0)
    6459           0 :                 return error;
    6460             : 
    6461             :         /* Initialize TX scheduler. */
    6462           0 :         iwn_prph_write(sc, sc->sched_txfact_addr, 0);
    6463             : 
    6464             :         /* Set physical address of "keep warm" page (16-byte aligned). */
    6465           0 :         IWN_WRITE(sc, IWN_FH_KW_ADDR, sc->kw_dma.paddr >> 4);
    6466             : 
    6467             :         /* Initialize TX rings. */
    6468           0 :         for (qid = 0; qid < sc->ntxqs; qid++) {
    6469           0 :                 struct iwn_tx_ring *txq = &sc->txq[qid];
    6470             : 
    6471             :                 /* Set physical address of TX ring (256-byte aligned). */
    6472           0 :                 IWN_WRITE(sc, IWN_FH_CBBC_QUEUE(qid),
    6473             :                     txq->desc_dma.paddr >> 8);
    6474             :         }
    6475           0 :         iwn_nic_unlock(sc);
    6476             : 
    6477             :         /* Enable DMA channels. */
    6478           0 :         for (chnl = 0; chnl < sc->ndmachnls; chnl++) {
    6479           0 :                 IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl),
    6480             :                     IWN_FH_TX_CONFIG_DMA_ENA |
    6481             :                     IWN_FH_TX_CONFIG_DMA_CREDIT_ENA);
    6482             :         }
    6483             : 
    6484             :         /* Clear "radio off" and "commands blocked" bits. */
    6485           0 :         IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL);
    6486           0 :         IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_CMD_BLOCKED);
    6487             : 
    6488             :         /* Clear pending interrupts. */
    6489           0 :         IWN_WRITE(sc, IWN_INT, 0xffffffff);
    6490             :         /* Enable interrupt coalescing. */
    6491           0 :         IWN_WRITE(sc, IWN_INT_COALESCING, 512 / 8);
    6492             :         /* Enable interrupts. */
    6493           0 :         IWN_WRITE(sc, IWN_INT_MASK, sc->int_mask);
    6494             : 
    6495             :         /* _Really_ make sure "radio off" bit is cleared! */
    6496           0 :         IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL);
    6497           0 :         IWN_WRITE(sc, IWN_UCODE_GP1_CLR, IWN_UCODE_GP1_RFKILL);
    6498             : 
    6499             :         /* Enable shadow registers. */
    6500           0 :         if (sc->hw_type >= IWN_HW_REV_TYPE_6000)
    6501           0 :                 IWN_SETBITS(sc, IWN_SHADOW_REG_CTRL, 0x800fffff);
    6502             : 
    6503           0 :         if ((error = ops->load_firmware(sc)) != 0) {
    6504           0 :                 printf("%s: could not load firmware\n", sc->sc_dev.dv_xname);
    6505           0 :                 return error;
    6506             :         }
    6507             :         /* Wait at most one second for firmware alive notification. */
    6508           0 :         if ((error = tsleep(sc, PCATCH, "iwninit", hz)) != 0) {
    6509           0 :                 printf("%s: timeout waiting for adapter to initialize\n",
    6510           0 :                     sc->sc_dev.dv_xname);
    6511           0 :                 return error;
    6512             :         }
    6513             :         /* Do post-firmware initialization. */
    6514           0 :         return ops->post_alive(sc);
    6515           0 : }
    6516             : 
    6517             : void
    6518           0 : iwn_hw_stop(struct iwn_softc *sc)
    6519             : {
    6520             :         int chnl, qid, ntries;
    6521             : 
    6522           0 :         IWN_WRITE(sc, IWN_RESET, IWN_RESET_NEVO);
    6523             : 
    6524             :         /* Disable interrupts. */
    6525           0 :         IWN_WRITE(sc, IWN_INT_MASK, 0);
    6526           0 :         IWN_WRITE(sc, IWN_INT, 0xffffffff);
    6527           0 :         IWN_WRITE(sc, IWN_FH_INT, 0xffffffff);
    6528           0 :         sc->sc_flags &= ~IWN_FLAG_USE_ICT;
    6529             : 
    6530             :         /* Make sure we no longer hold the NIC lock. */
    6531           0 :         iwn_nic_unlock(sc);
    6532             : 
    6533             :         /* Stop TX scheduler. */
    6534           0 :         iwn_prph_write(sc, sc->sched_txfact_addr, 0);
    6535             : 
    6536             :         /* Stop all DMA channels. */
    6537           0 :         if (iwn_nic_lock(sc) == 0) {
    6538           0 :                 for (chnl = 0; chnl < sc->ndmachnls; chnl++) {
    6539           0 :                         IWN_WRITE(sc, IWN_FH_TX_CONFIG(chnl), 0);
    6540           0 :                         for (ntries = 0; ntries < 200; ntries++) {
    6541           0 :                                 if (IWN_READ(sc, IWN_FH_TX_STATUS) &
    6542           0 :                                     IWN_FH_TX_STATUS_IDLE(chnl))
    6543             :                                         break;
    6544           0 :                                 DELAY(10);
    6545             :                         }
    6546             :                 }
    6547           0 :                 iwn_nic_unlock(sc);
    6548           0 :         }
    6549             : 
    6550             :         /* Stop RX ring. */
    6551           0 :         iwn_reset_rx_ring(sc, &sc->rxq);
    6552             : 
    6553             :         /* Reset all TX rings. */
    6554           0 :         for (qid = 0; qid < sc->ntxqs; qid++)
    6555           0 :                 iwn_reset_tx_ring(sc, &sc->txq[qid]);
    6556             : 
    6557           0 :         if (iwn_nic_lock(sc) == 0) {
    6558           0 :                 iwn_prph_write(sc, IWN_APMG_CLK_DIS,
    6559             :                     IWN_APMG_CLK_CTRL_DMA_CLK_RQT);
    6560           0 :                 iwn_nic_unlock(sc);
    6561           0 :         }
    6562           0 :         DELAY(5);
    6563             :         /* Power OFF adapter. */
    6564           0 :         iwn_apm_stop(sc);
    6565           0 : }
    6566             : 
    6567             : int
    6568           0 : iwn_init(struct ifnet *ifp)
    6569             : {
    6570           0 :         struct iwn_softc *sc = ifp->if_softc;
    6571           0 :         struct ieee80211com *ic = &sc->sc_ic;
    6572             :         int error;
    6573             : 
    6574           0 :         memset(sc->bss_node_addr, 0, sizeof(sc->bss_node_addr));
    6575             : 
    6576           0 :         if ((error = iwn_hw_prepare(sc)) != 0) {
    6577           0 :                 printf("%s: hardware not ready\n", sc->sc_dev.dv_xname);
    6578           0 :                 goto fail;
    6579             :         }
    6580             : 
    6581             :         /* Check that the radio is not disabled by hardware switch. */
    6582           0 :         if (!(IWN_READ(sc, IWN_GP_CNTRL) & IWN_GP_CNTRL_RFKILL)) {
    6583           0 :                 printf("%s: radio is disabled by hardware switch\n",
    6584           0 :                     sc->sc_dev.dv_xname);
    6585             :                 error = EPERM;  /* :-) */
    6586           0 :                 goto fail;
    6587             :         }
    6588             : 
    6589             :         /* Read firmware images from the filesystem. */
    6590           0 :         if ((error = iwn_read_firmware(sc)) != 0) {
    6591           0 :                 printf("%s: could not read firmware\n", sc->sc_dev.dv_xname);
    6592           0 :                 goto fail;
    6593             :         }
    6594             : 
    6595             :         /* Initialize interrupt mask to default value. */
    6596           0 :         sc->int_mask = IWN_INT_MASK_DEF;
    6597           0 :         sc->sc_flags &= ~IWN_FLAG_USE_ICT;
    6598             : 
    6599             :         /* Initialize hardware and upload firmware. */
    6600           0 :         error = iwn_hw_init(sc);
    6601           0 :         free(sc->fw.data, M_DEVBUF, sc->fw.size);
    6602           0 :         if (error != 0) {
    6603           0 :                 printf("%s: could not initialize hardware\n",
    6604           0 :                     sc->sc_dev.dv_xname);
    6605           0 :                 goto fail;
    6606             :         }
    6607             : 
    6608             :         /* Configure adapter now that it is ready. */
    6609           0 :         if ((error = iwn_config(sc)) != 0) {
    6610           0 :                 printf("%s: could not configure device\n",
    6611           0 :                     sc->sc_dev.dv_xname);
    6612           0 :                 goto fail;
    6613             :         }
    6614             : 
    6615           0 :         ifq_clr_oactive(&ifp->if_snd);
    6616           0 :         ifp->if_flags |= IFF_RUNNING;
    6617             : 
    6618           0 :         if (ic->ic_opmode != IEEE80211_M_MONITOR)
    6619           0 :                 ieee80211_begin_scan(ifp);
    6620             :         else
    6621           0 :                 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
    6622             : 
    6623           0 :         return 0;
    6624             : 
    6625           0 : fail:   iwn_stop(ifp, 1);
    6626           0 :         return error;
    6627           0 : }
    6628             : 
    6629             : void
    6630           0 : iwn_stop(struct ifnet *ifp, int disable)
    6631             : {
    6632           0 :         struct iwn_softc *sc = ifp->if_softc;
    6633           0 :         struct ieee80211com *ic = &sc->sc_ic;
    6634             : 
    6635           0 :         timeout_del(&sc->calib_to);
    6636           0 :         ifp->if_timer = sc->sc_tx_timer = 0;
    6637           0 :         ifp->if_flags &= ~IFF_RUNNING;
    6638           0 :         ifq_clr_oactive(&ifp->if_snd);
    6639             : 
    6640           0 :         ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
    6641             : 
    6642             :         /* Power OFF hardware. */
    6643           0 :         iwn_hw_stop(sc);
    6644           0 : }

Generated by: LCOV version 1.13