Home | History | Annotate | Line # | Download | only in pci
if_iwm.c revision 1.29.2.8
      1  1.29.2.8  skrll /*	$NetBSD: if_iwm.c,v 1.29.2.8 2016/07/09 20:25:04 skrll Exp $	*/
      2  1.29.2.3  skrll /*	OpenBSD: if_iwm.c,v 1.41 2015/05/22 06:50:54 kettenis Exp	*/
      3  1.29.2.2  skrll 
      4  1.29.2.2  skrll /*
      5  1.29.2.2  skrll  * Copyright (c) 2014 genua mbh <info (at) genua.de>
      6  1.29.2.2  skrll  * Copyright (c) 2014 Fixup Software Ltd.
      7  1.29.2.2  skrll  *
      8  1.29.2.2  skrll  * Permission to use, copy, modify, and distribute this software for any
      9  1.29.2.2  skrll  * purpose with or without fee is hereby granted, provided that the above
     10  1.29.2.2  skrll  * copyright notice and this permission notice appear in all copies.
     11  1.29.2.2  skrll  *
     12  1.29.2.2  skrll  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     13  1.29.2.2  skrll  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     14  1.29.2.2  skrll  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     15  1.29.2.2  skrll  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     16  1.29.2.2  skrll  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     17  1.29.2.2  skrll  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     18  1.29.2.2  skrll  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     19  1.29.2.2  skrll  */
     20  1.29.2.2  skrll 
     21  1.29.2.2  skrll /*-
     22  1.29.2.2  skrll  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
     23  1.29.2.2  skrll  * which were used as the reference documentation for this implementation.
     24  1.29.2.2  skrll  *
     25  1.29.2.2  skrll  * Driver version we are currently based off of is
     26  1.29.2.2  skrll  * Linux 3.14.3 (tag id a2df521e42b1d9a23f620ac79dbfe8655a8391dd)
     27  1.29.2.2  skrll  *
     28  1.29.2.2  skrll  ***********************************************************************
     29  1.29.2.2  skrll  *
     30  1.29.2.2  skrll  * This file is provided under a dual BSD/GPLv2 license.  When using or
     31  1.29.2.2  skrll  * redistributing this file, you may do so under either license.
     32  1.29.2.2  skrll  *
     33  1.29.2.2  skrll  * GPL LICENSE SUMMARY
     34  1.29.2.2  skrll  *
     35  1.29.2.2  skrll  * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
     36  1.29.2.2  skrll  *
     37  1.29.2.2  skrll  * This program is free software; you can redistribute it and/or modify
     38  1.29.2.2  skrll  * it under the terms of version 2 of the GNU General Public License as
     39  1.29.2.2  skrll  * published by the Free Software Foundation.
     40  1.29.2.2  skrll  *
     41  1.29.2.2  skrll  * This program is distributed in the hope that it will be useful, but
     42  1.29.2.2  skrll  * WITHOUT ANY WARRANTY; without even the implied warranty of
     43  1.29.2.2  skrll  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     44  1.29.2.2  skrll  * General Public License for more details.
     45  1.29.2.2  skrll  *
     46  1.29.2.2  skrll  * You should have received a copy of the GNU General Public License
     47  1.29.2.2  skrll  * along with this program; if not, write to the Free Software
     48  1.29.2.2  skrll  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
     49  1.29.2.2  skrll  * USA
     50  1.29.2.2  skrll  *
     51  1.29.2.2  skrll  * The full GNU General Public License is included in this distribution
     52  1.29.2.2  skrll  * in the file called COPYING.
     53  1.29.2.2  skrll  *
     54  1.29.2.2  skrll  * Contact Information:
     55  1.29.2.2  skrll  *  Intel Linux Wireless <ilw (at) linux.intel.com>
     56  1.29.2.2  skrll  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
     57  1.29.2.2  skrll  *
     58  1.29.2.2  skrll  *
     59  1.29.2.2  skrll  * BSD LICENSE
     60  1.29.2.2  skrll  *
     61  1.29.2.2  skrll  * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
     62  1.29.2.2  skrll  * All rights reserved.
     63  1.29.2.2  skrll  *
     64  1.29.2.2  skrll  * Redistribution and use in source and binary forms, with or without
     65  1.29.2.2  skrll  * modification, are permitted provided that the following conditions
     66  1.29.2.2  skrll  * are met:
     67  1.29.2.2  skrll  *
     68  1.29.2.2  skrll  *  * Redistributions of source code must retain the above copyright
     69  1.29.2.2  skrll  *    notice, this list of conditions and the following disclaimer.
     70  1.29.2.2  skrll  *  * Redistributions in binary form must reproduce the above copyright
     71  1.29.2.2  skrll  *    notice, this list of conditions and the following disclaimer in
     72  1.29.2.2  skrll  *    the documentation and/or other materials provided with the
     73  1.29.2.2  skrll  *    distribution.
     74  1.29.2.2  skrll  *  * Neither the name Intel Corporation nor the names of its
     75  1.29.2.2  skrll  *    contributors may be used to endorse or promote products derived
     76  1.29.2.2  skrll  *    from this software without specific prior written permission.
     77  1.29.2.2  skrll  *
     78  1.29.2.2  skrll  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     79  1.29.2.2  skrll  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     80  1.29.2.2  skrll  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     81  1.29.2.2  skrll  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     82  1.29.2.2  skrll  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     83  1.29.2.2  skrll  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     84  1.29.2.2  skrll  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     85  1.29.2.2  skrll  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     86  1.29.2.2  skrll  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     87  1.29.2.2  skrll  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     88  1.29.2.2  skrll  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     89  1.29.2.2  skrll  */
     90  1.29.2.2  skrll 
     91  1.29.2.2  skrll /*-
     92  1.29.2.2  skrll  * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini (at) free.fr>
     93  1.29.2.2  skrll  *
     94  1.29.2.2  skrll  * Permission to use, copy, modify, and distribute this software for any
     95  1.29.2.2  skrll  * purpose with or without fee is hereby granted, provided that the above
     96  1.29.2.2  skrll  * copyright notice and this permission notice appear in all copies.
     97  1.29.2.2  skrll  *
     98  1.29.2.2  skrll  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     99  1.29.2.2  skrll  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    100  1.29.2.2  skrll  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    101  1.29.2.2  skrll  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    102  1.29.2.2  skrll  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    103  1.29.2.2  skrll  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    104  1.29.2.2  skrll  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    105  1.29.2.2  skrll  */
    106  1.29.2.2  skrll 
    107  1.29.2.2  skrll #include <sys/cdefs.h>
    108  1.29.2.8  skrll __KERNEL_RCSID(0, "$NetBSD: if_iwm.c,v 1.29.2.8 2016/07/09 20:25:04 skrll Exp $");
    109  1.29.2.2  skrll 
    110  1.29.2.2  skrll #include <sys/param.h>
    111  1.29.2.2  skrll #include <sys/conf.h>
    112  1.29.2.2  skrll #include <sys/kernel.h>
    113  1.29.2.2  skrll #include <sys/kmem.h>
    114  1.29.2.2  skrll #include <sys/mbuf.h>
    115  1.29.2.2  skrll #include <sys/mutex.h>
    116  1.29.2.2  skrll #include <sys/proc.h>
    117  1.29.2.2  skrll #include <sys/socket.h>
    118  1.29.2.2  skrll #include <sys/sockio.h>
    119  1.29.2.3  skrll #include <sys/sysctl.h>
    120  1.29.2.2  skrll #include <sys/systm.h>
    121  1.29.2.2  skrll 
    122  1.29.2.2  skrll #include <sys/cpu.h>
    123  1.29.2.2  skrll #include <sys/bus.h>
    124  1.29.2.2  skrll #include <sys/workqueue.h>
    125  1.29.2.2  skrll #include <machine/endian.h>
    126  1.29.2.2  skrll #include <machine/intr.h>
    127  1.29.2.2  skrll 
    128  1.29.2.2  skrll #include <dev/pci/pcireg.h>
    129  1.29.2.2  skrll #include <dev/pci/pcivar.h>
    130  1.29.2.2  skrll #include <dev/pci/pcidevs.h>
    131  1.29.2.2  skrll #include <dev/firmload.h>
    132  1.29.2.2  skrll 
    133  1.29.2.2  skrll #include <net/bpf.h>
    134  1.29.2.2  skrll #include <net/if.h>
    135  1.29.2.2  skrll #include <net/if_arp.h>
    136  1.29.2.2  skrll #include <net/if_dl.h>
    137  1.29.2.2  skrll #include <net/if_media.h>
    138  1.29.2.2  skrll #include <net/if_types.h>
    139  1.29.2.2  skrll #include <net/if_ether.h>
    140  1.29.2.2  skrll 
    141  1.29.2.2  skrll #include <netinet/in.h>
    142  1.29.2.2  skrll #include <netinet/in_systm.h>
    143  1.29.2.2  skrll #include <netinet/ip.h>
    144  1.29.2.2  skrll 
    145  1.29.2.2  skrll #include <net80211/ieee80211_var.h>
    146  1.29.2.2  skrll #include <net80211/ieee80211_amrr.h>
    147  1.29.2.2  skrll #include <net80211/ieee80211_radiotap.h>
    148  1.29.2.2  skrll 
    149  1.29.2.2  skrll #define DEVNAME(_s)	device_xname((_s)->sc_dev)
    150  1.29.2.2  skrll #define IC2IFP(_ic_)	((_ic_)->ic_ifp)
    151  1.29.2.2  skrll 
    152  1.29.2.2  skrll #define le16_to_cpup(_a_) (le16toh(*(const uint16_t *)(_a_)))
    153  1.29.2.2  skrll #define le32_to_cpup(_a_) (le32toh(*(const uint32_t *)(_a_)))
    154  1.29.2.2  skrll 
    155  1.29.2.2  skrll #ifdef IWM_DEBUG
    156  1.29.2.2  skrll #define DPRINTF(x)	do { if (iwm_debug > 0) printf x; } while (0)
    157  1.29.2.2  skrll #define DPRINTFN(n, x)	do { if (iwm_debug >= (n)) printf x; } while (0)
    158  1.29.2.3  skrll int iwm_debug = 0;
    159  1.29.2.2  skrll #else
    160  1.29.2.2  skrll #define DPRINTF(x)	do { ; } while (0)
    161  1.29.2.2  skrll #define DPRINTFN(n, x)	do { ; } while (0)
    162  1.29.2.2  skrll #endif
    163  1.29.2.2  skrll 
    164  1.29.2.2  skrll #include <dev/pci/if_iwmreg.h>
    165  1.29.2.2  skrll #include <dev/pci/if_iwmvar.h>
    166  1.29.2.2  skrll 
    167  1.29.2.2  skrll static const uint8_t iwm_nvm_channels[] = {
    168  1.29.2.2  skrll 	/* 2.4 GHz */
    169  1.29.2.2  skrll 	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
    170  1.29.2.2  skrll 	/* 5 GHz */
    171  1.29.2.2  skrll 	36, 40, 44 , 48, 52, 56, 60, 64,
    172  1.29.2.2  skrll 	100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144,
    173  1.29.2.2  skrll 	149, 153, 157, 161, 165
    174  1.29.2.2  skrll };
    175  1.29.2.2  skrll #define IWM_NUM_2GHZ_CHANNELS	14
    176  1.29.2.2  skrll 
    177  1.29.2.2  skrll static const struct iwm_rate {
    178  1.29.2.2  skrll 	uint8_t rate;
    179  1.29.2.2  skrll 	uint8_t plcp;
    180  1.29.2.2  skrll } iwm_rates[] = {
    181  1.29.2.2  skrll 	{   2,	IWM_RATE_1M_PLCP  },
    182  1.29.2.2  skrll 	{   4,	IWM_RATE_2M_PLCP  },
    183  1.29.2.2  skrll 	{  11,	IWM_RATE_5M_PLCP  },
    184  1.29.2.2  skrll 	{  22,	IWM_RATE_11M_PLCP },
    185  1.29.2.2  skrll 	{  12,	IWM_RATE_6M_PLCP  },
    186  1.29.2.2  skrll 	{  18,	IWM_RATE_9M_PLCP  },
    187  1.29.2.2  skrll 	{  24,	IWM_RATE_12M_PLCP },
    188  1.29.2.2  skrll 	{  36,	IWM_RATE_18M_PLCP },
    189  1.29.2.2  skrll 	{  48,	IWM_RATE_24M_PLCP },
    190  1.29.2.2  skrll 	{  72,	IWM_RATE_36M_PLCP },
    191  1.29.2.2  skrll 	{  96,	IWM_RATE_48M_PLCP },
    192  1.29.2.2  skrll 	{ 108,	IWM_RATE_54M_PLCP },
    193  1.29.2.2  skrll };
    194  1.29.2.2  skrll #define IWM_RIDX_CCK	0
    195  1.29.2.2  skrll #define IWM_RIDX_OFDM	4
    196  1.29.2.2  skrll #define IWM_RIDX_MAX	(__arraycount(iwm_rates)-1)
    197  1.29.2.2  skrll #define IWM_RIDX_IS_CCK(_i_) ((_i_) < IWM_RIDX_OFDM)
    198  1.29.2.2  skrll #define IWM_RIDX_IS_OFDM(_i_) ((_i_) >= IWM_RIDX_OFDM)
    199  1.29.2.2  skrll 
    200  1.29.2.2  skrll struct iwm_newstate_state {
    201  1.29.2.2  skrll 	struct work ns_wk;
    202  1.29.2.2  skrll 	enum ieee80211_state ns_nstate;
    203  1.29.2.2  skrll 	int ns_arg;
    204  1.29.2.2  skrll 	int ns_generation;
    205  1.29.2.2  skrll };
    206  1.29.2.2  skrll 
    207  1.29.2.2  skrll static int	iwm_store_cscheme(struct iwm_softc *, uint8_t *, size_t);
    208  1.29.2.2  skrll static int	iwm_firmware_store_section(struct iwm_softc *,
    209  1.29.2.2  skrll 		    enum iwm_ucode_type, uint8_t *, size_t);
    210  1.29.2.2  skrll static int	iwm_set_default_calib(struct iwm_softc *, const void *);
    211  1.29.2.2  skrll static int	iwm_read_firmware(struct iwm_softc *);
    212  1.29.2.2  skrll static uint32_t iwm_read_prph(struct iwm_softc *, uint32_t);
    213  1.29.2.2  skrll static void	iwm_write_prph(struct iwm_softc *, uint32_t, uint32_t);
    214  1.29.2.2  skrll #ifdef IWM_DEBUG
    215  1.29.2.2  skrll static int	iwm_read_mem(struct iwm_softc *, uint32_t, void *, int);
    216  1.29.2.2  skrll #endif
    217  1.29.2.2  skrll static int	iwm_write_mem(struct iwm_softc *, uint32_t, const void *, int);
    218  1.29.2.2  skrll static int	iwm_write_mem32(struct iwm_softc *, uint32_t, uint32_t);
    219  1.29.2.2  skrll static int	iwm_poll_bit(struct iwm_softc *, int, uint32_t, uint32_t, int);
    220  1.29.2.2  skrll static int	iwm_nic_lock(struct iwm_softc *);
    221  1.29.2.2  skrll static void	iwm_nic_unlock(struct iwm_softc *);
    222  1.29.2.2  skrll static void	iwm_set_bits_mask_prph(struct iwm_softc *, uint32_t, uint32_t,
    223  1.29.2.2  skrll 		    uint32_t);
    224  1.29.2.2  skrll static void	iwm_set_bits_prph(struct iwm_softc *, uint32_t, uint32_t);
    225  1.29.2.2  skrll static void	iwm_clear_bits_prph(struct iwm_softc *, uint32_t, uint32_t);
    226  1.29.2.2  skrll static int	iwm_dma_contig_alloc(bus_dma_tag_t, struct iwm_dma_info *,
    227  1.29.2.2  skrll 		    bus_size_t, bus_size_t);
    228  1.29.2.2  skrll static void	iwm_dma_contig_free(struct iwm_dma_info *);
    229  1.29.2.2  skrll static int	iwm_alloc_fwmem(struct iwm_softc *);
    230  1.29.2.2  skrll static void	iwm_free_fwmem(struct iwm_softc *);
    231  1.29.2.2  skrll static int	iwm_alloc_sched(struct iwm_softc *);
    232  1.29.2.2  skrll static void	iwm_free_sched(struct iwm_softc *);
    233  1.29.2.2  skrll static int	iwm_alloc_kw(struct iwm_softc *);
    234  1.29.2.2  skrll static void	iwm_free_kw(struct iwm_softc *);
    235  1.29.2.2  skrll static int	iwm_alloc_ict(struct iwm_softc *);
    236  1.29.2.2  skrll static void	iwm_free_ict(struct iwm_softc *);
    237  1.29.2.2  skrll static int	iwm_alloc_rx_ring(struct iwm_softc *, struct iwm_rx_ring *);
    238  1.29.2.2  skrll static void	iwm_reset_rx_ring(struct iwm_softc *, struct iwm_rx_ring *);
    239  1.29.2.2  skrll static void	iwm_free_rx_ring(struct iwm_softc *, struct iwm_rx_ring *);
    240  1.29.2.2  skrll static int	iwm_alloc_tx_ring(struct iwm_softc *, struct iwm_tx_ring *,
    241  1.29.2.2  skrll 		    int);
    242  1.29.2.2  skrll static void	iwm_reset_tx_ring(struct iwm_softc *, struct iwm_tx_ring *);
    243  1.29.2.2  skrll static void	iwm_free_tx_ring(struct iwm_softc *, struct iwm_tx_ring *);
    244  1.29.2.2  skrll static void	iwm_enable_rfkill_int(struct iwm_softc *);
    245  1.29.2.2  skrll static int	iwm_check_rfkill(struct iwm_softc *);
    246  1.29.2.2  skrll static void	iwm_enable_interrupts(struct iwm_softc *);
    247  1.29.2.2  skrll static void	iwm_restore_interrupts(struct iwm_softc *);
    248  1.29.2.2  skrll static void	iwm_disable_interrupts(struct iwm_softc *);
    249  1.29.2.2  skrll static void	iwm_ict_reset(struct iwm_softc *);
    250  1.29.2.2  skrll static int	iwm_set_hw_ready(struct iwm_softc *);
    251  1.29.2.2  skrll static int	iwm_prepare_card_hw(struct iwm_softc *);
    252  1.29.2.2  skrll static void	iwm_apm_config(struct iwm_softc *);
    253  1.29.2.2  skrll static int	iwm_apm_init(struct iwm_softc *);
    254  1.29.2.2  skrll static void	iwm_apm_stop(struct iwm_softc *);
    255  1.29.2.2  skrll static int	iwm_allow_mcast(struct iwm_softc *);
    256  1.29.2.2  skrll static int	iwm_start_hw(struct iwm_softc *);
    257  1.29.2.2  skrll static void	iwm_stop_device(struct iwm_softc *);
    258  1.29.2.2  skrll static void	iwm_set_pwr(struct iwm_softc *);
    259  1.29.2.2  skrll static void	iwm_mvm_nic_config(struct iwm_softc *);
    260  1.29.2.2  skrll static int	iwm_nic_rx_init(struct iwm_softc *);
    261  1.29.2.2  skrll static int	iwm_nic_tx_init(struct iwm_softc *);
    262  1.29.2.2  skrll static int	iwm_nic_init(struct iwm_softc *);
    263  1.29.2.2  skrll static void	iwm_enable_txq(struct iwm_softc *, int, int);
    264  1.29.2.2  skrll static int	iwm_post_alive(struct iwm_softc *);
    265  1.29.2.2  skrll static int	iwm_is_valid_channel(uint16_t);
    266  1.29.2.2  skrll static uint8_t	iwm_ch_id_to_ch_index(uint16_t);
    267  1.29.2.2  skrll static uint16_t iwm_channel_id_to_papd(uint16_t);
    268  1.29.2.2  skrll static uint16_t iwm_channel_id_to_txp(struct iwm_softc *, uint16_t);
    269  1.29.2.2  skrll static int	iwm_phy_db_get_section_data(struct iwm_softc *, uint32_t,
    270  1.29.2.2  skrll 		    uint8_t **, uint16_t *, uint16_t);
    271  1.29.2.2  skrll static int	iwm_send_phy_db_cmd(struct iwm_softc *, uint16_t, uint16_t,
    272  1.29.2.2  skrll 		    void *);
    273  1.29.2.2  skrll static int	iwm_send_phy_db_data(struct iwm_softc *);
    274  1.29.2.2  skrll static int	iwm_send_phy_db_data(struct iwm_softc *);
    275  1.29.2.2  skrll static void	iwm_mvm_te_v2_to_v1(const struct iwm_time_event_cmd_v2 *,
    276  1.29.2.2  skrll 		    struct iwm_time_event_cmd_v1 *);
    277  1.29.2.2  skrll static int	iwm_mvm_send_time_event_cmd(struct iwm_softc *,
    278  1.29.2.2  skrll 		    const struct iwm_time_event_cmd_v2 *);
    279  1.29.2.2  skrll static int	iwm_mvm_time_event_send_add(struct iwm_softc *,
    280  1.29.2.2  skrll 		    struct iwm_node *, void *, struct iwm_time_event_cmd_v2 *);
    281  1.29.2.2  skrll static void	iwm_mvm_protect_session(struct iwm_softc *, struct iwm_node *,
    282  1.29.2.2  skrll 		    uint32_t, uint32_t, uint32_t);
    283  1.29.2.2  skrll static int	iwm_nvm_read_chunk(struct iwm_softc *, uint16_t, uint16_t,
    284  1.29.2.2  skrll 		    uint16_t, uint8_t *, uint16_t *);
    285  1.29.2.2  skrll static int	iwm_nvm_read_section(struct iwm_softc *, uint16_t, uint8_t *,
    286  1.29.2.2  skrll 		    uint16_t *);
    287  1.29.2.2  skrll static void	iwm_init_channel_map(struct iwm_softc *,
    288  1.29.2.2  skrll 		    const uint16_t * const);
    289  1.29.2.2  skrll static int	iwm_parse_nvm_data(struct iwm_softc *, const uint16_t *,
    290  1.29.2.2  skrll 		    const uint16_t *, const uint16_t *, uint8_t, uint8_t);
    291  1.29.2.2  skrll static int	iwm_nvm_init(struct iwm_softc *);
    292  1.29.2.2  skrll static int	iwm_firmware_load_chunk(struct iwm_softc *, uint32_t,
    293  1.29.2.2  skrll 		    const uint8_t *, uint32_t);
    294  1.29.2.2  skrll static int	iwm_load_firmware(struct iwm_softc *, enum iwm_ucode_type);
    295  1.29.2.2  skrll static int	iwm_start_fw(struct iwm_softc *, enum iwm_ucode_type);
    296  1.29.2.2  skrll static int	iwm_fw_alive(struct iwm_softc *, uint32_t);
    297  1.29.2.2  skrll static int	iwm_send_tx_ant_cfg(struct iwm_softc *, uint8_t);
    298  1.29.2.2  skrll static int	iwm_send_phy_cfg_cmd(struct iwm_softc *);
    299  1.29.2.2  skrll static int	iwm_mvm_load_ucode_wait_alive(struct iwm_softc *,
    300  1.29.2.2  skrll 		    enum iwm_ucode_type);
    301  1.29.2.2  skrll static int	iwm_run_init_mvm_ucode(struct iwm_softc *, int);
    302  1.29.2.2  skrll static int	iwm_rx_addbuf(struct iwm_softc *, int, int);
    303  1.29.2.2  skrll static int	iwm_mvm_calc_rssi(struct iwm_softc *, struct iwm_rx_phy_info *);
    304  1.29.2.2  skrll static int	iwm_mvm_get_signal_strength(struct iwm_softc *,
    305  1.29.2.2  skrll 		    struct iwm_rx_phy_info *);
    306  1.29.2.2  skrll static void	iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *,
    307  1.29.2.2  skrll 		    struct iwm_rx_packet *, struct iwm_rx_data *);
    308  1.29.2.2  skrll static int	iwm_get_noise(const struct iwm_mvm_statistics_rx_non_phy *);
    309  1.29.2.2  skrll static void	iwm_mvm_rx_rx_mpdu(struct iwm_softc *, struct iwm_rx_packet *,
    310  1.29.2.2  skrll 		    struct iwm_rx_data *);
    311  1.29.2.2  skrll static void	iwm_mvm_rx_tx_cmd_single(struct iwm_softc *,
    312  1.29.2.2  skrll 		    struct iwm_rx_packet *, struct iwm_node *);
    313  1.29.2.2  skrll static void	iwm_mvm_rx_tx_cmd(struct iwm_softc *, struct iwm_rx_packet *,
    314  1.29.2.2  skrll 		    struct iwm_rx_data *);
    315  1.29.2.2  skrll static int	iwm_mvm_binding_cmd(struct iwm_softc *, struct iwm_node *,
    316  1.29.2.2  skrll 		    uint32_t);
    317  1.29.2.2  skrll static int	iwm_mvm_binding_update(struct iwm_softc *, struct iwm_node *,
    318  1.29.2.2  skrll 		    int);
    319  1.29.2.2  skrll static int	iwm_mvm_binding_add_vif(struct iwm_softc *, struct iwm_node *);
    320  1.29.2.2  skrll static void	iwm_mvm_phy_ctxt_cmd_hdr(struct iwm_softc *,
    321  1.29.2.2  skrll 		    struct iwm_mvm_phy_ctxt *, struct iwm_phy_context_cmd *,
    322  1.29.2.2  skrll 		    uint32_t, uint32_t);
    323  1.29.2.2  skrll static void	iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *,
    324  1.29.2.2  skrll 		    struct iwm_phy_context_cmd *, struct ieee80211_channel *,
    325  1.29.2.2  skrll 		    uint8_t, uint8_t);
    326  1.29.2.2  skrll static int	iwm_mvm_phy_ctxt_apply(struct iwm_softc *,
    327  1.29.2.2  skrll 		    struct iwm_mvm_phy_ctxt *, uint8_t, uint8_t, uint32_t,
    328  1.29.2.2  skrll 		    uint32_t);
    329  1.29.2.2  skrll static int	iwm_mvm_phy_ctxt_add(struct iwm_softc *,
    330  1.29.2.2  skrll 		    struct iwm_mvm_phy_ctxt *, struct ieee80211_channel *,
    331  1.29.2.2  skrll 		    uint8_t, uint8_t);
    332  1.29.2.2  skrll static int	iwm_mvm_phy_ctxt_changed(struct iwm_softc *,
    333  1.29.2.2  skrll 		    struct iwm_mvm_phy_ctxt *, struct ieee80211_channel *,
    334  1.29.2.2  skrll 		    uint8_t, uint8_t);
    335  1.29.2.2  skrll static int	iwm_send_cmd(struct iwm_softc *, struct iwm_host_cmd *);
    336  1.29.2.2  skrll static int	iwm_mvm_send_cmd_pdu(struct iwm_softc *, uint8_t, uint32_t,
    337  1.29.2.2  skrll 		    uint16_t, const void *);
    338  1.29.2.2  skrll static int	iwm_mvm_send_cmd_status(struct iwm_softc *,
    339  1.29.2.2  skrll 		    struct iwm_host_cmd *, uint32_t *);
    340  1.29.2.2  skrll static int	iwm_mvm_send_cmd_pdu_status(struct iwm_softc *, uint8_t,
    341  1.29.2.2  skrll 		    uint16_t, const void *, uint32_t *);
    342  1.29.2.2  skrll static void	iwm_free_resp(struct iwm_softc *, struct iwm_host_cmd *);
    343  1.29.2.2  skrll static void	iwm_cmd_done(struct iwm_softc *, struct iwm_rx_packet *);
    344  1.29.2.2  skrll #if 0
    345  1.29.2.2  skrll static void	iwm_update_sched(struct iwm_softc *, int, int, uint8_t,
    346  1.29.2.2  skrll 		    uint16_t);
    347  1.29.2.2  skrll #endif
    348  1.29.2.2  skrll static const struct iwm_rate *iwm_tx_fill_cmd(struct iwm_softc *,
    349  1.29.2.2  skrll 		    struct iwm_node *, struct ieee80211_frame *,
    350  1.29.2.2  skrll 		    struct iwm_tx_cmd *);
    351  1.29.2.2  skrll static int	iwm_tx(struct iwm_softc *, struct mbuf *,
    352  1.29.2.2  skrll 		    struct ieee80211_node *, int);
    353  1.29.2.2  skrll static int	iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *,
    354  1.29.2.2  skrll 		    struct iwm_beacon_filter_cmd *);
    355  1.29.2.2  skrll static void	iwm_mvm_beacon_filter_set_cqm_params(struct iwm_softc *,
    356  1.29.2.2  skrll 		    struct iwm_node *, struct iwm_beacon_filter_cmd *);
    357  1.29.2.2  skrll static int	iwm_mvm_update_beacon_abort(struct iwm_softc *,
    358  1.29.2.2  skrll 		    struct iwm_node *, int);
    359  1.29.2.2  skrll static void	iwm_mvm_power_log(struct iwm_softc *,
    360  1.29.2.2  skrll 		    struct iwm_mac_power_cmd *);
    361  1.29.2.2  skrll static void	iwm_mvm_power_build_cmd(struct iwm_softc *, struct iwm_node *,
    362  1.29.2.2  skrll 		    struct iwm_mac_power_cmd *);
    363  1.29.2.2  skrll static int	iwm_mvm_power_mac_update_mode(struct iwm_softc *,
    364  1.29.2.2  skrll 		    struct iwm_node *);
    365  1.29.2.2  skrll static int	iwm_mvm_power_update_device(struct iwm_softc *);
    366  1.29.2.2  skrll static int	iwm_mvm_enable_beacon_filter(struct iwm_softc *,
    367  1.29.2.2  skrll 		    struct iwm_node *);
    368  1.29.2.2  skrll static int	iwm_mvm_disable_beacon_filter(struct iwm_softc *,
    369  1.29.2.2  skrll 		    struct iwm_node *);
    370  1.29.2.2  skrll static void	iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *,
    371  1.29.2.2  skrll 		    struct iwm_mvm_add_sta_cmd_v5 *);
    372  1.29.2.2  skrll static int	iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *,
    373  1.29.2.2  skrll 		    struct iwm_mvm_add_sta_cmd_v6 *, int *);
    374  1.29.2.2  skrll static int	iwm_mvm_sta_send_to_fw(struct iwm_softc *, struct iwm_node *,
    375  1.29.2.2  skrll 		    int);
    376  1.29.2.2  skrll static int	iwm_mvm_add_sta(struct iwm_softc *, struct iwm_node *);
    377  1.29.2.2  skrll static int	iwm_mvm_update_sta(struct iwm_softc *, struct iwm_node *);
    378  1.29.2.2  skrll static int	iwm_mvm_add_int_sta_common(struct iwm_softc *,
    379  1.29.2.2  skrll 		    struct iwm_int_sta *, const uint8_t *, uint16_t, uint16_t);
    380  1.29.2.2  skrll static int	iwm_mvm_add_aux_sta(struct iwm_softc *);
    381  1.29.2.2  skrll static uint16_t iwm_mvm_scan_rx_chain(struct iwm_softc *);
    382  1.29.2.2  skrll static uint32_t iwm_mvm_scan_max_out_time(struct iwm_softc *, uint32_t, int);
    383  1.29.2.2  skrll static uint32_t iwm_mvm_scan_suspend_time(struct iwm_softc *, int);
    384  1.29.2.2  skrll static uint32_t iwm_mvm_scan_rxon_flags(struct iwm_softc *, int);
    385  1.29.2.2  skrll static uint32_t iwm_mvm_scan_rate_n_flags(struct iwm_softc *, int, int);
    386  1.29.2.2  skrll static uint16_t iwm_mvm_get_active_dwell(struct iwm_softc *, int, int);
    387  1.29.2.2  skrll static uint16_t iwm_mvm_get_passive_dwell(struct iwm_softc *, int);
    388  1.29.2.2  skrll static int	iwm_mvm_scan_fill_channels(struct iwm_softc *,
    389  1.29.2.2  skrll 		    struct iwm_scan_cmd *, int, int, int);
    390  1.29.2.2  skrll static uint16_t iwm_mvm_fill_probe_req(struct iwm_softc *,
    391  1.29.2.2  skrll 		    struct ieee80211_frame *, const uint8_t *, int,
    392  1.29.2.2  skrll 		    const uint8_t *, int, const uint8_t *, int, int);
    393  1.29.2.2  skrll static int	iwm_mvm_scan_request(struct iwm_softc *, int, int, uint8_t *,
    394  1.29.2.2  skrll 		    int);
    395  1.29.2.2  skrll static void	iwm_mvm_ack_rates(struct iwm_softc *, struct iwm_node *, int *,
    396  1.29.2.2  skrll 		    int *);
    397  1.29.2.2  skrll static void	iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *,
    398  1.29.2.2  skrll 		    struct iwm_node *, struct iwm_mac_ctx_cmd *, uint32_t);
    399  1.29.2.2  skrll static int	iwm_mvm_mac_ctxt_send_cmd(struct iwm_softc *,
    400  1.29.2.2  skrll 		    struct iwm_mac_ctx_cmd *);
    401  1.29.2.2  skrll static void	iwm_mvm_mac_ctxt_cmd_fill_sta(struct iwm_softc *,
    402  1.29.2.2  skrll 		    struct iwm_node *, struct iwm_mac_data_sta *, int);
    403  1.29.2.2  skrll static int	iwm_mvm_mac_ctxt_cmd_station(struct iwm_softc *,
    404  1.29.2.2  skrll 		    struct iwm_node *, uint32_t);
    405  1.29.2.2  skrll static int	iwm_mvm_mac_ctx_send(struct iwm_softc *, struct iwm_node *,
    406  1.29.2.2  skrll 		    uint32_t);
    407  1.29.2.2  skrll static int	iwm_mvm_mac_ctxt_add(struct iwm_softc *, struct iwm_node *);
    408  1.29.2.2  skrll static int	iwm_mvm_mac_ctxt_changed(struct iwm_softc *, struct iwm_node *);
    409  1.29.2.2  skrll static int	iwm_mvm_update_quotas(struct iwm_softc *, struct iwm_node *);
    410  1.29.2.2  skrll static int	iwm_auth(struct iwm_softc *);
    411  1.29.2.2  skrll static int	iwm_assoc(struct iwm_softc *);
    412  1.29.2.2  skrll static int	iwm_release(struct iwm_softc *, struct iwm_node *);
    413  1.29.2.2  skrll static void	iwm_calib_timeout(void *);
    414  1.29.2.2  skrll static void	iwm_setrates(struct iwm_node *);
    415  1.29.2.2  skrll static int	iwm_media_change(struct ifnet *);
    416  1.29.2.2  skrll static void	iwm_newstate_cb(struct work *, void *);
    417  1.29.2.2  skrll static int	iwm_newstate(struct ieee80211com *, enum ieee80211_state, int);
    418  1.29.2.2  skrll static void	iwm_endscan_cb(struct work *, void *);
    419  1.29.2.2  skrll static int	iwm_init_hw(struct iwm_softc *);
    420  1.29.2.2  skrll static int	iwm_init(struct ifnet *);
    421  1.29.2.2  skrll static void	iwm_start(struct ifnet *);
    422  1.29.2.2  skrll static void	iwm_stop(struct ifnet *, int);
    423  1.29.2.2  skrll static void	iwm_watchdog(struct ifnet *);
    424  1.29.2.2  skrll static int	iwm_ioctl(struct ifnet *, u_long, void *);
    425  1.29.2.2  skrll #ifdef IWM_DEBUG
    426  1.29.2.2  skrll static const char *iwm_desc_lookup(uint32_t);
    427  1.29.2.2  skrll static void	iwm_nic_error(struct iwm_softc *);
    428  1.29.2.2  skrll #endif
    429  1.29.2.2  skrll static void	iwm_notif_intr(struct iwm_softc *);
    430  1.29.2.2  skrll static int	iwm_intr(void *);
    431  1.29.2.2  skrll static int	iwm_preinit(struct iwm_softc *);
    432  1.29.2.2  skrll static void	iwm_attach_hook(device_t);
    433  1.29.2.2  skrll static void	iwm_attach(device_t, device_t, void *);
    434  1.29.2.2  skrll #if 0
    435  1.29.2.2  skrll static void	iwm_init_task(void *);
    436  1.29.2.2  skrll static int	iwm_activate(device_t, enum devact);
    437  1.29.2.2  skrll static void	iwm_wakeup(struct iwm_softc *);
    438  1.29.2.2  skrll #endif
    439  1.29.2.2  skrll static void	iwm_radiotap_attach(struct iwm_softc *);
    440  1.29.2.4  skrll static int	iwm_sysctl_fw_loaded_handler(SYSCTLFN_PROTO);
    441  1.29.2.4  skrll 
    442  1.29.2.4  skrll static int iwm_sysctl_root_num;
    443  1.29.2.2  skrll 
    444  1.29.2.2  skrll static int
    445  1.29.2.2  skrll iwm_firmload(struct iwm_softc *sc)
    446  1.29.2.2  skrll {
    447  1.29.2.2  skrll 	struct iwm_fw_info *fw = &sc->sc_fw;
    448  1.29.2.2  skrll 	firmware_handle_t fwh;
    449  1.29.2.2  skrll 	int error;
    450  1.29.2.2  skrll 
    451  1.29.2.4  skrll 	if (ISSET(sc->sc_flags, IWM_FLAG_FW_LOADED))
    452  1.29.2.4  skrll 		return 0;
    453  1.29.2.4  skrll 
    454  1.29.2.2  skrll 	/* Open firmware image. */
    455  1.29.2.2  skrll 	if ((error = firmware_open("if_iwm", sc->sc_fwname, &fwh)) != 0) {
    456  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    457  1.29.2.2  skrll 		    "could not get firmware handle %s\n", sc->sc_fwname);
    458  1.29.2.2  skrll 		return error;
    459  1.29.2.2  skrll 	}
    460  1.29.2.2  skrll 
    461  1.29.2.4  skrll 	if (fw->fw_rawdata != NULL && fw->fw_rawsize > 0) {
    462  1.29.2.4  skrll 		kmem_free(fw->fw_rawdata, fw->fw_rawsize);
    463  1.29.2.4  skrll 		fw->fw_rawdata = NULL;
    464  1.29.2.4  skrll 	}
    465  1.29.2.4  skrll 
    466  1.29.2.2  skrll 	fw->fw_rawsize = firmware_get_size(fwh);
    467  1.29.2.2  skrll 	/*
    468  1.29.2.2  skrll 	 * Well, this is how the Linux driver checks it ....
    469  1.29.2.2  skrll 	 */
    470  1.29.2.2  skrll 	if (fw->fw_rawsize < sizeof(uint32_t)) {
    471  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    472  1.29.2.2  skrll 		    "firmware too short: %zd bytes\n", fw->fw_rawsize);
    473  1.29.2.2  skrll 		error = EINVAL;
    474  1.29.2.2  skrll 		goto out;
    475  1.29.2.2  skrll 	}
    476  1.29.2.2  skrll 
    477  1.29.2.2  skrll 	/* some sanity */
    478  1.29.2.2  skrll 	if (fw->fw_rawsize > IWM_FWMAXSIZE) {
    479  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    480  1.29.2.4  skrll 		    "firmware size is ridiculous: %zd bytes\n", fw->fw_rawsize);
    481  1.29.2.2  skrll 		error = EINVAL;
    482  1.29.2.2  skrll 		goto out;
    483  1.29.2.2  skrll 	}
    484  1.29.2.2  skrll 
    485  1.29.2.2  skrll 	/* Read the firmware. */
    486  1.29.2.2  skrll 	fw->fw_rawdata = kmem_alloc(fw->fw_rawsize, KM_SLEEP);
    487  1.29.2.2  skrll 	if (fw->fw_rawdata == NULL) {
    488  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    489  1.29.2.2  skrll 		    "not enough memory to stock firmware %s\n", sc->sc_fwname);
    490  1.29.2.2  skrll 		error = ENOMEM;
    491  1.29.2.2  skrll 		goto out;
    492  1.29.2.2  skrll 	}
    493  1.29.2.2  skrll 	error = firmware_read(fwh, 0, fw->fw_rawdata, fw->fw_rawsize);
    494  1.29.2.2  skrll 	if (error) {
    495  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    496  1.29.2.2  skrll 		    "could not read firmware %s\n", sc->sc_fwname);
    497  1.29.2.2  skrll 		goto out;
    498  1.29.2.2  skrll 	}
    499  1.29.2.2  skrll 
    500  1.29.2.4  skrll 	SET(sc->sc_flags, IWM_FLAG_FW_LOADED);
    501  1.29.2.2  skrll  out:
    502  1.29.2.2  skrll 	/* caller will release memory, if necessary */
    503  1.29.2.2  skrll 
    504  1.29.2.2  skrll 	firmware_close(fwh);
    505  1.29.2.2  skrll 	return error;
    506  1.29.2.2  skrll }
    507  1.29.2.2  skrll 
    508  1.29.2.2  skrll /*
    509  1.29.2.2  skrll  * just maintaining status quo.
    510  1.29.2.2  skrll  */
    511  1.29.2.2  skrll static void
    512  1.29.2.2  skrll iwm_fix_channel(struct ieee80211com *ic, struct mbuf *m)
    513  1.29.2.2  skrll {
    514  1.29.2.3  skrll 	struct iwm_softc *sc = ic->ic_ifp->if_softc;
    515  1.29.2.2  skrll 	struct ieee80211_frame *wh;
    516  1.29.2.2  skrll 	uint8_t subtype;
    517  1.29.2.2  skrll 	uint8_t *frm, *efrm;
    518  1.29.2.2  skrll 
    519  1.29.2.2  skrll 	wh = mtod(m, struct ieee80211_frame *);
    520  1.29.2.2  skrll 
    521  1.29.2.2  skrll 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_MGT)
    522  1.29.2.2  skrll 		return;
    523  1.29.2.2  skrll 
    524  1.29.2.2  skrll 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
    525  1.29.2.2  skrll 
    526  1.29.2.2  skrll 	if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
    527  1.29.2.2  skrll 	    subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP)
    528  1.29.2.2  skrll 		return;
    529  1.29.2.2  skrll 
    530  1.29.2.3  skrll 	if (sc->sc_scanband == IEEE80211_CHAN_5GHZ) {
    531  1.29.2.3  skrll 		int chan = le32toh(sc->sc_last_phy_info.channel);
    532  1.29.2.3  skrll 		if (chan < __arraycount(ic->ic_channels))
    533  1.29.2.3  skrll 			ic->ic_curchan = &ic->ic_channels[chan];
    534  1.29.2.3  skrll 		return;
    535  1.29.2.3  skrll 	}
    536  1.29.2.3  skrll 
    537  1.29.2.2  skrll 	frm = (uint8_t *)(wh + 1);
    538  1.29.2.2  skrll 	efrm = mtod(m, uint8_t *) + m->m_len;
    539  1.29.2.2  skrll 
    540  1.29.2.2  skrll 	frm += 12;      /* skip tstamp, bintval and capinfo fields */
    541  1.29.2.2  skrll 	while (frm < efrm) {
    542  1.29.2.2  skrll 		if (*frm == IEEE80211_ELEMID_DSPARMS) {
    543  1.29.2.2  skrll #if IEEE80211_CHAN_MAX < 255
    544  1.29.2.2  skrll 			if (frm[2] <= IEEE80211_CHAN_MAX)
    545  1.29.2.2  skrll #endif
    546  1.29.2.2  skrll 				ic->ic_curchan = &ic->ic_channels[frm[2]];
    547  1.29.2.2  skrll 		}
    548  1.29.2.2  skrll 		frm += frm[1] + 2;
    549  1.29.2.2  skrll 	}
    550  1.29.2.2  skrll }
    551  1.29.2.2  skrll 
    552  1.29.2.2  skrll /*
    553  1.29.2.2  skrll  * Firmware parser.
    554  1.29.2.2  skrll  */
    555  1.29.2.2  skrll 
    556  1.29.2.2  skrll static int
    557  1.29.2.2  skrll iwm_store_cscheme(struct iwm_softc *sc, uint8_t *data, size_t dlen)
    558  1.29.2.2  skrll {
    559  1.29.2.2  skrll 	struct iwm_fw_cscheme_list *l = (void *)data;
    560  1.29.2.2  skrll 
    561  1.29.2.2  skrll 	if (dlen < sizeof(*l) ||
    562  1.29.2.2  skrll 	    dlen < sizeof(l->size) + l->size * sizeof(*l->cs))
    563  1.29.2.2  skrll 		return EINVAL;
    564  1.29.2.2  skrll 
    565  1.29.2.2  skrll 	/* we don't actually store anything for now, always use s/w crypto */
    566  1.29.2.2  skrll 
    567  1.29.2.2  skrll 	return 0;
    568  1.29.2.2  skrll }
    569  1.29.2.2  skrll 
    570  1.29.2.2  skrll static int
    571  1.29.2.2  skrll iwm_firmware_store_section(struct iwm_softc *sc,
    572  1.29.2.2  skrll 	enum iwm_ucode_type type, uint8_t *data, size_t dlen)
    573  1.29.2.2  skrll {
    574  1.29.2.2  skrll 	struct iwm_fw_sects *fws;
    575  1.29.2.2  skrll 	struct iwm_fw_onesect *fwone;
    576  1.29.2.2  skrll 
    577  1.29.2.2  skrll 	if (type >= IWM_UCODE_TYPE_MAX)
    578  1.29.2.2  skrll 		return EINVAL;
    579  1.29.2.2  skrll 	if (dlen < sizeof(uint32_t))
    580  1.29.2.2  skrll 		return EINVAL;
    581  1.29.2.2  skrll 
    582  1.29.2.2  skrll 	fws = &sc->sc_fw.fw_sects[type];
    583  1.29.2.2  skrll 	if (fws->fw_count >= IWM_UCODE_SECT_MAX)
    584  1.29.2.2  skrll 		return EINVAL;
    585  1.29.2.2  skrll 
    586  1.29.2.2  skrll 	fwone = &fws->fw_sect[fws->fw_count];
    587  1.29.2.2  skrll 
    588  1.29.2.2  skrll 	/* first 32bit are device load offset */
    589  1.29.2.2  skrll 	memcpy(&fwone->fws_devoff, data, sizeof(uint32_t));
    590  1.29.2.2  skrll 
    591  1.29.2.2  skrll 	/* rest is data */
    592  1.29.2.2  skrll 	fwone->fws_data = data + sizeof(uint32_t);
    593  1.29.2.2  skrll 	fwone->fws_len = dlen - sizeof(uint32_t);
    594  1.29.2.2  skrll 
    595  1.29.2.2  skrll 	/* for freeing the buffer during driver unload */
    596  1.29.2.2  skrll 	fwone->fws_alloc = data;
    597  1.29.2.2  skrll 	fwone->fws_allocsize = dlen;
    598  1.29.2.2  skrll 
    599  1.29.2.2  skrll 	fws->fw_count++;
    600  1.29.2.2  skrll 	fws->fw_totlen += fwone->fws_len;
    601  1.29.2.2  skrll 
    602  1.29.2.2  skrll 	return 0;
    603  1.29.2.2  skrll }
    604  1.29.2.2  skrll 
    605  1.29.2.2  skrll /* iwlwifi: iwl-drv.c */
    606  1.29.2.2  skrll struct iwm_tlv_calib_data {
    607  1.29.2.2  skrll 	uint32_t ucode_type;
    608  1.29.2.2  skrll 	struct iwm_tlv_calib_ctrl calib;
    609  1.29.2.2  skrll } __packed;
    610  1.29.2.2  skrll 
    611  1.29.2.2  skrll static int
    612  1.29.2.2  skrll iwm_set_default_calib(struct iwm_softc *sc, const void *data)
    613  1.29.2.2  skrll {
    614  1.29.2.2  skrll 	const struct iwm_tlv_calib_data *def_calib = data;
    615  1.29.2.2  skrll 	uint32_t ucode_type = le32toh(def_calib->ucode_type);
    616  1.29.2.2  skrll 
    617  1.29.2.2  skrll 	if (ucode_type >= IWM_UCODE_TYPE_MAX) {
    618  1.29.2.2  skrll 		DPRINTF(("%s: Wrong ucode_type %u for default "
    619  1.29.2.2  skrll 		    "calibration.\n", DEVNAME(sc), ucode_type));
    620  1.29.2.2  skrll 		return EINVAL;
    621  1.29.2.2  skrll 	}
    622  1.29.2.2  skrll 
    623  1.29.2.2  skrll 	sc->sc_default_calib[ucode_type].flow_trigger =
    624  1.29.2.2  skrll 	    def_calib->calib.flow_trigger;
    625  1.29.2.2  skrll 	sc->sc_default_calib[ucode_type].event_trigger =
    626  1.29.2.2  skrll 	    def_calib->calib.event_trigger;
    627  1.29.2.2  skrll 
    628  1.29.2.2  skrll 	return 0;
    629  1.29.2.2  skrll }
    630  1.29.2.2  skrll 
    631  1.29.2.2  skrll static int
    632  1.29.2.2  skrll iwm_read_firmware(struct iwm_softc *sc)
    633  1.29.2.2  skrll {
    634  1.29.2.2  skrll 	struct iwm_fw_info *fw = &sc->sc_fw;
    635  1.29.2.2  skrll 	struct iwm_tlv_ucode_header *uhdr;
    636  1.29.2.2  skrll 	struct iwm_ucode_tlv tlv;
    637  1.29.2.2  skrll 	enum iwm_ucode_tlv_type tlv_type;
    638  1.29.2.2  skrll 	uint8_t *data;
    639  1.29.2.2  skrll 	int error, status;
    640  1.29.2.2  skrll 	size_t len;
    641  1.29.2.2  skrll 
    642  1.29.2.2  skrll 	if (fw->fw_status == IWM_FW_STATUS_NONE) {
    643  1.29.2.2  skrll 		fw->fw_status = IWM_FW_STATUS_INPROGRESS;
    644  1.29.2.2  skrll 	} else {
    645  1.29.2.2  skrll 		while (fw->fw_status == IWM_FW_STATUS_INPROGRESS)
    646  1.29.2.2  skrll 			tsleep(&sc->sc_fw, 0, "iwmfwp", 0);
    647  1.29.2.2  skrll 	}
    648  1.29.2.2  skrll 	status = fw->fw_status;
    649  1.29.2.2  skrll 
    650  1.29.2.2  skrll 	if (status == IWM_FW_STATUS_DONE)
    651  1.29.2.2  skrll 		return 0;
    652  1.29.2.2  skrll 
    653  1.29.2.2  skrll 	/*
    654  1.29.2.2  skrll 	 * Load firmware into driver memory.
    655  1.29.2.2  skrll 	 * fw_rawdata and fw_rawsize will be set.
    656  1.29.2.2  skrll 	 */
    657  1.29.2.2  skrll 	error = iwm_firmload(sc);
    658  1.29.2.2  skrll 	if (error != 0) {
    659  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    660  1.29.2.2  skrll 		    "could not read firmware %s (error %d)\n",
    661  1.29.2.2  skrll 		    sc->sc_fwname, error);
    662  1.29.2.2  skrll 		goto out;
    663  1.29.2.2  skrll 	}
    664  1.29.2.2  skrll 
    665  1.29.2.2  skrll 	/*
    666  1.29.2.2  skrll 	 * Parse firmware contents
    667  1.29.2.2  skrll 	 */
    668  1.29.2.2  skrll 
    669  1.29.2.2  skrll 	uhdr = (void *)fw->fw_rawdata;
    670  1.29.2.2  skrll 	if (*(uint32_t *)fw->fw_rawdata != 0
    671  1.29.2.2  skrll 	    || le32toh(uhdr->magic) != IWM_TLV_UCODE_MAGIC) {
    672  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "invalid firmware %s\n",
    673  1.29.2.2  skrll 		    sc->sc_fwname);
    674  1.29.2.2  skrll 		error = EINVAL;
    675  1.29.2.2  skrll 		goto out;
    676  1.29.2.2  skrll 	}
    677  1.29.2.2  skrll 
    678  1.29.2.2  skrll 	sc->sc_fwver = le32toh(uhdr->ver);
    679  1.29.2.2  skrll 	data = uhdr->data;
    680  1.29.2.2  skrll 	len = fw->fw_rawsize - sizeof(*uhdr);
    681  1.29.2.2  skrll 
    682  1.29.2.2  skrll 	while (len >= sizeof(tlv)) {
    683  1.29.2.2  skrll 		size_t tlv_len;
    684  1.29.2.2  skrll 		void *tlv_data;
    685  1.29.2.2  skrll 
    686  1.29.2.2  skrll 		memcpy(&tlv, data, sizeof(tlv));
    687  1.29.2.2  skrll 		tlv_len = le32toh(tlv.length);
    688  1.29.2.2  skrll 		tlv_type = le32toh(tlv.type);
    689  1.29.2.2  skrll 
    690  1.29.2.2  skrll 		len -= sizeof(tlv);
    691  1.29.2.2  skrll 		data += sizeof(tlv);
    692  1.29.2.2  skrll 		tlv_data = data;
    693  1.29.2.2  skrll 
    694  1.29.2.2  skrll 		if (len < tlv_len) {
    695  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
    696  1.29.2.2  skrll 			    "firmware too short: %zu bytes\n", len);
    697  1.29.2.2  skrll 			error = EINVAL;
    698  1.29.2.2  skrll 			goto parse_out;
    699  1.29.2.2  skrll 		}
    700  1.29.2.2  skrll 
    701  1.29.2.2  skrll 		switch ((int)tlv_type) {
    702  1.29.2.2  skrll 		case IWM_UCODE_TLV_PROBE_MAX_LEN:
    703  1.29.2.2  skrll 			if (tlv_len < sizeof(uint32_t)) {
    704  1.29.2.2  skrll 				error = EINVAL;
    705  1.29.2.2  skrll 				goto parse_out;
    706  1.29.2.2  skrll 			}
    707  1.29.2.2  skrll 			sc->sc_capa_max_probe_len
    708  1.29.2.2  skrll 			    = le32toh(*(uint32_t *)tlv_data);
    709  1.29.2.2  skrll 			/* limit it to something sensible */
    710  1.29.2.2  skrll 			if (sc->sc_capa_max_probe_len > (1<<16)) {
    711  1.29.2.2  skrll 				DPRINTF(("%s: IWM_UCODE_TLV_PROBE_MAX_LEN "
    712  1.29.2.2  skrll 				    "ridiculous\n", DEVNAME(sc)));
    713  1.29.2.2  skrll 				error = EINVAL;
    714  1.29.2.2  skrll 				goto parse_out;
    715  1.29.2.2  skrll 			}
    716  1.29.2.2  skrll 			break;
    717  1.29.2.2  skrll 		case IWM_UCODE_TLV_PAN:
    718  1.29.2.2  skrll 			if (tlv_len) {
    719  1.29.2.2  skrll 				error = EINVAL;
    720  1.29.2.2  skrll 				goto parse_out;
    721  1.29.2.2  skrll 			}
    722  1.29.2.2  skrll 			sc->sc_capaflags |= IWM_UCODE_TLV_FLAGS_PAN;
    723  1.29.2.2  skrll 			break;
    724  1.29.2.2  skrll 		case IWM_UCODE_TLV_FLAGS:
    725  1.29.2.2  skrll 			if (tlv_len < sizeof(uint32_t)) {
    726  1.29.2.2  skrll 				error = EINVAL;
    727  1.29.2.2  skrll 				goto parse_out;
    728  1.29.2.2  skrll 			}
    729  1.29.2.2  skrll 			/*
    730  1.29.2.2  skrll 			 * Apparently there can be many flags, but Linux driver
    731  1.29.2.2  skrll 			 * parses only the first one, and so do we.
    732  1.29.2.2  skrll 			 *
    733  1.29.2.2  skrll 			 * XXX: why does this override IWM_UCODE_TLV_PAN?
    734  1.29.2.2  skrll 			 * Intentional or a bug?  Observations from
    735  1.29.2.2  skrll 			 * current firmware file:
    736  1.29.2.2  skrll 			 *  1) TLV_PAN is parsed first
    737  1.29.2.2  skrll 			 *  2) TLV_FLAGS contains TLV_FLAGS_PAN
    738  1.29.2.2  skrll 			 * ==> this resets TLV_PAN to itself... hnnnk
    739  1.29.2.2  skrll 			 */
    740  1.29.2.2  skrll 			sc->sc_capaflags = le32toh(*(uint32_t *)tlv_data);
    741  1.29.2.2  skrll 			break;
    742  1.29.2.2  skrll 		case IWM_UCODE_TLV_CSCHEME:
    743  1.29.2.2  skrll 			if ((error = iwm_store_cscheme(sc,
    744  1.29.2.2  skrll 			    tlv_data, tlv_len)) != 0)
    745  1.29.2.2  skrll 				goto parse_out;
    746  1.29.2.2  skrll 			break;
    747  1.29.2.2  skrll 		case IWM_UCODE_TLV_NUM_OF_CPU:
    748  1.29.2.2  skrll 			if (tlv_len != sizeof(uint32_t)) {
    749  1.29.2.2  skrll 				error = EINVAL;
    750  1.29.2.2  skrll 				goto parse_out;
    751  1.29.2.2  skrll 			}
    752  1.29.2.2  skrll 			if (le32toh(*(uint32_t*)tlv_data) != 1) {
    753  1.29.2.2  skrll 				DPRINTF(("%s: driver supports "
    754  1.29.2.2  skrll 				    "only TLV_NUM_OF_CPU == 1", DEVNAME(sc)));
    755  1.29.2.2  skrll 				error = EINVAL;
    756  1.29.2.2  skrll 				goto parse_out;
    757  1.29.2.2  skrll 			}
    758  1.29.2.2  skrll 			break;
    759  1.29.2.2  skrll 		case IWM_UCODE_TLV_SEC_RT:
    760  1.29.2.2  skrll 			if ((error = iwm_firmware_store_section(sc,
    761  1.29.2.2  skrll 			    IWM_UCODE_TYPE_REGULAR, tlv_data, tlv_len)) != 0)
    762  1.29.2.2  skrll 				goto parse_out;
    763  1.29.2.2  skrll 			break;
    764  1.29.2.2  skrll 		case IWM_UCODE_TLV_SEC_INIT:
    765  1.29.2.2  skrll 			if ((error = iwm_firmware_store_section(sc,
    766  1.29.2.2  skrll 			    IWM_UCODE_TYPE_INIT, tlv_data, tlv_len)) != 0)
    767  1.29.2.2  skrll 				goto parse_out;
    768  1.29.2.2  skrll 			break;
    769  1.29.2.2  skrll 		case IWM_UCODE_TLV_SEC_WOWLAN:
    770  1.29.2.2  skrll 			if ((error = iwm_firmware_store_section(sc,
    771  1.29.2.2  skrll 			    IWM_UCODE_TYPE_WOW, tlv_data, tlv_len)) != 0)
    772  1.29.2.2  skrll 				goto parse_out;
    773  1.29.2.2  skrll 			break;
    774  1.29.2.2  skrll 		case IWM_UCODE_TLV_DEF_CALIB:
    775  1.29.2.2  skrll 			if (tlv_len != sizeof(struct iwm_tlv_calib_data)) {
    776  1.29.2.2  skrll 				error = EINVAL;
    777  1.29.2.2  skrll 				goto parse_out;
    778  1.29.2.2  skrll 			}
    779  1.29.2.2  skrll 			if ((error = iwm_set_default_calib(sc, tlv_data)) != 0)
    780  1.29.2.2  skrll 				goto parse_out;
    781  1.29.2.2  skrll 			break;
    782  1.29.2.2  skrll 		case IWM_UCODE_TLV_PHY_SKU:
    783  1.29.2.2  skrll 			if (tlv_len != sizeof(uint32_t)) {
    784  1.29.2.2  skrll 				error = EINVAL;
    785  1.29.2.2  skrll 				goto parse_out;
    786  1.29.2.2  skrll 			}
    787  1.29.2.2  skrll 			sc->sc_fw_phy_config = le32toh(*(uint32_t *)tlv_data);
    788  1.29.2.2  skrll 			break;
    789  1.29.2.2  skrll 
    790  1.29.2.2  skrll 		case IWM_UCODE_TLV_API_CHANGES_SET:
    791  1.29.2.2  skrll 		case IWM_UCODE_TLV_ENABLED_CAPABILITIES:
    792  1.29.2.2  skrll 			/* ignore, not used by current driver */
    793  1.29.2.2  skrll 			break;
    794  1.29.2.2  skrll 
    795  1.29.2.2  skrll 		default:
    796  1.29.2.2  skrll 			DPRINTF(("%s: unknown firmware section %d, abort\n",
    797  1.29.2.2  skrll 			    DEVNAME(sc), tlv_type));
    798  1.29.2.2  skrll 			error = EINVAL;
    799  1.29.2.2  skrll 			goto parse_out;
    800  1.29.2.2  skrll 		}
    801  1.29.2.2  skrll 
    802  1.29.2.2  skrll 		len -= roundup(tlv_len, 4);
    803  1.29.2.2  skrll 		data += roundup(tlv_len, 4);
    804  1.29.2.2  skrll 	}
    805  1.29.2.2  skrll 
    806  1.29.2.2  skrll 	KASSERT(error == 0);
    807  1.29.2.2  skrll 
    808  1.29.2.2  skrll  parse_out:
    809  1.29.2.2  skrll 	if (error) {
    810  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    811  1.29.2.2  skrll 		    "firmware parse error, section type %d\n", tlv_type);
    812  1.29.2.2  skrll 	}
    813  1.29.2.2  skrll 
    814  1.29.2.2  skrll 	if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_PM_CMD_SUPPORT)) {
    815  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
    816  1.29.2.2  skrll 		    "device uses unsupported power ops\n");
    817  1.29.2.2  skrll 		error = ENOTSUP;
    818  1.29.2.2  skrll 	}
    819  1.29.2.2  skrll 
    820  1.29.2.2  skrll  out:
    821  1.29.2.2  skrll 	if (error)
    822  1.29.2.2  skrll 		fw->fw_status = IWM_FW_STATUS_NONE;
    823  1.29.2.2  skrll 	else
    824  1.29.2.2  skrll 		fw->fw_status = IWM_FW_STATUS_DONE;
    825  1.29.2.2  skrll 	wakeup(&sc->sc_fw);
    826  1.29.2.2  skrll 
    827  1.29.2.2  skrll 	if (error && fw->fw_rawdata != NULL) {
    828  1.29.2.2  skrll 		kmem_free(fw->fw_rawdata, fw->fw_rawsize);
    829  1.29.2.2  skrll 		fw->fw_rawdata = NULL;
    830  1.29.2.4  skrll 		CLR(sc->sc_flags, IWM_FLAG_FW_LOADED);
    831  1.29.2.2  skrll 	}
    832  1.29.2.2  skrll 	return error;
    833  1.29.2.2  skrll }
    834  1.29.2.2  skrll 
    835  1.29.2.2  skrll /*
    836  1.29.2.2  skrll  * basic device access
    837  1.29.2.2  skrll  */
    838  1.29.2.2  skrll 
    839  1.29.2.2  skrll static uint32_t
    840  1.29.2.2  skrll iwm_read_prph(struct iwm_softc *sc, uint32_t addr)
    841  1.29.2.2  skrll {
    842  1.29.2.2  skrll 	IWM_WRITE(sc,
    843  1.29.2.2  skrll 	    IWM_HBUS_TARG_PRPH_RADDR, ((addr & 0x000fffff) | (3 << 24)));
    844  1.29.2.2  skrll 	IWM_BARRIER_READ_WRITE(sc);
    845  1.29.2.2  skrll 	return IWM_READ(sc, IWM_HBUS_TARG_PRPH_RDAT);
    846  1.29.2.2  skrll }
    847  1.29.2.2  skrll 
    848  1.29.2.2  skrll static void
    849  1.29.2.2  skrll iwm_write_prph(struct iwm_softc *sc, uint32_t addr, uint32_t val)
    850  1.29.2.2  skrll {
    851  1.29.2.2  skrll 	IWM_WRITE(sc,
    852  1.29.2.2  skrll 	    IWM_HBUS_TARG_PRPH_WADDR, ((addr & 0x000fffff) | (3 << 24)));
    853  1.29.2.2  skrll 	IWM_BARRIER_WRITE(sc);
    854  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_HBUS_TARG_PRPH_WDAT, val);
    855  1.29.2.2  skrll }
    856  1.29.2.2  skrll 
    857  1.29.2.2  skrll #ifdef IWM_DEBUG
    858  1.29.2.2  skrll /* iwlwifi: pcie/trans.c */
    859  1.29.2.2  skrll static int
    860  1.29.2.2  skrll iwm_read_mem(struct iwm_softc *sc, uint32_t addr, void *buf, int dwords)
    861  1.29.2.2  skrll {
    862  1.29.2.2  skrll 	int offs, ret = 0;
    863  1.29.2.2  skrll 	uint32_t *vals = buf;
    864  1.29.2.2  skrll 
    865  1.29.2.2  skrll 	if (iwm_nic_lock(sc)) {
    866  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_HBUS_TARG_MEM_RADDR, addr);
    867  1.29.2.2  skrll 		for (offs = 0; offs < dwords; offs++)
    868  1.29.2.2  skrll 			vals[offs] = IWM_READ(sc, IWM_HBUS_TARG_MEM_RDAT);
    869  1.29.2.2  skrll 		iwm_nic_unlock(sc);
    870  1.29.2.2  skrll 	} else {
    871  1.29.2.2  skrll 		ret = EBUSY;
    872  1.29.2.2  skrll 	}
    873  1.29.2.2  skrll 	return ret;
    874  1.29.2.2  skrll }
    875  1.29.2.2  skrll #endif
    876  1.29.2.2  skrll 
    877  1.29.2.2  skrll /* iwlwifi: pcie/trans.c */
    878  1.29.2.2  skrll static int
    879  1.29.2.2  skrll iwm_write_mem(struct iwm_softc *sc, uint32_t addr, const void *buf, int dwords)
    880  1.29.2.2  skrll {
    881  1.29.2.2  skrll 	int offs;
    882  1.29.2.2  skrll 	const uint32_t *vals = buf;
    883  1.29.2.2  skrll 
    884  1.29.2.2  skrll 	if (iwm_nic_lock(sc)) {
    885  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WADDR, addr);
    886  1.29.2.2  skrll 		/* WADDR auto-increments */
    887  1.29.2.2  skrll 		for (offs = 0; offs < dwords; offs++) {
    888  1.29.2.2  skrll 			uint32_t val = vals ? vals[offs] : 0;
    889  1.29.2.2  skrll 			IWM_WRITE(sc, IWM_HBUS_TARG_MEM_WDAT, val);
    890  1.29.2.2  skrll 		}
    891  1.29.2.2  skrll 		iwm_nic_unlock(sc);
    892  1.29.2.2  skrll 	} else {
    893  1.29.2.2  skrll 		DPRINTF(("%s: write_mem failed\n", DEVNAME(sc)));
    894  1.29.2.2  skrll 		return EBUSY;
    895  1.29.2.2  skrll 	}
    896  1.29.2.2  skrll 	return 0;
    897  1.29.2.2  skrll }
    898  1.29.2.2  skrll 
    899  1.29.2.2  skrll static int
    900  1.29.2.2  skrll iwm_write_mem32(struct iwm_softc *sc, uint32_t addr, uint32_t val)
    901  1.29.2.2  skrll {
    902  1.29.2.2  skrll 	return iwm_write_mem(sc, addr, &val, 1);
    903  1.29.2.2  skrll }
    904  1.29.2.2  skrll 
    905  1.29.2.2  skrll static int
    906  1.29.2.2  skrll iwm_poll_bit(struct iwm_softc *sc, int reg,
    907  1.29.2.2  skrll 	uint32_t bits, uint32_t mask, int timo)
    908  1.29.2.2  skrll {
    909  1.29.2.2  skrll 	for (;;) {
    910  1.29.2.2  skrll 		if ((IWM_READ(sc, reg) & mask) == (bits & mask)) {
    911  1.29.2.2  skrll 			return 1;
    912  1.29.2.2  skrll 		}
    913  1.29.2.2  skrll 		if (timo < 10) {
    914  1.29.2.2  skrll 			return 0;
    915  1.29.2.2  skrll 		}
    916  1.29.2.2  skrll 		timo -= 10;
    917  1.29.2.2  skrll 		DELAY(10);
    918  1.29.2.2  skrll 	}
    919  1.29.2.2  skrll }
    920  1.29.2.2  skrll 
    921  1.29.2.2  skrll static int
    922  1.29.2.2  skrll iwm_nic_lock(struct iwm_softc *sc)
    923  1.29.2.2  skrll {
    924  1.29.2.2  skrll 	int rv = 0;
    925  1.29.2.2  skrll 
    926  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
    927  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
    928  1.29.2.2  skrll 
    929  1.29.2.2  skrll 	if (iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
    930  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
    931  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY
    932  1.29.2.2  skrll 	     | IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP, 15000)) {
    933  1.29.2.5  skrll 		rv = 1;
    934  1.29.2.2  skrll 	} else {
    935  1.29.2.2  skrll 		/* jolt */
    936  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_FORCE_NMI);
    937  1.29.2.2  skrll 	}
    938  1.29.2.2  skrll 
    939  1.29.2.2  skrll 	return rv;
    940  1.29.2.2  skrll }
    941  1.29.2.2  skrll 
    942  1.29.2.2  skrll static void
    943  1.29.2.2  skrll iwm_nic_unlock(struct iwm_softc *sc)
    944  1.29.2.2  skrll {
    945  1.29.2.2  skrll 	IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
    946  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
    947  1.29.2.2  skrll }
    948  1.29.2.2  skrll 
    949  1.29.2.2  skrll static void
    950  1.29.2.2  skrll iwm_set_bits_mask_prph(struct iwm_softc *sc,
    951  1.29.2.2  skrll 	uint32_t reg, uint32_t bits, uint32_t mask)
    952  1.29.2.2  skrll {
    953  1.29.2.2  skrll 	uint32_t val;
    954  1.29.2.2  skrll 
    955  1.29.2.2  skrll 	/* XXX: no error path? */
    956  1.29.2.2  skrll 	if (iwm_nic_lock(sc)) {
    957  1.29.2.2  skrll 		val = iwm_read_prph(sc, reg) & mask;
    958  1.29.2.2  skrll 		val |= bits;
    959  1.29.2.2  skrll 		iwm_write_prph(sc, reg, val);
    960  1.29.2.2  skrll 		iwm_nic_unlock(sc);
    961  1.29.2.2  skrll 	}
    962  1.29.2.2  skrll }
    963  1.29.2.2  skrll 
    964  1.29.2.2  skrll static void
    965  1.29.2.2  skrll iwm_set_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits)
    966  1.29.2.2  skrll {
    967  1.29.2.2  skrll 	iwm_set_bits_mask_prph(sc, reg, bits, ~0);
    968  1.29.2.2  skrll }
    969  1.29.2.2  skrll 
    970  1.29.2.2  skrll static void
    971  1.29.2.2  skrll iwm_clear_bits_prph(struct iwm_softc *sc, uint32_t reg, uint32_t bits)
    972  1.29.2.2  skrll {
    973  1.29.2.2  skrll 	iwm_set_bits_mask_prph(sc, reg, 0, ~bits);
    974  1.29.2.2  skrll }
    975  1.29.2.2  skrll 
    976  1.29.2.2  skrll /*
    977  1.29.2.2  skrll  * DMA resource routines
    978  1.29.2.2  skrll  */
    979  1.29.2.2  skrll 
    980  1.29.2.2  skrll static int
    981  1.29.2.2  skrll iwm_dma_contig_alloc(bus_dma_tag_t tag, struct iwm_dma_info *dma,
    982  1.29.2.2  skrll     bus_size_t size, bus_size_t alignment)
    983  1.29.2.2  skrll {
    984  1.29.2.2  skrll 	int nsegs, error;
    985  1.29.2.2  skrll 	void *va;
    986  1.29.2.2  skrll 
    987  1.29.2.2  skrll 	dma->tag = tag;
    988  1.29.2.2  skrll 	dma->size = size;
    989  1.29.2.2  skrll 
    990  1.29.2.2  skrll 	error = bus_dmamap_create(tag, size, 1, size, 0, BUS_DMA_NOWAIT,
    991  1.29.2.2  skrll 	    &dma->map);
    992  1.29.2.2  skrll 	if (error != 0)
    993  1.29.2.2  skrll 		goto fail;
    994  1.29.2.2  skrll 
    995  1.29.2.2  skrll 	error = bus_dmamem_alloc(tag, size, alignment, 0, &dma->seg, 1, &nsegs,
    996  1.29.2.2  skrll 	    BUS_DMA_NOWAIT);
    997  1.29.2.2  skrll 	if (error != 0)
    998  1.29.2.2  skrll 		goto fail;
    999  1.29.2.2  skrll 
   1000  1.29.2.2  skrll 	error = bus_dmamem_map(tag, &dma->seg, 1, size, &va,
   1001  1.29.2.2  skrll 	    BUS_DMA_NOWAIT);
   1002  1.29.2.2  skrll 	if (error != 0)
   1003  1.29.2.2  skrll 		goto fail;
   1004  1.29.2.2  skrll 	dma->vaddr = va;
   1005  1.29.2.2  skrll 
   1006  1.29.2.2  skrll 	error = bus_dmamap_load(tag, dma->map, dma->vaddr, size, NULL,
   1007  1.29.2.2  skrll 	    BUS_DMA_NOWAIT);
   1008  1.29.2.2  skrll 	if (error != 0)
   1009  1.29.2.2  skrll 		goto fail;
   1010  1.29.2.2  skrll 
   1011  1.29.2.2  skrll 	memset(dma->vaddr, 0, size);
   1012  1.29.2.2  skrll 	bus_dmamap_sync(tag, dma->map, 0, size, BUS_DMASYNC_PREWRITE);
   1013  1.29.2.2  skrll 	dma->paddr = dma->map->dm_segs[0].ds_addr;
   1014  1.29.2.2  skrll 
   1015  1.29.2.2  skrll 	return 0;
   1016  1.29.2.2  skrll 
   1017  1.29.2.2  skrll fail:	iwm_dma_contig_free(dma);
   1018  1.29.2.2  skrll 	return error;
   1019  1.29.2.2  skrll }
   1020  1.29.2.2  skrll 
   1021  1.29.2.2  skrll static void
   1022  1.29.2.2  skrll iwm_dma_contig_free(struct iwm_dma_info *dma)
   1023  1.29.2.2  skrll {
   1024  1.29.2.2  skrll 	if (dma->map != NULL) {
   1025  1.29.2.2  skrll 		if (dma->vaddr != NULL) {
   1026  1.29.2.2  skrll 			bus_dmamap_sync(dma->tag, dma->map, 0, dma->size,
   1027  1.29.2.2  skrll 			    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
   1028  1.29.2.2  skrll 			bus_dmamap_unload(dma->tag, dma->map);
   1029  1.29.2.2  skrll 			bus_dmamem_unmap(dma->tag, dma->vaddr, dma->size);
   1030  1.29.2.2  skrll 			bus_dmamem_free(dma->tag, &dma->seg, 1);
   1031  1.29.2.2  skrll 			dma->vaddr = NULL;
   1032  1.29.2.2  skrll 		}
   1033  1.29.2.2  skrll 		bus_dmamap_destroy(dma->tag, dma->map);
   1034  1.29.2.2  skrll 		dma->map = NULL;
   1035  1.29.2.2  skrll 	}
   1036  1.29.2.2  skrll }
   1037  1.29.2.2  skrll 
   1038  1.29.2.2  skrll /* fwmem is used to load firmware onto the card */
   1039  1.29.2.2  skrll static int
   1040  1.29.2.2  skrll iwm_alloc_fwmem(struct iwm_softc *sc)
   1041  1.29.2.2  skrll {
   1042  1.29.2.2  skrll 	/* Must be aligned on a 16-byte boundary. */
   1043  1.29.2.2  skrll 	return iwm_dma_contig_alloc(sc->sc_dmat, &sc->fw_dma,
   1044  1.29.2.2  skrll 	    sc->sc_fwdmasegsz, 16);
   1045  1.29.2.2  skrll }
   1046  1.29.2.2  skrll 
   1047  1.29.2.2  skrll static void
   1048  1.29.2.2  skrll iwm_free_fwmem(struct iwm_softc *sc)
   1049  1.29.2.2  skrll {
   1050  1.29.2.2  skrll 	iwm_dma_contig_free(&sc->fw_dma);
   1051  1.29.2.2  skrll }
   1052  1.29.2.2  skrll 
   1053  1.29.2.2  skrll /* tx scheduler rings.  not used? */
   1054  1.29.2.2  skrll static int
   1055  1.29.2.2  skrll iwm_alloc_sched(struct iwm_softc *sc)
   1056  1.29.2.2  skrll {
   1057  1.29.2.2  skrll 	int rv;
   1058  1.29.2.2  skrll 
   1059  1.29.2.2  skrll 	/* TX scheduler rings must be aligned on a 1KB boundary. */
   1060  1.29.2.2  skrll 	rv = iwm_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma,
   1061  1.29.2.2  skrll 	    __arraycount(sc->txq) * sizeof(struct iwm_agn_scd_bc_tbl), 1024);
   1062  1.29.2.2  skrll 	return rv;
   1063  1.29.2.2  skrll }
   1064  1.29.2.2  skrll 
   1065  1.29.2.2  skrll static void
   1066  1.29.2.2  skrll iwm_free_sched(struct iwm_softc *sc)
   1067  1.29.2.2  skrll {
   1068  1.29.2.2  skrll 	iwm_dma_contig_free(&sc->sched_dma);
   1069  1.29.2.2  skrll }
   1070  1.29.2.2  skrll 
   1071  1.29.2.2  skrll /* keep-warm page is used internally by the card.  see iwl-fh.h for more info */
   1072  1.29.2.2  skrll static int
   1073  1.29.2.2  skrll iwm_alloc_kw(struct iwm_softc *sc)
   1074  1.29.2.2  skrll {
   1075  1.29.2.2  skrll 	return iwm_dma_contig_alloc(sc->sc_dmat, &sc->kw_dma, 4096, 4096);
   1076  1.29.2.2  skrll }
   1077  1.29.2.2  skrll 
   1078  1.29.2.2  skrll static void
   1079  1.29.2.2  skrll iwm_free_kw(struct iwm_softc *sc)
   1080  1.29.2.2  skrll {
   1081  1.29.2.2  skrll 	iwm_dma_contig_free(&sc->kw_dma);
   1082  1.29.2.2  skrll }
   1083  1.29.2.2  skrll 
   1084  1.29.2.2  skrll /* interrupt cause table */
   1085  1.29.2.2  skrll static int
   1086  1.29.2.2  skrll iwm_alloc_ict(struct iwm_softc *sc)
   1087  1.29.2.2  skrll {
   1088  1.29.2.2  skrll 	return iwm_dma_contig_alloc(sc->sc_dmat, &sc->ict_dma,
   1089  1.29.2.2  skrll 	    IWM_ICT_SIZE, 1<<IWM_ICT_PADDR_SHIFT);
   1090  1.29.2.2  skrll }
   1091  1.29.2.2  skrll 
   1092  1.29.2.2  skrll static void
   1093  1.29.2.2  skrll iwm_free_ict(struct iwm_softc *sc)
   1094  1.29.2.2  skrll {
   1095  1.29.2.2  skrll 	iwm_dma_contig_free(&sc->ict_dma);
   1096  1.29.2.2  skrll }
   1097  1.29.2.2  skrll 
   1098  1.29.2.2  skrll static int
   1099  1.29.2.2  skrll iwm_alloc_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
   1100  1.29.2.2  skrll {
   1101  1.29.2.2  skrll 	bus_size_t size;
   1102  1.29.2.2  skrll 	int i, error;
   1103  1.29.2.2  skrll 
   1104  1.29.2.2  skrll 	ring->cur = 0;
   1105  1.29.2.2  skrll 
   1106  1.29.2.2  skrll 	/* Allocate RX descriptors (256-byte aligned). */
   1107  1.29.2.2  skrll 	size = IWM_RX_RING_COUNT * sizeof(uint32_t);
   1108  1.29.2.2  skrll 	error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256);
   1109  1.29.2.2  skrll 	if (error != 0) {
   1110  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   1111  1.29.2.2  skrll 		    "could not allocate RX ring DMA memory\n");
   1112  1.29.2.2  skrll 		goto fail;
   1113  1.29.2.2  skrll 	}
   1114  1.29.2.2  skrll 	ring->desc = ring->desc_dma.vaddr;
   1115  1.29.2.2  skrll 
   1116  1.29.2.2  skrll 	/* Allocate RX status area (16-byte aligned). */
   1117  1.29.2.2  skrll 	error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->stat_dma,
   1118  1.29.2.2  skrll 	    sizeof(*ring->stat), 16);
   1119  1.29.2.2  skrll 	if (error != 0) {
   1120  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   1121  1.29.2.2  skrll 		    "could not allocate RX status DMA memory\n");
   1122  1.29.2.2  skrll 		goto fail;
   1123  1.29.2.2  skrll 	}
   1124  1.29.2.2  skrll 	ring->stat = ring->stat_dma.vaddr;
   1125  1.29.2.2  skrll 
   1126  1.29.2.2  skrll 	/*
   1127  1.29.2.2  skrll 	 * Allocate and map RX buffers.
   1128  1.29.2.2  skrll 	 */
   1129  1.29.2.2  skrll 	for (i = 0; i < IWM_RX_RING_COUNT; i++) {
   1130  1.29.2.2  skrll 		struct iwm_rx_data *data = &ring->data[i];
   1131  1.29.2.2  skrll 
   1132  1.29.2.2  skrll 		memset(data, 0, sizeof(*data));
   1133  1.29.2.2  skrll 		error = bus_dmamap_create(sc->sc_dmat, IWM_RBUF_SIZE, 1,
   1134  1.29.2.2  skrll 		    IWM_RBUF_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
   1135  1.29.2.2  skrll 		    &data->map);
   1136  1.29.2.2  skrll 		if (error != 0) {
   1137  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   1138  1.29.2.2  skrll 			    "could not create RX buf DMA map\n");
   1139  1.29.2.2  skrll 			goto fail;
   1140  1.29.2.2  skrll 		}
   1141  1.29.2.2  skrll 
   1142  1.29.2.2  skrll 		if ((error = iwm_rx_addbuf(sc, IWM_RBUF_SIZE, i)) != 0) {
   1143  1.29.2.2  skrll 			goto fail;
   1144  1.29.2.2  skrll 		}
   1145  1.29.2.2  skrll 	}
   1146  1.29.2.2  skrll 	return 0;
   1147  1.29.2.2  skrll 
   1148  1.29.2.2  skrll fail:	iwm_free_rx_ring(sc, ring);
   1149  1.29.2.2  skrll 	return error;
   1150  1.29.2.2  skrll }
   1151  1.29.2.2  skrll 
   1152  1.29.2.2  skrll static void
   1153  1.29.2.2  skrll iwm_reset_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
   1154  1.29.2.2  skrll {
   1155  1.29.2.2  skrll 	int ntries;
   1156  1.29.2.2  skrll 
   1157  1.29.2.2  skrll 	if (iwm_nic_lock(sc)) {
   1158  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
   1159  1.29.2.2  skrll 		for (ntries = 0; ntries < 1000; ntries++) {
   1160  1.29.2.2  skrll 			if (IWM_READ(sc, IWM_FH_MEM_RSSR_RX_STATUS_REG) &
   1161  1.29.2.2  skrll 			    IWM_FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE)
   1162  1.29.2.2  skrll 				break;
   1163  1.29.2.2  skrll 			DELAY(10);
   1164  1.29.2.2  skrll 		}
   1165  1.29.2.2  skrll 		iwm_nic_unlock(sc);
   1166  1.29.2.2  skrll 	}
   1167  1.29.2.2  skrll 	ring->cur = 0;
   1168  1.29.2.2  skrll }
   1169  1.29.2.2  skrll 
   1170  1.29.2.2  skrll static void
   1171  1.29.2.2  skrll iwm_free_rx_ring(struct iwm_softc *sc, struct iwm_rx_ring *ring)
   1172  1.29.2.2  skrll {
   1173  1.29.2.2  skrll 	int i;
   1174  1.29.2.2  skrll 
   1175  1.29.2.2  skrll 	iwm_dma_contig_free(&ring->desc_dma);
   1176  1.29.2.2  skrll 	iwm_dma_contig_free(&ring->stat_dma);
   1177  1.29.2.2  skrll 
   1178  1.29.2.2  skrll 	for (i = 0; i < IWM_RX_RING_COUNT; i++) {
   1179  1.29.2.2  skrll 		struct iwm_rx_data *data = &ring->data[i];
   1180  1.29.2.2  skrll 
   1181  1.29.2.2  skrll 		if (data->m != NULL) {
   1182  1.29.2.2  skrll 			bus_dmamap_sync(sc->sc_dmat, data->map, 0,
   1183  1.29.2.2  skrll 			    data->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
   1184  1.29.2.2  skrll 			bus_dmamap_unload(sc->sc_dmat, data->map);
   1185  1.29.2.2  skrll 			m_freem(data->m);
   1186  1.29.2.2  skrll 		}
   1187  1.29.2.2  skrll 		if (data->map != NULL)
   1188  1.29.2.2  skrll 			bus_dmamap_destroy(sc->sc_dmat, data->map);
   1189  1.29.2.2  skrll 	}
   1190  1.29.2.2  skrll }
   1191  1.29.2.2  skrll 
   1192  1.29.2.2  skrll static int
   1193  1.29.2.2  skrll iwm_alloc_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring, int qid)
   1194  1.29.2.2  skrll {
   1195  1.29.2.2  skrll 	bus_addr_t paddr;
   1196  1.29.2.2  skrll 	bus_size_t size;
   1197  1.29.2.2  skrll 	int i, error;
   1198  1.29.2.2  skrll 
   1199  1.29.2.2  skrll 	ring->qid = qid;
   1200  1.29.2.2  skrll 	ring->queued = 0;
   1201  1.29.2.2  skrll 	ring->cur = 0;
   1202  1.29.2.2  skrll 
   1203  1.29.2.2  skrll 	/* Allocate TX descriptors (256-byte aligned). */
   1204  1.29.2.2  skrll 	size = IWM_TX_RING_COUNT * sizeof (struct iwm_tfd);
   1205  1.29.2.2  skrll 	error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->desc_dma, size, 256);
   1206  1.29.2.2  skrll 	if (error != 0) {
   1207  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   1208  1.29.2.2  skrll 		    "could not allocate TX ring DMA memory\n");
   1209  1.29.2.2  skrll 		goto fail;
   1210  1.29.2.2  skrll 	}
   1211  1.29.2.2  skrll 	ring->desc = ring->desc_dma.vaddr;
   1212  1.29.2.2  skrll 
   1213  1.29.2.2  skrll 	/*
   1214  1.29.2.2  skrll 	 * We only use rings 0 through 9 (4 EDCA + cmd) so there is no need
   1215  1.29.2.2  skrll 	 * to allocate commands space for other rings.
   1216  1.29.2.2  skrll 	 */
   1217  1.29.2.2  skrll 	if (qid > IWM_MVM_CMD_QUEUE)
   1218  1.29.2.2  skrll 		return 0;
   1219  1.29.2.2  skrll 
   1220  1.29.2.2  skrll 	size = IWM_TX_RING_COUNT * sizeof(struct iwm_device_cmd);
   1221  1.29.2.2  skrll 	error = iwm_dma_contig_alloc(sc->sc_dmat, &ring->cmd_dma, size, 4);
   1222  1.29.2.2  skrll 	if (error != 0) {
   1223  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   1224  1.29.2.2  skrll 		    "could not allocate TX cmd DMA memory\n");
   1225  1.29.2.2  skrll 		goto fail;
   1226  1.29.2.2  skrll 	}
   1227  1.29.2.2  skrll 	ring->cmd = ring->cmd_dma.vaddr;
   1228  1.29.2.2  skrll 
   1229  1.29.2.2  skrll 	paddr = ring->cmd_dma.paddr;
   1230  1.29.2.2  skrll 	for (i = 0; i < IWM_TX_RING_COUNT; i++) {
   1231  1.29.2.2  skrll 		struct iwm_tx_data *data = &ring->data[i];
   1232  1.29.2.2  skrll 
   1233  1.29.2.2  skrll 		data->cmd_paddr = paddr;
   1234  1.29.2.2  skrll 		data->scratch_paddr = paddr + sizeof(struct iwm_cmd_header)
   1235  1.29.2.2  skrll 		    + offsetof(struct iwm_tx_cmd, scratch);
   1236  1.29.2.2  skrll 		paddr += sizeof(struct iwm_device_cmd);
   1237  1.29.2.2  skrll 
   1238  1.29.2.2  skrll 		error = bus_dmamap_create(sc->sc_dmat, IWM_RBUF_SIZE,
   1239  1.29.2.3  skrll 		    IWM_NUM_OF_TBS - 2, IWM_RBUF_SIZE, 0, BUS_DMA_NOWAIT,
   1240  1.29.2.2  skrll 		    &data->map);
   1241  1.29.2.2  skrll 		if (error != 0) {
   1242  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   1243  1.29.2.2  skrll 			    "could not create TX buf DMA map\n");
   1244  1.29.2.2  skrll 			goto fail;
   1245  1.29.2.2  skrll 		}
   1246  1.29.2.2  skrll 	}
   1247  1.29.2.2  skrll 	KASSERT(paddr == ring->cmd_dma.paddr + size);
   1248  1.29.2.2  skrll 	return 0;
   1249  1.29.2.2  skrll 
   1250  1.29.2.2  skrll fail:	iwm_free_tx_ring(sc, ring);
   1251  1.29.2.2  skrll 	return error;
   1252  1.29.2.2  skrll }
   1253  1.29.2.2  skrll 
   1254  1.29.2.2  skrll static void
   1255  1.29.2.2  skrll iwm_reset_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring)
   1256  1.29.2.2  skrll {
   1257  1.29.2.2  skrll 	int i;
   1258  1.29.2.2  skrll 
   1259  1.29.2.2  skrll 	for (i = 0; i < IWM_TX_RING_COUNT; i++) {
   1260  1.29.2.2  skrll 		struct iwm_tx_data *data = &ring->data[i];
   1261  1.29.2.2  skrll 
   1262  1.29.2.2  skrll 		if (data->m != NULL) {
   1263  1.29.2.2  skrll 			bus_dmamap_sync(sc->sc_dmat, data->map, 0,
   1264  1.29.2.2  skrll 			    data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
   1265  1.29.2.2  skrll 			bus_dmamap_unload(sc->sc_dmat, data->map);
   1266  1.29.2.2  skrll 			m_freem(data->m);
   1267  1.29.2.2  skrll 			data->m = NULL;
   1268  1.29.2.2  skrll 		}
   1269  1.29.2.2  skrll 	}
   1270  1.29.2.2  skrll 	/* Clear TX descriptors. */
   1271  1.29.2.2  skrll 	memset(ring->desc, 0, ring->desc_dma.size);
   1272  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map, 0,
   1273  1.29.2.2  skrll 	    ring->desc_dma.size, BUS_DMASYNC_PREWRITE);
   1274  1.29.2.2  skrll 	sc->qfullmsk &= ~(1 << ring->qid);
   1275  1.29.2.2  skrll 	ring->queued = 0;
   1276  1.29.2.2  skrll 	ring->cur = 0;
   1277  1.29.2.2  skrll }
   1278  1.29.2.2  skrll 
   1279  1.29.2.2  skrll static void
   1280  1.29.2.2  skrll iwm_free_tx_ring(struct iwm_softc *sc, struct iwm_tx_ring *ring)
   1281  1.29.2.2  skrll {
   1282  1.29.2.2  skrll 	int i;
   1283  1.29.2.2  skrll 
   1284  1.29.2.2  skrll 	iwm_dma_contig_free(&ring->desc_dma);
   1285  1.29.2.2  skrll 	iwm_dma_contig_free(&ring->cmd_dma);
   1286  1.29.2.2  skrll 
   1287  1.29.2.2  skrll 	for (i = 0; i < IWM_TX_RING_COUNT; i++) {
   1288  1.29.2.2  skrll 		struct iwm_tx_data *data = &ring->data[i];
   1289  1.29.2.2  skrll 
   1290  1.29.2.2  skrll 		if (data->m != NULL) {
   1291  1.29.2.2  skrll 			bus_dmamap_sync(sc->sc_dmat, data->map, 0,
   1292  1.29.2.2  skrll 			    data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
   1293  1.29.2.2  skrll 			bus_dmamap_unload(sc->sc_dmat, data->map);
   1294  1.29.2.2  skrll 			m_freem(data->m);
   1295  1.29.2.2  skrll 		}
   1296  1.29.2.2  skrll 		if (data->map != NULL)
   1297  1.29.2.2  skrll 			bus_dmamap_destroy(sc->sc_dmat, data->map);
   1298  1.29.2.2  skrll 	}
   1299  1.29.2.2  skrll }
   1300  1.29.2.2  skrll 
   1301  1.29.2.2  skrll /*
   1302  1.29.2.2  skrll  * High-level hardware frobbing routines
   1303  1.29.2.2  skrll  */
   1304  1.29.2.2  skrll 
   1305  1.29.2.2  skrll static void
   1306  1.29.2.2  skrll iwm_enable_rfkill_int(struct iwm_softc *sc)
   1307  1.29.2.2  skrll {
   1308  1.29.2.2  skrll 	sc->sc_intmask = IWM_CSR_INT_BIT_RF_KILL;
   1309  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
   1310  1.29.2.2  skrll }
   1311  1.29.2.2  skrll 
   1312  1.29.2.2  skrll static int
   1313  1.29.2.2  skrll iwm_check_rfkill(struct iwm_softc *sc)
   1314  1.29.2.2  skrll {
   1315  1.29.2.2  skrll 	uint32_t v;
   1316  1.29.2.2  skrll 	int s;
   1317  1.29.2.2  skrll 	int rv;
   1318  1.29.2.2  skrll 
   1319  1.29.2.2  skrll 	s = splnet();
   1320  1.29.2.2  skrll 
   1321  1.29.2.2  skrll 	/*
   1322  1.29.2.2  skrll 	 * "documentation" is not really helpful here:
   1323  1.29.2.2  skrll 	 *  27:	HW_RF_KILL_SW
   1324  1.29.2.2  skrll 	 *	Indicates state of (platform's) hardware RF-Kill switch
   1325  1.29.2.2  skrll 	 *
   1326  1.29.2.2  skrll 	 * But apparently when it's off, it's on ...
   1327  1.29.2.2  skrll 	 */
   1328  1.29.2.2  skrll 	v = IWM_READ(sc, IWM_CSR_GP_CNTRL);
   1329  1.29.2.2  skrll 	rv = (v & IWM_CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) == 0;
   1330  1.29.2.2  skrll 	if (rv) {
   1331  1.29.2.2  skrll 		sc->sc_flags |= IWM_FLAG_RFKILL;
   1332  1.29.2.2  skrll 	} else {
   1333  1.29.2.2  skrll 		sc->sc_flags &= ~IWM_FLAG_RFKILL;
   1334  1.29.2.2  skrll 	}
   1335  1.29.2.2  skrll 
   1336  1.29.2.2  skrll 	splx(s);
   1337  1.29.2.2  skrll 	return rv;
   1338  1.29.2.2  skrll }
   1339  1.29.2.2  skrll 
   1340  1.29.2.2  skrll static void
   1341  1.29.2.2  skrll iwm_enable_interrupts(struct iwm_softc *sc)
   1342  1.29.2.2  skrll {
   1343  1.29.2.2  skrll 	sc->sc_intmask = IWM_CSR_INI_SET_MASK;
   1344  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
   1345  1.29.2.2  skrll }
   1346  1.29.2.2  skrll 
   1347  1.29.2.2  skrll static void
   1348  1.29.2.2  skrll iwm_restore_interrupts(struct iwm_softc *sc)
   1349  1.29.2.2  skrll {
   1350  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT_MASK, sc->sc_intmask);
   1351  1.29.2.2  skrll }
   1352  1.29.2.2  skrll 
   1353  1.29.2.2  skrll static void
   1354  1.29.2.2  skrll iwm_disable_interrupts(struct iwm_softc *sc)
   1355  1.29.2.2  skrll {
   1356  1.29.2.2  skrll 	int s = splnet();
   1357  1.29.2.2  skrll 
   1358  1.29.2.2  skrll 	/* disable interrupts */
   1359  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
   1360  1.29.2.2  skrll 
   1361  1.29.2.2  skrll 	/* acknowledge all interrupts */
   1362  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT, ~0);
   1363  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, ~0);
   1364  1.29.2.2  skrll 
   1365  1.29.2.2  skrll 	splx(s);
   1366  1.29.2.2  skrll }
   1367  1.29.2.2  skrll 
   1368  1.29.2.2  skrll static void
   1369  1.29.2.2  skrll iwm_ict_reset(struct iwm_softc *sc)
   1370  1.29.2.2  skrll {
   1371  1.29.2.2  skrll 	iwm_disable_interrupts(sc);
   1372  1.29.2.2  skrll 
   1373  1.29.2.2  skrll 	/* Reset ICT table. */
   1374  1.29.2.2  skrll 	memset(sc->ict_dma.vaddr, 0, IWM_ICT_SIZE);
   1375  1.29.2.2  skrll 	sc->ict_cur = 0;
   1376  1.29.2.2  skrll 
   1377  1.29.2.2  skrll 	/* Set physical address of ICT table (4KB aligned). */
   1378  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_DRAM_INT_TBL_REG,
   1379  1.29.2.2  skrll 	    IWM_CSR_DRAM_INT_TBL_ENABLE
   1380  1.29.2.2  skrll 	    | IWM_CSR_DRAM_INIT_TBL_WRAP_CHECK
   1381  1.29.2.2  skrll 	    | sc->ict_dma.paddr >> IWM_ICT_PADDR_SHIFT);
   1382  1.29.2.2  skrll 
   1383  1.29.2.2  skrll 	/* Switch to ICT interrupt mode in driver. */
   1384  1.29.2.2  skrll 	sc->sc_flags |= IWM_FLAG_USE_ICT;
   1385  1.29.2.2  skrll 
   1386  1.29.2.2  skrll 	/* Re-enable interrupts. */
   1387  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT, ~0);
   1388  1.29.2.2  skrll 	iwm_enable_interrupts(sc);
   1389  1.29.2.2  skrll }
   1390  1.29.2.2  skrll 
   1391  1.29.2.2  skrll #define IWM_HW_READY_TIMEOUT 50
   1392  1.29.2.2  skrll static int
   1393  1.29.2.2  skrll iwm_set_hw_ready(struct iwm_softc *sc)
   1394  1.29.2.2  skrll {
   1395  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
   1396  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
   1397  1.29.2.2  skrll 
   1398  1.29.2.2  skrll 	return iwm_poll_bit(sc, IWM_CSR_HW_IF_CONFIG_REG,
   1399  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
   1400  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
   1401  1.29.2.2  skrll 	    IWM_HW_READY_TIMEOUT);
   1402  1.29.2.2  skrll }
   1403  1.29.2.2  skrll #undef IWM_HW_READY_TIMEOUT
   1404  1.29.2.2  skrll 
   1405  1.29.2.2  skrll static int
   1406  1.29.2.2  skrll iwm_prepare_card_hw(struct iwm_softc *sc)
   1407  1.29.2.2  skrll {
   1408  1.29.2.2  skrll 	int rv = 0;
   1409  1.29.2.2  skrll 	int t = 0;
   1410  1.29.2.2  skrll 
   1411  1.29.2.2  skrll 	if (iwm_set_hw_ready(sc))
   1412  1.29.2.2  skrll 		goto out;
   1413  1.29.2.2  skrll 
   1414  1.29.2.2  skrll 	/* If HW is not ready, prepare the conditions to check again */
   1415  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
   1416  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_PREPARE);
   1417  1.29.2.2  skrll 
   1418  1.29.2.2  skrll 	do {
   1419  1.29.2.2  skrll 		if (iwm_set_hw_ready(sc))
   1420  1.29.2.2  skrll 			goto out;
   1421  1.29.2.2  skrll 		DELAY(200);
   1422  1.29.2.2  skrll 		t += 200;
   1423  1.29.2.2  skrll 	} while (t < 150000);
   1424  1.29.2.2  skrll 
   1425  1.29.2.2  skrll 	rv = ETIMEDOUT;
   1426  1.29.2.2  skrll 
   1427  1.29.2.2  skrll  out:
   1428  1.29.2.2  skrll 	return rv;
   1429  1.29.2.2  skrll }
   1430  1.29.2.2  skrll 
   1431  1.29.2.2  skrll static void
   1432  1.29.2.2  skrll iwm_apm_config(struct iwm_softc *sc)
   1433  1.29.2.2  skrll {
   1434  1.29.2.2  skrll 	pcireg_t reg;
   1435  1.29.2.2  skrll 
   1436  1.29.2.2  skrll 	reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag,
   1437  1.29.2.2  skrll 	    sc->sc_cap_off + PCIE_LCSR);
   1438  1.29.2.2  skrll 	if (reg & PCIE_LCSR_ASPM_L1) {
   1439  1.29.2.2  skrll 		/* Um the Linux driver prints "Disabling L0S for this one ... */
   1440  1.29.2.2  skrll 		IWM_SETBITS(sc, IWM_CSR_GIO_REG,
   1441  1.29.2.2  skrll 		    IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
   1442  1.29.2.2  skrll 	} else {
   1443  1.29.2.2  skrll 		/* ... and "Enabling" here */
   1444  1.29.2.2  skrll 		IWM_CLRBITS(sc, IWM_CSR_GIO_REG,
   1445  1.29.2.2  skrll 		    IWM_CSR_GIO_REG_VAL_L0S_ENABLED);
   1446  1.29.2.2  skrll 	}
   1447  1.29.2.2  skrll }
   1448  1.29.2.2  skrll 
   1449  1.29.2.2  skrll /*
   1450  1.29.2.2  skrll  * Start up NIC's basic functionality after it has been reset
   1451  1.29.2.2  skrll  * (e.g. after platform boot, or shutdown via iwm_pcie_apm_stop())
   1452  1.29.2.2  skrll  * NOTE:  This does not load uCode nor start the embedded processor
   1453  1.29.2.2  skrll  */
   1454  1.29.2.2  skrll static int
   1455  1.29.2.2  skrll iwm_apm_init(struct iwm_softc *sc)
   1456  1.29.2.2  skrll {
   1457  1.29.2.2  skrll 	int error = 0;
   1458  1.29.2.2  skrll 
   1459  1.29.2.2  skrll 	DPRINTF(("iwm apm start\n"));
   1460  1.29.2.2  skrll 
   1461  1.29.2.2  skrll 	/* Disable L0S exit timer (platform NMI Work/Around) */
   1462  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
   1463  1.29.2.2  skrll 	    IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER);
   1464  1.29.2.2  skrll 
   1465  1.29.2.2  skrll 	/*
   1466  1.29.2.2  skrll 	 * Disable L0s without affecting L1;
   1467  1.29.2.2  skrll 	 *  don't wait for ICH L0s (ICH bug W/A)
   1468  1.29.2.2  skrll 	 */
   1469  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_GIO_CHICKEN_BITS,
   1470  1.29.2.2  skrll 	    IWM_CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX);
   1471  1.29.2.2  skrll 
   1472  1.29.2.2  skrll 	/* Set FH wait threshold to maximum (HW error during stress W/A) */
   1473  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_DBG_HPET_MEM_REG, IWM_CSR_DBG_HPET_MEM_REG_VAL);
   1474  1.29.2.2  skrll 
   1475  1.29.2.2  skrll 	/*
   1476  1.29.2.2  skrll 	 * Enable HAP INTA (interrupt from management bus) to
   1477  1.29.2.2  skrll 	 * wake device's PCI Express link L1a -> L0s
   1478  1.29.2.2  skrll 	 */
   1479  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_HW_IF_CONFIG_REG,
   1480  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
   1481  1.29.2.2  skrll 
   1482  1.29.2.2  skrll 	iwm_apm_config(sc);
   1483  1.29.2.2  skrll 
   1484  1.29.2.2  skrll #if 0 /* not for 7k */
   1485  1.29.2.2  skrll 	/* Configure analog phase-lock-loop before activating to D0A */
   1486  1.29.2.2  skrll 	if (trans->cfg->base_params->pll_cfg_val)
   1487  1.29.2.2  skrll 		IWM_SETBITS(trans, IWM_CSR_ANA_PLL_CFG,
   1488  1.29.2.2  skrll 		    trans->cfg->base_params->pll_cfg_val);
   1489  1.29.2.2  skrll #endif
   1490  1.29.2.2  skrll 
   1491  1.29.2.2  skrll 	/*
   1492  1.29.2.2  skrll 	 * Set "initialization complete" bit to move adapter from
   1493  1.29.2.2  skrll 	 * D0U* --> D0A* (powered-up active) state.
   1494  1.29.2.2  skrll 	 */
   1495  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_GP_CNTRL, IWM_CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
   1496  1.29.2.2  skrll 
   1497  1.29.2.2  skrll 	/*
   1498  1.29.2.2  skrll 	 * Wait for clock stabilization; once stabilized, access to
   1499  1.29.2.2  skrll 	 * device-internal resources is supported, e.g. iwm_write_prph()
   1500  1.29.2.2  skrll 	 * and accesses to uCode SRAM.
   1501  1.29.2.2  skrll 	 */
   1502  1.29.2.2  skrll 	if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
   1503  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
   1504  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000)) {
   1505  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   1506  1.29.2.2  skrll 		    "timeout waiting for clock stabilization\n");
   1507  1.29.2.2  skrll 		goto out;
   1508  1.29.2.2  skrll 	}
   1509  1.29.2.2  skrll 
   1510  1.29.2.2  skrll 	if (sc->host_interrupt_operation_mode) {
   1511  1.29.2.2  skrll 		/*
   1512  1.29.2.2  skrll 		 * This is a bit of an abuse - This is needed for 7260 / 3160
   1513  1.29.2.2  skrll 		 * only check host_interrupt_operation_mode even if this is
   1514  1.29.2.2  skrll 		 * not related to host_interrupt_operation_mode.
   1515  1.29.2.2  skrll 		 *
   1516  1.29.2.2  skrll 		 * Enable the oscillator to count wake up time for L1 exit. This
   1517  1.29.2.2  skrll 		 * consumes slightly more power (100uA) - but allows to be sure
   1518  1.29.2.2  skrll 		 * that we wake up from L1 on time.
   1519  1.29.2.2  skrll 		 *
   1520  1.29.2.2  skrll 		 * This looks weird: read twice the same register, discard the
   1521  1.29.2.2  skrll 		 * value, set a bit, and yet again, read that same register
   1522  1.29.2.2  skrll 		 * just to discard the value. But that's the way the hardware
   1523  1.29.2.2  skrll 		 * seems to like it.
   1524  1.29.2.2  skrll 		 */
   1525  1.29.2.2  skrll 		iwm_read_prph(sc, IWM_OSC_CLK);
   1526  1.29.2.2  skrll 		iwm_read_prph(sc, IWM_OSC_CLK);
   1527  1.29.2.2  skrll 		iwm_set_bits_prph(sc, IWM_OSC_CLK, IWM_OSC_CLK_FORCE_CONTROL);
   1528  1.29.2.2  skrll 		iwm_read_prph(sc, IWM_OSC_CLK);
   1529  1.29.2.2  skrll 		iwm_read_prph(sc, IWM_OSC_CLK);
   1530  1.29.2.2  skrll 	}
   1531  1.29.2.2  skrll 
   1532  1.29.2.2  skrll 	/*
   1533  1.29.2.2  skrll 	 * Enable DMA clock and wait for it to stabilize.
   1534  1.29.2.2  skrll 	 *
   1535  1.29.2.2  skrll 	 * Write to "CLK_EN_REG"; "1" bits enable clocks, while "0" bits
   1536  1.29.2.2  skrll 	 * do not disable clocks.  This preserves any hardware bits already
   1537  1.29.2.2  skrll 	 * set by default in "CLK_CTRL_REG" after reset.
   1538  1.29.2.2  skrll 	 */
   1539  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_APMG_CLK_EN_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT);
   1540  1.29.2.2  skrll 	//kpause("iwmapm", 0, mstohz(20), NULL);
   1541  1.29.2.2  skrll 	DELAY(20);
   1542  1.29.2.2  skrll 
   1543  1.29.2.2  skrll 	/* Disable L1-Active */
   1544  1.29.2.2  skrll 	iwm_set_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
   1545  1.29.2.2  skrll 	    IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
   1546  1.29.2.2  skrll 
   1547  1.29.2.2  skrll 	/* Clear the interrupt in APMG if the NIC is in RFKILL */
   1548  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_APMG_RTC_INT_STT_REG,
   1549  1.29.2.2  skrll 	    IWM_APMG_RTC_INT_STT_RFKILL);
   1550  1.29.2.2  skrll 
   1551  1.29.2.2  skrll  out:
   1552  1.29.2.2  skrll 	if (error)
   1553  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "apm init error %d\n", error);
   1554  1.29.2.2  skrll 	return error;
   1555  1.29.2.2  skrll }
   1556  1.29.2.2  skrll 
   1557  1.29.2.2  skrll /* iwlwifi/pcie/trans.c */
   1558  1.29.2.2  skrll static void
   1559  1.29.2.2  skrll iwm_apm_stop(struct iwm_softc *sc)
   1560  1.29.2.2  skrll {
   1561  1.29.2.2  skrll 	/* stop device's busmaster DMA activity */
   1562  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_STOP_MASTER);
   1563  1.29.2.2  skrll 
   1564  1.29.2.2  skrll 	if (!iwm_poll_bit(sc, IWM_CSR_RESET,
   1565  1.29.2.2  skrll 	    IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED,
   1566  1.29.2.2  skrll 	    IWM_CSR_RESET_REG_FLAG_MASTER_DISABLED, 100))
   1567  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "timeout waiting for master\n");
   1568  1.29.2.2  skrll 	DPRINTF(("iwm apm stop\n"));
   1569  1.29.2.2  skrll }
   1570  1.29.2.2  skrll 
   1571  1.29.2.2  skrll /* iwlwifi pcie/trans.c */
   1572  1.29.2.2  skrll static int
   1573  1.29.2.2  skrll iwm_start_hw(struct iwm_softc *sc)
   1574  1.29.2.2  skrll {
   1575  1.29.2.2  skrll 	int error;
   1576  1.29.2.2  skrll 
   1577  1.29.2.2  skrll 	if ((error = iwm_prepare_card_hw(sc)) != 0)
   1578  1.29.2.2  skrll 		return error;
   1579  1.29.2.2  skrll 
   1580  1.29.2.2  skrll 	/* Reset the entire device */
   1581  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_RESET,
   1582  1.29.2.2  skrll 	    IWM_CSR_RESET_REG_FLAG_SW_RESET |
   1583  1.29.2.2  skrll 	    IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
   1584  1.29.2.2  skrll 	DELAY(10);
   1585  1.29.2.2  skrll 
   1586  1.29.2.2  skrll 	if ((error = iwm_apm_init(sc)) != 0)
   1587  1.29.2.2  skrll 		return error;
   1588  1.29.2.2  skrll 
   1589  1.29.2.2  skrll 	iwm_enable_rfkill_int(sc);
   1590  1.29.2.2  skrll 	iwm_check_rfkill(sc);
   1591  1.29.2.2  skrll 
   1592  1.29.2.2  skrll 	return 0;
   1593  1.29.2.2  skrll }
   1594  1.29.2.2  skrll 
   1595  1.29.2.2  skrll /* iwlwifi pcie/trans.c */
   1596  1.29.2.2  skrll 
   1597  1.29.2.2  skrll static void
   1598  1.29.2.2  skrll iwm_stop_device(struct iwm_softc *sc)
   1599  1.29.2.2  skrll {
   1600  1.29.2.2  skrll 	int chnl, ntries;
   1601  1.29.2.2  skrll 	int qid;
   1602  1.29.2.2  skrll 
   1603  1.29.2.2  skrll 	/* tell the device to stop sending interrupts */
   1604  1.29.2.2  skrll 	iwm_disable_interrupts(sc);
   1605  1.29.2.2  skrll 
   1606  1.29.2.2  skrll 	/* device going down, Stop using ICT table */
   1607  1.29.2.2  skrll 	sc->sc_flags &= ~IWM_FLAG_USE_ICT;
   1608  1.29.2.2  skrll 
   1609  1.29.2.2  skrll 	/* stop tx and rx.  tx and rx bits, as usual, are from if_iwn */
   1610  1.29.2.2  skrll 
   1611  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_TXFACT, 0);
   1612  1.29.2.2  skrll 
   1613  1.29.2.2  skrll 	/* Stop all DMA channels. */
   1614  1.29.2.2  skrll 	if (iwm_nic_lock(sc)) {
   1615  1.29.2.2  skrll 		for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) {
   1616  1.29.2.2  skrll 			IWM_WRITE(sc,
   1617  1.29.2.2  skrll 			    IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), 0);
   1618  1.29.2.2  skrll 			for (ntries = 0; ntries < 200; ntries++) {
   1619  1.29.2.2  skrll 				uint32_t r;
   1620  1.29.2.2  skrll 
   1621  1.29.2.2  skrll 				r = IWM_READ(sc, IWM_FH_TSSR_TX_STATUS_REG);
   1622  1.29.2.2  skrll 				if (r & IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(
   1623  1.29.2.2  skrll 				    chnl))
   1624  1.29.2.2  skrll 					break;
   1625  1.29.2.2  skrll 				DELAY(20);
   1626  1.29.2.2  skrll 			}
   1627  1.29.2.2  skrll 		}
   1628  1.29.2.2  skrll 		iwm_nic_unlock(sc);
   1629  1.29.2.2  skrll 	}
   1630  1.29.2.2  skrll 
   1631  1.29.2.2  skrll 	/* Stop RX ring. */
   1632  1.29.2.2  skrll 	iwm_reset_rx_ring(sc, &sc->rxq);
   1633  1.29.2.2  skrll 
   1634  1.29.2.2  skrll 	/* Reset all TX rings. */
   1635  1.29.2.2  skrll 	for (qid = 0; qid < __arraycount(sc->txq); qid++)
   1636  1.29.2.2  skrll 		iwm_reset_tx_ring(sc, &sc->txq[qid]);
   1637  1.29.2.2  skrll 
   1638  1.29.2.2  skrll 	/*
   1639  1.29.2.2  skrll 	 * Power-down device's busmaster DMA clocks
   1640  1.29.2.2  skrll 	 */
   1641  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_APMG_CLK_DIS_REG, IWM_APMG_CLK_VAL_DMA_CLK_RQT);
   1642  1.29.2.2  skrll 	DELAY(5);
   1643  1.29.2.2  skrll 
   1644  1.29.2.2  skrll 	/* Make sure (redundant) we've released our request to stay awake */
   1645  1.29.2.2  skrll 	IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
   1646  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
   1647  1.29.2.2  skrll 
   1648  1.29.2.2  skrll 	/* Stop the device, and put it in low power state */
   1649  1.29.2.2  skrll 	iwm_apm_stop(sc);
   1650  1.29.2.2  skrll 
   1651  1.29.2.2  skrll 	/* Upon stop, the APM issues an interrupt if HW RF kill is set.
   1652  1.29.2.2  skrll 	 * Clean again the interrupt here
   1653  1.29.2.2  skrll 	 */
   1654  1.29.2.2  skrll 	iwm_disable_interrupts(sc);
   1655  1.29.2.2  skrll 	/* stop and reset the on-board processor */
   1656  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_RESET, IWM_CSR_RESET_REG_FLAG_NEVO_RESET);
   1657  1.29.2.2  skrll 
   1658  1.29.2.2  skrll 	/*
   1659  1.29.2.2  skrll 	 * Even if we stop the HW, we still want the RF kill
   1660  1.29.2.2  skrll 	 * interrupt
   1661  1.29.2.2  skrll 	 */
   1662  1.29.2.2  skrll 	iwm_enable_rfkill_int(sc);
   1663  1.29.2.2  skrll 	iwm_check_rfkill(sc);
   1664  1.29.2.2  skrll }
   1665  1.29.2.2  skrll 
   1666  1.29.2.2  skrll /* iwlwifi pcie/trans.c (always main power) */
   1667  1.29.2.2  skrll static void
   1668  1.29.2.2  skrll iwm_set_pwr(struct iwm_softc *sc)
   1669  1.29.2.2  skrll {
   1670  1.29.2.2  skrll 	iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
   1671  1.29.2.2  skrll 	    IWM_APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, ~IWM_APMG_PS_CTRL_MSK_PWR_SRC);
   1672  1.29.2.2  skrll }
   1673  1.29.2.2  skrll 
   1674  1.29.2.2  skrll /* iwlwifi: mvm/ops.c */
   1675  1.29.2.2  skrll static void
   1676  1.29.2.2  skrll iwm_mvm_nic_config(struct iwm_softc *sc)
   1677  1.29.2.2  skrll {
   1678  1.29.2.2  skrll 	uint8_t radio_cfg_type, radio_cfg_step, radio_cfg_dash;
   1679  1.29.2.2  skrll 	uint32_t reg_val = 0;
   1680  1.29.2.2  skrll 
   1681  1.29.2.2  skrll 	radio_cfg_type = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_TYPE) >>
   1682  1.29.2.2  skrll 	    IWM_FW_PHY_CFG_RADIO_TYPE_POS;
   1683  1.29.2.2  skrll 	radio_cfg_step = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_STEP) >>
   1684  1.29.2.2  skrll 	    IWM_FW_PHY_CFG_RADIO_STEP_POS;
   1685  1.29.2.2  skrll 	radio_cfg_dash = (sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RADIO_DASH) >>
   1686  1.29.2.2  skrll 	    IWM_FW_PHY_CFG_RADIO_DASH_POS;
   1687  1.29.2.2  skrll 
   1688  1.29.2.2  skrll 	/* SKU control */
   1689  1.29.2.2  skrll 	reg_val |= IWM_CSR_HW_REV_STEP(sc->sc_hw_rev) <<
   1690  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_STEP;
   1691  1.29.2.2  skrll 	reg_val |= IWM_CSR_HW_REV_DASH(sc->sc_hw_rev) <<
   1692  1.29.2.2  skrll 	    IWM_CSR_HW_IF_CONFIG_REG_POS_MAC_DASH;
   1693  1.29.2.2  skrll 
   1694  1.29.2.2  skrll 	/* radio configuration */
   1695  1.29.2.2  skrll 	reg_val |= radio_cfg_type << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_TYPE;
   1696  1.29.2.2  skrll 	reg_val |= radio_cfg_step << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_STEP;
   1697  1.29.2.2  skrll 	reg_val |= radio_cfg_dash << IWM_CSR_HW_IF_CONFIG_REG_POS_PHY_DASH;
   1698  1.29.2.2  skrll 
   1699  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_HW_IF_CONFIG_REG, reg_val);
   1700  1.29.2.2  skrll 
   1701  1.29.2.2  skrll 	DPRINTF(("Radio type=0x%x-0x%x-0x%x\n", radio_cfg_type,
   1702  1.29.2.2  skrll 	    radio_cfg_step, radio_cfg_dash));
   1703  1.29.2.2  skrll 
   1704  1.29.2.2  skrll 	/*
   1705  1.29.2.2  skrll 	 * W/A : NIC is stuck in a reset state after Early PCIe power off
   1706  1.29.2.2  skrll 	 * (PCIe power is lost before PERST# is asserted), causing ME FW
   1707  1.29.2.2  skrll 	 * to lose ownership and not being able to obtain it back.
   1708  1.29.2.2  skrll 	 */
   1709  1.29.2.2  skrll 	iwm_set_bits_mask_prph(sc, IWM_APMG_PS_CTRL_REG,
   1710  1.29.2.2  skrll 	    IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS,
   1711  1.29.2.2  skrll 	    ~IWM_APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS);
   1712  1.29.2.2  skrll }
   1713  1.29.2.2  skrll 
   1714  1.29.2.2  skrll static int
   1715  1.29.2.2  skrll iwm_nic_rx_init(struct iwm_softc *sc)
   1716  1.29.2.2  skrll {
   1717  1.29.2.2  skrll 	if (!iwm_nic_lock(sc))
   1718  1.29.2.2  skrll 		return EBUSY;
   1719  1.29.2.2  skrll 
   1720  1.29.2.2  skrll 	/*
   1721  1.29.2.2  skrll 	 * Initialize RX ring.  This is from the iwn driver.
   1722  1.29.2.2  skrll 	 */
   1723  1.29.2.2  skrll 	memset(sc->rxq.stat, 0, sizeof(*sc->rxq.stat));
   1724  1.29.2.2  skrll 
   1725  1.29.2.2  skrll 	/* stop DMA */
   1726  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
   1727  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0);
   1728  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0);
   1729  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RDPTR, 0);
   1730  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
   1731  1.29.2.2  skrll 
   1732  1.29.2.2  skrll 	/* Set physical address of RX ring (256-byte aligned). */
   1733  1.29.2.2  skrll 	IWM_WRITE(sc,
   1734  1.29.2.2  skrll 	    IWM_FH_RSCSR_CHNL0_RBDCB_BASE_REG, sc->rxq.desc_dma.paddr >> 8);
   1735  1.29.2.2  skrll 
   1736  1.29.2.2  skrll 	/* Set physical address of RX status (16-byte aligned). */
   1737  1.29.2.2  skrll 	IWM_WRITE(sc,
   1738  1.29.2.2  skrll 	    IWM_FH_RSCSR_CHNL0_STTS_WPTR_REG, sc->rxq.stat_dma.paddr >> 4);
   1739  1.29.2.2  skrll 
   1740  1.29.2.2  skrll 	/* Enable RX. */
   1741  1.29.2.2  skrll 	/*
   1742  1.29.2.2  skrll 	 * Note: Linux driver also sets this:
   1743  1.29.2.2  skrll 	 *  (IWM_RX_RB_TIMEOUT << IWM_FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) |
   1744  1.29.2.2  skrll 	 *
   1745  1.29.2.2  skrll 	 * It causes weird behavior.  YMMV.
   1746  1.29.2.2  skrll 	 */
   1747  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_MEM_RCSR_CHNL0_CONFIG_REG,
   1748  1.29.2.2  skrll 	    IWM_FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL		|
   1749  1.29.2.2  skrll 	    IWM_FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY		|  /* HW bug */
   1750  1.29.2.2  skrll 	    IWM_FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL	|
   1751  1.29.2.2  skrll 	    IWM_FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K		|
   1752  1.29.2.2  skrll 	    IWM_RX_QUEUE_SIZE_LOG << IWM_FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS);
   1753  1.29.2.2  skrll 
   1754  1.29.2.2  skrll 	IWM_WRITE_1(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_TIMEOUT_DEF);
   1755  1.29.2.2  skrll 
   1756  1.29.2.2  skrll 	/* W/A for interrupt coalescing bug in 7260 and 3160 */
   1757  1.29.2.2  skrll 	if (sc->host_interrupt_operation_mode)
   1758  1.29.2.2  skrll 		IWM_SETBITS(sc, IWM_CSR_INT_COALESCING, IWM_HOST_INT_OPER_MODE);
   1759  1.29.2.2  skrll 
   1760  1.29.2.2  skrll 	/*
   1761  1.29.2.2  skrll 	 * Thus sayeth el jefe (iwlwifi) via a comment:
   1762  1.29.2.2  skrll 	 *
   1763  1.29.2.2  skrll 	 * This value should initially be 0 (before preparing any
   1764  1.29.2.5  skrll 	 * RBs), should be 8 after preparing the first 8 RBs (for example)
   1765  1.29.2.2  skrll 	 */
   1766  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, 8);
   1767  1.29.2.2  skrll 
   1768  1.29.2.2  skrll 	iwm_nic_unlock(sc);
   1769  1.29.2.2  skrll 
   1770  1.29.2.2  skrll 	return 0;
   1771  1.29.2.2  skrll }
   1772  1.29.2.2  skrll 
   1773  1.29.2.2  skrll static int
   1774  1.29.2.2  skrll iwm_nic_tx_init(struct iwm_softc *sc)
   1775  1.29.2.2  skrll {
   1776  1.29.2.2  skrll 	int qid;
   1777  1.29.2.2  skrll 
   1778  1.29.2.2  skrll 	if (!iwm_nic_lock(sc))
   1779  1.29.2.2  skrll 		return EBUSY;
   1780  1.29.2.2  skrll 
   1781  1.29.2.2  skrll 	/* Deactivate TX scheduler. */
   1782  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_TXFACT, 0);
   1783  1.29.2.2  skrll 
   1784  1.29.2.2  skrll 	/* Set physical address of "keep warm" page (16-byte aligned). */
   1785  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_KW_MEM_ADDR_REG, sc->kw_dma.paddr >> 4);
   1786  1.29.2.2  skrll 
   1787  1.29.2.2  skrll 	/* Initialize TX rings. */
   1788  1.29.2.2  skrll 	for (qid = 0; qid < __arraycount(sc->txq); qid++) {
   1789  1.29.2.2  skrll 		struct iwm_tx_ring *txq = &sc->txq[qid];
   1790  1.29.2.2  skrll 
   1791  1.29.2.2  skrll 		/* Set physical address of TX ring (256-byte aligned). */
   1792  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_FH_MEM_CBBC_QUEUE(qid),
   1793  1.29.2.2  skrll 		    txq->desc_dma.paddr >> 8);
   1794  1.29.2.2  skrll 		DPRINTF(("loading ring %d descriptors (%p) at %"PRIxMAX"\n",
   1795  1.29.2.2  skrll 		    qid, txq->desc, (uintmax_t)(txq->desc_dma.paddr >> 8)));
   1796  1.29.2.2  skrll 	}
   1797  1.29.2.2  skrll 	iwm_nic_unlock(sc);
   1798  1.29.2.2  skrll 
   1799  1.29.2.2  skrll 	return 0;
   1800  1.29.2.2  skrll }
   1801  1.29.2.2  skrll 
   1802  1.29.2.2  skrll static int
   1803  1.29.2.2  skrll iwm_nic_init(struct iwm_softc *sc)
   1804  1.29.2.2  skrll {
   1805  1.29.2.2  skrll 	int error;
   1806  1.29.2.2  skrll 
   1807  1.29.2.2  skrll 	iwm_apm_init(sc);
   1808  1.29.2.2  skrll 	iwm_set_pwr(sc);
   1809  1.29.2.2  skrll 
   1810  1.29.2.2  skrll 	iwm_mvm_nic_config(sc);
   1811  1.29.2.2  skrll 
   1812  1.29.2.2  skrll 	if ((error = iwm_nic_rx_init(sc)) != 0)
   1813  1.29.2.2  skrll 		return error;
   1814  1.29.2.2  skrll 
   1815  1.29.2.2  skrll 	/*
   1816  1.29.2.2  skrll 	 * Ditto for TX, from iwn
   1817  1.29.2.2  skrll 	 */
   1818  1.29.2.2  skrll 	if ((error = iwm_nic_tx_init(sc)) != 0)
   1819  1.29.2.2  skrll 		return error;
   1820  1.29.2.2  skrll 
   1821  1.29.2.2  skrll 	DPRINTF(("shadow registers enabled\n"));
   1822  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_MAC_SHADOW_REG_CTRL, 0x800fffff);
   1823  1.29.2.2  skrll 
   1824  1.29.2.2  skrll 	return 0;
   1825  1.29.2.2  skrll }
   1826  1.29.2.2  skrll 
   1827  1.29.2.2  skrll #if 0
   1828  1.29.2.2  skrll enum iwm_mvm_tx_fifo {
   1829  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_BK = 0,
   1830  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_BE,
   1831  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_VI,
   1832  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_VO,
   1833  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_MCAST = 5,
   1834  1.29.2.2  skrll };
   1835  1.29.2.2  skrll 
   1836  1.29.2.2  skrll static const uint8_t iwm_mvm_ac_to_tx_fifo[] = {
   1837  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_VO,
   1838  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_VI,
   1839  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_BE,
   1840  1.29.2.2  skrll 	IWM_MVM_TX_FIFO_BK,
   1841  1.29.2.2  skrll };
   1842  1.29.2.2  skrll #endif
   1843  1.29.2.2  skrll 
   1844  1.29.2.2  skrll static void
   1845  1.29.2.2  skrll iwm_enable_txq(struct iwm_softc *sc, int qid, int fifo)
   1846  1.29.2.2  skrll {
   1847  1.29.2.2  skrll 	if (!iwm_nic_lock(sc)) {
   1848  1.29.2.2  skrll 		DPRINTF(("%s: cannot enable txq %d\n", DEVNAME(sc), qid));
   1849  1.29.2.2  skrll 		return; /* XXX return EBUSY */
   1850  1.29.2.2  skrll 	}
   1851  1.29.2.2  skrll 
   1852  1.29.2.2  skrll 	/* unactivate before configuration */
   1853  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
   1854  1.29.2.2  skrll 	    (0 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE)
   1855  1.29.2.2  skrll 	    | (1 << IWM_SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
   1856  1.29.2.2  skrll 
   1857  1.29.2.2  skrll 	if (qid != IWM_MVM_CMD_QUEUE) {
   1858  1.29.2.2  skrll 		iwm_set_bits_prph(sc, IWM_SCD_QUEUECHAIN_SEL, (1 << qid));
   1859  1.29.2.2  skrll 	}
   1860  1.29.2.2  skrll 
   1861  1.29.2.2  skrll 	iwm_clear_bits_prph(sc, IWM_SCD_AGGR_SEL, (1 << qid));
   1862  1.29.2.2  skrll 
   1863  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, qid << 8 | 0);
   1864  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_QUEUE_RDPTR(qid), 0);
   1865  1.29.2.2  skrll 
   1866  1.29.2.2  skrll 	iwm_write_mem32(sc, sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid), 0);
   1867  1.29.2.2  skrll 	/* Set scheduler window size and frame limit. */
   1868  1.29.2.2  skrll 	iwm_write_mem32(sc,
   1869  1.29.2.2  skrll 	    sc->sched_base + IWM_SCD_CONTEXT_QUEUE_OFFSET(qid) +
   1870  1.29.2.2  skrll 	    sizeof(uint32_t),
   1871  1.29.2.2  skrll 	    ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
   1872  1.29.2.2  skrll 	    IWM_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
   1873  1.29.2.2  skrll 	    ((IWM_FRAME_LIMIT << IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
   1874  1.29.2.2  skrll 	    IWM_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
   1875  1.29.2.2  skrll 
   1876  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_QUEUE_STATUS_BITS(qid),
   1877  1.29.2.2  skrll 	    (1 << IWM_SCD_QUEUE_STTS_REG_POS_ACTIVE) |
   1878  1.29.2.2  skrll 	    (fifo << IWM_SCD_QUEUE_STTS_REG_POS_TXF) |
   1879  1.29.2.2  skrll 	    (1 << IWM_SCD_QUEUE_STTS_REG_POS_WSL) |
   1880  1.29.2.2  skrll 	    IWM_SCD_QUEUE_STTS_REG_MSK);
   1881  1.29.2.2  skrll 
   1882  1.29.2.2  skrll 	iwm_nic_unlock(sc);
   1883  1.29.2.2  skrll 
   1884  1.29.2.2  skrll 	DPRINTF(("enabled txq %d FIFO %d\n", qid, fifo));
   1885  1.29.2.2  skrll }
   1886  1.29.2.2  skrll 
   1887  1.29.2.2  skrll static int
   1888  1.29.2.2  skrll iwm_post_alive(struct iwm_softc *sc)
   1889  1.29.2.2  skrll {
   1890  1.29.2.2  skrll 	int nwords;
   1891  1.29.2.2  skrll 	int error, chnl;
   1892  1.29.2.2  skrll 
   1893  1.29.2.2  skrll 	if (!iwm_nic_lock(sc))
   1894  1.29.2.2  skrll 		return EBUSY;
   1895  1.29.2.2  skrll 
   1896  1.29.2.2  skrll 	if (sc->sched_base != iwm_read_prph(sc, IWM_SCD_SRAM_BASE_ADDR)) {
   1897  1.29.2.2  skrll 		DPRINTF(("%s: sched addr mismatch\n", DEVNAME(sc)));
   1898  1.29.2.2  skrll 		error = EINVAL;
   1899  1.29.2.2  skrll 		goto out;
   1900  1.29.2.2  skrll 	}
   1901  1.29.2.2  skrll 
   1902  1.29.2.2  skrll 	iwm_ict_reset(sc);
   1903  1.29.2.2  skrll 
   1904  1.29.2.2  skrll 	/* Clear TX scheduler state in SRAM. */
   1905  1.29.2.2  skrll 	nwords = (IWM_SCD_TRANS_TBL_MEM_UPPER_BOUND -
   1906  1.29.2.2  skrll 	    IWM_SCD_CONTEXT_MEM_LOWER_BOUND)
   1907  1.29.2.2  skrll 	    / sizeof(uint32_t);
   1908  1.29.2.2  skrll 	error = iwm_write_mem(sc,
   1909  1.29.2.2  skrll 	    sc->sched_base + IWM_SCD_CONTEXT_MEM_LOWER_BOUND,
   1910  1.29.2.2  skrll 	    NULL, nwords);
   1911  1.29.2.2  skrll 	if (error)
   1912  1.29.2.2  skrll 		goto out;
   1913  1.29.2.2  skrll 
   1914  1.29.2.2  skrll 	/* Set physical address of TX scheduler rings (1KB aligned). */
   1915  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_DRAM_BASE_ADDR, sc->sched_dma.paddr >> 10);
   1916  1.29.2.2  skrll 
   1917  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_CHAINEXT_EN, 0);
   1918  1.29.2.2  skrll 
   1919  1.29.2.2  skrll 	/* enable command channel */
   1920  1.29.2.2  skrll 	iwm_enable_txq(sc, IWM_MVM_CMD_QUEUE, 7);
   1921  1.29.2.2  skrll 
   1922  1.29.2.2  skrll 	iwm_write_prph(sc, IWM_SCD_TXFACT, 0xff);
   1923  1.29.2.2  skrll 
   1924  1.29.2.2  skrll 	/* Enable DMA channels. */
   1925  1.29.2.2  skrll 	for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) {
   1926  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl),
   1927  1.29.2.2  skrll 		    IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
   1928  1.29.2.2  skrll 		    IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
   1929  1.29.2.2  skrll 	}
   1930  1.29.2.2  skrll 
   1931  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_FH_TX_CHICKEN_BITS_REG,
   1932  1.29.2.2  skrll 	    IWM_FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
   1933  1.29.2.2  skrll 
   1934  1.29.2.2  skrll 	/* Enable L1-Active */
   1935  1.29.2.2  skrll 	iwm_clear_bits_prph(sc, IWM_APMG_PCIDEV_STT_REG,
   1936  1.29.2.2  skrll 	    IWM_APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
   1937  1.29.2.2  skrll 
   1938  1.29.2.2  skrll  out:
   1939  1.29.2.5  skrll 	iwm_nic_unlock(sc);
   1940  1.29.2.2  skrll 	return error;
   1941  1.29.2.2  skrll }
   1942  1.29.2.2  skrll 
   1943  1.29.2.2  skrll /*
   1944  1.29.2.2  skrll  * PHY db
   1945  1.29.2.2  skrll  * iwlwifi/iwl-phy-db.c
   1946  1.29.2.2  skrll  */
   1947  1.29.2.2  skrll 
   1948  1.29.2.2  skrll /*
   1949  1.29.2.2  skrll  * BEGIN iwl-phy-db.c
   1950  1.29.2.2  skrll  */
   1951  1.29.2.2  skrll 
   1952  1.29.2.2  skrll enum iwm_phy_db_section_type {
   1953  1.29.2.2  skrll 	IWM_PHY_DB_CFG = 1,
   1954  1.29.2.2  skrll 	IWM_PHY_DB_CALIB_NCH,
   1955  1.29.2.2  skrll 	IWM_PHY_DB_UNUSED,
   1956  1.29.2.2  skrll 	IWM_PHY_DB_CALIB_CHG_PAPD,
   1957  1.29.2.2  skrll 	IWM_PHY_DB_CALIB_CHG_TXP,
   1958  1.29.2.2  skrll 	IWM_PHY_DB_MAX
   1959  1.29.2.2  skrll };
   1960  1.29.2.2  skrll 
   1961  1.29.2.2  skrll #define IWM_PHY_DB_CMD 0x6c /* TEMP API - The actual is 0x8c */
   1962  1.29.2.2  skrll 
   1963  1.29.2.2  skrll /*
   1964  1.29.2.2  skrll  * phy db - configure operational ucode
   1965  1.29.2.2  skrll  */
   1966  1.29.2.2  skrll struct iwm_phy_db_cmd {
   1967  1.29.2.2  skrll 	uint16_t type;
   1968  1.29.2.2  skrll 	uint16_t length;
   1969  1.29.2.2  skrll 	uint8_t data[];
   1970  1.29.2.2  skrll } __packed;
   1971  1.29.2.2  skrll 
   1972  1.29.2.2  skrll /* for parsing of tx power channel group data that comes from the firmware*/
   1973  1.29.2.2  skrll struct iwm_phy_db_chg_txp {
   1974  1.29.2.2  skrll 	uint32_t space;
   1975  1.29.2.2  skrll 	uint16_t max_channel_idx;
   1976  1.29.2.2  skrll } __packed;
   1977  1.29.2.2  skrll 
   1978  1.29.2.2  skrll /*
   1979  1.29.2.2  skrll  * phy db - Receive phy db chunk after calibrations
   1980  1.29.2.2  skrll  */
   1981  1.29.2.2  skrll struct iwm_calib_res_notif_phy_db {
   1982  1.29.2.2  skrll 	uint16_t type;
   1983  1.29.2.2  skrll 	uint16_t length;
   1984  1.29.2.2  skrll 	uint8_t data[];
   1985  1.29.2.2  skrll } __packed;
   1986  1.29.2.2  skrll 
   1987  1.29.2.2  skrll /*
   1988  1.29.2.2  skrll  * get phy db section: returns a pointer to a phy db section specified by
   1989  1.29.2.2  skrll  * type and channel group id.
   1990  1.29.2.2  skrll  */
   1991  1.29.2.2  skrll static struct iwm_phy_db_entry *
   1992  1.29.2.2  skrll iwm_phy_db_get_section(struct iwm_softc *sc,
   1993  1.29.2.2  skrll 	enum iwm_phy_db_section_type type, uint16_t chg_id)
   1994  1.29.2.2  skrll {
   1995  1.29.2.2  skrll 	struct iwm_phy_db *phy_db = &sc->sc_phy_db;
   1996  1.29.2.2  skrll 
   1997  1.29.2.2  skrll 	if (type >= IWM_PHY_DB_MAX)
   1998  1.29.2.2  skrll 		return NULL;
   1999  1.29.2.2  skrll 
   2000  1.29.2.2  skrll 	switch (type) {
   2001  1.29.2.2  skrll 	case IWM_PHY_DB_CFG:
   2002  1.29.2.2  skrll 		return &phy_db->cfg;
   2003  1.29.2.2  skrll 	case IWM_PHY_DB_CALIB_NCH:
   2004  1.29.2.2  skrll 		return &phy_db->calib_nch;
   2005  1.29.2.2  skrll 	case IWM_PHY_DB_CALIB_CHG_PAPD:
   2006  1.29.2.2  skrll 		if (chg_id >= IWM_NUM_PAPD_CH_GROUPS)
   2007  1.29.2.2  skrll 			return NULL;
   2008  1.29.2.2  skrll 		return &phy_db->calib_ch_group_papd[chg_id];
   2009  1.29.2.2  skrll 	case IWM_PHY_DB_CALIB_CHG_TXP:
   2010  1.29.2.2  skrll 		if (chg_id >= IWM_NUM_TXP_CH_GROUPS)
   2011  1.29.2.2  skrll 			return NULL;
   2012  1.29.2.2  skrll 		return &phy_db->calib_ch_group_txp[chg_id];
   2013  1.29.2.2  skrll 	default:
   2014  1.29.2.2  skrll 		return NULL;
   2015  1.29.2.2  skrll 	}
   2016  1.29.2.2  skrll 	return NULL;
   2017  1.29.2.2  skrll }
   2018  1.29.2.2  skrll 
   2019  1.29.2.2  skrll static int
   2020  1.29.2.2  skrll iwm_phy_db_set_section(struct iwm_softc *sc,
   2021  1.29.2.2  skrll     struct iwm_calib_res_notif_phy_db *phy_db_notif, uint16_t size)
   2022  1.29.2.2  skrll {
   2023  1.29.2.2  skrll 	enum iwm_phy_db_section_type type = le16toh(phy_db_notif->type);
   2024  1.29.2.2  skrll 	struct iwm_phy_db_entry *entry;
   2025  1.29.2.2  skrll 	uint16_t chg_id = 0;
   2026  1.29.2.2  skrll 
   2027  1.29.2.2  skrll 	if (type == IWM_PHY_DB_CALIB_CHG_PAPD ||
   2028  1.29.2.2  skrll 	    type == IWM_PHY_DB_CALIB_CHG_TXP)
   2029  1.29.2.2  skrll 		chg_id = le16toh(*(uint16_t *)phy_db_notif->data);
   2030  1.29.2.2  skrll 
   2031  1.29.2.2  skrll 	entry = iwm_phy_db_get_section(sc, type, chg_id);
   2032  1.29.2.2  skrll 	if (!entry)
   2033  1.29.2.2  skrll 		return EINVAL;
   2034  1.29.2.2  skrll 
   2035  1.29.2.2  skrll 	if (entry->data)
   2036  1.29.2.2  skrll 		kmem_intr_free(entry->data, entry->size);
   2037  1.29.2.2  skrll 	entry->data = kmem_intr_alloc(size, KM_NOSLEEP);
   2038  1.29.2.2  skrll 	if (!entry->data) {
   2039  1.29.2.2  skrll 		entry->size = 0;
   2040  1.29.2.2  skrll 		return ENOMEM;
   2041  1.29.2.2  skrll 	}
   2042  1.29.2.2  skrll 	memcpy(entry->data, phy_db_notif->data, size);
   2043  1.29.2.2  skrll 	entry->size = size;
   2044  1.29.2.2  skrll 
   2045  1.29.2.2  skrll 	DPRINTFN(10, ("%s(%d): [PHYDB]SET: Type %d, Size: %d, data: %p\n",
   2046  1.29.2.2  skrll 	    __func__, __LINE__, type, size, entry->data));
   2047  1.29.2.2  skrll 
   2048  1.29.2.2  skrll 	return 0;
   2049  1.29.2.2  skrll }
   2050  1.29.2.2  skrll 
   2051  1.29.2.2  skrll static int
   2052  1.29.2.2  skrll iwm_is_valid_channel(uint16_t ch_id)
   2053  1.29.2.2  skrll {
   2054  1.29.2.2  skrll 	if (ch_id <= 14 ||
   2055  1.29.2.2  skrll 	    (36 <= ch_id && ch_id <= 64 && ch_id % 4 == 0) ||
   2056  1.29.2.2  skrll 	    (100 <= ch_id && ch_id <= 140 && ch_id % 4 == 0) ||
   2057  1.29.2.2  skrll 	    (145 <= ch_id && ch_id <= 165 && ch_id % 4 == 1))
   2058  1.29.2.2  skrll 		return 1;
   2059  1.29.2.2  skrll 	return 0;
   2060  1.29.2.2  skrll }
   2061  1.29.2.2  skrll 
   2062  1.29.2.2  skrll static uint8_t
   2063  1.29.2.2  skrll iwm_ch_id_to_ch_index(uint16_t ch_id)
   2064  1.29.2.2  skrll {
   2065  1.29.2.2  skrll 	if (!iwm_is_valid_channel(ch_id))
   2066  1.29.2.2  skrll 		return 0xff;
   2067  1.29.2.2  skrll 
   2068  1.29.2.2  skrll 	if (ch_id <= 14)
   2069  1.29.2.2  skrll 		return ch_id - 1;
   2070  1.29.2.2  skrll 	if (ch_id <= 64)
   2071  1.29.2.2  skrll 		return (ch_id + 20) / 4;
   2072  1.29.2.2  skrll 	if (ch_id <= 140)
   2073  1.29.2.2  skrll 		return (ch_id - 12) / 4;
   2074  1.29.2.2  skrll 	return (ch_id - 13) / 4;
   2075  1.29.2.2  skrll }
   2076  1.29.2.2  skrll 
   2077  1.29.2.2  skrll 
   2078  1.29.2.2  skrll static uint16_t
   2079  1.29.2.2  skrll iwm_channel_id_to_papd(uint16_t ch_id)
   2080  1.29.2.2  skrll {
   2081  1.29.2.2  skrll 	if (!iwm_is_valid_channel(ch_id))
   2082  1.29.2.2  skrll 		return 0xff;
   2083  1.29.2.2  skrll 
   2084  1.29.2.2  skrll 	if (1 <= ch_id && ch_id <= 14)
   2085  1.29.2.2  skrll 		return 0;
   2086  1.29.2.2  skrll 	if (36 <= ch_id && ch_id <= 64)
   2087  1.29.2.2  skrll 		return 1;
   2088  1.29.2.2  skrll 	if (100 <= ch_id && ch_id <= 140)
   2089  1.29.2.2  skrll 		return 2;
   2090  1.29.2.2  skrll 	return 3;
   2091  1.29.2.2  skrll }
   2092  1.29.2.2  skrll 
   2093  1.29.2.2  skrll static uint16_t
   2094  1.29.2.2  skrll iwm_channel_id_to_txp(struct iwm_softc *sc, uint16_t ch_id)
   2095  1.29.2.2  skrll {
   2096  1.29.2.2  skrll 	struct iwm_phy_db *phy_db = &sc->sc_phy_db;
   2097  1.29.2.2  skrll 	struct iwm_phy_db_chg_txp *txp_chg;
   2098  1.29.2.2  skrll 	int i;
   2099  1.29.2.2  skrll 	uint8_t ch_index = iwm_ch_id_to_ch_index(ch_id);
   2100  1.29.2.2  skrll 
   2101  1.29.2.2  skrll 	if (ch_index == 0xff)
   2102  1.29.2.2  skrll 		return 0xff;
   2103  1.29.2.2  skrll 
   2104  1.29.2.2  skrll 	for (i = 0; i < IWM_NUM_TXP_CH_GROUPS; i++) {
   2105  1.29.2.2  skrll 		txp_chg = (void *)phy_db->calib_ch_group_txp[i].data;
   2106  1.29.2.2  skrll 		if (!txp_chg)
   2107  1.29.2.2  skrll 			return 0xff;
   2108  1.29.2.2  skrll 		/*
   2109  1.29.2.2  skrll 		 * Looking for the first channel group that its max channel is
   2110  1.29.2.2  skrll 		 * higher then wanted channel.
   2111  1.29.2.2  skrll 		 */
   2112  1.29.2.2  skrll 		if (le16toh(txp_chg->max_channel_idx) >= ch_index)
   2113  1.29.2.2  skrll 			return i;
   2114  1.29.2.2  skrll 	}
   2115  1.29.2.2  skrll 	return 0xff;
   2116  1.29.2.2  skrll }
   2117  1.29.2.2  skrll 
   2118  1.29.2.2  skrll static int
   2119  1.29.2.2  skrll iwm_phy_db_get_section_data(struct iwm_softc *sc,
   2120  1.29.2.2  skrll 	uint32_t type, uint8_t **data, uint16_t *size, uint16_t ch_id)
   2121  1.29.2.2  skrll {
   2122  1.29.2.2  skrll 	struct iwm_phy_db_entry *entry;
   2123  1.29.2.2  skrll 	uint16_t ch_group_id = 0;
   2124  1.29.2.2  skrll 
   2125  1.29.2.2  skrll 	/* find wanted channel group */
   2126  1.29.2.2  skrll 	if (type == IWM_PHY_DB_CALIB_CHG_PAPD)
   2127  1.29.2.2  skrll 		ch_group_id = iwm_channel_id_to_papd(ch_id);
   2128  1.29.2.2  skrll 	else if (type == IWM_PHY_DB_CALIB_CHG_TXP)
   2129  1.29.2.2  skrll 		ch_group_id = iwm_channel_id_to_txp(sc, ch_id);
   2130  1.29.2.2  skrll 
   2131  1.29.2.2  skrll 	entry = iwm_phy_db_get_section(sc, type, ch_group_id);
   2132  1.29.2.2  skrll 	if (!entry)
   2133  1.29.2.2  skrll 		return EINVAL;
   2134  1.29.2.2  skrll 
   2135  1.29.2.2  skrll 	*data = entry->data;
   2136  1.29.2.2  skrll 	*size = entry->size;
   2137  1.29.2.2  skrll 
   2138  1.29.2.2  skrll 	DPRINTFN(10, ("%s(%d): [PHYDB] GET: Type %d , Size: %d\n",
   2139  1.29.2.2  skrll 		       __func__, __LINE__, type, *size));
   2140  1.29.2.2  skrll 
   2141  1.29.2.2  skrll 	return 0;
   2142  1.29.2.2  skrll }
   2143  1.29.2.2  skrll 
   2144  1.29.2.2  skrll static int
   2145  1.29.2.2  skrll iwm_send_phy_db_cmd(struct iwm_softc *sc, uint16_t type,
   2146  1.29.2.2  skrll 	uint16_t length, void *data)
   2147  1.29.2.2  skrll {
   2148  1.29.2.2  skrll 	struct iwm_phy_db_cmd phy_db_cmd;
   2149  1.29.2.2  skrll 	struct iwm_host_cmd cmd = {
   2150  1.29.2.2  skrll 		.id = IWM_PHY_DB_CMD,
   2151  1.29.2.2  skrll 		.flags = IWM_CMD_SYNC,
   2152  1.29.2.2  skrll 	};
   2153  1.29.2.2  skrll 
   2154  1.29.2.2  skrll 	DPRINTFN(10, ("Sending PHY-DB hcmd of type %d, of length %d\n",
   2155  1.29.2.2  skrll 	    type, length));
   2156  1.29.2.2  skrll 
   2157  1.29.2.2  skrll 	/* Set phy db cmd variables */
   2158  1.29.2.2  skrll 	phy_db_cmd.type = le16toh(type);
   2159  1.29.2.2  skrll 	phy_db_cmd.length = le16toh(length);
   2160  1.29.2.2  skrll 
   2161  1.29.2.2  skrll 	/* Set hcmd variables */
   2162  1.29.2.2  skrll 	cmd.data[0] = &phy_db_cmd;
   2163  1.29.2.2  skrll 	cmd.len[0] = sizeof(struct iwm_phy_db_cmd);
   2164  1.29.2.2  skrll 	cmd.data[1] = data;
   2165  1.29.2.2  skrll 	cmd.len[1] = length;
   2166  1.29.2.2  skrll 	cmd.dataflags[1] = IWM_HCMD_DFL_NOCOPY;
   2167  1.29.2.2  skrll 
   2168  1.29.2.2  skrll 	return iwm_send_cmd(sc, &cmd);
   2169  1.29.2.2  skrll }
   2170  1.29.2.2  skrll 
   2171  1.29.2.2  skrll static int
   2172  1.29.2.2  skrll iwm_phy_db_send_all_channel_groups(struct iwm_softc *sc,
   2173  1.29.2.2  skrll 	enum iwm_phy_db_section_type type, uint8_t max_ch_groups)
   2174  1.29.2.2  skrll {
   2175  1.29.2.2  skrll 	uint16_t i;
   2176  1.29.2.2  skrll 	int err;
   2177  1.29.2.2  skrll 	struct iwm_phy_db_entry *entry;
   2178  1.29.2.2  skrll 
   2179  1.29.2.2  skrll 	/* Send all the channel-specific groups to operational fw */
   2180  1.29.2.2  skrll 	for (i = 0; i < max_ch_groups; i++) {
   2181  1.29.2.2  skrll 		entry = iwm_phy_db_get_section(sc, type, i);
   2182  1.29.2.2  skrll 		if (!entry)
   2183  1.29.2.2  skrll 			return EINVAL;
   2184  1.29.2.2  skrll 
   2185  1.29.2.2  skrll 		if (!entry->size)
   2186  1.29.2.2  skrll 			continue;
   2187  1.29.2.2  skrll 
   2188  1.29.2.2  skrll 		/* Send the requested PHY DB section */
   2189  1.29.2.2  skrll 		err = iwm_send_phy_db_cmd(sc, type, entry->size, entry->data);
   2190  1.29.2.2  skrll 		if (err) {
   2191  1.29.2.2  skrll 			DPRINTF(("%s: Can't SEND phy_db section %d (%d), "
   2192  1.29.2.2  skrll 			    "err %d\n", DEVNAME(sc), type, i, err));
   2193  1.29.2.2  skrll 			return err;
   2194  1.29.2.2  skrll 		}
   2195  1.29.2.2  skrll 
   2196  1.29.2.2  skrll 		DPRINTFN(10, ("Sent PHY_DB HCMD, type = %d num = %d\n", type, i));
   2197  1.29.2.2  skrll 	}
   2198  1.29.2.2  skrll 
   2199  1.29.2.2  skrll 	return 0;
   2200  1.29.2.2  skrll }
   2201  1.29.2.2  skrll 
   2202  1.29.2.2  skrll static int
   2203  1.29.2.2  skrll iwm_send_phy_db_data(struct iwm_softc *sc)
   2204  1.29.2.2  skrll {
   2205  1.29.2.2  skrll 	uint8_t *data = NULL;
   2206  1.29.2.2  skrll 	uint16_t size = 0;
   2207  1.29.2.2  skrll 	int err;
   2208  1.29.2.2  skrll 
   2209  1.29.2.2  skrll 	DPRINTF(("Sending phy db data and configuration to runtime image\n"));
   2210  1.29.2.2  skrll 
   2211  1.29.2.2  skrll 	/* Send PHY DB CFG section */
   2212  1.29.2.2  skrll 	err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CFG, &data, &size, 0);
   2213  1.29.2.2  skrll 	if (err) {
   2214  1.29.2.2  skrll 		DPRINTF(("%s: Cannot get Phy DB cfg section, %d\n",
   2215  1.29.2.2  skrll 		    DEVNAME(sc), err));
   2216  1.29.2.2  skrll 		return err;
   2217  1.29.2.2  skrll 	}
   2218  1.29.2.2  skrll 
   2219  1.29.2.2  skrll 	err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CFG, size, data);
   2220  1.29.2.2  skrll 	if (err) {
   2221  1.29.2.2  skrll 		DPRINTF(("%s: Cannot send HCMD of Phy DB cfg section, %d\n",
   2222  1.29.2.2  skrll 		    DEVNAME(sc), err));
   2223  1.29.2.2  skrll 		return err;
   2224  1.29.2.2  skrll 	}
   2225  1.29.2.2  skrll 
   2226  1.29.2.2  skrll 	err = iwm_phy_db_get_section_data(sc, IWM_PHY_DB_CALIB_NCH,
   2227  1.29.2.2  skrll 	    &data, &size, 0);
   2228  1.29.2.2  skrll 	if (err) {
   2229  1.29.2.2  skrll 		DPRINTF(("%s: Cannot get Phy DB non specific channel section, "
   2230  1.29.2.2  skrll 		    "%d\n", DEVNAME(sc), err));
   2231  1.29.2.2  skrll 		return err;
   2232  1.29.2.2  skrll 	}
   2233  1.29.2.2  skrll 
   2234  1.29.2.2  skrll 	err = iwm_send_phy_db_cmd(sc, IWM_PHY_DB_CALIB_NCH, size, data);
   2235  1.29.2.2  skrll 	if (err) {
   2236  1.29.2.2  skrll 		DPRINTF(("%s: Cannot send HCMD of Phy DB non specific channel "
   2237  1.29.2.2  skrll 		    "sect, %d\n", DEVNAME(sc), err));
   2238  1.29.2.2  skrll 		return err;
   2239  1.29.2.2  skrll 	}
   2240  1.29.2.2  skrll 
   2241  1.29.2.2  skrll 	/* Send all the TXP channel specific data */
   2242  1.29.2.2  skrll 	err = iwm_phy_db_send_all_channel_groups(sc,
   2243  1.29.2.2  skrll 	    IWM_PHY_DB_CALIB_CHG_PAPD, IWM_NUM_PAPD_CH_GROUPS);
   2244  1.29.2.2  skrll 	if (err) {
   2245  1.29.2.2  skrll 		DPRINTF(("%s: Cannot send channel specific PAPD groups, %d\n",
   2246  1.29.2.2  skrll 		    DEVNAME(sc), err));
   2247  1.29.2.2  skrll 		return err;
   2248  1.29.2.2  skrll 	}
   2249  1.29.2.2  skrll 
   2250  1.29.2.2  skrll 	/* Send all the TXP channel specific data */
   2251  1.29.2.2  skrll 	err = iwm_phy_db_send_all_channel_groups(sc,
   2252  1.29.2.2  skrll 	    IWM_PHY_DB_CALIB_CHG_TXP, IWM_NUM_TXP_CH_GROUPS);
   2253  1.29.2.2  skrll 	if (err) {
   2254  1.29.2.2  skrll 		DPRINTF(("%s: Cannot send channel specific TX power groups, "
   2255  1.29.2.2  skrll 		    "%d\n", DEVNAME(sc), err));
   2256  1.29.2.2  skrll 		return err;
   2257  1.29.2.2  skrll 	}
   2258  1.29.2.2  skrll 
   2259  1.29.2.2  skrll 	DPRINTF(("Finished sending phy db non channel data\n"));
   2260  1.29.2.2  skrll 	return 0;
   2261  1.29.2.2  skrll }
   2262  1.29.2.2  skrll 
   2263  1.29.2.2  skrll /*
   2264  1.29.2.2  skrll  * END iwl-phy-db.c
   2265  1.29.2.2  skrll  */
   2266  1.29.2.2  skrll 
   2267  1.29.2.2  skrll /*
   2268  1.29.2.2  skrll  * BEGIN iwlwifi/mvm/time-event.c
   2269  1.29.2.2  skrll  */
   2270  1.29.2.2  skrll 
   2271  1.29.2.2  skrll /*
   2272  1.29.2.2  skrll  * For the high priority TE use a time event type that has similar priority to
   2273  1.29.2.2  skrll  * the FW's action scan priority.
   2274  1.29.2.2  skrll  */
   2275  1.29.2.2  skrll #define IWM_MVM_ROC_TE_TYPE_NORMAL IWM_TE_P2P_DEVICE_DISCOVERABLE
   2276  1.29.2.2  skrll #define IWM_MVM_ROC_TE_TYPE_MGMT_TX IWM_TE_P2P_CLIENT_ASSOC
   2277  1.29.2.2  skrll 
   2278  1.29.2.2  skrll /* used to convert from time event API v2 to v1 */
   2279  1.29.2.2  skrll #define IWM_TE_V2_DEP_POLICY_MSK (IWM_TE_V2_DEP_OTHER | IWM_TE_V2_DEP_TSF |\
   2280  1.29.2.2  skrll 			     IWM_TE_V2_EVENT_SOCIOPATHIC)
   2281  1.29.2.2  skrll static inline uint16_t
   2282  1.29.2.2  skrll iwm_te_v2_get_notify(uint16_t policy)
   2283  1.29.2.2  skrll {
   2284  1.29.2.2  skrll 	return le16toh(policy) & IWM_TE_V2_NOTIF_MSK;
   2285  1.29.2.2  skrll }
   2286  1.29.2.2  skrll 
   2287  1.29.2.2  skrll static inline uint16_t
   2288  1.29.2.2  skrll iwm_te_v2_get_dep_policy(uint16_t policy)
   2289  1.29.2.2  skrll {
   2290  1.29.2.2  skrll 	return (le16toh(policy) & IWM_TE_V2_DEP_POLICY_MSK) >>
   2291  1.29.2.2  skrll 		IWM_TE_V2_PLACEMENT_POS;
   2292  1.29.2.2  skrll }
   2293  1.29.2.2  skrll 
   2294  1.29.2.2  skrll static inline uint16_t
   2295  1.29.2.2  skrll iwm_te_v2_get_absence(uint16_t policy)
   2296  1.29.2.2  skrll {
   2297  1.29.2.2  skrll 	return (le16toh(policy) & IWM_TE_V2_ABSENCE) >> IWM_TE_V2_ABSENCE_POS;
   2298  1.29.2.2  skrll }
   2299  1.29.2.2  skrll 
   2300  1.29.2.2  skrll static void
   2301  1.29.2.2  skrll iwm_mvm_te_v2_to_v1(const struct iwm_time_event_cmd_v2 *cmd_v2,
   2302  1.29.2.2  skrll 	struct iwm_time_event_cmd_v1 *cmd_v1)
   2303  1.29.2.2  skrll {
   2304  1.29.2.2  skrll 	cmd_v1->id_and_color = cmd_v2->id_and_color;
   2305  1.29.2.2  skrll 	cmd_v1->action = cmd_v2->action;
   2306  1.29.2.2  skrll 	cmd_v1->id = cmd_v2->id;
   2307  1.29.2.2  skrll 	cmd_v1->apply_time = cmd_v2->apply_time;
   2308  1.29.2.2  skrll 	cmd_v1->max_delay = cmd_v2->max_delay;
   2309  1.29.2.2  skrll 	cmd_v1->depends_on = cmd_v2->depends_on;
   2310  1.29.2.2  skrll 	cmd_v1->interval = cmd_v2->interval;
   2311  1.29.2.2  skrll 	cmd_v1->duration = cmd_v2->duration;
   2312  1.29.2.2  skrll 	if (cmd_v2->repeat == IWM_TE_V2_REPEAT_ENDLESS)
   2313  1.29.2.2  skrll 		cmd_v1->repeat = htole32(IWM_TE_V1_REPEAT_ENDLESS);
   2314  1.29.2.2  skrll 	else
   2315  1.29.2.2  skrll 		cmd_v1->repeat = htole32(cmd_v2->repeat);
   2316  1.29.2.2  skrll 	cmd_v1->max_frags = htole32(cmd_v2->max_frags);
   2317  1.29.2.2  skrll 	cmd_v1->interval_reciprocal = 0; /* unused */
   2318  1.29.2.2  skrll 
   2319  1.29.2.2  skrll 	cmd_v1->dep_policy = htole32(iwm_te_v2_get_dep_policy(cmd_v2->policy));
   2320  1.29.2.2  skrll 	cmd_v1->is_present = htole32(!iwm_te_v2_get_absence(cmd_v2->policy));
   2321  1.29.2.2  skrll 	cmd_v1->notify = htole32(iwm_te_v2_get_notify(cmd_v2->policy));
   2322  1.29.2.2  skrll }
   2323  1.29.2.2  skrll 
   2324  1.29.2.2  skrll static int
   2325  1.29.2.2  skrll iwm_mvm_send_time_event_cmd(struct iwm_softc *sc,
   2326  1.29.2.2  skrll 	const struct iwm_time_event_cmd_v2 *cmd)
   2327  1.29.2.2  skrll {
   2328  1.29.2.2  skrll 	struct iwm_time_event_cmd_v1 cmd_v1;
   2329  1.29.2.2  skrll 
   2330  1.29.2.2  skrll 	if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_TIME_EVENT_API_V2)
   2331  1.29.2.2  skrll 		return iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD,
   2332  1.29.2.2  skrll 		    IWM_CMD_SYNC, sizeof(*cmd), cmd);
   2333  1.29.2.2  skrll 
   2334  1.29.2.2  skrll 	iwm_mvm_te_v2_to_v1(cmd, &cmd_v1);
   2335  1.29.2.2  skrll 	return iwm_mvm_send_cmd_pdu(sc, IWM_TIME_EVENT_CMD, IWM_CMD_SYNC,
   2336  1.29.2.2  skrll 	    sizeof(cmd_v1), &cmd_v1);
   2337  1.29.2.2  skrll }
   2338  1.29.2.2  skrll 
   2339  1.29.2.2  skrll static int
   2340  1.29.2.2  skrll iwm_mvm_time_event_send_add(struct iwm_softc *sc, struct iwm_node *in,
   2341  1.29.2.2  skrll 	void *te_data, struct iwm_time_event_cmd_v2 *te_cmd)
   2342  1.29.2.2  skrll {
   2343  1.29.2.2  skrll 	int ret;
   2344  1.29.2.2  skrll 
   2345  1.29.2.2  skrll 	DPRINTF(("Add new TE, duration %d TU\n", le32toh(te_cmd->duration)));
   2346  1.29.2.2  skrll 
   2347  1.29.2.2  skrll 	ret = iwm_mvm_send_time_event_cmd(sc, te_cmd);
   2348  1.29.2.2  skrll 	if (ret) {
   2349  1.29.2.2  skrll 		DPRINTF(("%s: Couldn't send IWM_TIME_EVENT_CMD: %d\n",
   2350  1.29.2.2  skrll 		    DEVNAME(sc), ret));
   2351  1.29.2.2  skrll 	}
   2352  1.29.2.2  skrll 
   2353  1.29.2.2  skrll 	return ret;
   2354  1.29.2.2  skrll }
   2355  1.29.2.2  skrll 
   2356  1.29.2.2  skrll static void
   2357  1.29.2.2  skrll iwm_mvm_protect_session(struct iwm_softc *sc, struct iwm_node *in,
   2358  1.29.2.2  skrll 	uint32_t duration, uint32_t min_duration, uint32_t max_delay)
   2359  1.29.2.2  skrll {
   2360  1.29.2.2  skrll 	struct iwm_time_event_cmd_v2 time_cmd;
   2361  1.29.2.2  skrll 
   2362  1.29.2.2  skrll 	memset(&time_cmd, 0, sizeof(time_cmd));
   2363  1.29.2.2  skrll 
   2364  1.29.2.2  skrll 	time_cmd.action = htole32(IWM_FW_CTXT_ACTION_ADD);
   2365  1.29.2.2  skrll 	time_cmd.id_and_color =
   2366  1.29.2.2  skrll 	    htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
   2367  1.29.2.2  skrll 	time_cmd.id = htole32(IWM_TE_BSS_STA_AGGRESSIVE_ASSOC);
   2368  1.29.2.2  skrll 
   2369  1.29.2.2  skrll 	time_cmd.apply_time = htole32(iwm_read_prph(sc,
   2370  1.29.2.2  skrll 	    IWM_DEVICE_SYSTEM_TIME_REG));
   2371  1.29.2.2  skrll 
   2372  1.29.2.2  skrll 	time_cmd.max_frags = IWM_TE_V2_FRAG_NONE;
   2373  1.29.2.2  skrll 	time_cmd.max_delay = htole32(max_delay);
   2374  1.29.2.2  skrll 	/* TODO: why do we need to interval = bi if it is not periodic? */
   2375  1.29.2.2  skrll 	time_cmd.interval = htole32(1);
   2376  1.29.2.2  skrll 	time_cmd.duration = htole32(duration);
   2377  1.29.2.2  skrll 	time_cmd.repeat = 1;
   2378  1.29.2.2  skrll 	time_cmd.policy
   2379  1.29.2.2  skrll 	    = htole32(IWM_TE_V2_NOTIF_HOST_EVENT_START |
   2380  1.29.2.2  skrll 	        IWM_TE_V2_NOTIF_HOST_EVENT_END);
   2381  1.29.2.2  skrll 
   2382  1.29.2.2  skrll 	iwm_mvm_time_event_send_add(sc, in, /*te_data*/NULL, &time_cmd);
   2383  1.29.2.2  skrll }
   2384  1.29.2.2  skrll 
   2385  1.29.2.2  skrll /*
   2386  1.29.2.2  skrll  * END iwlwifi/mvm/time-event.c
   2387  1.29.2.2  skrll  */
   2388  1.29.2.2  skrll 
   2389  1.29.2.2  skrll /*
   2390  1.29.2.2  skrll  * NVM read access and content parsing.  We do not support
   2391  1.29.2.2  skrll  * external NVM or writing NVM.
   2392  1.29.2.2  skrll  * iwlwifi/mvm/nvm.c
   2393  1.29.2.2  skrll  */
   2394  1.29.2.2  skrll 
   2395  1.29.2.2  skrll /* list of NVM sections we are allowed/need to read */
   2396  1.29.2.2  skrll static const int nvm_to_read[] = {
   2397  1.29.2.2  skrll 	IWM_NVM_SECTION_TYPE_HW,
   2398  1.29.2.2  skrll 	IWM_NVM_SECTION_TYPE_SW,
   2399  1.29.2.2  skrll 	IWM_NVM_SECTION_TYPE_CALIBRATION,
   2400  1.29.2.2  skrll 	IWM_NVM_SECTION_TYPE_PRODUCTION,
   2401  1.29.2.2  skrll };
   2402  1.29.2.2  skrll 
   2403  1.29.2.2  skrll /* Default NVM size to read */
   2404  1.29.2.2  skrll #define IWM_NVM_DEFAULT_CHUNK_SIZE (2*1024)
   2405  1.29.2.2  skrll #define IWM_MAX_NVM_SECTION_SIZE 7000
   2406  1.29.2.2  skrll 
   2407  1.29.2.2  skrll #define IWM_NVM_WRITE_OPCODE 1
   2408  1.29.2.2  skrll #define IWM_NVM_READ_OPCODE 0
   2409  1.29.2.2  skrll 
   2410  1.29.2.2  skrll static int
   2411  1.29.2.2  skrll iwm_nvm_read_chunk(struct iwm_softc *sc, uint16_t section,
   2412  1.29.2.2  skrll 	uint16_t offset, uint16_t length, uint8_t *data, uint16_t *len)
   2413  1.29.2.2  skrll {
   2414  1.29.2.2  skrll 	offset = 0;
   2415  1.29.2.2  skrll 	struct iwm_nvm_access_cmd nvm_access_cmd = {
   2416  1.29.2.2  skrll 		.offset = htole16(offset),
   2417  1.29.2.2  skrll 		.length = htole16(length),
   2418  1.29.2.2  skrll 		.type = htole16(section),
   2419  1.29.2.2  skrll 		.op_code = IWM_NVM_READ_OPCODE,
   2420  1.29.2.2  skrll 	};
   2421  1.29.2.2  skrll 	struct iwm_nvm_access_resp *nvm_resp;
   2422  1.29.2.2  skrll 	struct iwm_rx_packet *pkt;
   2423  1.29.2.2  skrll 	struct iwm_host_cmd cmd = {
   2424  1.29.2.2  skrll 		.id = IWM_NVM_ACCESS_CMD,
   2425  1.29.2.2  skrll 		.flags = IWM_CMD_SYNC | IWM_CMD_WANT_SKB |
   2426  1.29.2.2  skrll 		    IWM_CMD_SEND_IN_RFKILL,
   2427  1.29.2.2  skrll 		.data = { &nvm_access_cmd, },
   2428  1.29.2.2  skrll 	};
   2429  1.29.2.2  skrll 	int ret, bytes_read, offset_read;
   2430  1.29.2.2  skrll 	uint8_t *resp_data;
   2431  1.29.2.2  skrll 
   2432  1.29.2.2  skrll 	cmd.len[0] = sizeof(struct iwm_nvm_access_cmd);
   2433  1.29.2.2  skrll 
   2434  1.29.2.2  skrll 	ret = iwm_send_cmd(sc, &cmd);
   2435  1.29.2.2  skrll 	if (ret)
   2436  1.29.2.2  skrll 		return ret;
   2437  1.29.2.2  skrll 
   2438  1.29.2.2  skrll 	pkt = cmd.resp_pkt;
   2439  1.29.2.2  skrll 	if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) {
   2440  1.29.2.2  skrll 		DPRINTF(("%s: Bad return from IWM_NVM_ACCES_COMMAND (0x%08X)\n",
   2441  1.29.2.2  skrll 		    DEVNAME(sc), pkt->hdr.flags));
   2442  1.29.2.2  skrll 		ret = EIO;
   2443  1.29.2.2  skrll 		goto exit;
   2444  1.29.2.2  skrll 	}
   2445  1.29.2.2  skrll 
   2446  1.29.2.2  skrll 	/* Extract NVM response */
   2447  1.29.2.2  skrll 	nvm_resp = (void *)pkt->data;
   2448  1.29.2.2  skrll 
   2449  1.29.2.2  skrll 	ret = le16toh(nvm_resp->status);
   2450  1.29.2.2  skrll 	bytes_read = le16toh(nvm_resp->length);
   2451  1.29.2.2  skrll 	offset_read = le16toh(nvm_resp->offset);
   2452  1.29.2.2  skrll 	resp_data = nvm_resp->data;
   2453  1.29.2.2  skrll 	if (ret) {
   2454  1.29.2.2  skrll 		DPRINTF(("%s: NVM access command failed with status %d\n",
   2455  1.29.2.2  skrll 		    DEVNAME(sc), ret));
   2456  1.29.2.2  skrll 		ret = EINVAL;
   2457  1.29.2.2  skrll 		goto exit;
   2458  1.29.2.2  skrll 	}
   2459  1.29.2.2  skrll 
   2460  1.29.2.2  skrll 	if (offset_read != offset) {
   2461  1.29.2.2  skrll 		DPRINTF(("%s: NVM ACCESS response with invalid offset %d\n",
   2462  1.29.2.2  skrll 		    DEVNAME(sc), offset_read));
   2463  1.29.2.2  skrll 		ret = EINVAL;
   2464  1.29.2.2  skrll 		goto exit;
   2465  1.29.2.2  skrll 	}
   2466  1.29.2.2  skrll 
   2467  1.29.2.2  skrll 	memcpy(data + offset, resp_data, bytes_read);
   2468  1.29.2.2  skrll 	*len = bytes_read;
   2469  1.29.2.2  skrll 
   2470  1.29.2.2  skrll  exit:
   2471  1.29.2.2  skrll 	iwm_free_resp(sc, &cmd);
   2472  1.29.2.2  skrll 	return ret;
   2473  1.29.2.2  skrll }
   2474  1.29.2.2  skrll 
   2475  1.29.2.2  skrll /*
   2476  1.29.2.2  skrll  * Reads an NVM section completely.
   2477  1.29.2.2  skrll  * NICs prior to 7000 family doesn't have a real NVM, but just read
   2478  1.29.2.2  skrll  * section 0 which is the EEPROM. Because the EEPROM reading is unlimited
   2479  1.29.2.2  skrll  * by uCode, we need to manually check in this case that we don't
   2480  1.29.2.2  skrll  * overflow and try to read more than the EEPROM size.
   2481  1.29.2.2  skrll  * For 7000 family NICs, we supply the maximal size we can read, and
   2482  1.29.2.2  skrll  * the uCode fills the response with as much data as we can,
   2483  1.29.2.2  skrll  * without overflowing, so no check is needed.
   2484  1.29.2.2  skrll  */
   2485  1.29.2.2  skrll static int
   2486  1.29.2.2  skrll iwm_nvm_read_section(struct iwm_softc *sc,
   2487  1.29.2.2  skrll 	uint16_t section, uint8_t *data, uint16_t *len)
   2488  1.29.2.2  skrll {
   2489  1.29.2.2  skrll 	uint16_t length, seglen;
   2490  1.29.2.2  skrll 	int error;
   2491  1.29.2.2  skrll 
   2492  1.29.2.2  skrll 	/* Set nvm section read length */
   2493  1.29.2.2  skrll 	length = seglen = IWM_NVM_DEFAULT_CHUNK_SIZE;
   2494  1.29.2.2  skrll 	*len = 0;
   2495  1.29.2.2  skrll 
   2496  1.29.2.2  skrll 	/* Read the NVM until exhausted (reading less than requested) */
   2497  1.29.2.2  skrll 	while (seglen == length) {
   2498  1.29.2.2  skrll 		error = iwm_nvm_read_chunk(sc,
   2499  1.29.2.2  skrll 		    section, *len, length, data, &seglen);
   2500  1.29.2.2  skrll 		if (error) {
   2501  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   2502  1.29.2.2  skrll 			    "Cannot read NVM from section %d offset %d, "
   2503  1.29.2.2  skrll 			    "length %d\n", section, *len, length);
   2504  1.29.2.2  skrll 			return error;
   2505  1.29.2.2  skrll 		}
   2506  1.29.2.2  skrll 		*len += seglen;
   2507  1.29.2.2  skrll 	}
   2508  1.29.2.2  skrll 
   2509  1.29.2.2  skrll 	DPRINTFN(4, ("NVM section %d read completed\n", section));
   2510  1.29.2.2  skrll 	return 0;
   2511  1.29.2.2  skrll }
   2512  1.29.2.2  skrll 
   2513  1.29.2.2  skrll /*
   2514  1.29.2.2  skrll  * BEGIN IWM_NVM_PARSE
   2515  1.29.2.2  skrll  */
   2516  1.29.2.2  skrll 
   2517  1.29.2.2  skrll /* iwlwifi/iwl-nvm-parse.c */
   2518  1.29.2.2  skrll 
   2519  1.29.2.2  skrll /* NVM offsets (in words) definitions */
   2520  1.29.2.2  skrll enum wkp_nvm_offsets {
   2521  1.29.2.2  skrll 	/* NVM HW-Section offset (in words) definitions */
   2522  1.29.2.2  skrll 	IWM_HW_ADDR = 0x15,
   2523  1.29.2.2  skrll 
   2524  1.29.2.2  skrll /* NVM SW-Section offset (in words) definitions */
   2525  1.29.2.2  skrll 	IWM_NVM_SW_SECTION = 0x1C0,
   2526  1.29.2.2  skrll 	IWM_NVM_VERSION = 0,
   2527  1.29.2.2  skrll 	IWM_RADIO_CFG = 1,
   2528  1.29.2.2  skrll 	IWM_SKU = 2,
   2529  1.29.2.2  skrll 	IWM_N_HW_ADDRS = 3,
   2530  1.29.2.2  skrll 	IWM_NVM_CHANNELS = 0x1E0 - IWM_NVM_SW_SECTION,
   2531  1.29.2.2  skrll 
   2532  1.29.2.2  skrll /* NVM calibration section offset (in words) definitions */
   2533  1.29.2.2  skrll 	IWM_NVM_CALIB_SECTION = 0x2B8,
   2534  1.29.2.2  skrll 	IWM_XTAL_CALIB = 0x316 - IWM_NVM_CALIB_SECTION
   2535  1.29.2.2  skrll };
   2536  1.29.2.2  skrll 
   2537  1.29.2.2  skrll /* SKU Capabilities (actual values from NVM definition) */
   2538  1.29.2.2  skrll enum nvm_sku_bits {
   2539  1.29.2.2  skrll 	IWM_NVM_SKU_CAP_BAND_24GHZ	= (1 << 0),
   2540  1.29.2.2  skrll 	IWM_NVM_SKU_CAP_BAND_52GHZ	= (1 << 1),
   2541  1.29.2.2  skrll 	IWM_NVM_SKU_CAP_11N_ENABLE	= (1 << 2),
   2542  1.29.2.2  skrll 	IWM_NVM_SKU_CAP_11AC_ENABLE	= (1 << 3),
   2543  1.29.2.2  skrll };
   2544  1.29.2.2  skrll 
   2545  1.29.2.2  skrll /* radio config bits (actual values from NVM definition) */
   2546  1.29.2.2  skrll #define IWM_NVM_RF_CFG_DASH_MSK(x)   (x & 0x3)         /* bits 0-1   */
   2547  1.29.2.2  skrll #define IWM_NVM_RF_CFG_STEP_MSK(x)   ((x >> 2)  & 0x3) /* bits 2-3   */
   2548  1.29.2.2  skrll #define IWM_NVM_RF_CFG_TYPE_MSK(x)   ((x >> 4)  & 0x3) /* bits 4-5   */
   2549  1.29.2.2  skrll #define IWM_NVM_RF_CFG_PNUM_MSK(x)   ((x >> 6)  & 0x3) /* bits 6-7   */
   2550  1.29.2.2  skrll #define IWM_NVM_RF_CFG_TX_ANT_MSK(x) ((x >> 8)  & 0xF) /* bits 8-11  */
   2551  1.29.2.2  skrll #define IWM_NVM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */
   2552  1.29.2.2  skrll 
   2553  1.29.2.2  skrll #define DEFAULT_MAX_TX_POWER 16
   2554  1.29.2.2  skrll 
   2555  1.29.2.2  skrll /**
   2556  1.29.2.2  skrll  * enum iwm_nvm_channel_flags - channel flags in NVM
   2557  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_VALID: channel is usable for this SKU/geo
   2558  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_IBSS: usable as an IBSS channel
   2559  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_ACTIVE: active scanning allowed
   2560  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_RADAR: radar detection required
   2561  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_DFS: dynamic freq selection candidate
   2562  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_WIDE: 20 MHz channel okay (?)
   2563  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_40MHZ: 40 MHz channel okay (?)
   2564  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_80MHZ: 80 MHz channel okay (?)
   2565  1.29.2.2  skrll  * @IWM_NVM_CHANNEL_160MHZ: 160 MHz channel okay (?)
   2566  1.29.2.2  skrll  */
   2567  1.29.2.2  skrll enum iwm_nvm_channel_flags {
   2568  1.29.2.2  skrll 	IWM_NVM_CHANNEL_VALID = (1 << 0),
   2569  1.29.2.2  skrll 	IWM_NVM_CHANNEL_IBSS = (1 << 1),
   2570  1.29.2.2  skrll 	IWM_NVM_CHANNEL_ACTIVE = (1 << 3),
   2571  1.29.2.2  skrll 	IWM_NVM_CHANNEL_RADAR = (1 << 4),
   2572  1.29.2.2  skrll 	IWM_NVM_CHANNEL_DFS = (1 << 7),
   2573  1.29.2.2  skrll 	IWM_NVM_CHANNEL_WIDE = (1 << 8),
   2574  1.29.2.2  skrll 	IWM_NVM_CHANNEL_40MHZ = (1 << 9),
   2575  1.29.2.2  skrll 	IWM_NVM_CHANNEL_80MHZ = (1 << 10),
   2576  1.29.2.2  skrll 	IWM_NVM_CHANNEL_160MHZ = (1 << 11),
   2577  1.29.2.2  skrll };
   2578  1.29.2.2  skrll 
   2579  1.29.2.2  skrll static void
   2580  1.29.2.2  skrll iwm_init_channel_map(struct iwm_softc *sc, const uint16_t * const nvm_ch_flags)
   2581  1.29.2.2  skrll {
   2582  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   2583  1.29.2.2  skrll 	struct iwm_nvm_data *data = &sc->sc_nvm;
   2584  1.29.2.2  skrll 	int ch_idx;
   2585  1.29.2.2  skrll 	struct ieee80211_channel *channel;
   2586  1.29.2.2  skrll 	uint16_t ch_flags;
   2587  1.29.2.2  skrll 	int is_5ghz;
   2588  1.29.2.2  skrll 	int flags, hw_value;
   2589  1.29.2.2  skrll 
   2590  1.29.2.2  skrll 	for (ch_idx = 0; ch_idx < __arraycount(iwm_nvm_channels); ch_idx++) {
   2591  1.29.2.2  skrll 		ch_flags = le16_to_cpup(nvm_ch_flags + ch_idx);
   2592  1.29.2.2  skrll 
   2593  1.29.2.2  skrll 		if (ch_idx >= IWM_NUM_2GHZ_CHANNELS &&
   2594  1.29.2.2  skrll 		    !data->sku_cap_band_52GHz_enable)
   2595  1.29.2.2  skrll 			ch_flags &= ~IWM_NVM_CHANNEL_VALID;
   2596  1.29.2.2  skrll 
   2597  1.29.2.2  skrll 		if (!(ch_flags & IWM_NVM_CHANNEL_VALID)) {
   2598  1.29.2.2  skrll 			DPRINTF(("Ch. %d Flags %x [%sGHz] - No traffic\n",
   2599  1.29.2.2  skrll 			    iwm_nvm_channels[ch_idx],
   2600  1.29.2.2  skrll 			    ch_flags,
   2601  1.29.2.2  skrll 			    (ch_idx >= IWM_NUM_2GHZ_CHANNELS) ?
   2602  1.29.2.2  skrll 			    "5.2" : "2.4"));
   2603  1.29.2.2  skrll 			continue;
   2604  1.29.2.2  skrll 		}
   2605  1.29.2.2  skrll 
   2606  1.29.2.2  skrll 		hw_value = iwm_nvm_channels[ch_idx];
   2607  1.29.2.2  skrll 		channel = &ic->ic_channels[hw_value];
   2608  1.29.2.2  skrll 
   2609  1.29.2.2  skrll 		is_5ghz = ch_idx >= IWM_NUM_2GHZ_CHANNELS;
   2610  1.29.2.2  skrll 		if (!is_5ghz) {
   2611  1.29.2.2  skrll 			flags = IEEE80211_CHAN_2GHZ;
   2612  1.29.2.2  skrll 			channel->ic_flags
   2613  1.29.2.2  skrll 			    = IEEE80211_CHAN_CCK
   2614  1.29.2.2  skrll 			    | IEEE80211_CHAN_OFDM
   2615  1.29.2.2  skrll 			    | IEEE80211_CHAN_DYN
   2616  1.29.2.2  skrll 			    | IEEE80211_CHAN_2GHZ;
   2617  1.29.2.2  skrll 		} else {
   2618  1.29.2.2  skrll 			flags = IEEE80211_CHAN_5GHZ;
   2619  1.29.2.2  skrll 			channel->ic_flags =
   2620  1.29.2.2  skrll 			    IEEE80211_CHAN_A;
   2621  1.29.2.2  skrll 		}
   2622  1.29.2.2  skrll 		channel->ic_freq = ieee80211_ieee2mhz(hw_value, flags);
   2623  1.29.2.2  skrll 
   2624  1.29.2.2  skrll 		if (!(ch_flags & IWM_NVM_CHANNEL_ACTIVE))
   2625  1.29.2.2  skrll 			channel->ic_flags |= IEEE80211_CHAN_PASSIVE;
   2626  1.29.2.2  skrll 	}
   2627  1.29.2.2  skrll }
   2628  1.29.2.2  skrll 
   2629  1.29.2.2  skrll static int
   2630  1.29.2.2  skrll iwm_parse_nvm_data(struct iwm_softc *sc,
   2631  1.29.2.2  skrll 	const uint16_t *nvm_hw, const uint16_t *nvm_sw,
   2632  1.29.2.2  skrll 	const uint16_t *nvm_calib, uint8_t tx_chains, uint8_t rx_chains)
   2633  1.29.2.2  skrll {
   2634  1.29.2.2  skrll 	struct iwm_nvm_data *data = &sc->sc_nvm;
   2635  1.29.2.2  skrll 	uint8_t hw_addr[ETHER_ADDR_LEN];
   2636  1.29.2.2  skrll 	uint16_t radio_cfg, sku;
   2637  1.29.2.2  skrll 
   2638  1.29.2.2  skrll 	data->nvm_version = le16_to_cpup(nvm_sw + IWM_NVM_VERSION);
   2639  1.29.2.2  skrll 
   2640  1.29.2.2  skrll 	radio_cfg = le16_to_cpup(nvm_sw + IWM_RADIO_CFG);
   2641  1.29.2.2  skrll 	data->radio_cfg_type = IWM_NVM_RF_CFG_TYPE_MSK(radio_cfg);
   2642  1.29.2.2  skrll 	data->radio_cfg_step = IWM_NVM_RF_CFG_STEP_MSK(radio_cfg);
   2643  1.29.2.2  skrll 	data->radio_cfg_dash = IWM_NVM_RF_CFG_DASH_MSK(radio_cfg);
   2644  1.29.2.2  skrll 	data->radio_cfg_pnum = IWM_NVM_RF_CFG_PNUM_MSK(radio_cfg);
   2645  1.29.2.2  skrll 	data->valid_tx_ant = IWM_NVM_RF_CFG_TX_ANT_MSK(radio_cfg);
   2646  1.29.2.2  skrll 	data->valid_rx_ant = IWM_NVM_RF_CFG_RX_ANT_MSK(radio_cfg);
   2647  1.29.2.2  skrll 
   2648  1.29.2.2  skrll 	sku = le16_to_cpup(nvm_sw + IWM_SKU);
   2649  1.29.2.2  skrll 	data->sku_cap_band_24GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_24GHZ;
   2650  1.29.2.2  skrll 	data->sku_cap_band_52GHz_enable = sku & IWM_NVM_SKU_CAP_BAND_52GHZ;
   2651  1.29.2.2  skrll 	data->sku_cap_11n_enable = 0;
   2652  1.29.2.2  skrll 
   2653  1.29.2.2  skrll 	if (!data->valid_tx_ant || !data->valid_rx_ant) {
   2654  1.29.2.2  skrll 		DPRINTF(("%s: invalid antennas (0x%x, 0x%x)\n", DEVNAME(sc),
   2655  1.29.2.2  skrll 		    data->valid_tx_ant, data->valid_rx_ant));
   2656  1.29.2.2  skrll 		return EINVAL;
   2657  1.29.2.2  skrll 	}
   2658  1.29.2.2  skrll 
   2659  1.29.2.2  skrll 	data->n_hw_addrs = le16_to_cpup(nvm_sw + IWM_N_HW_ADDRS);
   2660  1.29.2.2  skrll 
   2661  1.29.2.2  skrll 	data->xtal_calib[0] = *(nvm_calib + IWM_XTAL_CALIB);
   2662  1.29.2.2  skrll 	data->xtal_calib[1] = *(nvm_calib + IWM_XTAL_CALIB + 1);
   2663  1.29.2.2  skrll 
   2664  1.29.2.2  skrll 	/* The byte order is little endian 16 bit, meaning 214365 */
   2665  1.29.2.2  skrll 	memcpy(hw_addr, nvm_hw + IWM_HW_ADDR, ETHER_ADDR_LEN);
   2666  1.29.2.2  skrll 	data->hw_addr[0] = hw_addr[1];
   2667  1.29.2.2  skrll 	data->hw_addr[1] = hw_addr[0];
   2668  1.29.2.2  skrll 	data->hw_addr[2] = hw_addr[3];
   2669  1.29.2.2  skrll 	data->hw_addr[3] = hw_addr[2];
   2670  1.29.2.2  skrll 	data->hw_addr[4] = hw_addr[5];
   2671  1.29.2.2  skrll 	data->hw_addr[5] = hw_addr[4];
   2672  1.29.2.2  skrll 
   2673  1.29.2.2  skrll 	iwm_init_channel_map(sc, &nvm_sw[IWM_NVM_CHANNELS]);
   2674  1.29.2.2  skrll 	data->calib_version = 255;   /* TODO:
   2675  1.29.2.2  skrll 					this value will prevent some checks from
   2676  1.29.2.2  skrll 					failing, we need to check if this
   2677  1.29.2.2  skrll 					field is still needed, and if it does,
   2678  1.29.2.2  skrll 					where is it in the NVM */
   2679  1.29.2.2  skrll 
   2680  1.29.2.2  skrll 	return 0;
   2681  1.29.2.2  skrll }
   2682  1.29.2.2  skrll 
   2683  1.29.2.2  skrll /*
   2684  1.29.2.2  skrll  * END NVM PARSE
   2685  1.29.2.2  skrll  */
   2686  1.29.2.2  skrll 
   2687  1.29.2.2  skrll struct iwm_nvm_section {
   2688  1.29.2.2  skrll 	uint16_t length;
   2689  1.29.2.2  skrll 	const uint8_t *data;
   2690  1.29.2.2  skrll };
   2691  1.29.2.2  skrll 
   2692  1.29.2.2  skrll #define IWM_FW_VALID_TX_ANT(sc) \
   2693  1.29.2.2  skrll     ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_TX_CHAIN) \
   2694  1.29.2.2  skrll     >> IWM_FW_PHY_CFG_TX_CHAIN_POS)
   2695  1.29.2.2  skrll #define IWM_FW_VALID_RX_ANT(sc) \
   2696  1.29.2.2  skrll     ((sc->sc_fw_phy_config & IWM_FW_PHY_CFG_RX_CHAIN) \
   2697  1.29.2.2  skrll     >> IWM_FW_PHY_CFG_RX_CHAIN_POS)
   2698  1.29.2.2  skrll 
   2699  1.29.2.2  skrll static int
   2700  1.29.2.2  skrll iwm_parse_nvm_sections(struct iwm_softc *sc, struct iwm_nvm_section *sections)
   2701  1.29.2.2  skrll {
   2702  1.29.2.2  skrll 	const uint16_t *hw, *sw, *calib;
   2703  1.29.2.2  skrll 
   2704  1.29.2.2  skrll 	/* Checking for required sections */
   2705  1.29.2.2  skrll 	if (!sections[IWM_NVM_SECTION_TYPE_SW].data ||
   2706  1.29.2.2  skrll 	    !sections[IWM_NVM_SECTION_TYPE_HW].data) {
   2707  1.29.2.2  skrll 		DPRINTF(("%s: Can't parse empty NVM sections\n", DEVNAME(sc)));
   2708  1.29.2.2  skrll 		return ENOENT;
   2709  1.29.2.2  skrll 	}
   2710  1.29.2.2  skrll 
   2711  1.29.2.2  skrll 	hw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_HW].data;
   2712  1.29.2.2  skrll 	sw = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_SW].data;
   2713  1.29.2.2  skrll 	calib = (const uint16_t *)sections[IWM_NVM_SECTION_TYPE_CALIBRATION].data;
   2714  1.29.2.2  skrll 	return iwm_parse_nvm_data(sc, hw, sw, calib,
   2715  1.29.2.2  skrll 	    IWM_FW_VALID_TX_ANT(sc), IWM_FW_VALID_RX_ANT(sc));
   2716  1.29.2.2  skrll }
   2717  1.29.2.2  skrll 
   2718  1.29.2.2  skrll static int
   2719  1.29.2.2  skrll iwm_nvm_init(struct iwm_softc *sc)
   2720  1.29.2.2  skrll {
   2721  1.29.2.2  skrll 	struct iwm_nvm_section nvm_sections[IWM_NVM_NUM_OF_SECTIONS];
   2722  1.29.2.2  skrll 	int i, section, error;
   2723  1.29.2.2  skrll 	uint16_t len;
   2724  1.29.2.2  skrll 	uint8_t *nvm_buffer, *temp;
   2725  1.29.2.2  skrll 
   2726  1.29.2.2  skrll 	/* Read From FW NVM */
   2727  1.29.2.2  skrll 	DPRINTF(("Read NVM\n"));
   2728  1.29.2.2  skrll 
   2729  1.29.2.2  skrll 	/* TODO: find correct NVM max size for a section */
   2730  1.29.2.2  skrll 	nvm_buffer = kmem_alloc(IWM_OTP_LOW_IMAGE_SIZE, KM_SLEEP);
   2731  1.29.2.2  skrll 	for (i = 0; i < __arraycount(nvm_to_read); i++) {
   2732  1.29.2.2  skrll 		section = nvm_to_read[i];
   2733  1.29.2.2  skrll 		KASSERT(section <= __arraycount(nvm_sections));
   2734  1.29.2.2  skrll 
   2735  1.29.2.2  skrll 		error = iwm_nvm_read_section(sc, section, nvm_buffer, &len);
   2736  1.29.2.2  skrll 		if (error)
   2737  1.29.2.2  skrll 			break;
   2738  1.29.2.2  skrll 
   2739  1.29.2.2  skrll 		temp = kmem_alloc(len, KM_SLEEP);
   2740  1.29.2.2  skrll 		memcpy(temp, nvm_buffer, len);
   2741  1.29.2.2  skrll 		nvm_sections[section].data = temp;
   2742  1.29.2.2  skrll 		nvm_sections[section].length = len;
   2743  1.29.2.2  skrll 	}
   2744  1.29.2.2  skrll 	kmem_free(nvm_buffer, IWM_OTP_LOW_IMAGE_SIZE);
   2745  1.29.2.2  skrll 	if (error)
   2746  1.29.2.2  skrll 		return error;
   2747  1.29.2.2  skrll 
   2748  1.29.2.2  skrll 	return iwm_parse_nvm_sections(sc, nvm_sections);
   2749  1.29.2.2  skrll }
   2750  1.29.2.2  skrll 
   2751  1.29.2.2  skrll /*
   2752  1.29.2.2  skrll  * Firmware loading gunk.  This is kind of a weird hybrid between the
   2753  1.29.2.2  skrll  * iwn driver and the Linux iwlwifi driver.
   2754  1.29.2.2  skrll  */
   2755  1.29.2.2  skrll 
   2756  1.29.2.2  skrll static int
   2757  1.29.2.2  skrll iwm_firmware_load_chunk(struct iwm_softc *sc, uint32_t dst_addr,
   2758  1.29.2.2  skrll 	const uint8_t *section, uint32_t byte_cnt)
   2759  1.29.2.2  skrll {
   2760  1.29.2.2  skrll 	struct iwm_dma_info *dma = &sc->fw_dma;
   2761  1.29.2.2  skrll 	int error;
   2762  1.29.2.2  skrll 
   2763  1.29.2.2  skrll 	/* Copy firmware section into pre-allocated DMA-safe memory. */
   2764  1.29.2.2  skrll 	memcpy(dma->vaddr, section, byte_cnt);
   2765  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat,
   2766  1.29.2.2  skrll 	    dma->map, 0, byte_cnt, BUS_DMASYNC_PREWRITE);
   2767  1.29.2.2  skrll 
   2768  1.29.2.2  skrll 	if (!iwm_nic_lock(sc))
   2769  1.29.2.2  skrll 		return EBUSY;
   2770  1.29.2.2  skrll 
   2771  1.29.2.2  skrll 	sc->sc_fw_chunk_done = 0;
   2772  1.29.2.2  skrll 
   2773  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL),
   2774  1.29.2.2  skrll 	    IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
   2775  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_SRVC_CHNL_SRAM_ADDR_REG(IWM_FH_SRVC_CHNL),
   2776  1.29.2.2  skrll 	    dst_addr);
   2777  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_TFDIB_CTRL0_REG(IWM_FH_SRVC_CHNL),
   2778  1.29.2.2  skrll 	    dma->paddr & IWM_FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
   2779  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_TFDIB_CTRL1_REG(IWM_FH_SRVC_CHNL),
   2780  1.29.2.2  skrll 	    (iwm_get_dma_hi_addr(dma->paddr)
   2781  1.29.2.2  skrll 	      << IWM_FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
   2782  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_BUF_STS_REG(IWM_FH_SRVC_CHNL),
   2783  1.29.2.2  skrll 	    1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
   2784  1.29.2.2  skrll 	    1 << IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
   2785  1.29.2.2  skrll 	    IWM_FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
   2786  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(IWM_FH_SRVC_CHNL),
   2787  1.29.2.2  skrll 	    IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE    |
   2788  1.29.2.2  skrll 	    IWM_FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
   2789  1.29.2.2  skrll 	    IWM_FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
   2790  1.29.2.2  skrll 
   2791  1.29.2.2  skrll 	iwm_nic_unlock(sc);
   2792  1.29.2.2  skrll 
   2793  1.29.2.2  skrll 	/* wait 1s for this segment to load */
   2794  1.29.2.2  skrll 	while (!sc->sc_fw_chunk_done)
   2795  1.29.2.2  skrll 		if ((error = tsleep(&sc->sc_fw, 0, "iwmfw", hz)) != 0)
   2796  1.29.2.2  skrll 			break;
   2797  1.29.2.2  skrll 
   2798  1.29.2.2  skrll 	return error;
   2799  1.29.2.2  skrll }
   2800  1.29.2.2  skrll 
   2801  1.29.2.2  skrll static int
   2802  1.29.2.2  skrll iwm_load_firmware(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
   2803  1.29.2.2  skrll {
   2804  1.29.2.2  skrll 	struct iwm_fw_sects *fws;
   2805  1.29.2.2  skrll 	int error, i, w;
   2806  1.29.2.2  skrll 	void *data;
   2807  1.29.2.2  skrll 	uint32_t dlen;
   2808  1.29.2.2  skrll 	uint32_t offset;
   2809  1.29.2.2  skrll 
   2810  1.29.2.2  skrll 	sc->sc_uc.uc_intr = 0;
   2811  1.29.2.2  skrll 
   2812  1.29.2.2  skrll 	fws = &sc->sc_fw.fw_sects[ucode_type];
   2813  1.29.2.2  skrll 	for (i = 0; i < fws->fw_count; i++) {
   2814  1.29.2.2  skrll 		data = fws->fw_sect[i].fws_data;
   2815  1.29.2.2  skrll 		dlen = fws->fw_sect[i].fws_len;
   2816  1.29.2.2  skrll 		offset = fws->fw_sect[i].fws_devoff;
   2817  1.29.2.2  skrll 		DPRINTF(("LOAD FIRMWARE type %d offset %u len %d\n",
   2818  1.29.2.2  skrll 		    ucode_type, offset, dlen));
   2819  1.29.2.2  skrll 		error = iwm_firmware_load_chunk(sc, offset, data, dlen);
   2820  1.29.2.2  skrll 		if (error) {
   2821  1.29.2.2  skrll 			DPRINTF(("iwm_firmware_load_chunk() chunk %u of %u "
   2822  1.29.2.2  skrll 			    "returned error %02d\n", i, fws->fw_count, error));
   2823  1.29.2.2  skrll 			return error;
   2824  1.29.2.2  skrll 		}
   2825  1.29.2.2  skrll 	}
   2826  1.29.2.2  skrll 
   2827  1.29.2.2  skrll 	/* wait for the firmware to load */
   2828  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_RESET, 0);
   2829  1.29.2.2  skrll 
   2830  1.29.2.2  skrll 	for (w = 0; !sc->sc_uc.uc_intr && w < 10; w++) {
   2831  1.29.2.2  skrll 		error = tsleep(&sc->sc_uc, 0, "iwmuc", hz/10);
   2832  1.29.2.2  skrll 	}
   2833  1.29.2.2  skrll 
   2834  1.29.2.2  skrll 	return error;
   2835  1.29.2.2  skrll }
   2836  1.29.2.2  skrll 
   2837  1.29.2.2  skrll /* iwlwifi: pcie/trans.c */
   2838  1.29.2.2  skrll static int
   2839  1.29.2.2  skrll iwm_start_fw(struct iwm_softc *sc, enum iwm_ucode_type ucode_type)
   2840  1.29.2.2  skrll {
   2841  1.29.2.2  skrll 	int error;
   2842  1.29.2.2  skrll 
   2843  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT, ~0);
   2844  1.29.2.2  skrll 
   2845  1.29.2.2  skrll 	if ((error = iwm_nic_init(sc)) != 0) {
   2846  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "Unable to init nic\n");
   2847  1.29.2.2  skrll 		return error;
   2848  1.29.2.2  skrll 	}
   2849  1.29.2.2  skrll 
   2850  1.29.2.2  skrll 	/* make sure rfkill handshake bits are cleared */
   2851  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL);
   2852  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR,
   2853  1.29.2.2  skrll 	    IWM_CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
   2854  1.29.2.2  skrll 
   2855  1.29.2.2  skrll 	/* clear (again), then enable host interrupts */
   2856  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT, ~0);
   2857  1.29.2.2  skrll 	iwm_enable_interrupts(sc);
   2858  1.29.2.2  skrll 
   2859  1.29.2.2  skrll 	/* really make sure rfkill handshake bits are cleared */
   2860  1.29.2.2  skrll 	/* maybe we should write a few times more?  just to make sure */
   2861  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL);
   2862  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_UCODE_DRV_GP1_CLR, IWM_CSR_UCODE_SW_BIT_RFKILL);
   2863  1.29.2.2  skrll 
   2864  1.29.2.2  skrll 	/* Load the given image to the HW */
   2865  1.29.2.2  skrll 	error = iwm_load_firmware(sc, ucode_type);
   2866  1.29.2.2  skrll 	if (error) {
   2867  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "failed to load firmware: %d\n",
   2868  1.29.2.2  skrll 		    error);
   2869  1.29.2.2  skrll 	}
   2870  1.29.2.2  skrll 	return error;
   2871  1.29.2.2  skrll }
   2872  1.29.2.2  skrll 
   2873  1.29.2.2  skrll static int
   2874  1.29.2.2  skrll iwm_fw_alive(struct iwm_softc *sc, uint32_t sched_base)
   2875  1.29.2.2  skrll {
   2876  1.29.2.2  skrll 	return iwm_post_alive(sc);
   2877  1.29.2.2  skrll }
   2878  1.29.2.2  skrll 
   2879  1.29.2.2  skrll static int
   2880  1.29.2.2  skrll iwm_send_tx_ant_cfg(struct iwm_softc *sc, uint8_t valid_tx_ant)
   2881  1.29.2.2  skrll {
   2882  1.29.2.2  skrll 	struct iwm_tx_ant_cfg_cmd tx_ant_cmd = {
   2883  1.29.2.2  skrll 		.valid = htole32(valid_tx_ant),
   2884  1.29.2.2  skrll 	};
   2885  1.29.2.2  skrll 
   2886  1.29.2.2  skrll 	return iwm_mvm_send_cmd_pdu(sc, IWM_TX_ANT_CONFIGURATION_CMD,
   2887  1.29.2.2  skrll 	    IWM_CMD_SYNC, sizeof(tx_ant_cmd), &tx_ant_cmd);
   2888  1.29.2.2  skrll }
   2889  1.29.2.2  skrll 
   2890  1.29.2.2  skrll /* iwlwifi: mvm/fw.c */
   2891  1.29.2.2  skrll static int
   2892  1.29.2.2  skrll iwm_send_phy_cfg_cmd(struct iwm_softc *sc)
   2893  1.29.2.2  skrll {
   2894  1.29.2.2  skrll 	struct iwm_phy_cfg_cmd phy_cfg_cmd;
   2895  1.29.2.2  skrll 	enum iwm_ucode_type ucode_type = sc->sc_uc_current;
   2896  1.29.2.2  skrll 
   2897  1.29.2.2  skrll 	/* Set parameters */
   2898  1.29.2.2  skrll 	phy_cfg_cmd.phy_cfg = htole32(sc->sc_fw_phy_config);
   2899  1.29.2.2  skrll 	phy_cfg_cmd.calib_control.event_trigger =
   2900  1.29.2.2  skrll 	    sc->sc_default_calib[ucode_type].event_trigger;
   2901  1.29.2.2  skrll 	phy_cfg_cmd.calib_control.flow_trigger =
   2902  1.29.2.2  skrll 	    sc->sc_default_calib[ucode_type].flow_trigger;
   2903  1.29.2.2  skrll 
   2904  1.29.2.2  skrll 	DPRINTFN(10, ("Sending Phy CFG command: 0x%x\n", phy_cfg_cmd.phy_cfg));
   2905  1.29.2.2  skrll 	return iwm_mvm_send_cmd_pdu(sc, IWM_PHY_CONFIGURATION_CMD, IWM_CMD_SYNC,
   2906  1.29.2.2  skrll 	    sizeof(phy_cfg_cmd), &phy_cfg_cmd);
   2907  1.29.2.2  skrll }
   2908  1.29.2.2  skrll 
   2909  1.29.2.2  skrll static int
   2910  1.29.2.2  skrll iwm_mvm_load_ucode_wait_alive(struct iwm_softc *sc,
   2911  1.29.2.2  skrll 	enum iwm_ucode_type ucode_type)
   2912  1.29.2.2  skrll {
   2913  1.29.2.2  skrll 	enum iwm_ucode_type old_type = sc->sc_uc_current;
   2914  1.29.2.2  skrll 	int error;
   2915  1.29.2.2  skrll 
   2916  1.29.2.2  skrll 	if ((error = iwm_read_firmware(sc)) != 0)
   2917  1.29.2.2  skrll 		return error;
   2918  1.29.2.2  skrll 
   2919  1.29.2.2  skrll 	sc->sc_uc_current = ucode_type;
   2920  1.29.2.2  skrll 	error = iwm_start_fw(sc, ucode_type);
   2921  1.29.2.2  skrll 	if (error) {
   2922  1.29.2.2  skrll 		sc->sc_uc_current = old_type;
   2923  1.29.2.2  skrll 		return error;
   2924  1.29.2.2  skrll 	}
   2925  1.29.2.2  skrll 
   2926  1.29.2.2  skrll 	return iwm_fw_alive(sc, sc->sched_base);
   2927  1.29.2.2  skrll }
   2928  1.29.2.2  skrll 
   2929  1.29.2.2  skrll /*
   2930  1.29.2.2  skrll  * mvm misc bits
   2931  1.29.2.2  skrll  */
   2932  1.29.2.2  skrll 
   2933  1.29.2.2  skrll /*
   2934  1.29.2.2  skrll  * follows iwlwifi/fw.c
   2935  1.29.2.2  skrll  */
   2936  1.29.2.2  skrll static int
   2937  1.29.2.2  skrll iwm_run_init_mvm_ucode(struct iwm_softc *sc, int justnvm)
   2938  1.29.2.2  skrll {
   2939  1.29.2.2  skrll 	int error;
   2940  1.29.2.2  skrll 
   2941  1.29.2.2  skrll 	/* do not operate with rfkill switch turned on */
   2942  1.29.2.2  skrll 	if ((sc->sc_flags & IWM_FLAG_RFKILL) && !justnvm) {
   2943  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   2944  1.29.2.2  skrll 		    "radio is disabled by hardware switch\n");
   2945  1.29.2.2  skrll 		return EPERM;
   2946  1.29.2.2  skrll 	}
   2947  1.29.2.2  skrll 
   2948  1.29.2.2  skrll 	sc->sc_init_complete = 0;
   2949  1.29.2.2  skrll 	if ((error = iwm_mvm_load_ucode_wait_alive(sc,
   2950  1.29.2.2  skrll 	    IWM_UCODE_TYPE_INIT)) != 0)
   2951  1.29.2.2  skrll 		return error;
   2952  1.29.2.2  skrll 
   2953  1.29.2.2  skrll 	if (justnvm) {
   2954  1.29.2.2  skrll 		if ((error = iwm_nvm_init(sc)) != 0) {
   2955  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev, "failed to read nvm\n");
   2956  1.29.2.2  skrll 			return error;
   2957  1.29.2.2  skrll 		}
   2958  1.29.2.2  skrll 		memcpy(&sc->sc_ic.ic_myaddr,
   2959  1.29.2.2  skrll 		    &sc->sc_nvm.hw_addr, ETHER_ADDR_LEN);
   2960  1.29.2.2  skrll 
   2961  1.29.2.2  skrll 		sc->sc_scan_cmd_len = sizeof(struct iwm_scan_cmd)
   2962  1.29.2.2  skrll 		    + sc->sc_capa_max_probe_len
   2963  1.29.2.2  skrll 		    + IWM_MAX_NUM_SCAN_CHANNELS
   2964  1.29.2.2  skrll 		    * sizeof(struct iwm_scan_channel);
   2965  1.29.2.2  skrll 		sc->sc_scan_cmd = kmem_alloc(sc->sc_scan_cmd_len, KM_SLEEP);
   2966  1.29.2.2  skrll 
   2967  1.29.2.2  skrll 		return 0;
   2968  1.29.2.2  skrll 	}
   2969  1.29.2.2  skrll 
   2970  1.29.2.2  skrll 	/* Send TX valid antennas before triggering calibrations */
   2971  1.29.2.2  skrll 	if ((error = iwm_send_tx_ant_cfg(sc, IWM_FW_VALID_TX_ANT(sc))) != 0)
   2972  1.29.2.2  skrll 		return error;
   2973  1.29.2.2  skrll 
   2974  1.29.2.2  skrll 	/*
   2975  1.29.2.2  skrll 	* Send phy configurations command to init uCode
   2976  1.29.2.2  skrll 	* to start the 16.0 uCode init image internal calibrations.
   2977  1.29.2.2  skrll 	*/
   2978  1.29.2.2  skrll 	if ((error = iwm_send_phy_cfg_cmd(sc)) != 0 ) {
   2979  1.29.2.2  skrll 		DPRINTF(("%s: failed to run internal calibration: %d\n",
   2980  1.29.2.2  skrll 		    DEVNAME(sc), error));
   2981  1.29.2.2  skrll 		return error;
   2982  1.29.2.2  skrll 	}
   2983  1.29.2.2  skrll 
   2984  1.29.2.2  skrll 	/*
   2985  1.29.2.2  skrll 	 * Nothing to do but wait for the init complete notification
   2986  1.29.2.2  skrll 	 * from the firmware
   2987  1.29.2.2  skrll 	 */
   2988  1.29.2.2  skrll 	while (!sc->sc_init_complete)
   2989  1.29.2.2  skrll 		if ((error = tsleep(&sc->sc_init_complete,
   2990  1.29.2.2  skrll 		    0, "iwminit", 2*hz)) != 0)
   2991  1.29.2.2  skrll 			break;
   2992  1.29.2.2  skrll 
   2993  1.29.2.2  skrll 	return error;
   2994  1.29.2.2  skrll }
   2995  1.29.2.2  skrll 
   2996  1.29.2.2  skrll /*
   2997  1.29.2.2  skrll  * receive side
   2998  1.29.2.2  skrll  */
   2999  1.29.2.2  skrll 
   3000  1.29.2.2  skrll /* (re)stock rx ring, called at init-time and at runtime */
   3001  1.29.2.2  skrll static int
   3002  1.29.2.2  skrll iwm_rx_addbuf(struct iwm_softc *sc, int size, int idx)
   3003  1.29.2.2  skrll {
   3004  1.29.2.2  skrll 	struct iwm_rx_ring *ring = &sc->rxq;
   3005  1.29.2.2  skrll 	struct iwm_rx_data *data = &ring->data[idx];
   3006  1.29.2.2  skrll 	struct mbuf *m;
   3007  1.29.2.2  skrll 	int error;
   3008  1.29.2.2  skrll 	int fatal = 0;
   3009  1.29.2.2  skrll 
   3010  1.29.2.2  skrll 	m = m_gethdr(M_DONTWAIT, MT_DATA);
   3011  1.29.2.2  skrll 	if (m == NULL)
   3012  1.29.2.2  skrll 		return ENOBUFS;
   3013  1.29.2.2  skrll 
   3014  1.29.2.2  skrll 	if (size <= MCLBYTES) {
   3015  1.29.2.2  skrll 		MCLGET(m, M_DONTWAIT);
   3016  1.29.2.2  skrll 	} else {
   3017  1.29.2.2  skrll 		MEXTMALLOC(m, IWM_RBUF_SIZE, M_DONTWAIT);
   3018  1.29.2.2  skrll 	}
   3019  1.29.2.2  skrll 	if ((m->m_flags & M_EXT) == 0) {
   3020  1.29.2.2  skrll 		m_freem(m);
   3021  1.29.2.2  skrll 		return ENOBUFS;
   3022  1.29.2.2  skrll 	}
   3023  1.29.2.2  skrll 
   3024  1.29.2.2  skrll 	if (data->m != NULL) {
   3025  1.29.2.2  skrll 		bus_dmamap_unload(sc->sc_dmat, data->map);
   3026  1.29.2.2  skrll 		fatal = 1;
   3027  1.29.2.2  skrll 	}
   3028  1.29.2.2  skrll 
   3029  1.29.2.2  skrll 	m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
   3030  1.29.2.2  skrll 	if ((error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
   3031  1.29.2.2  skrll 	    BUS_DMA_READ|BUS_DMA_NOWAIT)) != 0) {
   3032  1.29.2.2  skrll 		/* XXX */
   3033  1.29.2.2  skrll 		if (fatal)
   3034  1.29.2.2  skrll 			panic("iwm: could not load RX mbuf");
   3035  1.29.2.2  skrll 		m_freem(m);
   3036  1.29.2.2  skrll 		return error;
   3037  1.29.2.2  skrll 	}
   3038  1.29.2.2  skrll 	data->m = m;
   3039  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, 0, size, BUS_DMASYNC_PREREAD);
   3040  1.29.2.2  skrll 
   3041  1.29.2.2  skrll 	/* Update RX descriptor. */
   3042  1.29.2.2  skrll 	ring->desc[idx] = htole32(data->map->dm_segs[0].ds_addr >> 8);
   3043  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
   3044  1.29.2.2  skrll 	    idx * sizeof(uint32_t), sizeof(uint32_t), BUS_DMASYNC_PREWRITE);
   3045  1.29.2.2  skrll 
   3046  1.29.2.2  skrll 	return 0;
   3047  1.29.2.2  skrll }
   3048  1.29.2.2  skrll 
   3049  1.29.2.2  skrll /* iwlwifi: mvm/rx.c */
   3050  1.29.2.2  skrll #define IWM_RSSI_OFFSET 50
   3051  1.29.2.2  skrll static int
   3052  1.29.2.2  skrll iwm_mvm_calc_rssi(struct iwm_softc *sc, struct iwm_rx_phy_info *phy_info)
   3053  1.29.2.2  skrll {
   3054  1.29.2.2  skrll 	int rssi_a, rssi_b, rssi_a_dbm, rssi_b_dbm, max_rssi_dbm;
   3055  1.29.2.2  skrll 	uint32_t agc_a, agc_b;
   3056  1.29.2.2  skrll 	uint32_t val;
   3057  1.29.2.2  skrll 
   3058  1.29.2.2  skrll 	val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_AGC_IDX]);
   3059  1.29.2.2  skrll 	agc_a = (val & IWM_OFDM_AGC_A_MSK) >> IWM_OFDM_AGC_A_POS;
   3060  1.29.2.2  skrll 	agc_b = (val & IWM_OFDM_AGC_B_MSK) >> IWM_OFDM_AGC_B_POS;
   3061  1.29.2.2  skrll 
   3062  1.29.2.2  skrll 	val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_RSSI_AB_IDX]);
   3063  1.29.2.2  skrll 	rssi_a = (val & IWM_OFDM_RSSI_INBAND_A_MSK) >> IWM_OFDM_RSSI_A_POS;
   3064  1.29.2.2  skrll 	rssi_b = (val & IWM_OFDM_RSSI_INBAND_B_MSK) >> IWM_OFDM_RSSI_B_POS;
   3065  1.29.2.2  skrll 
   3066  1.29.2.2  skrll 	/*
   3067  1.29.2.2  skrll 	 * dBm = rssi dB - agc dB - constant.
   3068  1.29.2.2  skrll 	 * Higher AGC (higher radio gain) means lower signal.
   3069  1.29.2.2  skrll 	 */
   3070  1.29.2.2  skrll 	rssi_a_dbm = rssi_a - IWM_RSSI_OFFSET - agc_a;
   3071  1.29.2.2  skrll 	rssi_b_dbm = rssi_b - IWM_RSSI_OFFSET - agc_b;
   3072  1.29.2.2  skrll 	max_rssi_dbm = MAX(rssi_a_dbm, rssi_b_dbm);
   3073  1.29.2.2  skrll 
   3074  1.29.2.2  skrll 	DPRINTF(("Rssi In A %d B %d Max %d AGCA %d AGCB %d\n",
   3075  1.29.2.2  skrll 	    rssi_a_dbm, rssi_b_dbm, max_rssi_dbm, agc_a, agc_b));
   3076  1.29.2.2  skrll 
   3077  1.29.2.2  skrll 	return max_rssi_dbm;
   3078  1.29.2.2  skrll }
   3079  1.29.2.2  skrll 
   3080  1.29.2.2  skrll /* iwlwifi: mvm/rx.c */
   3081  1.29.2.2  skrll /*
   3082  1.29.2.2  skrll  * iwm_mvm_get_signal_strength - use new rx PHY INFO API
   3083  1.29.2.2  skrll  * values are reported by the fw as positive values - need to negate
   3084  1.29.2.2  skrll  * to obtain their dBM.  Account for missing antennas by replacing 0
   3085  1.29.2.2  skrll  * values by -256dBm: practically 0 power and a non-feasible 8 bit value.
   3086  1.29.2.2  skrll  */
   3087  1.29.2.2  skrll static int
   3088  1.29.2.2  skrll iwm_mvm_get_signal_strength(struct iwm_softc *sc,
   3089  1.29.2.2  skrll     struct iwm_rx_phy_info *phy_info)
   3090  1.29.2.2  skrll {
   3091  1.29.2.2  skrll 	int energy_a, energy_b, energy_c, max_energy;
   3092  1.29.2.2  skrll 	uint32_t val;
   3093  1.29.2.2  skrll 
   3094  1.29.2.2  skrll 	val = le32toh(phy_info->non_cfg_phy[IWM_RX_INFO_ENERGY_ANT_ABC_IDX]);
   3095  1.29.2.2  skrll 	energy_a = (val & IWM_RX_INFO_ENERGY_ANT_A_MSK) >>
   3096  1.29.2.2  skrll 	    IWM_RX_INFO_ENERGY_ANT_A_POS;
   3097  1.29.2.2  skrll 	energy_a = energy_a ? -energy_a : -256;
   3098  1.29.2.2  skrll 	energy_b = (val & IWM_RX_INFO_ENERGY_ANT_B_MSK) >>
   3099  1.29.2.2  skrll 	    IWM_RX_INFO_ENERGY_ANT_B_POS;
   3100  1.29.2.2  skrll 	energy_b = energy_b ? -energy_b : -256;
   3101  1.29.2.2  skrll 	energy_c = (val & IWM_RX_INFO_ENERGY_ANT_C_MSK) >>
   3102  1.29.2.2  skrll 	    IWM_RX_INFO_ENERGY_ANT_C_POS;
   3103  1.29.2.2  skrll 	energy_c = energy_c ? -energy_c : -256;
   3104  1.29.2.2  skrll 	max_energy = MAX(energy_a, energy_b);
   3105  1.29.2.2  skrll 	max_energy = MAX(max_energy, energy_c);
   3106  1.29.2.2  skrll 
   3107  1.29.2.2  skrll 	DPRINTFN(12, ("energy In A %d B %d C %d, and max %d\n",
   3108  1.29.2.2  skrll 	    energy_a, energy_b, energy_c, max_energy));
   3109  1.29.2.2  skrll 
   3110  1.29.2.2  skrll 	return max_energy;
   3111  1.29.2.2  skrll }
   3112  1.29.2.2  skrll 
   3113  1.29.2.2  skrll static void
   3114  1.29.2.2  skrll iwm_mvm_rx_rx_phy_cmd(struct iwm_softc *sc,
   3115  1.29.2.2  skrll 	struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
   3116  1.29.2.2  skrll {
   3117  1.29.2.2  skrll 	struct iwm_rx_phy_info *phy_info = (void *)pkt->data;
   3118  1.29.2.2  skrll 
   3119  1.29.2.2  skrll 	DPRINTFN(20, ("received PHY stats\n"));
   3120  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*pkt),
   3121  1.29.2.2  skrll 	    sizeof(*phy_info), BUS_DMASYNC_POSTREAD);
   3122  1.29.2.2  skrll 
   3123  1.29.2.2  skrll 	memcpy(&sc->sc_last_phy_info, phy_info, sizeof(sc->sc_last_phy_info));
   3124  1.29.2.2  skrll }
   3125  1.29.2.2  skrll 
   3126  1.29.2.2  skrll /*
   3127  1.29.2.2  skrll  * Retrieve the average noise (in dBm) among receivers.
   3128  1.29.2.2  skrll  */
   3129  1.29.2.2  skrll static int
   3130  1.29.2.2  skrll iwm_get_noise(const struct iwm_mvm_statistics_rx_non_phy *stats)
   3131  1.29.2.2  skrll {
   3132  1.29.2.2  skrll 	int i, total, nbant, noise;
   3133  1.29.2.2  skrll 
   3134  1.29.2.2  skrll 	total = nbant = noise = 0;
   3135  1.29.2.2  skrll 	for (i = 0; i < 3; i++) {
   3136  1.29.2.2  skrll 		noise = le32toh(stats->beacon_silence_rssi[i]) & 0xff;
   3137  1.29.2.2  skrll 		if (noise) {
   3138  1.29.2.2  skrll 			total += noise;
   3139  1.29.2.2  skrll 			nbant++;
   3140  1.29.2.2  skrll 		}
   3141  1.29.2.2  skrll 	}
   3142  1.29.2.2  skrll 
   3143  1.29.2.2  skrll 	/* There should be at least one antenna but check anyway. */
   3144  1.29.2.2  skrll 	return (nbant == 0) ? -127 : (total / nbant) - 107;
   3145  1.29.2.2  skrll }
   3146  1.29.2.2  skrll 
   3147  1.29.2.2  skrll /*
   3148  1.29.2.2  skrll  * iwm_mvm_rx_rx_mpdu - IWM_REPLY_RX_MPDU_CMD handler
   3149  1.29.2.2  skrll  *
   3150  1.29.2.2  skrll  * Handles the actual data of the Rx packet from the fw
   3151  1.29.2.2  skrll  */
   3152  1.29.2.2  skrll static void
   3153  1.29.2.2  skrll iwm_mvm_rx_rx_mpdu(struct iwm_softc *sc,
   3154  1.29.2.2  skrll 	struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
   3155  1.29.2.2  skrll {
   3156  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   3157  1.29.2.2  skrll 	struct ieee80211_frame *wh;
   3158  1.29.2.2  skrll 	struct ieee80211_node *ni;
   3159  1.29.2.2  skrll 	struct ieee80211_channel *c = NULL;
   3160  1.29.2.2  skrll 	struct mbuf *m;
   3161  1.29.2.2  skrll 	struct iwm_rx_phy_info *phy_info;
   3162  1.29.2.2  skrll 	struct iwm_rx_mpdu_res_start *rx_res;
   3163  1.29.2.2  skrll 	int device_timestamp;
   3164  1.29.2.2  skrll 	uint32_t len;
   3165  1.29.2.2  skrll 	uint32_t rx_pkt_status;
   3166  1.29.2.2  skrll 	int rssi;
   3167  1.29.2.2  skrll 
   3168  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
   3169  1.29.2.2  skrll 	    BUS_DMASYNC_POSTREAD);
   3170  1.29.2.2  skrll 
   3171  1.29.2.2  skrll 	phy_info = &sc->sc_last_phy_info;
   3172  1.29.2.2  skrll 	rx_res = (struct iwm_rx_mpdu_res_start *)pkt->data;
   3173  1.29.2.2  skrll 	wh = (struct ieee80211_frame *)(pkt->data + sizeof(*rx_res));
   3174  1.29.2.2  skrll 	len = le16toh(rx_res->byte_count);
   3175  1.29.2.2  skrll 	rx_pkt_status = le32toh(*(uint32_t *)(pkt->data + sizeof(*rx_res) + len));
   3176  1.29.2.2  skrll 
   3177  1.29.2.2  skrll 	m = data->m;
   3178  1.29.2.2  skrll 	m->m_data = pkt->data + sizeof(*rx_res);
   3179  1.29.2.2  skrll 	m->m_pkthdr.len = m->m_len = len;
   3180  1.29.2.2  skrll 
   3181  1.29.2.2  skrll 	if (__predict_false(phy_info->cfg_phy_cnt > 20)) {
   3182  1.29.2.2  skrll 		DPRINTF(("dsp size out of range [0,20]: %d\n",
   3183  1.29.2.2  skrll 		    phy_info->cfg_phy_cnt));
   3184  1.29.2.2  skrll 		return;
   3185  1.29.2.2  skrll 	}
   3186  1.29.2.2  skrll 
   3187  1.29.2.2  skrll 	if (!(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_CRC_OK) ||
   3188  1.29.2.2  skrll 	    !(rx_pkt_status & IWM_RX_MPDU_RES_STATUS_OVERRUN_OK)) {
   3189  1.29.2.2  skrll 		DPRINTF(("Bad CRC or FIFO: 0x%08X.\n", rx_pkt_status));
   3190  1.29.2.2  skrll 		return; /* drop */
   3191  1.29.2.2  skrll 	}
   3192  1.29.2.2  skrll 
   3193  1.29.2.2  skrll 	device_timestamp = le32toh(phy_info->system_timestamp);
   3194  1.29.2.2  skrll 
   3195  1.29.2.2  skrll 	if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_RX_ENERGY_API) {
   3196  1.29.2.2  skrll 		rssi = iwm_mvm_get_signal_strength(sc, phy_info);
   3197  1.29.2.2  skrll 	} else {
   3198  1.29.2.2  skrll 		rssi = iwm_mvm_calc_rssi(sc, phy_info);
   3199  1.29.2.2  skrll 	}
   3200  1.29.2.2  skrll 	rssi = -rssi;
   3201  1.29.2.2  skrll 
   3202  1.29.2.2  skrll 	if (ic->ic_state == IEEE80211_S_SCAN)
   3203  1.29.2.2  skrll 		iwm_fix_channel(ic, m);
   3204  1.29.2.2  skrll 
   3205  1.29.2.2  skrll 	/* replenish ring for the buffer we're going to feed to the sharks */
   3206  1.29.2.2  skrll 	if (iwm_rx_addbuf(sc, IWM_RBUF_SIZE, sc->rxq.cur) != 0)
   3207  1.29.2.2  skrll 		return;
   3208  1.29.2.2  skrll 
   3209  1.29.2.8  skrll 	m_set_rcvif(m, IC2IFP(ic));
   3210  1.29.2.2  skrll 
   3211  1.29.2.2  skrll 	if (sc->sc_scanband == IEEE80211_CHAN_5GHZ) {
   3212  1.29.2.2  skrll 		if (le32toh(phy_info->channel) < __arraycount(ic->ic_channels))
   3213  1.29.2.2  skrll 			c = &ic->ic_channels[le32toh(phy_info->channel)];
   3214  1.29.2.2  skrll 	}
   3215  1.29.2.2  skrll 
   3216  1.29.2.2  skrll 	ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh);
   3217  1.29.2.2  skrll 	if (c)
   3218  1.29.2.2  skrll 		ni->ni_chan = c;
   3219  1.29.2.2  skrll 
   3220  1.29.2.2  skrll 	if (sc->sc_drvbpf != NULL) {
   3221  1.29.2.2  skrll 		struct iwm_rx_radiotap_header *tap = &sc->sc_rxtap;
   3222  1.29.2.2  skrll 
   3223  1.29.2.2  skrll 		tap->wr_flags = 0;
   3224  1.29.2.2  skrll 		if (phy_info->phy_flags & htole16(IWM_PHY_INFO_FLAG_SHPREAMBLE))
   3225  1.29.2.2  skrll 			tap->wr_flags |= IEEE80211_RADIOTAP_F_SHORTPRE;
   3226  1.29.2.2  skrll 		tap->wr_chan_freq =
   3227  1.29.2.2  skrll 		    htole16(ic->ic_channels[phy_info->channel].ic_freq);
   3228  1.29.2.2  skrll 		tap->wr_chan_flags =
   3229  1.29.2.2  skrll 		    htole16(ic->ic_channels[phy_info->channel].ic_flags);
   3230  1.29.2.2  skrll 		tap->wr_dbm_antsignal = (int8_t)rssi;
   3231  1.29.2.2  skrll 		tap->wr_dbm_antnoise = (int8_t)sc->sc_noise;
   3232  1.29.2.2  skrll 		tap->wr_tsft = phy_info->system_timestamp;
   3233  1.29.2.2  skrll 		switch (phy_info->rate) {
   3234  1.29.2.2  skrll 		/* CCK rates. */
   3235  1.29.2.2  skrll 		case  10: tap->wr_rate =   2; break;
   3236  1.29.2.2  skrll 		case  20: tap->wr_rate =   4; break;
   3237  1.29.2.2  skrll 		case  55: tap->wr_rate =  11; break;
   3238  1.29.2.2  skrll 		case 110: tap->wr_rate =  22; break;
   3239  1.29.2.2  skrll 		/* OFDM rates. */
   3240  1.29.2.2  skrll 		case 0xd: tap->wr_rate =  12; break;
   3241  1.29.2.2  skrll 		case 0xf: tap->wr_rate =  18; break;
   3242  1.29.2.2  skrll 		case 0x5: tap->wr_rate =  24; break;
   3243  1.29.2.2  skrll 		case 0x7: tap->wr_rate =  36; break;
   3244  1.29.2.2  skrll 		case 0x9: tap->wr_rate =  48; break;
   3245  1.29.2.2  skrll 		case 0xb: tap->wr_rate =  72; break;
   3246  1.29.2.2  skrll 		case 0x1: tap->wr_rate =  96; break;
   3247  1.29.2.2  skrll 		case 0x3: tap->wr_rate = 108; break;
   3248  1.29.2.2  skrll 		/* Unknown rate: should not happen. */
   3249  1.29.2.2  skrll 		default:  tap->wr_rate =   0;
   3250  1.29.2.2  skrll 		}
   3251  1.29.2.2  skrll 
   3252  1.29.2.2  skrll 		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m);
   3253  1.29.2.2  skrll 	}
   3254  1.29.2.2  skrll 	ieee80211_input(ic, m, ni, rssi, device_timestamp);
   3255  1.29.2.2  skrll 	ieee80211_free_node(ni);
   3256  1.29.2.2  skrll }
   3257  1.29.2.2  skrll 
   3258  1.29.2.2  skrll static void
   3259  1.29.2.2  skrll iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct iwm_rx_packet *pkt,
   3260  1.29.2.2  skrll 	struct iwm_node *in)
   3261  1.29.2.2  skrll {
   3262  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   3263  1.29.2.2  skrll 	struct ifnet *ifp = IC2IFP(ic);
   3264  1.29.2.2  skrll 	struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data;
   3265  1.29.2.2  skrll 	int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
   3266  1.29.2.2  skrll 	int failack = tx_resp->failure_frame;
   3267  1.29.2.2  skrll 
   3268  1.29.2.2  skrll 	KASSERT(tx_resp->frame_count == 1);
   3269  1.29.2.2  skrll 
   3270  1.29.2.2  skrll 	/* Update rate control statistics. */
   3271  1.29.2.2  skrll 	in->in_amn.amn_txcnt++;
   3272  1.29.2.2  skrll 	if (failack > 0) {
   3273  1.29.2.2  skrll 		in->in_amn.amn_retrycnt++;
   3274  1.29.2.2  skrll 	}
   3275  1.29.2.2  skrll 
   3276  1.29.2.2  skrll 	if (status != IWM_TX_STATUS_SUCCESS &&
   3277  1.29.2.2  skrll 	    status != IWM_TX_STATUS_DIRECT_DONE)
   3278  1.29.2.2  skrll 		ifp->if_oerrors++;
   3279  1.29.2.2  skrll 	else
   3280  1.29.2.2  skrll 		ifp->if_opackets++;
   3281  1.29.2.2  skrll }
   3282  1.29.2.2  skrll 
   3283  1.29.2.2  skrll static void
   3284  1.29.2.2  skrll iwm_mvm_rx_tx_cmd(struct iwm_softc *sc,
   3285  1.29.2.2  skrll 	struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
   3286  1.29.2.2  skrll {
   3287  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   3288  1.29.2.2  skrll 	struct ifnet *ifp = IC2IFP(ic);
   3289  1.29.2.2  skrll 	struct iwm_cmd_header *cmd_hdr = &pkt->hdr;
   3290  1.29.2.2  skrll 	int idx = cmd_hdr->idx;
   3291  1.29.2.2  skrll 	int qid = cmd_hdr->qid;
   3292  1.29.2.2  skrll 	struct iwm_tx_ring *ring = &sc->txq[qid];
   3293  1.29.2.2  skrll 	struct iwm_tx_data *txd = &ring->data[idx];
   3294  1.29.2.2  skrll 	struct iwm_node *in = txd->in;
   3295  1.29.2.2  skrll 
   3296  1.29.2.2  skrll 	if (txd->done) {
   3297  1.29.2.2  skrll 		DPRINTF(("%s: got tx interrupt that's already been handled!\n",
   3298  1.29.2.2  skrll 		    DEVNAME(sc)));
   3299  1.29.2.2  skrll 		return;
   3300  1.29.2.2  skrll 	}
   3301  1.29.2.2  skrll 
   3302  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, 0, IWM_RBUF_SIZE,
   3303  1.29.2.2  skrll 	    BUS_DMASYNC_POSTREAD);
   3304  1.29.2.2  skrll 
   3305  1.29.2.2  skrll 	sc->sc_tx_timer = 0;
   3306  1.29.2.2  skrll 
   3307  1.29.2.2  skrll 	iwm_mvm_rx_tx_cmd_single(sc, pkt, in);
   3308  1.29.2.2  skrll 
   3309  1.29.2.2  skrll 	/* Unmap and free mbuf. */
   3310  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, txd->map, 0, txd->map->dm_mapsize,
   3311  1.29.2.2  skrll 	    BUS_DMASYNC_POSTWRITE);
   3312  1.29.2.2  skrll 	bus_dmamap_unload(sc->sc_dmat, txd->map);
   3313  1.29.2.2  skrll 	m_freem(txd->m);
   3314  1.29.2.2  skrll 
   3315  1.29.2.2  skrll 	DPRINTFN(8, ("free txd %p, in %p\n", txd, txd->in));
   3316  1.29.2.2  skrll 	KASSERT(txd->done == 0);
   3317  1.29.2.2  skrll 	txd->done = 1;
   3318  1.29.2.2  skrll 	KASSERT(txd->in);
   3319  1.29.2.2  skrll 
   3320  1.29.2.2  skrll 	txd->m = NULL;
   3321  1.29.2.2  skrll 	txd->in = NULL;
   3322  1.29.2.2  skrll 	ieee80211_free_node(&in->in_ni);
   3323  1.29.2.2  skrll 
   3324  1.29.2.2  skrll 	if (--ring->queued < IWM_TX_RING_LOMARK) {
   3325  1.29.2.2  skrll 		sc->qfullmsk &= ~(1 << ring->qid);
   3326  1.29.2.2  skrll 		if (sc->qfullmsk == 0 && (ifp->if_flags & IFF_OACTIVE)) {
   3327  1.29.2.2  skrll 			ifp->if_flags &= ~IFF_OACTIVE;
   3328  1.29.2.2  skrll 			/*
   3329  1.29.2.2  skrll 			 * Well, we're in interrupt context, but then again
   3330  1.29.2.2  skrll 			 * I guess net80211 does all sorts of stunts in
   3331  1.29.2.2  skrll 			 * interrupt context, so maybe this is no biggie.
   3332  1.29.2.2  skrll 			 */
   3333  1.29.2.2  skrll 			(*ifp->if_start)(ifp);
   3334  1.29.2.2  skrll 		}
   3335  1.29.2.2  skrll 	}
   3336  1.29.2.2  skrll }
   3337  1.29.2.2  skrll 
   3338  1.29.2.2  skrll /*
   3339  1.29.2.2  skrll  * BEGIN iwlwifi/mvm/binding.c
   3340  1.29.2.2  skrll  */
   3341  1.29.2.2  skrll 
   3342  1.29.2.2  skrll static int
   3343  1.29.2.2  skrll iwm_mvm_binding_cmd(struct iwm_softc *sc, struct iwm_node *in, uint32_t action)
   3344  1.29.2.2  skrll {
   3345  1.29.2.2  skrll 	struct iwm_binding_cmd cmd;
   3346  1.29.2.2  skrll 	struct iwm_mvm_phy_ctxt *phyctxt = in->in_phyctxt;
   3347  1.29.2.2  skrll 	int i, ret;
   3348  1.29.2.2  skrll 	uint32_t status;
   3349  1.29.2.2  skrll 
   3350  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   3351  1.29.2.2  skrll 
   3352  1.29.2.2  skrll 	cmd.id_and_color
   3353  1.29.2.2  skrll 	    = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color));
   3354  1.29.2.2  skrll 	cmd.action = htole32(action);
   3355  1.29.2.2  skrll 	cmd.phy = htole32(IWM_FW_CMD_ID_AND_COLOR(phyctxt->id, phyctxt->color));
   3356  1.29.2.2  skrll 
   3357  1.29.2.2  skrll 	cmd.macs[0] = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
   3358  1.29.2.2  skrll 	for (i = 1; i < IWM_MAX_MACS_IN_BINDING; i++)
   3359  1.29.2.2  skrll 		cmd.macs[i] = htole32(IWM_FW_CTXT_INVALID);
   3360  1.29.2.2  skrll 
   3361  1.29.2.2  skrll 	status = 0;
   3362  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_pdu_status(sc, IWM_BINDING_CONTEXT_CMD,
   3363  1.29.2.2  skrll 	    sizeof(cmd), &cmd, &status);
   3364  1.29.2.2  skrll 	if (ret) {
   3365  1.29.2.2  skrll 		DPRINTF(("%s: Failed to send binding (action:%d): %d\n",
   3366  1.29.2.2  skrll 		    DEVNAME(sc), action, ret));
   3367  1.29.2.2  skrll 		return ret;
   3368  1.29.2.2  skrll 	}
   3369  1.29.2.2  skrll 
   3370  1.29.2.2  skrll 	if (status) {
   3371  1.29.2.2  skrll 		DPRINTF(("%s: Binding command failed: %u\n", DEVNAME(sc),
   3372  1.29.2.2  skrll 		    status));
   3373  1.29.2.2  skrll 		ret = EIO;
   3374  1.29.2.2  skrll 	}
   3375  1.29.2.2  skrll 
   3376  1.29.2.2  skrll 	return ret;
   3377  1.29.2.2  skrll }
   3378  1.29.2.2  skrll 
   3379  1.29.2.2  skrll static int
   3380  1.29.2.2  skrll iwm_mvm_binding_update(struct iwm_softc *sc, struct iwm_node *in, int add)
   3381  1.29.2.2  skrll {
   3382  1.29.2.2  skrll 	return iwm_mvm_binding_cmd(sc, in, IWM_FW_CTXT_ACTION_ADD);
   3383  1.29.2.2  skrll }
   3384  1.29.2.2  skrll 
   3385  1.29.2.2  skrll static int
   3386  1.29.2.2  skrll iwm_mvm_binding_add_vif(struct iwm_softc *sc, struct iwm_node *in)
   3387  1.29.2.2  skrll {
   3388  1.29.2.2  skrll 	return iwm_mvm_binding_update(sc, in, IWM_FW_CTXT_ACTION_ADD);
   3389  1.29.2.2  skrll }
   3390  1.29.2.2  skrll 
   3391  1.29.2.2  skrll /*
   3392  1.29.2.2  skrll  * END iwlwifi/mvm/binding.c
   3393  1.29.2.2  skrll  */
   3394  1.29.2.2  skrll 
   3395  1.29.2.2  skrll /*
   3396  1.29.2.2  skrll  * BEGIN iwlwifi/mvm/phy-ctxt.c
   3397  1.29.2.2  skrll  */
   3398  1.29.2.2  skrll 
   3399  1.29.2.2  skrll /*
   3400  1.29.2.2  skrll  * Construct the generic fields of the PHY context command
   3401  1.29.2.2  skrll  */
   3402  1.29.2.2  skrll static void
   3403  1.29.2.2  skrll iwm_mvm_phy_ctxt_cmd_hdr(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt,
   3404  1.29.2.2  skrll 	struct iwm_phy_context_cmd *cmd, uint32_t action, uint32_t apply_time)
   3405  1.29.2.2  skrll {
   3406  1.29.2.2  skrll 	memset(cmd, 0, sizeof(struct iwm_phy_context_cmd));
   3407  1.29.2.2  skrll 
   3408  1.29.2.2  skrll 	cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(ctxt->id,
   3409  1.29.2.2  skrll 	    ctxt->color));
   3410  1.29.2.2  skrll 	cmd->action = htole32(action);
   3411  1.29.2.2  skrll 	cmd->apply_time = htole32(apply_time);
   3412  1.29.2.2  skrll }
   3413  1.29.2.2  skrll 
   3414  1.29.2.2  skrll /*
   3415  1.29.2.2  skrll  * Add the phy configuration to the PHY context command
   3416  1.29.2.2  skrll  */
   3417  1.29.2.2  skrll static void
   3418  1.29.2.2  skrll iwm_mvm_phy_ctxt_cmd_data(struct iwm_softc *sc,
   3419  1.29.2.2  skrll 	struct iwm_phy_context_cmd *cmd, struct ieee80211_channel *chan,
   3420  1.29.2.2  skrll 	uint8_t chains_static, uint8_t chains_dynamic)
   3421  1.29.2.2  skrll {
   3422  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   3423  1.29.2.2  skrll 	uint8_t active_cnt, idle_cnt;
   3424  1.29.2.2  skrll 
   3425  1.29.2.2  skrll 	cmd->ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
   3426  1.29.2.2  skrll 	    IWM_PHY_BAND_24 : IWM_PHY_BAND_5;
   3427  1.29.2.2  skrll 
   3428  1.29.2.2  skrll 	cmd->ci.channel = ieee80211_chan2ieee(ic, chan);
   3429  1.29.2.2  skrll 	cmd->ci.width = IWM_PHY_VHT_CHANNEL_MODE20;
   3430  1.29.2.2  skrll 	cmd->ci.ctrl_pos = IWM_PHY_VHT_CTRL_POS_1_BELOW;
   3431  1.29.2.2  skrll 
   3432  1.29.2.2  skrll 	/* Set rx the chains */
   3433  1.29.2.2  skrll 	idle_cnt = chains_static;
   3434  1.29.2.2  skrll 	active_cnt = chains_dynamic;
   3435  1.29.2.2  skrll 
   3436  1.29.2.2  skrll 	cmd->rxchain_info = htole32(IWM_FW_VALID_RX_ANT(sc) <<
   3437  1.29.2.2  skrll 					IWM_PHY_RX_CHAIN_VALID_POS);
   3438  1.29.2.2  skrll 	cmd->rxchain_info |= htole32(idle_cnt << IWM_PHY_RX_CHAIN_CNT_POS);
   3439  1.29.2.2  skrll 	cmd->rxchain_info |= htole32(active_cnt <<
   3440  1.29.2.2  skrll 	    IWM_PHY_RX_CHAIN_MIMO_CNT_POS);
   3441  1.29.2.2  skrll 
   3442  1.29.2.2  skrll 	cmd->txchain_info = htole32(IWM_FW_VALID_TX_ANT(sc));
   3443  1.29.2.2  skrll }
   3444  1.29.2.2  skrll 
   3445  1.29.2.2  skrll /*
   3446  1.29.2.2  skrll  * Send a command
   3447  1.29.2.2  skrll  * only if something in the configuration changed: in case that this is the
   3448  1.29.2.2  skrll  * first time that the phy configuration is applied or in case that the phy
   3449  1.29.2.2  skrll  * configuration changed from the previous apply.
   3450  1.29.2.2  skrll  */
   3451  1.29.2.2  skrll static int
   3452  1.29.2.2  skrll iwm_mvm_phy_ctxt_apply(struct iwm_softc *sc,
   3453  1.29.2.2  skrll 	struct iwm_mvm_phy_ctxt *ctxt,
   3454  1.29.2.2  skrll 	uint8_t chains_static, uint8_t chains_dynamic,
   3455  1.29.2.2  skrll 	uint32_t action, uint32_t apply_time)
   3456  1.29.2.2  skrll {
   3457  1.29.2.2  skrll 	struct iwm_phy_context_cmd cmd;
   3458  1.29.2.2  skrll 	int ret;
   3459  1.29.2.2  skrll 
   3460  1.29.2.2  skrll 	/* Set the command header fields */
   3461  1.29.2.2  skrll 	iwm_mvm_phy_ctxt_cmd_hdr(sc, ctxt, &cmd, action, apply_time);
   3462  1.29.2.2  skrll 
   3463  1.29.2.2  skrll 	/* Set the command data */
   3464  1.29.2.2  skrll 	iwm_mvm_phy_ctxt_cmd_data(sc, &cmd, ctxt->channel,
   3465  1.29.2.2  skrll 	    chains_static, chains_dynamic);
   3466  1.29.2.2  skrll 
   3467  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_pdu(sc, IWM_PHY_CONTEXT_CMD, IWM_CMD_SYNC,
   3468  1.29.2.2  skrll 	    sizeof(struct iwm_phy_context_cmd), &cmd);
   3469  1.29.2.2  skrll 	if (ret) {
   3470  1.29.2.2  skrll 		DPRINTF(("PHY ctxt cmd error. ret=%d\n", ret));
   3471  1.29.2.2  skrll 	}
   3472  1.29.2.2  skrll 	return ret;
   3473  1.29.2.2  skrll }
   3474  1.29.2.2  skrll 
   3475  1.29.2.2  skrll /*
   3476  1.29.2.2  skrll  * Send a command to add a PHY context based on the current HW configuration.
   3477  1.29.2.2  skrll  */
   3478  1.29.2.2  skrll static int
   3479  1.29.2.2  skrll iwm_mvm_phy_ctxt_add(struct iwm_softc *sc, struct iwm_mvm_phy_ctxt *ctxt,
   3480  1.29.2.2  skrll 	struct ieee80211_channel *chan,
   3481  1.29.2.2  skrll 	uint8_t chains_static, uint8_t chains_dynamic)
   3482  1.29.2.2  skrll {
   3483  1.29.2.2  skrll 	ctxt->channel = chan;
   3484  1.29.2.2  skrll 	return iwm_mvm_phy_ctxt_apply(sc, ctxt,
   3485  1.29.2.2  skrll 	    chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_ADD, 0);
   3486  1.29.2.2  skrll }
   3487  1.29.2.2  skrll 
   3488  1.29.2.2  skrll /*
   3489  1.29.2.2  skrll  * Send a command to modify the PHY context based on the current HW
   3490  1.29.2.2  skrll  * configuration. Note that the function does not check that the configuration
   3491  1.29.2.2  skrll  * changed.
   3492  1.29.2.2  skrll  */
   3493  1.29.2.2  skrll static int
   3494  1.29.2.2  skrll iwm_mvm_phy_ctxt_changed(struct iwm_softc *sc,
   3495  1.29.2.2  skrll 	struct iwm_mvm_phy_ctxt *ctxt, struct ieee80211_channel *chan,
   3496  1.29.2.2  skrll 	uint8_t chains_static, uint8_t chains_dynamic)
   3497  1.29.2.2  skrll {
   3498  1.29.2.2  skrll 	ctxt->channel = chan;
   3499  1.29.2.2  skrll 	return iwm_mvm_phy_ctxt_apply(sc, ctxt,
   3500  1.29.2.2  skrll 	    chains_static, chains_dynamic, IWM_FW_CTXT_ACTION_MODIFY, 0);
   3501  1.29.2.2  skrll }
   3502  1.29.2.2  skrll 
   3503  1.29.2.2  skrll /*
   3504  1.29.2.2  skrll  * END iwlwifi/mvm/phy-ctxt.c
   3505  1.29.2.2  skrll  */
   3506  1.29.2.2  skrll 
   3507  1.29.2.2  skrll /*
   3508  1.29.2.2  skrll  * transmit side
   3509  1.29.2.2  skrll  */
   3510  1.29.2.2  skrll 
   3511  1.29.2.2  skrll /*
   3512  1.29.2.2  skrll  * Send a command to the firmware.  We try to implement the Linux
   3513  1.29.2.2  skrll  * driver interface for the routine.
   3514  1.29.2.2  skrll  * mostly from if_iwn (iwn_cmd()).
   3515  1.29.2.2  skrll  *
   3516  1.29.2.2  skrll  * For now, we always copy the first part and map the second one (if it exists).
   3517  1.29.2.2  skrll  */
   3518  1.29.2.2  skrll static int
   3519  1.29.2.2  skrll iwm_send_cmd(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
   3520  1.29.2.2  skrll {
   3521  1.29.2.2  skrll 	struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
   3522  1.29.2.2  skrll 	struct iwm_tfd *desc;
   3523  1.29.2.2  skrll 	struct iwm_tx_data *data;
   3524  1.29.2.2  skrll 	struct iwm_device_cmd *cmd;
   3525  1.29.2.2  skrll 	struct mbuf *m;
   3526  1.29.2.2  skrll 	bus_addr_t paddr;
   3527  1.29.2.2  skrll 	uint32_t addr_lo;
   3528  1.29.2.2  skrll 	int error = 0, i, paylen, off, s;
   3529  1.29.2.2  skrll 	int code;
   3530  1.29.2.2  skrll 	int async, wantresp;
   3531  1.29.2.2  skrll 
   3532  1.29.2.2  skrll 	code = hcmd->id;
   3533  1.29.2.2  skrll 	async = hcmd->flags & IWM_CMD_ASYNC;
   3534  1.29.2.2  skrll 	wantresp = hcmd->flags & IWM_CMD_WANT_SKB;
   3535  1.29.2.2  skrll 
   3536  1.29.2.2  skrll 	for (i = 0, paylen = 0; i < __arraycount(hcmd->len); i++) {
   3537  1.29.2.2  skrll 		paylen += hcmd->len[i];
   3538  1.29.2.2  skrll 	}
   3539  1.29.2.2  skrll 
   3540  1.29.2.2  skrll 	/* if the command wants an answer, busy sc_cmd_resp */
   3541  1.29.2.2  skrll 	if (wantresp) {
   3542  1.29.2.2  skrll 		KASSERT(!async);
   3543  1.29.2.2  skrll 		while (sc->sc_wantresp != -1)
   3544  1.29.2.2  skrll 			tsleep(&sc->sc_wantresp, 0, "iwmcmdsl", 0);
   3545  1.29.2.2  skrll 		sc->sc_wantresp = ring->qid << 16 | ring->cur;
   3546  1.29.2.2  skrll 		DPRINTFN(12, ("wantresp is %x\n", sc->sc_wantresp));
   3547  1.29.2.2  skrll 	}
   3548  1.29.2.2  skrll 
   3549  1.29.2.2  skrll 	/*
   3550  1.29.2.2  skrll 	 * Is the hardware still available?  (after e.g. above wait).
   3551  1.29.2.2  skrll 	 */
   3552  1.29.2.2  skrll 	s = splnet();
   3553  1.29.2.2  skrll 	if (sc->sc_flags & IWM_FLAG_STOPPED) {
   3554  1.29.2.2  skrll 		error = ENXIO;
   3555  1.29.2.2  skrll 		goto out;
   3556  1.29.2.2  skrll 	}
   3557  1.29.2.2  skrll 
   3558  1.29.2.2  skrll 	desc = &ring->desc[ring->cur];
   3559  1.29.2.2  skrll 	data = &ring->data[ring->cur];
   3560  1.29.2.2  skrll 
   3561  1.29.2.2  skrll 	if (paylen > sizeof(cmd->data)) {
   3562  1.29.2.2  skrll 		/* Command is too large */
   3563  1.29.2.2  skrll 		if (sizeof(cmd->hdr) + paylen > IWM_RBUF_SIZE) {
   3564  1.29.2.2  skrll 			error = EINVAL;
   3565  1.29.2.2  skrll 			goto out;
   3566  1.29.2.2  skrll 		}
   3567  1.29.2.2  skrll 		m = m_gethdr(M_DONTWAIT, MT_DATA);
   3568  1.29.2.2  skrll 		if (m == NULL) {
   3569  1.29.2.2  skrll 			error = ENOMEM;
   3570  1.29.2.2  skrll 			goto out;
   3571  1.29.2.2  skrll 		}
   3572  1.29.2.2  skrll 		MEXTMALLOC(m, IWM_RBUF_SIZE, M_DONTWAIT);
   3573  1.29.2.2  skrll 		if (!(m->m_flags & M_EXT)) {
   3574  1.29.2.2  skrll 			m_freem(m);
   3575  1.29.2.2  skrll 			error = ENOMEM;
   3576  1.29.2.2  skrll 			goto out;
   3577  1.29.2.2  skrll 		}
   3578  1.29.2.2  skrll 		cmd = mtod(m, struct iwm_device_cmd *);
   3579  1.29.2.2  skrll 		error = bus_dmamap_load(sc->sc_dmat, data->map, cmd,
   3580  1.29.2.2  skrll 		    IWM_RBUF_SIZE, NULL, BUS_DMA_NOWAIT | BUS_DMA_WRITE);
   3581  1.29.2.2  skrll 		if (error != 0) {
   3582  1.29.2.2  skrll 			m_freem(m);
   3583  1.29.2.2  skrll 			goto out;
   3584  1.29.2.2  skrll 		}
   3585  1.29.2.2  skrll 		data->m = m;
   3586  1.29.2.2  skrll 		paddr = data->map->dm_segs[0].ds_addr;
   3587  1.29.2.2  skrll 	} else {
   3588  1.29.2.2  skrll 		cmd = &ring->cmd[ring->cur];
   3589  1.29.2.2  skrll 		paddr = data->cmd_paddr;
   3590  1.29.2.2  skrll 	}
   3591  1.29.2.2  skrll 
   3592  1.29.2.2  skrll 	cmd->hdr.code = code;
   3593  1.29.2.2  skrll 	cmd->hdr.flags = 0;
   3594  1.29.2.2  skrll 	cmd->hdr.qid = ring->qid;
   3595  1.29.2.2  skrll 	cmd->hdr.idx = ring->cur;
   3596  1.29.2.2  skrll 
   3597  1.29.2.2  skrll 	for (i = 0, off = 0; i < __arraycount(hcmd->data); i++) {
   3598  1.29.2.2  skrll 		if (hcmd->len[i] == 0)
   3599  1.29.2.2  skrll 			continue;
   3600  1.29.2.2  skrll 		memcpy(cmd->data + off, hcmd->data[i], hcmd->len[i]);
   3601  1.29.2.2  skrll 		off += hcmd->len[i];
   3602  1.29.2.2  skrll 	}
   3603  1.29.2.2  skrll 	KASSERT(off == paylen);
   3604  1.29.2.2  skrll 
   3605  1.29.2.2  skrll 	/* lo field is not aligned */
   3606  1.29.2.2  skrll 	addr_lo = htole32((uint32_t)paddr);
   3607  1.29.2.2  skrll 	memcpy(&desc->tbs[0].lo, &addr_lo, sizeof(uint32_t));
   3608  1.29.2.2  skrll 	desc->tbs[0].hi_n_len  = htole16(iwm_get_dma_hi_addr(paddr)
   3609  1.29.2.2  skrll 	    | ((sizeof(cmd->hdr) + paylen) << 4));
   3610  1.29.2.2  skrll 	desc->num_tbs = 1;
   3611  1.29.2.2  skrll 
   3612  1.29.2.2  skrll 	DPRINTFN(8, ("iwm_send_cmd 0x%x size=%zu %s\n",
   3613  1.29.2.2  skrll 	    code, sizeof(cmd->hdr) + paylen, async ? " (async)" : ""));
   3614  1.29.2.2  skrll 
   3615  1.29.2.2  skrll 	if (paylen > sizeof(cmd->data)) {
   3616  1.29.2.2  skrll 		bus_dmamap_sync(sc->sc_dmat, data->map, 0,
   3617  1.29.2.2  skrll 		    sizeof(cmd->hdr) + paylen, BUS_DMASYNC_PREWRITE);
   3618  1.29.2.2  skrll 	} else {
   3619  1.29.2.2  skrll 		bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
   3620  1.29.2.2  skrll 		    (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr,
   3621  1.29.2.2  skrll 		    sizeof(cmd->hdr) + paylen, BUS_DMASYNC_PREWRITE);
   3622  1.29.2.2  skrll 	}
   3623  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
   3624  1.29.2.2  skrll 	    (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr,
   3625  1.29.2.2  skrll 	    sizeof (*desc), BUS_DMASYNC_PREWRITE);
   3626  1.29.2.2  skrll 
   3627  1.29.2.2  skrll 	IWM_SETBITS(sc, IWM_CSR_GP_CNTRL,
   3628  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
   3629  1.29.2.2  skrll 	if (!iwm_poll_bit(sc, IWM_CSR_GP_CNTRL,
   3630  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
   3631  1.29.2.2  skrll 	    (IWM_CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
   3632  1.29.2.2  skrll 	     IWM_CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000)) {
   3633  1.29.2.2  skrll 		DPRINTF(("%s: acquiring device failed\n", DEVNAME(sc)));
   3634  1.29.2.2  skrll 		error = EBUSY;
   3635  1.29.2.2  skrll 		goto out;
   3636  1.29.2.2  skrll 	}
   3637  1.29.2.2  skrll 
   3638  1.29.2.2  skrll #if 0
   3639  1.29.2.2  skrll 	iwm_update_sched(sc, ring->qid, ring->cur, 0, 0);
   3640  1.29.2.2  skrll #endif
   3641  1.29.2.2  skrll 	DPRINTF(("sending command 0x%x qid %d, idx %d\n",
   3642  1.29.2.2  skrll 	    code, ring->qid, ring->cur));
   3643  1.29.2.2  skrll 
   3644  1.29.2.2  skrll 	/* Kick command ring. */
   3645  1.29.2.2  skrll 	ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT;
   3646  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
   3647  1.29.2.2  skrll 
   3648  1.29.2.2  skrll 	if (!async) {
   3649  1.29.2.2  skrll 		/* m..m-mmyy-mmyyyy-mym-ym m-my generation */
   3650  1.29.2.2  skrll 		int generation = sc->sc_generation;
   3651  1.29.2.2  skrll 		error = tsleep(desc, PCATCH, "iwmcmd", hz);
   3652  1.29.2.2  skrll 		if (error == 0) {
   3653  1.29.2.2  skrll 			/* if hardware is no longer up, return error */
   3654  1.29.2.2  skrll 			if (generation != sc->sc_generation) {
   3655  1.29.2.2  skrll 				error = ENXIO;
   3656  1.29.2.2  skrll 			} else {
   3657  1.29.2.2  skrll 				hcmd->resp_pkt = (void *)sc->sc_cmd_resp;
   3658  1.29.2.2  skrll 			}
   3659  1.29.2.2  skrll 		}
   3660  1.29.2.2  skrll 	}
   3661  1.29.2.2  skrll  out:
   3662  1.29.2.2  skrll 	if (wantresp && error != 0) {
   3663  1.29.2.2  skrll 		iwm_free_resp(sc, hcmd);
   3664  1.29.2.2  skrll 	}
   3665  1.29.2.2  skrll 	splx(s);
   3666  1.29.2.2  skrll 
   3667  1.29.2.2  skrll 	return error;
   3668  1.29.2.2  skrll }
   3669  1.29.2.2  skrll 
   3670  1.29.2.2  skrll /* iwlwifi: mvm/utils.c */
   3671  1.29.2.2  skrll static int
   3672  1.29.2.2  skrll iwm_mvm_send_cmd_pdu(struct iwm_softc *sc, uint8_t id,
   3673  1.29.2.2  skrll 	uint32_t flags, uint16_t len, const void *data)
   3674  1.29.2.2  skrll {
   3675  1.29.2.2  skrll 	struct iwm_host_cmd cmd = {
   3676  1.29.2.2  skrll 		.id = id,
   3677  1.29.2.2  skrll 		.len = { len, },
   3678  1.29.2.2  skrll 		.data = { data, },
   3679  1.29.2.2  skrll 		.flags = flags,
   3680  1.29.2.2  skrll 	};
   3681  1.29.2.2  skrll 
   3682  1.29.2.2  skrll 	return iwm_send_cmd(sc, &cmd);
   3683  1.29.2.2  skrll }
   3684  1.29.2.2  skrll 
   3685  1.29.2.2  skrll /* iwlwifi: mvm/utils.c */
   3686  1.29.2.2  skrll static int
   3687  1.29.2.2  skrll iwm_mvm_send_cmd_status(struct iwm_softc *sc,
   3688  1.29.2.2  skrll 	struct iwm_host_cmd *cmd, uint32_t *status)
   3689  1.29.2.2  skrll {
   3690  1.29.2.2  skrll 	struct iwm_rx_packet *pkt;
   3691  1.29.2.2  skrll 	struct iwm_cmd_response *resp;
   3692  1.29.2.2  skrll 	int error, resp_len;
   3693  1.29.2.2  skrll 
   3694  1.29.2.2  skrll 	//lockdep_assert_held(&mvm->mutex);
   3695  1.29.2.2  skrll 
   3696  1.29.2.2  skrll 	KASSERT((cmd->flags & IWM_CMD_WANT_SKB) == 0);
   3697  1.29.2.2  skrll 	cmd->flags |= IWM_CMD_SYNC | IWM_CMD_WANT_SKB;
   3698  1.29.2.2  skrll 
   3699  1.29.2.2  skrll 	if ((error = iwm_send_cmd(sc, cmd)) != 0)
   3700  1.29.2.2  skrll 		return error;
   3701  1.29.2.2  skrll 	pkt = cmd->resp_pkt;
   3702  1.29.2.2  skrll 
   3703  1.29.2.2  skrll 	/* Can happen if RFKILL is asserted */
   3704  1.29.2.2  skrll 	if (!pkt) {
   3705  1.29.2.2  skrll 		error = 0;
   3706  1.29.2.2  skrll 		goto out_free_resp;
   3707  1.29.2.2  skrll 	}
   3708  1.29.2.2  skrll 
   3709  1.29.2.2  skrll 	if (pkt->hdr.flags & IWM_CMD_FAILED_MSK) {
   3710  1.29.2.2  skrll 		error = EIO;
   3711  1.29.2.2  skrll 		goto out_free_resp;
   3712  1.29.2.2  skrll 	}
   3713  1.29.2.2  skrll 
   3714  1.29.2.2  skrll 	resp_len = iwm_rx_packet_payload_len(pkt);
   3715  1.29.2.2  skrll 	if (resp_len != sizeof(*resp)) {
   3716  1.29.2.2  skrll 		error = EIO;
   3717  1.29.2.2  skrll 		goto out_free_resp;
   3718  1.29.2.2  skrll 	}
   3719  1.29.2.2  skrll 
   3720  1.29.2.2  skrll 	resp = (void *)pkt->data;
   3721  1.29.2.2  skrll 	*status = le32toh(resp->status);
   3722  1.29.2.2  skrll  out_free_resp:
   3723  1.29.2.2  skrll 	iwm_free_resp(sc, cmd);
   3724  1.29.2.2  skrll 	return error;
   3725  1.29.2.2  skrll }
   3726  1.29.2.2  skrll 
   3727  1.29.2.2  skrll /* iwlwifi/mvm/utils.c */
   3728  1.29.2.2  skrll static int
   3729  1.29.2.2  skrll iwm_mvm_send_cmd_pdu_status(struct iwm_softc *sc, uint8_t id,
   3730  1.29.2.2  skrll 	uint16_t len, const void *data, uint32_t *status)
   3731  1.29.2.2  skrll {
   3732  1.29.2.2  skrll 	struct iwm_host_cmd cmd = {
   3733  1.29.2.2  skrll 		.id = id,
   3734  1.29.2.2  skrll 		.len = { len, },
   3735  1.29.2.2  skrll 		.data = { data, },
   3736  1.29.2.2  skrll 	};
   3737  1.29.2.2  skrll 
   3738  1.29.2.2  skrll 	return iwm_mvm_send_cmd_status(sc, &cmd, status);
   3739  1.29.2.2  skrll }
   3740  1.29.2.2  skrll 
   3741  1.29.2.2  skrll static void
   3742  1.29.2.2  skrll iwm_free_resp(struct iwm_softc *sc, struct iwm_host_cmd *hcmd)
   3743  1.29.2.2  skrll {
   3744  1.29.2.2  skrll 	KASSERT(sc->sc_wantresp != -1);
   3745  1.29.2.2  skrll 	KASSERT((hcmd->flags & (IWM_CMD_WANT_SKB|IWM_CMD_SYNC))
   3746  1.29.2.2  skrll 	    == (IWM_CMD_WANT_SKB|IWM_CMD_SYNC));
   3747  1.29.2.2  skrll 	sc->sc_wantresp = -1;
   3748  1.29.2.2  skrll 	wakeup(&sc->sc_wantresp);
   3749  1.29.2.2  skrll }
   3750  1.29.2.2  skrll 
   3751  1.29.2.2  skrll /*
   3752  1.29.2.2  skrll  * Process a "command done" firmware notification.  This is where we wakeup
   3753  1.29.2.2  skrll  * processes waiting for a synchronous command completion.
   3754  1.29.2.2  skrll  * from if_iwn
   3755  1.29.2.2  skrll  */
   3756  1.29.2.2  skrll static void
   3757  1.29.2.2  skrll iwm_cmd_done(struct iwm_softc *sc, struct iwm_rx_packet *pkt)
   3758  1.29.2.2  skrll {
   3759  1.29.2.2  skrll 	struct iwm_tx_ring *ring = &sc->txq[IWM_MVM_CMD_QUEUE];
   3760  1.29.2.2  skrll 	struct iwm_tx_data *data;
   3761  1.29.2.2  skrll 
   3762  1.29.2.2  skrll 	if (pkt->hdr.qid != IWM_MVM_CMD_QUEUE) {
   3763  1.29.2.2  skrll 		return;	/* Not a command ack. */
   3764  1.29.2.2  skrll 	}
   3765  1.29.2.2  skrll 
   3766  1.29.2.2  skrll 	data = &ring->data[pkt->hdr.idx];
   3767  1.29.2.2  skrll 
   3768  1.29.2.2  skrll 	/* If the command was mapped in an mbuf, free it. */
   3769  1.29.2.2  skrll 	if (data->m != NULL) {
   3770  1.29.2.2  skrll 		bus_dmamap_sync(sc->sc_dmat, data->map, 0,
   3771  1.29.2.2  skrll 		    data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
   3772  1.29.2.2  skrll 		bus_dmamap_unload(sc->sc_dmat, data->map);
   3773  1.29.2.2  skrll 		m_freem(data->m);
   3774  1.29.2.2  skrll 		data->m = NULL;
   3775  1.29.2.2  skrll 	}
   3776  1.29.2.2  skrll 	wakeup(&ring->desc[pkt->hdr.idx]);
   3777  1.29.2.2  skrll }
   3778  1.29.2.2  skrll 
   3779  1.29.2.2  skrll #if 0
   3780  1.29.2.2  skrll /*
   3781  1.29.2.2  skrll  * necessary only for block ack mode
   3782  1.29.2.2  skrll  */
   3783  1.29.2.2  skrll void
   3784  1.29.2.2  skrll iwm_update_sched(struct iwm_softc *sc, int qid, int idx, uint8_t sta_id,
   3785  1.29.2.2  skrll 	uint16_t len)
   3786  1.29.2.2  skrll {
   3787  1.29.2.2  skrll 	struct iwm_agn_scd_bc_tbl *scd_bc_tbl;
   3788  1.29.2.2  skrll 	uint16_t w_val;
   3789  1.29.2.2  skrll 
   3790  1.29.2.2  skrll 	scd_bc_tbl = sc->sched_dma.vaddr;
   3791  1.29.2.2  skrll 
   3792  1.29.2.2  skrll 	len += 8; /* magic numbers came naturally from paris */
   3793  1.29.2.2  skrll 	if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DW_BC_TABLE)
   3794  1.29.2.2  skrll 		len = roundup(len, 4) / 4;
   3795  1.29.2.2  skrll 
   3796  1.29.2.2  skrll 	w_val = htole16(sta_id << 12 | len);
   3797  1.29.2.2  skrll 
   3798  1.29.2.2  skrll 	/* Update TX scheduler. */
   3799  1.29.2.2  skrll 	scd_bc_tbl[qid].tfd_offset[idx] = w_val;
   3800  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
   3801  1.29.2.2  skrll 	    (char *)(void *)w - (char *)(void *)sc->sched_dma.vaddr,
   3802  1.29.2.2  skrll 	    sizeof(uint16_t), BUS_DMASYNC_PREWRITE);
   3803  1.29.2.2  skrll 
   3804  1.29.2.2  skrll 	/* I really wonder what this is ?!? */
   3805  1.29.2.2  skrll 	if (idx < IWM_TFD_QUEUE_SIZE_BC_DUP) {
   3806  1.29.2.2  skrll 		scd_bc_tbl[qid].tfd_offset[IWM_TFD_QUEUE_SIZE_MAX + idx] = w_val;
   3807  1.29.2.2  skrll 		bus_dmamap_sync(sc->sc_dmat, sc->sched_dma.map,
   3808  1.29.2.2  skrll 		    (char *)(void *)(w + IWM_TFD_QUEUE_SIZE_MAX) -
   3809  1.29.2.2  skrll 		    (char *)(void *)sc->sched_dma.vaddr,
   3810  1.29.2.2  skrll 		    sizeof (uint16_t), BUS_DMASYNC_PREWRITE);
   3811  1.29.2.2  skrll 	}
   3812  1.29.2.2  skrll }
   3813  1.29.2.2  skrll #endif
   3814  1.29.2.2  skrll 
   3815  1.29.2.2  skrll /*
   3816  1.29.2.2  skrll  * Fill in various bit for management frames, and leave them
   3817  1.29.2.2  skrll  * unfilled for data frames (firmware takes care of that).
   3818  1.29.2.2  skrll  * Return the selected TX rate.
   3819  1.29.2.2  skrll  */
   3820  1.29.2.2  skrll static const struct iwm_rate *
   3821  1.29.2.2  skrll iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node *in,
   3822  1.29.2.2  skrll 	struct ieee80211_frame *wh, struct iwm_tx_cmd *tx)
   3823  1.29.2.2  skrll {
   3824  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   3825  1.29.2.2  skrll 	struct ieee80211_node *ni = &in->in_ni;
   3826  1.29.2.2  skrll 	const struct iwm_rate *rinfo;
   3827  1.29.2.2  skrll 	int type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
   3828  1.29.2.2  skrll 	int ridx, rate_flags;
   3829  1.29.2.2  skrll 	int nrates = ni->ni_rates.rs_nrates;
   3830  1.29.2.2  skrll 
   3831  1.29.2.2  skrll 	tx->rts_retry_limit = IWM_RTS_DFAULT_RETRY_LIMIT;
   3832  1.29.2.2  skrll 	tx->data_retry_limit = IWM_DEFAULT_TX_RETRY;
   3833  1.29.2.2  skrll 
   3834  1.29.2.2  skrll 	if (type != IEEE80211_FC0_TYPE_DATA) {
   3835  1.29.2.2  skrll 		/* for non-data, use the lowest supported rate */
   3836  1.29.2.2  skrll 		ridx = (ic->ic_curmode == IEEE80211_MODE_11A) ?
   3837  1.29.2.2  skrll 		    IWM_RIDX_OFDM : IWM_RIDX_CCK;
   3838  1.29.2.2  skrll 	} else if (ic->ic_fixed_rate != -1) {
   3839  1.29.2.2  skrll 		ridx = sc->sc_fixed_ridx;
   3840  1.29.2.2  skrll 	} else {
   3841  1.29.2.2  skrll 		/* for data frames, use RS table */
   3842  1.29.2.2  skrll 		tx->initial_rate_index = (nrates - 1) - ni->ni_txrate;
   3843  1.29.2.2  skrll 		tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
   3844  1.29.2.2  skrll 		DPRINTFN(12, ("start with txrate %d\n", tx->initial_rate_index));
   3845  1.29.2.2  skrll 		ridx = in->in_ridx[ni->ni_txrate];
   3846  1.29.2.2  skrll 		return &iwm_rates[ridx];
   3847  1.29.2.2  skrll 	}
   3848  1.29.2.2  skrll 
   3849  1.29.2.2  skrll 	rinfo = &iwm_rates[ridx];
   3850  1.29.2.2  skrll 	rate_flags = 1 << IWM_RATE_MCS_ANT_POS;
   3851  1.29.2.2  skrll 	if (IWM_RIDX_IS_CCK(ridx))
   3852  1.29.2.2  skrll 		rate_flags |= IWM_RATE_MCS_CCK_MSK;
   3853  1.29.2.2  skrll 	tx->rate_n_flags = htole32(rate_flags | rinfo->plcp);
   3854  1.29.2.2  skrll 
   3855  1.29.2.2  skrll 	return rinfo;
   3856  1.29.2.2  skrll }
   3857  1.29.2.2  skrll 
   3858  1.29.2.2  skrll #define TB0_SIZE 16
   3859  1.29.2.2  skrll static int
   3860  1.29.2.2  skrll iwm_tx(struct iwm_softc *sc, struct mbuf *m, struct ieee80211_node *ni, int ac)
   3861  1.29.2.2  skrll {
   3862  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   3863  1.29.2.2  skrll 	struct iwm_node *in = (void *)ni;
   3864  1.29.2.2  skrll 	struct iwm_tx_ring *ring;
   3865  1.29.2.2  skrll 	struct iwm_tx_data *data;
   3866  1.29.2.2  skrll 	struct iwm_tfd *desc;
   3867  1.29.2.2  skrll 	struct iwm_device_cmd *cmd;
   3868  1.29.2.2  skrll 	struct iwm_tx_cmd *tx;
   3869  1.29.2.2  skrll 	struct ieee80211_frame *wh;
   3870  1.29.2.2  skrll 	struct ieee80211_key *k = NULL;
   3871  1.29.2.2  skrll 	struct mbuf *m1;
   3872  1.29.2.2  skrll 	const struct iwm_rate *rinfo;
   3873  1.29.2.2  skrll 	uint32_t flags;
   3874  1.29.2.2  skrll 	u_int hdrlen;
   3875  1.29.2.2  skrll 	bus_dma_segment_t *seg;
   3876  1.29.2.2  skrll 	uint8_t tid, type;
   3877  1.29.2.2  skrll 	int i, totlen, error, pad;
   3878  1.29.2.2  skrll 	int hdrlen2;
   3879  1.29.2.2  skrll 
   3880  1.29.2.2  skrll 	wh = mtod(m, struct ieee80211_frame *);
   3881  1.29.2.2  skrll 	hdrlen = ieee80211_anyhdrsize(wh);
   3882  1.29.2.2  skrll 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
   3883  1.29.2.2  skrll 
   3884  1.29.2.2  skrll 	hdrlen2 = (ieee80211_has_qos(wh)) ?
   3885  1.29.2.2  skrll 	    sizeof (struct ieee80211_qosframe) :
   3886  1.29.2.2  skrll 	    sizeof (struct ieee80211_frame);
   3887  1.29.2.2  skrll 
   3888  1.29.2.2  skrll 	if (hdrlen != hdrlen2)
   3889  1.29.2.2  skrll 		DPRINTF(("%s: hdrlen error (%d != %d)\n",
   3890  1.29.2.2  skrll 		    DEVNAME(sc), hdrlen, hdrlen2));
   3891  1.29.2.2  skrll 
   3892  1.29.2.2  skrll 	tid = 0;
   3893  1.29.2.2  skrll 
   3894  1.29.2.2  skrll 	ring = &sc->txq[ac];
   3895  1.29.2.2  skrll 	desc = &ring->desc[ring->cur];
   3896  1.29.2.2  skrll 	memset(desc, 0, sizeof(*desc));
   3897  1.29.2.2  skrll 	data = &ring->data[ring->cur];
   3898  1.29.2.2  skrll 
   3899  1.29.2.2  skrll 	/* Fill out iwm_tx_cmd to send to the firmware */
   3900  1.29.2.2  skrll 	cmd = &ring->cmd[ring->cur];
   3901  1.29.2.2  skrll 	cmd->hdr.code = IWM_TX_CMD;
   3902  1.29.2.2  skrll 	cmd->hdr.flags = 0;
   3903  1.29.2.2  skrll 	cmd->hdr.qid = ring->qid;
   3904  1.29.2.2  skrll 	cmd->hdr.idx = ring->cur;
   3905  1.29.2.2  skrll 
   3906  1.29.2.2  skrll 	tx = (void *)cmd->data;
   3907  1.29.2.2  skrll 	memset(tx, 0, sizeof(*tx));
   3908  1.29.2.2  skrll 
   3909  1.29.2.2  skrll 	rinfo = iwm_tx_fill_cmd(sc, in, wh, tx);
   3910  1.29.2.2  skrll 
   3911  1.29.2.2  skrll 	if (sc->sc_drvbpf != NULL) {
   3912  1.29.2.2  skrll 		struct iwm_tx_radiotap_header *tap = &sc->sc_txtap;
   3913  1.29.2.2  skrll 
   3914  1.29.2.2  skrll 		tap->wt_flags = 0;
   3915  1.29.2.2  skrll 		tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq);
   3916  1.29.2.2  skrll 		tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags);
   3917  1.29.2.2  skrll 		tap->wt_rate = rinfo->rate;
   3918  1.29.2.2  skrll 		tap->wt_hwqueue = ac;
   3919  1.29.2.2  skrll 		if (wh->i_fc[1] & IEEE80211_FC1_WEP)
   3920  1.29.2.2  skrll 			tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP;
   3921  1.29.2.2  skrll 
   3922  1.29.2.2  skrll 		bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m);
   3923  1.29.2.2  skrll 	}
   3924  1.29.2.2  skrll 
   3925  1.29.2.2  skrll 	/* Encrypt the frame if need be. */
   3926  1.29.2.2  skrll 	if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
   3927  1.29.2.2  skrll 		k = ieee80211_crypto_encap(ic, ni, m);
   3928  1.29.2.2  skrll 		if (k == NULL) {
   3929  1.29.2.2  skrll 			m_freem(m);
   3930  1.29.2.2  skrll 			return ENOBUFS;
   3931  1.29.2.2  skrll 		}
   3932  1.29.2.2  skrll 		/* Packet header may have moved, reset our local pointer. */
   3933  1.29.2.2  skrll 		wh = mtod(m, struct ieee80211_frame *);
   3934  1.29.2.2  skrll 	}
   3935  1.29.2.2  skrll 	totlen = m->m_pkthdr.len;
   3936  1.29.2.2  skrll 
   3937  1.29.2.2  skrll 	flags = 0;
   3938  1.29.2.2  skrll 	if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) {
   3939  1.29.2.2  skrll 		flags |= IWM_TX_CMD_FLG_ACK;
   3940  1.29.2.2  skrll 	}
   3941  1.29.2.2  skrll 
   3942  1.29.2.2  skrll 	if (type != IEEE80211_FC0_TYPE_DATA
   3943  1.29.2.2  skrll 	    && (totlen + IEEE80211_CRC_LEN > ic->ic_rtsthreshold)
   3944  1.29.2.2  skrll 	    && !IEEE80211_IS_MULTICAST(wh->i_addr1)) {
   3945  1.29.2.2  skrll 		flags |= IWM_TX_CMD_FLG_PROT_REQUIRE;
   3946  1.29.2.2  skrll 	}
   3947  1.29.2.2  skrll 
   3948  1.29.2.2  skrll 	if (IEEE80211_IS_MULTICAST(wh->i_addr1) ||
   3949  1.29.2.2  skrll 	    type != IEEE80211_FC0_TYPE_DATA)
   3950  1.29.2.2  skrll 		tx->sta_id = sc->sc_aux_sta.sta_id;
   3951  1.29.2.2  skrll 	else
   3952  1.29.2.2  skrll 		tx->sta_id = IWM_STATION_ID;
   3953  1.29.2.2  skrll 
   3954  1.29.2.2  skrll 	if (type == IEEE80211_FC0_TYPE_MGT) {
   3955  1.29.2.2  skrll 		uint8_t subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
   3956  1.29.2.2  skrll 
   3957  1.29.2.2  skrll 		if (subtype == IEEE80211_FC0_SUBTYPE_ASSOC_REQ ||
   3958  1.29.2.2  skrll 		    subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ)
   3959  1.29.2.2  skrll 			tx->pm_frame_timeout = htole16(3);
   3960  1.29.2.2  skrll 		else
   3961  1.29.2.2  skrll 			tx->pm_frame_timeout = htole16(2);
   3962  1.29.2.2  skrll 	} else {
   3963  1.29.2.2  skrll 		tx->pm_frame_timeout = htole16(0);
   3964  1.29.2.2  skrll 	}
   3965  1.29.2.2  skrll 
   3966  1.29.2.2  skrll 	if (hdrlen & 3) {
   3967  1.29.2.2  skrll 		/* First segment length must be a multiple of 4. */
   3968  1.29.2.2  skrll 		flags |= IWM_TX_CMD_FLG_MH_PAD;
   3969  1.29.2.2  skrll 		pad = 4 - (hdrlen & 3);
   3970  1.29.2.2  skrll 	} else
   3971  1.29.2.2  skrll 		pad = 0;
   3972  1.29.2.2  skrll 
   3973  1.29.2.2  skrll 	tx->driver_txop = 0;
   3974  1.29.2.2  skrll 	tx->next_frame_len = 0;
   3975  1.29.2.2  skrll 
   3976  1.29.2.2  skrll 	tx->len = htole16(totlen);
   3977  1.29.2.2  skrll 	tx->tid_tspec = tid;
   3978  1.29.2.2  skrll 	tx->life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE);
   3979  1.29.2.2  skrll 
   3980  1.29.2.2  skrll 	/* Set physical address of "scratch area". */
   3981  1.29.2.2  skrll 	tx->dram_lsb_ptr = htole32(data->scratch_paddr);
   3982  1.29.2.2  skrll 	tx->dram_msb_ptr = iwm_get_dma_hi_addr(data->scratch_paddr);
   3983  1.29.2.2  skrll 
   3984  1.29.2.2  skrll 	/* Copy 802.11 header in TX command. */
   3985  1.29.2.2  skrll 	memcpy(((uint8_t *)tx) + sizeof(*tx), wh, hdrlen);
   3986  1.29.2.2  skrll 
   3987  1.29.2.2  skrll 	flags |= IWM_TX_CMD_FLG_BT_DIS | IWM_TX_CMD_FLG_SEQ_CTL;
   3988  1.29.2.2  skrll 
   3989  1.29.2.2  skrll 	tx->sec_ctl = 0;
   3990  1.29.2.2  skrll 	tx->tx_flags |= htole32(flags);
   3991  1.29.2.2  skrll 
   3992  1.29.2.2  skrll 	/* Trim 802.11 header. */
   3993  1.29.2.2  skrll 	m_adj(m, hdrlen);
   3994  1.29.2.2  skrll 
   3995  1.29.2.2  skrll 	error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
   3996  1.29.2.2  skrll 	    BUS_DMA_NOWAIT | BUS_DMA_WRITE);
   3997  1.29.2.2  skrll 	if (error != 0) {
   3998  1.29.2.2  skrll 		if (error != EFBIG) {
   3999  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   4000  1.29.2.2  skrll 			    "can't map mbuf (error %d)\n", error);
   4001  1.29.2.2  skrll 			m_freem(m);
   4002  1.29.2.2  skrll 			return error;
   4003  1.29.2.2  skrll 		}
   4004  1.29.2.2  skrll 		/* Too many DMA segments, linearize mbuf. */
   4005  1.29.2.2  skrll 		MGETHDR(m1, M_DONTWAIT, MT_DATA);
   4006  1.29.2.2  skrll 		if (m1 == NULL) {
   4007  1.29.2.2  skrll 			m_freem(m);
   4008  1.29.2.2  skrll 			return ENOBUFS;
   4009  1.29.2.2  skrll 		}
   4010  1.29.2.2  skrll 		if (m->m_pkthdr.len > MHLEN) {
   4011  1.29.2.2  skrll 			MCLGET(m1, M_DONTWAIT);
   4012  1.29.2.2  skrll 			if (!(m1->m_flags & M_EXT)) {
   4013  1.29.2.2  skrll 				m_freem(m);
   4014  1.29.2.2  skrll 				m_freem(m1);
   4015  1.29.2.2  skrll 				return ENOBUFS;
   4016  1.29.2.2  skrll 			}
   4017  1.29.2.2  skrll 		}
   4018  1.29.2.2  skrll 		m_copydata(m, 0, m->m_pkthdr.len, mtod(m1, void *));
   4019  1.29.2.2  skrll 		m1->m_pkthdr.len = m1->m_len = m->m_pkthdr.len;
   4020  1.29.2.2  skrll 		m_freem(m);
   4021  1.29.2.2  skrll 		m = m1;
   4022  1.29.2.2  skrll 
   4023  1.29.2.2  skrll 		error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m,
   4024  1.29.2.2  skrll 		    BUS_DMA_NOWAIT | BUS_DMA_WRITE);
   4025  1.29.2.2  skrll 		if (error != 0) {
   4026  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   4027  1.29.2.2  skrll 			    "can't map mbuf (error %d)\n", error);
   4028  1.29.2.2  skrll 			m_freem(m);
   4029  1.29.2.2  skrll 			return error;
   4030  1.29.2.2  skrll 		}
   4031  1.29.2.2  skrll 	}
   4032  1.29.2.2  skrll 	data->m = m;
   4033  1.29.2.2  skrll 	data->in = in;
   4034  1.29.2.2  skrll 	data->done = 0;
   4035  1.29.2.2  skrll 
   4036  1.29.2.2  skrll 	DPRINTFN(8, ("sending txd %p, in %p\n", data, data->in));
   4037  1.29.2.2  skrll 	KASSERT(data->in != NULL);
   4038  1.29.2.2  skrll 
   4039  1.29.2.2  skrll 	DPRINTFN(8, ("sending data: qid=%d idx=%d len=%d nsegs=%d\n",
   4040  1.29.2.2  skrll 	    ring->qid, ring->cur, totlen, data->map->dm_nsegs));
   4041  1.29.2.2  skrll 
   4042  1.29.2.2  skrll 	/* Fill TX descriptor. */
   4043  1.29.2.2  skrll 	desc->num_tbs = 2 + data->map->dm_nsegs;
   4044  1.29.2.2  skrll 
   4045  1.29.2.2  skrll 	desc->tbs[0].lo = htole32(data->cmd_paddr);
   4046  1.29.2.2  skrll 	desc->tbs[0].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) |
   4047  1.29.2.2  skrll 	    (TB0_SIZE << 4);
   4048  1.29.2.2  skrll 	desc->tbs[1].lo = htole32(data->cmd_paddr + TB0_SIZE);
   4049  1.29.2.2  skrll 	desc->tbs[1].hi_n_len = htole16(iwm_get_dma_hi_addr(data->cmd_paddr)) |
   4050  1.29.2.2  skrll 	    ((sizeof(struct iwm_cmd_header) + sizeof(*tx)
   4051  1.29.2.2  skrll 	      + hdrlen + pad - TB0_SIZE) << 4);
   4052  1.29.2.2  skrll 
   4053  1.29.2.2  skrll 	/* Other DMA segments are for data payload. */
   4054  1.29.2.2  skrll 	seg = data->map->dm_segs;
   4055  1.29.2.2  skrll 	for (i = 0; i < data->map->dm_nsegs; i++, seg++) {
   4056  1.29.2.2  skrll 		desc->tbs[i+2].lo = htole32(seg->ds_addr);
   4057  1.29.2.2  skrll 		desc->tbs[i+2].hi_n_len = \
   4058  1.29.2.2  skrll 		    htole16(iwm_get_dma_hi_addr(seg->ds_addr))
   4059  1.29.2.2  skrll 		    | ((seg->ds_len) << 4);
   4060  1.29.2.2  skrll 	}
   4061  1.29.2.2  skrll 
   4062  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
   4063  1.29.2.2  skrll 	    BUS_DMASYNC_PREWRITE);
   4064  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, ring->cmd_dma.map,
   4065  1.29.2.2  skrll 	    (char *)(void *)cmd - (char *)(void *)ring->cmd_dma.vaddr,
   4066  1.29.2.2  skrll 	    sizeof (*cmd), BUS_DMASYNC_PREWRITE);
   4067  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, ring->desc_dma.map,
   4068  1.29.2.2  skrll 	    (char *)(void *)desc - (char *)(void *)ring->desc_dma.vaddr,
   4069  1.29.2.2  skrll 	    sizeof (*desc), BUS_DMASYNC_PREWRITE);
   4070  1.29.2.2  skrll 
   4071  1.29.2.2  skrll #if 0
   4072  1.29.2.2  skrll 	iwm_update_sched(sc, ring->qid, ring->cur, tx->sta_id, le16toh(tx->len));
   4073  1.29.2.2  skrll #endif
   4074  1.29.2.2  skrll 
   4075  1.29.2.2  skrll 	/* Kick TX ring. */
   4076  1.29.2.2  skrll 	ring->cur = (ring->cur + 1) % IWM_TX_RING_COUNT;
   4077  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_HBUS_TARG_WRPTR, ring->qid << 8 | ring->cur);
   4078  1.29.2.2  skrll 
   4079  1.29.2.2  skrll 	/* Mark TX ring as full if we reach a certain threshold. */
   4080  1.29.2.2  skrll 	if (++ring->queued > IWM_TX_RING_HIMARK) {
   4081  1.29.2.2  skrll 		sc->qfullmsk |= 1 << ring->qid;
   4082  1.29.2.2  skrll 	}
   4083  1.29.2.2  skrll 
   4084  1.29.2.2  skrll 	return 0;
   4085  1.29.2.2  skrll }
   4086  1.29.2.2  skrll 
   4087  1.29.2.2  skrll #if 0
   4088  1.29.2.2  skrll /* not necessary? */
   4089  1.29.2.2  skrll static int
   4090  1.29.2.2  skrll iwm_mvm_flush_tx_path(struct iwm_softc *sc, int tfd_msk, int sync)
   4091  1.29.2.2  skrll {
   4092  1.29.2.2  skrll 	struct iwm_tx_path_flush_cmd flush_cmd = {
   4093  1.29.2.2  skrll 		.queues_ctl = htole32(tfd_msk),
   4094  1.29.2.2  skrll 		.flush_ctl = htole16(IWM_DUMP_TX_FIFO_FLUSH),
   4095  1.29.2.2  skrll 	};
   4096  1.29.2.2  skrll 	int ret;
   4097  1.29.2.2  skrll 
   4098  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_pdu(sc, IWM_TXPATH_FLUSH,
   4099  1.29.2.2  skrll 	    sync ? IWM_CMD_SYNC : IWM_CMD_ASYNC,
   4100  1.29.2.2  skrll 	    sizeof(flush_cmd), &flush_cmd);
   4101  1.29.2.2  skrll 	if (ret)
   4102  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "Flushing tx queue failed: %d\n",
   4103  1.29.2.2  skrll 		    ret);
   4104  1.29.2.2  skrll 	return ret;
   4105  1.29.2.2  skrll }
   4106  1.29.2.2  skrll #endif
   4107  1.29.2.2  skrll 
   4108  1.29.2.2  skrll 
   4109  1.29.2.2  skrll /*
   4110  1.29.2.2  skrll  * BEGIN mvm/power.c
   4111  1.29.2.2  skrll  */
   4112  1.29.2.2  skrll 
   4113  1.29.2.2  skrll #define IWM_POWER_KEEP_ALIVE_PERIOD_SEC    25
   4114  1.29.2.2  skrll 
   4115  1.29.2.2  skrll static int
   4116  1.29.2.2  skrll iwm_mvm_beacon_filter_send_cmd(struct iwm_softc *sc,
   4117  1.29.2.2  skrll 	struct iwm_beacon_filter_cmd *cmd)
   4118  1.29.2.2  skrll {
   4119  1.29.2.2  skrll 	int ret;
   4120  1.29.2.2  skrll 
   4121  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_pdu(sc, IWM_REPLY_BEACON_FILTERING_CMD,
   4122  1.29.2.2  skrll 	    IWM_CMD_SYNC, sizeof(struct iwm_beacon_filter_cmd), cmd);
   4123  1.29.2.2  skrll 
   4124  1.29.2.2  skrll 	if (!ret) {
   4125  1.29.2.2  skrll 		DPRINTF(("ba_enable_beacon_abort is: %d\n",
   4126  1.29.2.2  skrll 		    le32toh(cmd->ba_enable_beacon_abort)));
   4127  1.29.2.2  skrll 		DPRINTF(("ba_escape_timer is: %d\n",
   4128  1.29.2.2  skrll 		    le32toh(cmd->ba_escape_timer)));
   4129  1.29.2.2  skrll 		DPRINTF(("bf_debug_flag is: %d\n",
   4130  1.29.2.2  skrll 		    le32toh(cmd->bf_debug_flag)));
   4131  1.29.2.2  skrll 		DPRINTF(("bf_enable_beacon_filter is: %d\n",
   4132  1.29.2.2  skrll 		    le32toh(cmd->bf_enable_beacon_filter)));
   4133  1.29.2.2  skrll 		DPRINTF(("bf_energy_delta is: %d\n",
   4134  1.29.2.2  skrll 		    le32toh(cmd->bf_energy_delta)));
   4135  1.29.2.2  skrll 		DPRINTF(("bf_escape_timer is: %d\n",
   4136  1.29.2.2  skrll 		    le32toh(cmd->bf_escape_timer)));
   4137  1.29.2.2  skrll 		DPRINTF(("bf_roaming_energy_delta is: %d\n",
   4138  1.29.2.2  skrll 		    le32toh(cmd->bf_roaming_energy_delta)));
   4139  1.29.2.2  skrll 		DPRINTF(("bf_roaming_state is: %d\n",
   4140  1.29.2.2  skrll 		    le32toh(cmd->bf_roaming_state)));
   4141  1.29.2.2  skrll 		DPRINTF(("bf_temp_threshold is: %d\n",
   4142  1.29.2.2  skrll 		    le32toh(cmd->bf_temp_threshold)));
   4143  1.29.2.2  skrll 		DPRINTF(("bf_temp_fast_filter is: %d\n",
   4144  1.29.2.2  skrll 		    le32toh(cmd->bf_temp_fast_filter)));
   4145  1.29.2.2  skrll 		DPRINTF(("bf_temp_slow_filter is: %d\n",
   4146  1.29.2.2  skrll 		    le32toh(cmd->bf_temp_slow_filter)));
   4147  1.29.2.2  skrll 	}
   4148  1.29.2.2  skrll 	return ret;
   4149  1.29.2.2  skrll }
   4150  1.29.2.2  skrll 
   4151  1.29.2.2  skrll static void
   4152  1.29.2.2  skrll iwm_mvm_beacon_filter_set_cqm_params(struct iwm_softc *sc,
   4153  1.29.2.2  skrll 	struct iwm_node *in, struct iwm_beacon_filter_cmd *cmd)
   4154  1.29.2.2  skrll {
   4155  1.29.2.2  skrll 	cmd->ba_enable_beacon_abort = htole32(sc->sc_bf.ba_enabled);
   4156  1.29.2.2  skrll }
   4157  1.29.2.2  skrll 
   4158  1.29.2.2  skrll static int
   4159  1.29.2.2  skrll iwm_mvm_update_beacon_abort(struct iwm_softc *sc, struct iwm_node *in,
   4160  1.29.2.2  skrll 	int enable)
   4161  1.29.2.2  skrll {
   4162  1.29.2.2  skrll 	struct iwm_beacon_filter_cmd cmd = {
   4163  1.29.2.2  skrll 		IWM_BF_CMD_CONFIG_DEFAULTS,
   4164  1.29.2.2  skrll 		.bf_enable_beacon_filter = htole32(1),
   4165  1.29.2.2  skrll 		.ba_enable_beacon_abort = htole32(enable),
   4166  1.29.2.2  skrll 	};
   4167  1.29.2.2  skrll 
   4168  1.29.2.2  skrll 	if (!sc->sc_bf.bf_enabled)
   4169  1.29.2.2  skrll 		return 0;
   4170  1.29.2.2  skrll 
   4171  1.29.2.2  skrll 	sc->sc_bf.ba_enabled = enable;
   4172  1.29.2.2  skrll 	iwm_mvm_beacon_filter_set_cqm_params(sc, in, &cmd);
   4173  1.29.2.2  skrll 	return iwm_mvm_beacon_filter_send_cmd(sc, &cmd);
   4174  1.29.2.2  skrll }
   4175  1.29.2.2  skrll 
   4176  1.29.2.2  skrll static void
   4177  1.29.2.2  skrll iwm_mvm_power_log(struct iwm_softc *sc, struct iwm_mac_power_cmd *cmd)
   4178  1.29.2.2  skrll {
   4179  1.29.2.2  skrll 	DPRINTF(("Sending power table command on mac id 0x%X for "
   4180  1.29.2.2  skrll 	    "power level %d, flags = 0x%X\n",
   4181  1.29.2.2  skrll 	    cmd->id_and_color, IWM_POWER_SCHEME_CAM, le16toh(cmd->flags)));
   4182  1.29.2.2  skrll 	DPRINTF(("Keep alive = %u sec\n", le16toh(cmd->keep_alive_seconds)));
   4183  1.29.2.2  skrll 
   4184  1.29.2.2  skrll 	if (!(cmd->flags & htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK))) {
   4185  1.29.2.2  skrll 		DPRINTF(("Disable power management\n"));
   4186  1.29.2.2  skrll 		return;
   4187  1.29.2.2  skrll 	}
   4188  1.29.2.2  skrll 	KASSERT(0);
   4189  1.29.2.2  skrll 
   4190  1.29.2.2  skrll #if 0
   4191  1.29.2.2  skrll 	DPRINTF(mvm, "Rx timeout = %u usec\n",
   4192  1.29.2.2  skrll 			le32_to_cpu(cmd->rx_data_timeout));
   4193  1.29.2.2  skrll 	DPRINTF(mvm, "Tx timeout = %u usec\n",
   4194  1.29.2.2  skrll 			le32_to_cpu(cmd->tx_data_timeout));
   4195  1.29.2.2  skrll 	if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_SKIP_OVER_DTIM_MSK))
   4196  1.29.2.2  skrll 		DPRINTF(mvm, "DTIM periods to skip = %u\n",
   4197  1.29.2.2  skrll 				cmd->skip_dtim_periods);
   4198  1.29.2.2  skrll 	if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_LPRX_ENA_MSK))
   4199  1.29.2.2  skrll 		DPRINTF(mvm, "LP RX RSSI threshold = %u\n",
   4200  1.29.2.2  skrll 				cmd->lprx_rssi_threshold);
   4201  1.29.2.2  skrll 	if (cmd->flags & cpu_to_le16(IWM_POWER_FLAGS_ADVANCE_PM_ENA_MSK)) {
   4202  1.29.2.2  skrll 		DPRINTF(mvm, "uAPSD enabled\n");
   4203  1.29.2.2  skrll 		DPRINTF(mvm, "Rx timeout (uAPSD) = %u usec\n",
   4204  1.29.2.2  skrll 				le32_to_cpu(cmd->rx_data_timeout_uapsd));
   4205  1.29.2.2  skrll 		DPRINTF(mvm, "Tx timeout (uAPSD) = %u usec\n",
   4206  1.29.2.2  skrll 				le32_to_cpu(cmd->tx_data_timeout_uapsd));
   4207  1.29.2.2  skrll 		DPRINTF(mvm, "QNDP TID = %d\n", cmd->qndp_tid);
   4208  1.29.2.2  skrll 		DPRINTF(mvm, "ACs flags = 0x%x\n", cmd->uapsd_ac_flags);
   4209  1.29.2.2  skrll 		DPRINTF(mvm, "Max SP = %d\n", cmd->uapsd_max_sp);
   4210  1.29.2.2  skrll 	}
   4211  1.29.2.2  skrll #endif
   4212  1.29.2.2  skrll }
   4213  1.29.2.2  skrll 
   4214  1.29.2.2  skrll static void
   4215  1.29.2.2  skrll iwm_mvm_power_build_cmd(struct iwm_softc *sc, struct iwm_node *in,
   4216  1.29.2.2  skrll 	struct iwm_mac_power_cmd *cmd)
   4217  1.29.2.2  skrll {
   4218  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   4219  1.29.2.2  skrll 	struct ieee80211_node *ni = &in->in_ni;
   4220  1.29.2.2  skrll 	int dtimper, dtimper_msec;
   4221  1.29.2.2  skrll 	int keep_alive;
   4222  1.29.2.2  skrll 
   4223  1.29.2.2  skrll 	cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id,
   4224  1.29.2.2  skrll 	    in->in_color));
   4225  1.29.2.2  skrll 	dtimper = ic->ic_dtim_period ?: 1;
   4226  1.29.2.2  skrll 
   4227  1.29.2.2  skrll 	/*
   4228  1.29.2.2  skrll 	 * Regardless of power management state the driver must set
   4229  1.29.2.2  skrll 	 * keep alive period. FW will use it for sending keep alive NDPs
   4230  1.29.2.2  skrll 	 * immediately after association. Check that keep alive period
   4231  1.29.2.2  skrll 	 * is at least 3 * DTIM
   4232  1.29.2.2  skrll 	 */
   4233  1.29.2.2  skrll 	dtimper_msec = dtimper * ni->ni_intval;
   4234  1.29.2.2  skrll 	keep_alive
   4235  1.29.2.2  skrll 	    = MAX(3 * dtimper_msec, 1000 * IWM_POWER_KEEP_ALIVE_PERIOD_SEC);
   4236  1.29.2.2  skrll 	keep_alive = roundup(keep_alive, 1000) / 1000;
   4237  1.29.2.2  skrll 	cmd->keep_alive_seconds = htole16(keep_alive);
   4238  1.29.2.2  skrll }
   4239  1.29.2.2  skrll 
   4240  1.29.2.2  skrll static int
   4241  1.29.2.2  skrll iwm_mvm_power_mac_update_mode(struct iwm_softc *sc, struct iwm_node *in)
   4242  1.29.2.2  skrll {
   4243  1.29.2.2  skrll 	int ret;
   4244  1.29.2.2  skrll 	int ba_enable;
   4245  1.29.2.2  skrll 	struct iwm_mac_power_cmd cmd;
   4246  1.29.2.2  skrll 
   4247  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   4248  1.29.2.2  skrll 
   4249  1.29.2.2  skrll 	iwm_mvm_power_build_cmd(sc, in, &cmd);
   4250  1.29.2.2  skrll 	iwm_mvm_power_log(sc, &cmd);
   4251  1.29.2.2  skrll 
   4252  1.29.2.2  skrll 	if ((ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_PM_POWER_TABLE,
   4253  1.29.2.2  skrll 	    IWM_CMD_SYNC, sizeof(cmd), &cmd)) != 0)
   4254  1.29.2.2  skrll 		return ret;
   4255  1.29.2.2  skrll 
   4256  1.29.2.2  skrll 	ba_enable = !!(cmd.flags &
   4257  1.29.2.2  skrll 	    htole16(IWM_POWER_FLAGS_POWER_MANAGEMENT_ENA_MSK));
   4258  1.29.2.2  skrll 	return iwm_mvm_update_beacon_abort(sc, in, ba_enable);
   4259  1.29.2.2  skrll }
   4260  1.29.2.2  skrll 
   4261  1.29.2.2  skrll static int
   4262  1.29.2.2  skrll iwm_mvm_power_update_device(struct iwm_softc *sc)
   4263  1.29.2.2  skrll {
   4264  1.29.2.2  skrll 	struct iwm_device_power_cmd cmd = {
   4265  1.29.2.2  skrll 		.flags = htole16(IWM_DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK),
   4266  1.29.2.2  skrll 	};
   4267  1.29.2.2  skrll 
   4268  1.29.2.2  skrll 	if (!(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_DEVICE_PS_CMD))
   4269  1.29.2.2  skrll 		return 0;
   4270  1.29.2.2  skrll 
   4271  1.29.2.2  skrll 	cmd.flags |= htole16(IWM_DEVICE_POWER_FLAGS_CAM_MSK);
   4272  1.29.2.2  skrll 	DPRINTF(("Sending device power command with flags = 0x%X\n", cmd.flags));
   4273  1.29.2.2  skrll 
   4274  1.29.2.2  skrll 	return iwm_mvm_send_cmd_pdu(sc,
   4275  1.29.2.2  skrll 	    IWM_POWER_TABLE_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd);
   4276  1.29.2.2  skrll }
   4277  1.29.2.2  skrll 
   4278  1.29.2.2  skrll static int
   4279  1.29.2.2  skrll iwm_mvm_enable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
   4280  1.29.2.2  skrll {
   4281  1.29.2.2  skrll 	struct iwm_beacon_filter_cmd cmd = {
   4282  1.29.2.2  skrll 		IWM_BF_CMD_CONFIG_DEFAULTS,
   4283  1.29.2.2  skrll 		.bf_enable_beacon_filter = htole32(1),
   4284  1.29.2.2  skrll 	};
   4285  1.29.2.2  skrll 	int ret;
   4286  1.29.2.2  skrll 
   4287  1.29.2.2  skrll 	iwm_mvm_beacon_filter_set_cqm_params(sc, in, &cmd);
   4288  1.29.2.2  skrll 	ret = iwm_mvm_beacon_filter_send_cmd(sc, &cmd);
   4289  1.29.2.2  skrll 
   4290  1.29.2.2  skrll 	if (ret == 0)
   4291  1.29.2.2  skrll 		sc->sc_bf.bf_enabled = 1;
   4292  1.29.2.2  skrll 
   4293  1.29.2.2  skrll 	return ret;
   4294  1.29.2.2  skrll }
   4295  1.29.2.2  skrll 
   4296  1.29.2.2  skrll static int
   4297  1.29.2.2  skrll iwm_mvm_disable_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
   4298  1.29.2.2  skrll {
   4299  1.29.2.2  skrll 	struct iwm_beacon_filter_cmd cmd;
   4300  1.29.2.2  skrll 	int ret;
   4301  1.29.2.2  skrll 
   4302  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   4303  1.29.2.2  skrll 	if ((sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_BF_UPDATED) == 0)
   4304  1.29.2.2  skrll 		return 0;
   4305  1.29.2.2  skrll 
   4306  1.29.2.2  skrll 	ret = iwm_mvm_beacon_filter_send_cmd(sc, &cmd);
   4307  1.29.2.2  skrll 	if (ret == 0)
   4308  1.29.2.2  skrll 		sc->sc_bf.bf_enabled = 0;
   4309  1.29.2.2  skrll 
   4310  1.29.2.2  skrll 	return ret;
   4311  1.29.2.2  skrll }
   4312  1.29.2.2  skrll 
   4313  1.29.2.2  skrll #if 0
   4314  1.29.2.2  skrll static int
   4315  1.29.2.2  skrll iwm_mvm_update_beacon_filter(struct iwm_softc *sc, struct iwm_node *in)
   4316  1.29.2.2  skrll {
   4317  1.29.2.2  skrll 	if (!sc->sc_bf.bf_enabled)
   4318  1.29.2.2  skrll 		return 0;
   4319  1.29.2.2  skrll 
   4320  1.29.2.2  skrll 	return iwm_mvm_enable_beacon_filter(sc, in);
   4321  1.29.2.2  skrll }
   4322  1.29.2.2  skrll #endif
   4323  1.29.2.2  skrll 
   4324  1.29.2.2  skrll /*
   4325  1.29.2.2  skrll  * END mvm/power.c
   4326  1.29.2.2  skrll  */
   4327  1.29.2.2  skrll 
   4328  1.29.2.2  skrll /*
   4329  1.29.2.2  skrll  * BEGIN mvm/sta.c
   4330  1.29.2.2  skrll  */
   4331  1.29.2.2  skrll 
   4332  1.29.2.2  skrll static void
   4333  1.29.2.2  skrll iwm_mvm_add_sta_cmd_v6_to_v5(struct iwm_mvm_add_sta_cmd_v6 *cmd_v6,
   4334  1.29.2.2  skrll 	struct iwm_mvm_add_sta_cmd_v5 *cmd_v5)
   4335  1.29.2.2  skrll {
   4336  1.29.2.2  skrll 	memset(cmd_v5, 0, sizeof(*cmd_v5));
   4337  1.29.2.2  skrll 
   4338  1.29.2.2  skrll 	cmd_v5->add_modify = cmd_v6->add_modify;
   4339  1.29.2.2  skrll 	cmd_v5->tid_disable_tx = cmd_v6->tid_disable_tx;
   4340  1.29.2.2  skrll 	cmd_v5->mac_id_n_color = cmd_v6->mac_id_n_color;
   4341  1.29.2.2  skrll 	memcpy(cmd_v5->addr, cmd_v6->addr, ETHER_ADDR_LEN);
   4342  1.29.2.2  skrll 	cmd_v5->sta_id = cmd_v6->sta_id;
   4343  1.29.2.2  skrll 	cmd_v5->modify_mask = cmd_v6->modify_mask;
   4344  1.29.2.2  skrll 	cmd_v5->station_flags = cmd_v6->station_flags;
   4345  1.29.2.2  skrll 	cmd_v5->station_flags_msk = cmd_v6->station_flags_msk;
   4346  1.29.2.2  skrll 	cmd_v5->add_immediate_ba_tid = cmd_v6->add_immediate_ba_tid;
   4347  1.29.2.2  skrll 	cmd_v5->remove_immediate_ba_tid = cmd_v6->remove_immediate_ba_tid;
   4348  1.29.2.2  skrll 	cmd_v5->add_immediate_ba_ssn = cmd_v6->add_immediate_ba_ssn;
   4349  1.29.2.2  skrll 	cmd_v5->sleep_tx_count = cmd_v6->sleep_tx_count;
   4350  1.29.2.2  skrll 	cmd_v5->sleep_state_flags = cmd_v6->sleep_state_flags;
   4351  1.29.2.2  skrll 	cmd_v5->assoc_id = cmd_v6->assoc_id;
   4352  1.29.2.2  skrll 	cmd_v5->beamform_flags = cmd_v6->beamform_flags;
   4353  1.29.2.2  skrll 	cmd_v5->tfd_queue_msk = cmd_v6->tfd_queue_msk;
   4354  1.29.2.2  skrll }
   4355  1.29.2.2  skrll 
   4356  1.29.2.2  skrll static int
   4357  1.29.2.2  skrll iwm_mvm_send_add_sta_cmd_status(struct iwm_softc *sc,
   4358  1.29.2.2  skrll 	struct iwm_mvm_add_sta_cmd_v6 *cmd, int *status)
   4359  1.29.2.2  skrll {
   4360  1.29.2.2  skrll 	struct iwm_mvm_add_sta_cmd_v5 cmd_v5;
   4361  1.29.2.2  skrll 
   4362  1.29.2.2  skrll 	if (sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_STA_KEY_CMD) {
   4363  1.29.2.2  skrll 		return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA,
   4364  1.29.2.2  skrll 		    sizeof(*cmd), cmd, status);
   4365  1.29.2.2  skrll 	}
   4366  1.29.2.2  skrll 
   4367  1.29.2.2  skrll 	iwm_mvm_add_sta_cmd_v6_to_v5(cmd, &cmd_v5);
   4368  1.29.2.2  skrll 
   4369  1.29.2.2  skrll 	return iwm_mvm_send_cmd_pdu_status(sc, IWM_ADD_STA, sizeof(cmd_v5),
   4370  1.29.2.2  skrll 	    &cmd_v5, status);
   4371  1.29.2.2  skrll }
   4372  1.29.2.2  skrll 
   4373  1.29.2.2  skrll /* send station add/update command to firmware */
   4374  1.29.2.2  skrll static int
   4375  1.29.2.2  skrll iwm_mvm_sta_send_to_fw(struct iwm_softc *sc, struct iwm_node *in, int update)
   4376  1.29.2.2  skrll {
   4377  1.29.2.2  skrll 	struct iwm_mvm_add_sta_cmd_v6 add_sta_cmd;
   4378  1.29.2.2  skrll 	int ret;
   4379  1.29.2.2  skrll 	uint32_t status;
   4380  1.29.2.2  skrll 
   4381  1.29.2.2  skrll 	memset(&add_sta_cmd, 0, sizeof(add_sta_cmd));
   4382  1.29.2.2  skrll 
   4383  1.29.2.2  skrll 	add_sta_cmd.sta_id = IWM_STATION_ID;
   4384  1.29.2.2  skrll 	add_sta_cmd.mac_id_n_color
   4385  1.29.2.2  skrll 	    = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id, in->in_color));
   4386  1.29.2.2  skrll 	if (!update) {
   4387  1.29.2.2  skrll 		add_sta_cmd.tfd_queue_msk = htole32(0xf);
   4388  1.29.2.2  skrll 		IEEE80211_ADDR_COPY(&add_sta_cmd.addr, in->in_ni.ni_bssid);
   4389  1.29.2.2  skrll 	}
   4390  1.29.2.2  skrll 	add_sta_cmd.add_modify = update ? 1 : 0;
   4391  1.29.2.2  skrll 	add_sta_cmd.station_flags_msk
   4392  1.29.2.2  skrll 	    |= htole32(IWM_STA_FLG_FAT_EN_MSK | IWM_STA_FLG_MIMO_EN_MSK);
   4393  1.29.2.2  skrll 
   4394  1.29.2.2  skrll 	status = IWM_ADD_STA_SUCCESS;
   4395  1.29.2.2  skrll 	ret = iwm_mvm_send_add_sta_cmd_status(sc, &add_sta_cmd, &status);
   4396  1.29.2.2  skrll 	if (ret)
   4397  1.29.2.2  skrll 		return ret;
   4398  1.29.2.2  skrll 
   4399  1.29.2.2  skrll 	switch (status) {
   4400  1.29.2.2  skrll 	case IWM_ADD_STA_SUCCESS:
   4401  1.29.2.2  skrll 		break;
   4402  1.29.2.2  skrll 	default:
   4403  1.29.2.2  skrll 		ret = EIO;
   4404  1.29.2.2  skrll 		DPRINTF(("IWM_ADD_STA failed\n"));
   4405  1.29.2.2  skrll 		break;
   4406  1.29.2.2  skrll 	}
   4407  1.29.2.2  skrll 
   4408  1.29.2.2  skrll 	return ret;
   4409  1.29.2.2  skrll }
   4410  1.29.2.2  skrll 
   4411  1.29.2.2  skrll static int
   4412  1.29.2.2  skrll iwm_mvm_add_sta(struct iwm_softc *sc, struct iwm_node *in)
   4413  1.29.2.2  skrll {
   4414  1.29.2.2  skrll 	int ret;
   4415  1.29.2.2  skrll 
   4416  1.29.2.2  skrll 	ret = iwm_mvm_sta_send_to_fw(sc, in, 0);
   4417  1.29.2.2  skrll 	if (ret)
   4418  1.29.2.2  skrll 		return ret;
   4419  1.29.2.2  skrll 
   4420  1.29.2.2  skrll 	return 0;
   4421  1.29.2.2  skrll }
   4422  1.29.2.2  skrll 
   4423  1.29.2.2  skrll static int
   4424  1.29.2.2  skrll iwm_mvm_update_sta(struct iwm_softc *sc, struct iwm_node *in)
   4425  1.29.2.2  skrll {
   4426  1.29.2.2  skrll 	return iwm_mvm_sta_send_to_fw(sc, in, 1);
   4427  1.29.2.2  skrll }
   4428  1.29.2.2  skrll 
   4429  1.29.2.2  skrll static int
   4430  1.29.2.2  skrll iwm_mvm_add_int_sta_common(struct iwm_softc *sc, struct iwm_int_sta *sta,
   4431  1.29.2.2  skrll 	const uint8_t *addr, uint16_t mac_id, uint16_t color)
   4432  1.29.2.2  skrll {
   4433  1.29.2.2  skrll 	struct iwm_mvm_add_sta_cmd_v6 cmd;
   4434  1.29.2.2  skrll 	int ret;
   4435  1.29.2.2  skrll 	uint32_t status;
   4436  1.29.2.2  skrll 
   4437  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   4438  1.29.2.2  skrll 	cmd.sta_id = sta->sta_id;
   4439  1.29.2.2  skrll 	cmd.mac_id_n_color = htole32(IWM_FW_CMD_ID_AND_COLOR(mac_id, color));
   4440  1.29.2.2  skrll 
   4441  1.29.2.2  skrll 	cmd.tfd_queue_msk = htole32(sta->tfd_queue_msk);
   4442  1.29.2.2  skrll 
   4443  1.29.2.2  skrll 	if (addr)
   4444  1.29.2.2  skrll 		memcpy(cmd.addr, addr, ETHER_ADDR_LEN);
   4445  1.29.2.2  skrll 
   4446  1.29.2.2  skrll 	ret = iwm_mvm_send_add_sta_cmd_status(sc, &cmd, &status);
   4447  1.29.2.2  skrll 	if (ret)
   4448  1.29.2.2  skrll 		return ret;
   4449  1.29.2.2  skrll 
   4450  1.29.2.2  skrll 	switch (status) {
   4451  1.29.2.2  skrll 	case IWM_ADD_STA_SUCCESS:
   4452  1.29.2.2  skrll 		DPRINTF(("Internal station added.\n"));
   4453  1.29.2.2  skrll 		return 0;
   4454  1.29.2.2  skrll 	default:
   4455  1.29.2.2  skrll 		DPRINTF(("%s: Add internal station failed, status=0x%x\n",
   4456  1.29.2.2  skrll 		    DEVNAME(sc), status));
   4457  1.29.2.2  skrll 		ret = EIO;
   4458  1.29.2.2  skrll 		break;
   4459  1.29.2.2  skrll 	}
   4460  1.29.2.2  skrll 	return ret;
   4461  1.29.2.2  skrll }
   4462  1.29.2.2  skrll 
   4463  1.29.2.2  skrll static int
   4464  1.29.2.2  skrll iwm_mvm_add_aux_sta(struct iwm_softc *sc)
   4465  1.29.2.2  skrll {
   4466  1.29.2.2  skrll 	int ret;
   4467  1.29.2.2  skrll 
   4468  1.29.2.2  skrll 	sc->sc_aux_sta.sta_id = 3;
   4469  1.29.2.2  skrll 	sc->sc_aux_sta.tfd_queue_msk = 0;
   4470  1.29.2.2  skrll 
   4471  1.29.2.2  skrll 	ret = iwm_mvm_add_int_sta_common(sc,
   4472  1.29.2.2  skrll 	    &sc->sc_aux_sta, NULL, IWM_MAC_INDEX_AUX, 0);
   4473  1.29.2.2  skrll 
   4474  1.29.2.2  skrll 	if (ret)
   4475  1.29.2.2  skrll 		memset(&sc->sc_aux_sta, 0, sizeof(sc->sc_aux_sta));
   4476  1.29.2.2  skrll 	return ret;
   4477  1.29.2.2  skrll }
   4478  1.29.2.2  skrll 
   4479  1.29.2.2  skrll /*
   4480  1.29.2.2  skrll  * END mvm/sta.c
   4481  1.29.2.2  skrll  */
   4482  1.29.2.2  skrll 
   4483  1.29.2.2  skrll /*
   4484  1.29.2.2  skrll  * BEGIN mvm/scan.c
   4485  1.29.2.2  skrll  */
   4486  1.29.2.2  skrll 
   4487  1.29.2.2  skrll #define IWM_PLCP_QUIET_THRESH 1
   4488  1.29.2.2  skrll #define IWM_ACTIVE_QUIET_TIME 10
   4489  1.29.2.2  skrll #define LONG_OUT_TIME_PERIOD 600
   4490  1.29.2.2  skrll #define SHORT_OUT_TIME_PERIOD 200
   4491  1.29.2.2  skrll #define SUSPEND_TIME_PERIOD 100
   4492  1.29.2.2  skrll 
   4493  1.29.2.2  skrll static uint16_t
   4494  1.29.2.2  skrll iwm_mvm_scan_rx_chain(struct iwm_softc *sc)
   4495  1.29.2.2  skrll {
   4496  1.29.2.2  skrll 	uint16_t rx_chain;
   4497  1.29.2.2  skrll 	uint8_t rx_ant;
   4498  1.29.2.2  skrll 
   4499  1.29.2.2  skrll 	rx_ant = IWM_FW_VALID_RX_ANT(sc);
   4500  1.29.2.2  skrll 	rx_chain = rx_ant << IWM_PHY_RX_CHAIN_VALID_POS;
   4501  1.29.2.2  skrll 	rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_MIMO_SEL_POS;
   4502  1.29.2.2  skrll 	rx_chain |= rx_ant << IWM_PHY_RX_CHAIN_FORCE_SEL_POS;
   4503  1.29.2.2  skrll 	rx_chain |= 0x1 << IWM_PHY_RX_CHAIN_DRIVER_FORCE_POS;
   4504  1.29.2.2  skrll 	return htole16(rx_chain);
   4505  1.29.2.2  skrll }
   4506  1.29.2.2  skrll 
   4507  1.29.2.2  skrll #define ieee80211_tu_to_usec(a) (1024*(a))
   4508  1.29.2.2  skrll 
   4509  1.29.2.2  skrll static uint32_t
   4510  1.29.2.2  skrll iwm_mvm_scan_max_out_time(struct iwm_softc *sc, uint32_t flags, int is_assoc)
   4511  1.29.2.2  skrll {
   4512  1.29.2.2  skrll 	if (!is_assoc)
   4513  1.29.2.2  skrll 		return 0;
   4514  1.29.2.2  skrll 	if (flags & 0x1)
   4515  1.29.2.2  skrll 		return htole32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD));
   4516  1.29.2.2  skrll 	return htole32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD));
   4517  1.29.2.2  skrll }
   4518  1.29.2.2  skrll 
   4519  1.29.2.2  skrll static uint32_t
   4520  1.29.2.2  skrll iwm_mvm_scan_suspend_time(struct iwm_softc *sc, int is_assoc)
   4521  1.29.2.2  skrll {
   4522  1.29.2.2  skrll 	if (!is_assoc)
   4523  1.29.2.2  skrll 		return 0;
   4524  1.29.2.2  skrll 	return htole32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD));
   4525  1.29.2.2  skrll }
   4526  1.29.2.2  skrll 
   4527  1.29.2.2  skrll static uint32_t
   4528  1.29.2.2  skrll iwm_mvm_scan_rxon_flags(struct iwm_softc *sc, int flags)
   4529  1.29.2.2  skrll {
   4530  1.29.2.2  skrll 	if (flags & IEEE80211_CHAN_2GHZ)
   4531  1.29.2.2  skrll 		return htole32(IWM_PHY_BAND_24);
   4532  1.29.2.2  skrll 	else
   4533  1.29.2.2  skrll 		return htole32(IWM_PHY_BAND_5);
   4534  1.29.2.2  skrll }
   4535  1.29.2.2  skrll 
   4536  1.29.2.2  skrll static uint32_t
   4537  1.29.2.2  skrll iwm_mvm_scan_rate_n_flags(struct iwm_softc *sc, int flags, int no_cck)
   4538  1.29.2.2  skrll {
   4539  1.29.2.2  skrll 	uint32_t tx_ant;
   4540  1.29.2.2  skrll 	int i, ind;
   4541  1.29.2.2  skrll 
   4542  1.29.2.2  skrll 	for (i = 0, ind = sc->sc_scan_last_antenna;
   4543  1.29.2.2  skrll 	    i < IWM_RATE_MCS_ANT_NUM; i++) {
   4544  1.29.2.2  skrll 		ind = (ind + 1) % IWM_RATE_MCS_ANT_NUM;
   4545  1.29.2.2  skrll 		if (IWM_FW_VALID_TX_ANT(sc) & (1 << ind)) {
   4546  1.29.2.2  skrll 			sc->sc_scan_last_antenna = ind;
   4547  1.29.2.2  skrll 			break;
   4548  1.29.2.2  skrll 		}
   4549  1.29.2.2  skrll 	}
   4550  1.29.2.2  skrll 	tx_ant = (1 << sc->sc_scan_last_antenna) << IWM_RATE_MCS_ANT_POS;
   4551  1.29.2.2  skrll 
   4552  1.29.2.2  skrll 	if ((flags & IEEE80211_CHAN_2GHZ) && !no_cck)
   4553  1.29.2.2  skrll 		return htole32(IWM_RATE_1M_PLCP | IWM_RATE_MCS_CCK_MSK |
   4554  1.29.2.2  skrll 				   tx_ant);
   4555  1.29.2.2  skrll 	else
   4556  1.29.2.2  skrll 		return htole32(IWM_RATE_6M_PLCP | tx_ant);
   4557  1.29.2.2  skrll }
   4558  1.29.2.2  skrll 
   4559  1.29.2.2  skrll /*
   4560  1.29.2.2  skrll  * If req->n_ssids > 0, it means we should do an active scan.
   4561  1.29.2.2  skrll  * In case of active scan w/o directed scan, we receive a zero-length SSID
   4562  1.29.2.2  skrll  * just to notify that this scan is active and not passive.
   4563  1.29.2.2  skrll  * In order to notify the FW of the number of SSIDs we wish to scan (including
   4564  1.29.2.2  skrll  * the zero-length one), we need to set the corresponding bits in chan->type,
   4565  1.29.2.2  skrll  * one for each SSID, and set the active bit (first). If the first SSID is
   4566  1.29.2.2  skrll  * already included in the probe template, so we need to set only
   4567  1.29.2.2  skrll  * req->n_ssids - 1 bits in addition to the first bit.
   4568  1.29.2.2  skrll  */
   4569  1.29.2.2  skrll static uint16_t
   4570  1.29.2.2  skrll iwm_mvm_get_active_dwell(struct iwm_softc *sc, int flags, int n_ssids)
   4571  1.29.2.2  skrll {
   4572  1.29.2.2  skrll 	if (flags & IEEE80211_CHAN_2GHZ)
   4573  1.29.2.2  skrll 		return 30  + 3 * (n_ssids + 1);
   4574  1.29.2.2  skrll 	return 20  + 2 * (n_ssids + 1);
   4575  1.29.2.2  skrll }
   4576  1.29.2.2  skrll 
   4577  1.29.2.2  skrll static uint16_t
   4578  1.29.2.2  skrll iwm_mvm_get_passive_dwell(struct iwm_softc *sc, int flags)
   4579  1.29.2.2  skrll {
   4580  1.29.2.2  skrll 	return (flags & IEEE80211_CHAN_2GHZ) ? 100 + 20 : 100 + 10;
   4581  1.29.2.2  skrll }
   4582  1.29.2.2  skrll 
   4583  1.29.2.2  skrll static int
   4584  1.29.2.2  skrll iwm_mvm_scan_fill_channels(struct iwm_softc *sc, struct iwm_scan_cmd *cmd,
   4585  1.29.2.2  skrll 	int flags, int n_ssids, int basic_ssid)
   4586  1.29.2.2  skrll {
   4587  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   4588  1.29.2.2  skrll 	uint16_t passive_dwell = iwm_mvm_get_passive_dwell(sc, flags);
   4589  1.29.2.2  skrll 	uint16_t active_dwell = iwm_mvm_get_active_dwell(sc, flags, n_ssids);
   4590  1.29.2.2  skrll 	struct iwm_scan_channel *chan = (struct iwm_scan_channel *)
   4591  1.29.2.2  skrll 		(cmd->data + le16toh(cmd->tx_cmd.len));
   4592  1.29.2.2  skrll 	int type = (1 << n_ssids) - 1;
   4593  1.29.2.2  skrll 	struct ieee80211_channel *c;
   4594  1.29.2.2  skrll 	int nchan;
   4595  1.29.2.2  skrll 
   4596  1.29.2.2  skrll 	if (!basic_ssid)
   4597  1.29.2.2  skrll 		type |= (1 << n_ssids);
   4598  1.29.2.2  skrll 
   4599  1.29.2.2  skrll 	for (nchan = 0, c = &ic->ic_channels[1];
   4600  1.29.2.2  skrll 	    c <= &ic->ic_channels[IEEE80211_CHAN_MAX];
   4601  1.29.2.2  skrll 	    c++) {
   4602  1.29.2.2  skrll 		if ((c->ic_flags & flags) != flags)
   4603  1.29.2.2  skrll 			continue;
   4604  1.29.2.2  skrll 
   4605  1.29.2.2  skrll 		chan->channel = htole16(ieee80211_mhz2ieee(c->ic_freq, flags));
   4606  1.29.2.2  skrll 		chan->type = htole32(type);
   4607  1.29.2.2  skrll 		if (c->ic_flags & IEEE80211_CHAN_PASSIVE)
   4608  1.29.2.2  skrll 			chan->type &= htole32(~IWM_SCAN_CHANNEL_TYPE_ACTIVE);
   4609  1.29.2.2  skrll 		chan->active_dwell = htole16(active_dwell);
   4610  1.29.2.2  skrll 		chan->passive_dwell = htole16(passive_dwell);
   4611  1.29.2.2  skrll 		chan->iteration_count = htole16(1);
   4612  1.29.2.2  skrll 		chan++;
   4613  1.29.2.2  skrll 		nchan++;
   4614  1.29.2.2  skrll 	}
   4615  1.29.2.2  skrll 	if (nchan == 0)
   4616  1.29.2.2  skrll 		DPRINTF(("%s: NO CHANNEL!\n", DEVNAME(sc)));
   4617  1.29.2.2  skrll 	return nchan;
   4618  1.29.2.2  skrll }
   4619  1.29.2.2  skrll 
   4620  1.29.2.2  skrll /*
   4621  1.29.2.2  skrll  * Fill in probe request with the following parameters:
   4622  1.29.2.2  skrll  * TA is our vif HW address, which mac80211 ensures we have.
   4623  1.29.2.2  skrll  * Packet is broadcasted, so this is both SA and DA.
   4624  1.29.2.2  skrll  * The probe request IE is made out of two: first comes the most prioritized
   4625  1.29.2.2  skrll  * SSID if a directed scan is requested. Second comes whatever extra
   4626  1.29.2.2  skrll  * information was given to us as the scan request IE.
   4627  1.29.2.2  skrll  */
   4628  1.29.2.2  skrll static uint16_t
   4629  1.29.2.2  skrll iwm_mvm_fill_probe_req(struct iwm_softc *sc, struct ieee80211_frame *frame,
   4630  1.29.2.2  skrll 	const uint8_t *ta, int n_ssids, const uint8_t *ssid, int ssid_len,
   4631  1.29.2.2  skrll 	const uint8_t *ie, int ie_len, int left)
   4632  1.29.2.2  skrll {
   4633  1.29.2.2  skrll 	int len = 0;
   4634  1.29.2.2  skrll 	uint8_t *pos = NULL;
   4635  1.29.2.2  skrll 
   4636  1.29.2.2  skrll 	/* Make sure there is enough space for the probe request,
   4637  1.29.2.2  skrll 	 * two mandatory IEs and the data */
   4638  1.29.2.2  skrll 	left -= sizeof(*frame);
   4639  1.29.2.2  skrll 	if (left < 0)
   4640  1.29.2.2  skrll 		return 0;
   4641  1.29.2.2  skrll 
   4642  1.29.2.2  skrll 	frame->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
   4643  1.29.2.2  skrll 	    IEEE80211_FC0_SUBTYPE_PROBE_REQ;
   4644  1.29.2.2  skrll 	frame->i_fc[1] = IEEE80211_FC1_DIR_NODS;
   4645  1.29.2.2  skrll 	IEEE80211_ADDR_COPY(frame->i_addr1, etherbroadcastaddr);
   4646  1.29.2.2  skrll 	memcpy(frame->i_addr2, ta, ETHER_ADDR_LEN);
   4647  1.29.2.2  skrll 	IEEE80211_ADDR_COPY(frame->i_addr3, etherbroadcastaddr);
   4648  1.29.2.2  skrll 
   4649  1.29.2.2  skrll 	len += sizeof(*frame);
   4650  1.29.2.2  skrll 	CTASSERT(sizeof(*frame) == 24);
   4651  1.29.2.2  skrll 
   4652  1.29.2.2  skrll 	/* for passive scans, no need to fill anything */
   4653  1.29.2.2  skrll 	if (n_ssids == 0)
   4654  1.29.2.2  skrll 		return (uint16_t)len;
   4655  1.29.2.2  skrll 
   4656  1.29.2.2  skrll 	/* points to the payload of the request */
   4657  1.29.2.2  skrll 	pos = (uint8_t *)frame + sizeof(*frame);
   4658  1.29.2.2  skrll 
   4659  1.29.2.2  skrll 	/* fill in our SSID IE */
   4660  1.29.2.2  skrll 	left -= ssid_len + 2;
   4661  1.29.2.2  skrll 	if (left < 0)
   4662  1.29.2.2  skrll 		return 0;
   4663  1.29.2.2  skrll 	*pos++ = IEEE80211_ELEMID_SSID;
   4664  1.29.2.2  skrll 	*pos++ = ssid_len;
   4665  1.29.2.2  skrll 	if (ssid && ssid_len) { /* ssid_len may be == 0 even if ssid is valid */
   4666  1.29.2.2  skrll 		memcpy(pos, ssid, ssid_len);
   4667  1.29.2.2  skrll 		pos += ssid_len;
   4668  1.29.2.2  skrll 	}
   4669  1.29.2.2  skrll 
   4670  1.29.2.2  skrll 	len += ssid_len + 2;
   4671  1.29.2.2  skrll 
   4672  1.29.2.2  skrll 	if (left < ie_len)
   4673  1.29.2.2  skrll 		return len;
   4674  1.29.2.2  skrll 
   4675  1.29.2.2  skrll 	if (ie && ie_len) {
   4676  1.29.2.2  skrll 		memcpy(pos, ie, ie_len);
   4677  1.29.2.2  skrll 		len += ie_len;
   4678  1.29.2.2  skrll 	}
   4679  1.29.2.2  skrll 
   4680  1.29.2.2  skrll 	return (uint16_t)len;
   4681  1.29.2.2  skrll }
   4682  1.29.2.2  skrll 
   4683  1.29.2.2  skrll static int
   4684  1.29.2.2  skrll iwm_mvm_scan_request(struct iwm_softc *sc, int flags,
   4685  1.29.2.2  skrll 	int n_ssids, uint8_t *ssid, int ssid_len)
   4686  1.29.2.2  skrll {
   4687  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   4688  1.29.2.2  skrll 	struct iwm_host_cmd hcmd = {
   4689  1.29.2.2  skrll 		.id = IWM_SCAN_REQUEST_CMD,
   4690  1.29.2.2  skrll 		.len = { 0, },
   4691  1.29.2.2  skrll 		.data = { sc->sc_scan_cmd, },
   4692  1.29.2.2  skrll 		.flags = IWM_CMD_SYNC,
   4693  1.29.2.2  skrll 		.dataflags = { IWM_HCMD_DFL_NOCOPY, },
   4694  1.29.2.2  skrll 	};
   4695  1.29.2.2  skrll 	struct iwm_scan_cmd *cmd = sc->sc_scan_cmd;
   4696  1.29.2.2  skrll 	int is_assoc = 0;
   4697  1.29.2.2  skrll 	int ret;
   4698  1.29.2.2  skrll 	uint32_t status;
   4699  1.29.2.2  skrll 	int basic_ssid = !(sc->sc_capaflags & IWM_UCODE_TLV_FLAGS_NO_BASIC_SSID);
   4700  1.29.2.2  skrll 
   4701  1.29.2.2  skrll 	//lockdep_assert_held(&mvm->mutex);
   4702  1.29.2.2  skrll 
   4703  1.29.2.2  skrll 	sc->sc_scanband = flags & (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ);
   4704  1.29.2.2  skrll 
   4705  1.29.2.2  skrll 	DPRINTF(("Handling ieee80211 scan request\n"));
   4706  1.29.2.2  skrll 	memset(cmd, 0, sc->sc_scan_cmd_len);
   4707  1.29.2.2  skrll 
   4708  1.29.2.2  skrll 	cmd->quiet_time = htole16(IWM_ACTIVE_QUIET_TIME);
   4709  1.29.2.2  skrll 	cmd->quiet_plcp_th = htole16(IWM_PLCP_QUIET_THRESH);
   4710  1.29.2.2  skrll 	cmd->rxchain_sel_flags = iwm_mvm_scan_rx_chain(sc);
   4711  1.29.2.2  skrll 	cmd->max_out_time = iwm_mvm_scan_max_out_time(sc, 0, is_assoc);
   4712  1.29.2.2  skrll 	cmd->suspend_time = iwm_mvm_scan_suspend_time(sc, is_assoc);
   4713  1.29.2.2  skrll 	cmd->rxon_flags = iwm_mvm_scan_rxon_flags(sc, flags);
   4714  1.29.2.2  skrll 	cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP |
   4715  1.29.2.2  skrll 	    IWM_MAC_FILTER_IN_BEACON);
   4716  1.29.2.2  skrll 
   4717  1.29.2.2  skrll 	cmd->type = htole32(IWM_SCAN_TYPE_FORCED);
   4718  1.29.2.2  skrll 	cmd->repeats = htole32(1);
   4719  1.29.2.2  skrll 
   4720  1.29.2.2  skrll 	/*
   4721  1.29.2.2  skrll 	 * If the user asked for passive scan, don't change to active scan if
   4722  1.29.2.2  skrll 	 * you see any activity on the channel - remain passive.
   4723  1.29.2.2  skrll 	 */
   4724  1.29.2.2  skrll 	if (n_ssids > 0) {
   4725  1.29.2.2  skrll 		cmd->passive2active = htole16(1);
   4726  1.29.2.2  skrll 		cmd->scan_flags |= IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
   4727  1.29.2.2  skrll #if 0
   4728  1.29.2.2  skrll 		if (basic_ssid) {
   4729  1.29.2.2  skrll 			ssid = req->ssids[0].ssid;
   4730  1.29.2.2  skrll 			ssid_len = req->ssids[0].ssid_len;
   4731  1.29.2.2  skrll 		}
   4732  1.29.2.2  skrll #endif
   4733  1.29.2.2  skrll 	} else {
   4734  1.29.2.2  skrll 		cmd->passive2active = 0;
   4735  1.29.2.2  skrll 		cmd->scan_flags &= ~IWM_SCAN_FLAGS_PASSIVE2ACTIVE;
   4736  1.29.2.2  skrll 	}
   4737  1.29.2.2  skrll 
   4738  1.29.2.2  skrll 	cmd->tx_cmd.tx_flags = htole32(IWM_TX_CMD_FLG_SEQ_CTL |
   4739  1.29.2.2  skrll 	    IWM_TX_CMD_FLG_BT_DIS);
   4740  1.29.2.2  skrll 	cmd->tx_cmd.sta_id = sc->sc_aux_sta.sta_id;
   4741  1.29.2.2  skrll 	cmd->tx_cmd.life_time = htole32(IWM_TX_CMD_LIFE_TIME_INFINITE);
   4742  1.29.2.2  skrll 	cmd->tx_cmd.rate_n_flags = iwm_mvm_scan_rate_n_flags(sc, flags, 1/*XXX*/);
   4743  1.29.2.2  skrll 
   4744  1.29.2.2  skrll 	cmd->tx_cmd.len = htole16(iwm_mvm_fill_probe_req(sc,
   4745  1.29.2.2  skrll 			    (struct ieee80211_frame *)cmd->data,
   4746  1.29.2.2  skrll 			    ic->ic_myaddr, n_ssids, ssid, ssid_len,
   4747  1.29.2.2  skrll 			    NULL, 0, sc->sc_capa_max_probe_len));
   4748  1.29.2.2  skrll 
   4749  1.29.2.2  skrll 	cmd->channel_count
   4750  1.29.2.2  skrll 	    = iwm_mvm_scan_fill_channels(sc, cmd, flags, n_ssids, basic_ssid);
   4751  1.29.2.2  skrll 
   4752  1.29.2.2  skrll 	cmd->len = htole16(sizeof(struct iwm_scan_cmd) +
   4753  1.29.2.2  skrll 		le16toh(cmd->tx_cmd.len) +
   4754  1.29.2.2  skrll 		(cmd->channel_count * sizeof(struct iwm_scan_channel)));
   4755  1.29.2.2  skrll 	hcmd.len[0] = le16toh(cmd->len);
   4756  1.29.2.2  skrll 
   4757  1.29.2.2  skrll 	status = IWM_SCAN_RESPONSE_OK;
   4758  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_status(sc, &hcmd, &status);
   4759  1.29.2.2  skrll 	if (!ret && status == IWM_SCAN_RESPONSE_OK) {
   4760  1.29.2.2  skrll 		DPRINTF(("Scan request was sent successfully\n"));
   4761  1.29.2.2  skrll 	} else {
   4762  1.29.2.2  skrll 		/*
   4763  1.29.2.2  skrll 		 * If the scan failed, it usually means that the FW was unable
   4764  1.29.2.2  skrll 		 * to allocate the time events. Warn on it, but maybe we
   4765  1.29.2.2  skrll 		 * should try to send the command again with different params.
   4766  1.29.2.2  skrll 		 */
   4767  1.29.2.2  skrll 		sc->sc_scanband = 0;
   4768  1.29.2.2  skrll 		ret = EIO;
   4769  1.29.2.2  skrll 	}
   4770  1.29.2.2  skrll 	return ret;
   4771  1.29.2.2  skrll }
   4772  1.29.2.2  skrll 
   4773  1.29.2.2  skrll /*
   4774  1.29.2.2  skrll  * END mvm/scan.c
   4775  1.29.2.2  skrll  */
   4776  1.29.2.2  skrll 
   4777  1.29.2.2  skrll /*
   4778  1.29.2.2  skrll  * BEGIN mvm/mac-ctxt.c
   4779  1.29.2.2  skrll  */
   4780  1.29.2.2  skrll 
   4781  1.29.2.2  skrll static void
   4782  1.29.2.2  skrll iwm_mvm_ack_rates(struct iwm_softc *sc, struct iwm_node *in,
   4783  1.29.2.2  skrll 	int *cck_rates, int *ofdm_rates)
   4784  1.29.2.2  skrll {
   4785  1.29.2.2  skrll 	struct ieee80211_node *ni = &in->in_ni;
   4786  1.29.2.2  skrll 	int lowest_present_ofdm = 100;
   4787  1.29.2.2  skrll 	int lowest_present_cck = 100;
   4788  1.29.2.2  skrll 	uint8_t cck = 0;
   4789  1.29.2.2  skrll 	uint8_t ofdm = 0;
   4790  1.29.2.2  skrll 	int i;
   4791  1.29.2.2  skrll 
   4792  1.29.2.2  skrll 	if (IEEE80211_IS_CHAN_2GHZ(ni->ni_chan)) {
   4793  1.29.2.2  skrll 		for (i = 0; i <= IWM_LAST_CCK_RATE; i++) {
   4794  1.29.2.2  skrll 			cck |= (1 << i);
   4795  1.29.2.2  skrll 			if (lowest_present_cck > i)
   4796  1.29.2.2  skrll 				lowest_present_cck = i;
   4797  1.29.2.2  skrll 		}
   4798  1.29.2.2  skrll 	}
   4799  1.29.2.2  skrll 	for (i = IWM_FIRST_OFDM_RATE; i <= IWM_LAST_NON_HT_RATE; i++) {
   4800  1.29.2.2  skrll 		int adj = i - IWM_FIRST_OFDM_RATE;
   4801  1.29.2.2  skrll 		ofdm |= (1 << adj);
   4802  1.29.2.2  skrll 		if (lowest_present_ofdm > i)
   4803  1.29.2.2  skrll 			lowest_present_ofdm = i;
   4804  1.29.2.2  skrll 	}
   4805  1.29.2.2  skrll 
   4806  1.29.2.2  skrll 	/*
   4807  1.29.2.2  skrll 	 * Now we've got the basic rates as bitmaps in the ofdm and cck
   4808  1.29.2.2  skrll 	 * variables. This isn't sufficient though, as there might not
   4809  1.29.2.2  skrll 	 * be all the right rates in the bitmap. E.g. if the only basic
   4810  1.29.2.2  skrll 	 * rates are 5.5 Mbps and 11 Mbps, we still need to add 1 Mbps
   4811  1.29.2.2  skrll 	 * and 6 Mbps because the 802.11-2007 standard says in 9.6:
   4812  1.29.2.2  skrll 	 *
   4813  1.29.2.2  skrll 	 *    [...] a STA responding to a received frame shall transmit
   4814  1.29.2.2  skrll 	 *    its Control Response frame [...] at the highest rate in the
   4815  1.29.2.2  skrll 	 *    BSSBasicRateSet parameter that is less than or equal to the
   4816  1.29.2.2  skrll 	 *    rate of the immediately previous frame in the frame exchange
   4817  1.29.2.2  skrll 	 *    sequence ([...]) and that is of the same modulation class
   4818  1.29.2.2  skrll 	 *    ([...]) as the received frame. If no rate contained in the
   4819  1.29.2.2  skrll 	 *    BSSBasicRateSet parameter meets these conditions, then the
   4820  1.29.2.2  skrll 	 *    control frame sent in response to a received frame shall be
   4821  1.29.2.2  skrll 	 *    transmitted at the highest mandatory rate of the PHY that is
   4822  1.29.2.2  skrll 	 *    less than or equal to the rate of the received frame, and
   4823  1.29.2.2  skrll 	 *    that is of the same modulation class as the received frame.
   4824  1.29.2.2  skrll 	 *
   4825  1.29.2.2  skrll 	 * As a consequence, we need to add all mandatory rates that are
   4826  1.29.2.2  skrll 	 * lower than all of the basic rates to these bitmaps.
   4827  1.29.2.2  skrll 	 */
   4828  1.29.2.2  skrll 
   4829  1.29.2.2  skrll 	if (IWM_RATE_24M_INDEX < lowest_present_ofdm)
   4830  1.29.2.2  skrll 		ofdm |= IWM_RATE_BIT_MSK(24) >> IWM_FIRST_OFDM_RATE;
   4831  1.29.2.2  skrll 	if (IWM_RATE_12M_INDEX < lowest_present_ofdm)
   4832  1.29.2.2  skrll 		ofdm |= IWM_RATE_BIT_MSK(12) >> IWM_FIRST_OFDM_RATE;
   4833  1.29.2.2  skrll 	/* 6M already there or needed so always add */
   4834  1.29.2.2  skrll 	ofdm |= IWM_RATE_BIT_MSK(6) >> IWM_FIRST_OFDM_RATE;
   4835  1.29.2.2  skrll 
   4836  1.29.2.2  skrll 	/*
   4837  1.29.2.2  skrll 	 * CCK is a bit more complex with DSSS vs. HR/DSSS vs. ERP.
   4838  1.29.2.2  skrll 	 * Note, however:
   4839  1.29.2.2  skrll 	 *  - if no CCK rates are basic, it must be ERP since there must
   4840  1.29.2.2  skrll 	 *    be some basic rates at all, so they're OFDM => ERP PHY
   4841  1.29.2.2  skrll 	 *    (or we're in 5 GHz, and the cck bitmap will never be used)
   4842  1.29.2.2  skrll 	 *  - if 11M is a basic rate, it must be ERP as well, so add 5.5M
   4843  1.29.2.2  skrll 	 *  - if 5.5M is basic, 1M and 2M are mandatory
   4844  1.29.2.2  skrll 	 *  - if 2M is basic, 1M is mandatory
   4845  1.29.2.2  skrll 	 *  - if 1M is basic, that's the only valid ACK rate.
   4846  1.29.2.2  skrll 	 * As a consequence, it's not as complicated as it sounds, just add
   4847  1.29.2.2  skrll 	 * any lower rates to the ACK rate bitmap.
   4848  1.29.2.2  skrll 	 */
   4849  1.29.2.2  skrll 	if (IWM_RATE_11M_INDEX < lowest_present_cck)
   4850  1.29.2.2  skrll 		cck |= IWM_RATE_BIT_MSK(11) >> IWM_FIRST_CCK_RATE;
   4851  1.29.2.2  skrll 	if (IWM_RATE_5M_INDEX < lowest_present_cck)
   4852  1.29.2.2  skrll 		cck |= IWM_RATE_BIT_MSK(5) >> IWM_FIRST_CCK_RATE;
   4853  1.29.2.2  skrll 	if (IWM_RATE_2M_INDEX < lowest_present_cck)
   4854  1.29.2.2  skrll 		cck |= IWM_RATE_BIT_MSK(2) >> IWM_FIRST_CCK_RATE;
   4855  1.29.2.2  skrll 	/* 1M already there or needed so always add */
   4856  1.29.2.2  skrll 	cck |= IWM_RATE_BIT_MSK(1) >> IWM_FIRST_CCK_RATE;
   4857  1.29.2.2  skrll 
   4858  1.29.2.2  skrll 	*cck_rates = cck;
   4859  1.29.2.2  skrll 	*ofdm_rates = ofdm;
   4860  1.29.2.2  skrll }
   4861  1.29.2.2  skrll 
   4862  1.29.2.2  skrll static void
   4863  1.29.2.2  skrll iwm_mvm_mac_ctxt_cmd_common(struct iwm_softc *sc, struct iwm_node *in,
   4864  1.29.2.2  skrll 	struct iwm_mac_ctx_cmd *cmd, uint32_t action)
   4865  1.29.2.2  skrll {
   4866  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   4867  1.29.2.2  skrll 	struct ieee80211_node *ni = ic->ic_bss;
   4868  1.29.2.2  skrll 	int cck_ack_rates, ofdm_ack_rates;
   4869  1.29.2.2  skrll 	int i;
   4870  1.29.2.2  skrll 
   4871  1.29.2.2  skrll 	cmd->id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id,
   4872  1.29.2.2  skrll 	    in->in_color));
   4873  1.29.2.2  skrll 	cmd->action = htole32(action);
   4874  1.29.2.2  skrll 
   4875  1.29.2.2  skrll 	cmd->mac_type = htole32(IWM_FW_MAC_TYPE_BSS_STA);
   4876  1.29.2.2  skrll 	cmd->tsf_id = htole32(in->in_tsfid);
   4877  1.29.2.2  skrll 
   4878  1.29.2.2  skrll 	IEEE80211_ADDR_COPY(cmd->node_addr, ic->ic_myaddr);
   4879  1.29.2.2  skrll 	if (in->in_assoc) {
   4880  1.29.2.2  skrll 		IEEE80211_ADDR_COPY(cmd->bssid_addr, ni->ni_bssid);
   4881  1.29.2.2  skrll 	} else {
   4882  1.29.2.2  skrll 		memset(cmd->bssid_addr, 0, sizeof(cmd->bssid_addr));
   4883  1.29.2.2  skrll 	}
   4884  1.29.2.2  skrll 	iwm_mvm_ack_rates(sc, in, &cck_ack_rates, &ofdm_ack_rates);
   4885  1.29.2.2  skrll 	cmd->cck_rates = htole32(cck_ack_rates);
   4886  1.29.2.2  skrll 	cmd->ofdm_rates = htole32(ofdm_ack_rates);
   4887  1.29.2.2  skrll 
   4888  1.29.2.2  skrll 	cmd->cck_short_preamble
   4889  1.29.2.2  skrll 	    = htole32((ic->ic_flags & IEEE80211_F_SHPREAMBLE)
   4890  1.29.2.2  skrll 	      ? IWM_MAC_FLG_SHORT_PREAMBLE : 0);
   4891  1.29.2.2  skrll 	cmd->short_slot
   4892  1.29.2.2  skrll 	    = htole32((ic->ic_flags & IEEE80211_F_SHSLOT)
   4893  1.29.2.2  skrll 	      ? IWM_MAC_FLG_SHORT_SLOT : 0);
   4894  1.29.2.2  skrll 
   4895  1.29.2.2  skrll 	for (i = 0; i < IWM_AC_NUM+1; i++) {
   4896  1.29.2.2  skrll 		int txf = i;
   4897  1.29.2.2  skrll 
   4898  1.29.2.2  skrll 		cmd->ac[txf].cw_min = htole16(0x0f);
   4899  1.29.2.2  skrll 		cmd->ac[txf].cw_max = htole16(0x3f);
   4900  1.29.2.2  skrll 		cmd->ac[txf].aifsn = 1;
   4901  1.29.2.2  skrll 		cmd->ac[txf].fifos_mask = (1 << txf);
   4902  1.29.2.2  skrll 		cmd->ac[txf].edca_txop = 0;
   4903  1.29.2.2  skrll 	}
   4904  1.29.2.2  skrll 
   4905  1.29.2.2  skrll 	if (ic->ic_flags & IEEE80211_F_USEPROT)
   4906  1.29.2.2  skrll 		cmd->protection_flags |= htole32(IWM_MAC_PROT_FLG_TGG_PROTECT);
   4907  1.29.2.2  skrll 
   4908  1.29.2.2  skrll 	cmd->filter_flags = htole32(IWM_MAC_FILTER_ACCEPT_GRP);
   4909  1.29.2.2  skrll }
   4910  1.29.2.2  skrll 
   4911  1.29.2.2  skrll static int
   4912  1.29.2.2  skrll iwm_mvm_mac_ctxt_send_cmd(struct iwm_softc *sc, struct iwm_mac_ctx_cmd *cmd)
   4913  1.29.2.2  skrll {
   4914  1.29.2.2  skrll 	int ret = iwm_mvm_send_cmd_pdu(sc, IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC,
   4915  1.29.2.2  skrll 				       sizeof(*cmd), cmd);
   4916  1.29.2.2  skrll 	if (ret)
   4917  1.29.2.2  skrll 		DPRINTF(("%s: Failed to send MAC context (action:%d): %d\n",
   4918  1.29.2.2  skrll 		    DEVNAME(sc), le32toh(cmd->action), ret));
   4919  1.29.2.2  skrll 	return ret;
   4920  1.29.2.2  skrll }
   4921  1.29.2.2  skrll 
   4922  1.29.2.2  skrll /*
   4923  1.29.2.2  skrll  * Fill the specific data for mac context of type station or p2p client
   4924  1.29.2.2  skrll  */
   4925  1.29.2.2  skrll static void
   4926  1.29.2.2  skrll iwm_mvm_mac_ctxt_cmd_fill_sta(struct iwm_softc *sc, struct iwm_node *in,
   4927  1.29.2.2  skrll 	struct iwm_mac_data_sta *ctxt_sta, int force_assoc_off)
   4928  1.29.2.2  skrll {
   4929  1.29.2.2  skrll 	struct ieee80211_node *ni = &in->in_ni;
   4930  1.29.2.2  skrll 	unsigned dtim_period, dtim_count;
   4931  1.29.2.2  skrll 
   4932  1.29.2.2  skrll 	dtim_period = ni->ni_dtim_period;
   4933  1.29.2.2  skrll 	dtim_count = ni->ni_dtim_count;
   4934  1.29.2.2  skrll 
   4935  1.29.2.2  skrll 	/* We need the dtim_period to set the MAC as associated */
   4936  1.29.2.2  skrll 	if (in->in_assoc && dtim_period && !force_assoc_off) {
   4937  1.29.2.2  skrll 		uint64_t tsf;
   4938  1.29.2.2  skrll 		uint32_t dtim_offs;
   4939  1.29.2.2  skrll 
   4940  1.29.2.2  skrll 		/*
   4941  1.29.2.2  skrll 		 * The DTIM count counts down, so when it is N that means N
   4942  1.29.2.2  skrll 		 * more beacon intervals happen until the DTIM TBTT. Therefore
   4943  1.29.2.2  skrll 		 * add this to the current time. If that ends up being in the
   4944  1.29.2.2  skrll 		 * future, the firmware will handle it.
   4945  1.29.2.2  skrll 		 *
   4946  1.29.2.2  skrll 		 * Also note that the system_timestamp (which we get here as
   4947  1.29.2.2  skrll 		 * "sync_device_ts") and TSF timestamp aren't at exactly the
   4948  1.29.2.2  skrll 		 * same offset in the frame -- the TSF is at the first symbol
   4949  1.29.2.2  skrll 		 * of the TSF, the system timestamp is at signal acquisition
   4950  1.29.2.2  skrll 		 * time. This means there's an offset between them of at most
   4951  1.29.2.2  skrll 		 * a few hundred microseconds (24 * 8 bits + PLCP time gives
   4952  1.29.2.2  skrll 		 * 384us in the longest case), this is currently not relevant
   4953  1.29.2.2  skrll 		 * as the firmware wakes up around 2ms before the TBTT.
   4954  1.29.2.2  skrll 		 */
   4955  1.29.2.2  skrll 		dtim_offs = dtim_count * ni->ni_intval;
   4956  1.29.2.2  skrll 		/* convert TU to usecs */
   4957  1.29.2.2  skrll 		dtim_offs *= 1024;
   4958  1.29.2.2  skrll 
   4959  1.29.2.2  skrll 		tsf = ni->ni_tstamp.tsf;
   4960  1.29.2.2  skrll 
   4961  1.29.2.2  skrll 		ctxt_sta->dtim_tsf = htole64(tsf + dtim_offs);
   4962  1.29.2.2  skrll 		ctxt_sta->dtim_time = htole64(ni->ni_rstamp + dtim_offs);
   4963  1.29.2.2  skrll 
   4964  1.29.2.2  skrll 		DPRINTF(("DTIM TBTT is 0x%llx/0x%x, offset %d\n",
   4965  1.29.2.2  skrll 		    (long long)le64toh(ctxt_sta->dtim_tsf),
   4966  1.29.2.2  skrll 		    le32toh(ctxt_sta->dtim_time), dtim_offs));
   4967  1.29.2.2  skrll 
   4968  1.29.2.2  skrll 		ctxt_sta->is_assoc = htole32(1);
   4969  1.29.2.2  skrll 	} else {
   4970  1.29.2.2  skrll 		ctxt_sta->is_assoc = htole32(0);
   4971  1.29.2.2  skrll 	}
   4972  1.29.2.2  skrll 
   4973  1.29.2.2  skrll 	ctxt_sta->bi = htole32(ni->ni_intval);
   4974  1.29.2.2  skrll 	ctxt_sta->bi_reciprocal = htole32(iwm_mvm_reciprocal(ni->ni_intval));
   4975  1.29.2.2  skrll 	ctxt_sta->dtim_interval = htole32(ni->ni_intval * dtim_period);
   4976  1.29.2.2  skrll 	ctxt_sta->dtim_reciprocal =
   4977  1.29.2.2  skrll 	    htole32(iwm_mvm_reciprocal(ni->ni_intval * dtim_period));
   4978  1.29.2.2  skrll 
   4979  1.29.2.2  skrll 	/* 10 = CONN_MAX_LISTEN_INTERVAL */
   4980  1.29.2.2  skrll 	ctxt_sta->listen_interval = htole32(10);
   4981  1.29.2.2  skrll 	ctxt_sta->assoc_id = htole32(ni->ni_associd);
   4982  1.29.2.2  skrll }
   4983  1.29.2.2  skrll 
   4984  1.29.2.2  skrll static int
   4985  1.29.2.2  skrll iwm_mvm_mac_ctxt_cmd_station(struct iwm_softc *sc, struct iwm_node *in,
   4986  1.29.2.2  skrll 	uint32_t action)
   4987  1.29.2.2  skrll {
   4988  1.29.2.2  skrll 	struct iwm_mac_ctx_cmd cmd;
   4989  1.29.2.2  skrll 
   4990  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   4991  1.29.2.2  skrll 
   4992  1.29.2.2  skrll 	/* Fill the common data for all mac context types */
   4993  1.29.2.2  skrll 	iwm_mvm_mac_ctxt_cmd_common(sc, in, &cmd, action);
   4994  1.29.2.2  skrll 
   4995  1.29.2.2  skrll 	/* Allow beacons to pass through as long as we are not associated,or we
   4996  1.29.2.2  skrll 	 * do not have dtim period information */
   4997  1.29.2.2  skrll 	if (!in->in_assoc || !sc->sc_ic.ic_dtim_period)
   4998  1.29.2.2  skrll 		cmd.filter_flags |= htole32(IWM_MAC_FILTER_IN_BEACON);
   4999  1.29.2.2  skrll 	else
   5000  1.29.2.2  skrll 		cmd.filter_flags &= ~htole32(IWM_MAC_FILTER_IN_BEACON);
   5001  1.29.2.2  skrll 
   5002  1.29.2.2  skrll 	/* Fill the data specific for station mode */
   5003  1.29.2.2  skrll 	iwm_mvm_mac_ctxt_cmd_fill_sta(sc, in,
   5004  1.29.2.2  skrll 	    &cmd.sta, action == IWM_FW_CTXT_ACTION_ADD);
   5005  1.29.2.2  skrll 
   5006  1.29.2.2  skrll 	return iwm_mvm_mac_ctxt_send_cmd(sc, &cmd);
   5007  1.29.2.2  skrll }
   5008  1.29.2.2  skrll 
   5009  1.29.2.2  skrll static int
   5010  1.29.2.2  skrll iwm_mvm_mac_ctx_send(struct iwm_softc *sc, struct iwm_node *in, uint32_t action)
   5011  1.29.2.2  skrll {
   5012  1.29.2.2  skrll 	return iwm_mvm_mac_ctxt_cmd_station(sc, in, action);
   5013  1.29.2.2  skrll }
   5014  1.29.2.2  skrll 
   5015  1.29.2.2  skrll static int
   5016  1.29.2.2  skrll iwm_mvm_mac_ctxt_add(struct iwm_softc *sc, struct iwm_node *in)
   5017  1.29.2.2  skrll {
   5018  1.29.2.2  skrll 	int ret;
   5019  1.29.2.2  skrll 
   5020  1.29.2.2  skrll 	ret = iwm_mvm_mac_ctx_send(sc, in, IWM_FW_CTXT_ACTION_ADD);
   5021  1.29.2.2  skrll 	if (ret)
   5022  1.29.2.2  skrll 		return ret;
   5023  1.29.2.2  skrll 
   5024  1.29.2.2  skrll 	return 0;
   5025  1.29.2.2  skrll }
   5026  1.29.2.2  skrll 
   5027  1.29.2.2  skrll static int
   5028  1.29.2.2  skrll iwm_mvm_mac_ctxt_changed(struct iwm_softc *sc, struct iwm_node *in)
   5029  1.29.2.2  skrll {
   5030  1.29.2.2  skrll 	return iwm_mvm_mac_ctx_send(sc, in, IWM_FW_CTXT_ACTION_MODIFY);
   5031  1.29.2.2  skrll }
   5032  1.29.2.2  skrll 
   5033  1.29.2.2  skrll #if 0
   5034  1.29.2.2  skrll static int
   5035  1.29.2.2  skrll iwm_mvm_mac_ctxt_remove(struct iwm_softc *sc, struct iwm_node *in)
   5036  1.29.2.2  skrll {
   5037  1.29.2.2  skrll 	struct iwm_mac_ctx_cmd cmd;
   5038  1.29.2.2  skrll 	int ret;
   5039  1.29.2.2  skrll 
   5040  1.29.2.2  skrll 	if (!in->in_uploaded) {
   5041  1.29.2.2  skrll 		print("%s: attempt to remove !uploaded node %p", DEVNAME(sc), in);
   5042  1.29.2.2  skrll 		return EIO;
   5043  1.29.2.2  skrll 	}
   5044  1.29.2.2  skrll 
   5045  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   5046  1.29.2.2  skrll 
   5047  1.29.2.2  skrll 	cmd.id_and_color = htole32(IWM_FW_CMD_ID_AND_COLOR(in->in_id,
   5048  1.29.2.2  skrll 	    in->in_color));
   5049  1.29.2.2  skrll 	cmd.action = htole32(IWM_FW_CTXT_ACTION_REMOVE);
   5050  1.29.2.2  skrll 
   5051  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_pdu(sc,
   5052  1.29.2.2  skrll 	    IWM_MAC_CONTEXT_CMD, IWM_CMD_SYNC, sizeof(cmd), &cmd);
   5053  1.29.2.2  skrll 	if (ret) {
   5054  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   5055  1.29.2.2  skrll 		    "Failed to remove MAC context: %d\n", ret);
   5056  1.29.2.2  skrll 		return ret;
   5057  1.29.2.2  skrll 	}
   5058  1.29.2.2  skrll 	in->in_uploaded = 0;
   5059  1.29.2.2  skrll 
   5060  1.29.2.2  skrll 	return 0;
   5061  1.29.2.2  skrll }
   5062  1.29.2.2  skrll #endif
   5063  1.29.2.2  skrll 
   5064  1.29.2.2  skrll #define IWM_MVM_MISSED_BEACONS_THRESHOLD 8
   5065  1.29.2.2  skrll 
   5066  1.29.2.2  skrll static void
   5067  1.29.2.2  skrll iwm_mvm_rx_missed_beacons_notif(struct iwm_softc *sc,
   5068  1.29.2.2  skrll 	struct iwm_rx_packet *pkt, struct iwm_rx_data *data)
   5069  1.29.2.2  skrll {
   5070  1.29.2.2  skrll 	struct iwm_missed_beacons_notif *mb = (void *)pkt->data;
   5071  1.29.2.2  skrll 
   5072  1.29.2.2  skrll 	DPRINTF(("missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
   5073  1.29.2.2  skrll 	    le32toh(mb->mac_id),
   5074  1.29.2.2  skrll 	    le32toh(mb->consec_missed_beacons),
   5075  1.29.2.2  skrll 	    le32toh(mb->consec_missed_beacons_since_last_rx),
   5076  1.29.2.2  skrll 	    le32toh(mb->num_recvd_beacons),
   5077  1.29.2.2  skrll 	    le32toh(mb->num_expected_beacons)));
   5078  1.29.2.2  skrll 
   5079  1.29.2.2  skrll 	/*
   5080  1.29.2.2  skrll 	 * TODO: the threshold should be adjusted based on latency conditions,
   5081  1.29.2.2  skrll 	 * and/or in case of a CS flow on one of the other AP vifs.
   5082  1.29.2.2  skrll 	 */
   5083  1.29.2.2  skrll 	if (le32toh(mb->consec_missed_beacons_since_last_rx) >
   5084  1.29.2.2  skrll 	    IWM_MVM_MISSED_BEACONS_THRESHOLD)
   5085  1.29.2.2  skrll 		ieee80211_beacon_miss(&sc->sc_ic);
   5086  1.29.2.2  skrll }
   5087  1.29.2.2  skrll 
   5088  1.29.2.2  skrll /*
   5089  1.29.2.2  skrll  * END mvm/mac-ctxt.c
   5090  1.29.2.2  skrll  */
   5091  1.29.2.2  skrll 
   5092  1.29.2.2  skrll /*
   5093  1.29.2.2  skrll  * BEGIN mvm/quota.c
   5094  1.29.2.2  skrll  */
   5095  1.29.2.2  skrll 
   5096  1.29.2.2  skrll static int
   5097  1.29.2.2  skrll iwm_mvm_update_quotas(struct iwm_softc *sc, struct iwm_node *in)
   5098  1.29.2.2  skrll {
   5099  1.29.2.2  skrll 	struct iwm_time_quota_cmd cmd;
   5100  1.29.2.2  skrll 	int i, idx, ret, num_active_macs, quota, quota_rem;
   5101  1.29.2.2  skrll 	int colors[IWM_MAX_BINDINGS] = { -1, -1, -1, -1, };
   5102  1.29.2.2  skrll 	int n_ifs[IWM_MAX_BINDINGS] = {0, };
   5103  1.29.2.2  skrll 	uint16_t id;
   5104  1.29.2.2  skrll 
   5105  1.29.2.2  skrll 	memset(&cmd, 0, sizeof(cmd));
   5106  1.29.2.2  skrll 
   5107  1.29.2.2  skrll 	/* currently, PHY ID == binding ID */
   5108  1.29.2.2  skrll 	if (in) {
   5109  1.29.2.2  skrll 		id = in->in_phyctxt->id;
   5110  1.29.2.2  skrll 		KASSERT(id < IWM_MAX_BINDINGS);
   5111  1.29.2.2  skrll 		colors[id] = in->in_phyctxt->color;
   5112  1.29.2.2  skrll 
   5113  1.29.2.2  skrll 		if (1)
   5114  1.29.2.2  skrll 			n_ifs[id] = 1;
   5115  1.29.2.2  skrll 	}
   5116  1.29.2.2  skrll 
   5117  1.29.2.2  skrll 	/*
   5118  1.29.2.2  skrll 	 * The FW's scheduling session consists of
   5119  1.29.2.2  skrll 	 * IWM_MVM_MAX_QUOTA fragments. Divide these fragments
   5120  1.29.2.2  skrll 	 * equally between all the bindings that require quota
   5121  1.29.2.2  skrll 	 */
   5122  1.29.2.2  skrll 	num_active_macs = 0;
   5123  1.29.2.2  skrll 	for (i = 0; i < IWM_MAX_BINDINGS; i++) {
   5124  1.29.2.2  skrll 		cmd.quotas[i].id_and_color = htole32(IWM_FW_CTXT_INVALID);
   5125  1.29.2.2  skrll 		num_active_macs += n_ifs[i];
   5126  1.29.2.2  skrll 	}
   5127  1.29.2.2  skrll 
   5128  1.29.2.2  skrll 	quota = 0;
   5129  1.29.2.2  skrll 	quota_rem = 0;
   5130  1.29.2.2  skrll 	if (num_active_macs) {
   5131  1.29.2.2  skrll 		quota = IWM_MVM_MAX_QUOTA / num_active_macs;
   5132  1.29.2.2  skrll 		quota_rem = IWM_MVM_MAX_QUOTA % num_active_macs;
   5133  1.29.2.2  skrll 	}
   5134  1.29.2.2  skrll 
   5135  1.29.2.2  skrll 	for (idx = 0, i = 0; i < IWM_MAX_BINDINGS; i++) {
   5136  1.29.2.2  skrll 		if (colors[i] < 0)
   5137  1.29.2.2  skrll 			continue;
   5138  1.29.2.2  skrll 
   5139  1.29.2.2  skrll 		cmd.quotas[idx].id_and_color =
   5140  1.29.2.2  skrll 			htole32(IWM_FW_CMD_ID_AND_COLOR(i, colors[i]));
   5141  1.29.2.2  skrll 
   5142  1.29.2.2  skrll 		if (n_ifs[i] <= 0) {
   5143  1.29.2.2  skrll 			cmd.quotas[idx].quota = htole32(0);
   5144  1.29.2.2  skrll 			cmd.quotas[idx].max_duration = htole32(0);
   5145  1.29.2.2  skrll 		} else {
   5146  1.29.2.2  skrll 			cmd.quotas[idx].quota = htole32(quota * n_ifs[i]);
   5147  1.29.2.2  skrll 			cmd.quotas[idx].max_duration = htole32(0);
   5148  1.29.2.2  skrll 		}
   5149  1.29.2.2  skrll 		idx++;
   5150  1.29.2.2  skrll 	}
   5151  1.29.2.2  skrll 
   5152  1.29.2.2  skrll 	/* Give the remainder of the session to the first binding */
   5153  1.29.2.2  skrll 	cmd.quotas[0].quota = htole32(le32toh(cmd.quotas[0].quota) + quota_rem);
   5154  1.29.2.2  skrll 
   5155  1.29.2.2  skrll 	ret = iwm_mvm_send_cmd_pdu(sc, IWM_TIME_QUOTA_CMD, IWM_CMD_SYNC,
   5156  1.29.2.2  skrll 	    sizeof(cmd), &cmd);
   5157  1.29.2.2  skrll 	if (ret)
   5158  1.29.2.2  skrll 		DPRINTF(("%s: Failed to send quota: %d\n", DEVNAME(sc), ret));
   5159  1.29.2.2  skrll 	return ret;
   5160  1.29.2.2  skrll }
   5161  1.29.2.2  skrll 
   5162  1.29.2.2  skrll /*
   5163  1.29.2.2  skrll  * END mvm/quota.c
   5164  1.29.2.2  skrll  */
   5165  1.29.2.2  skrll 
   5166  1.29.2.2  skrll /*
   5167  1.29.2.2  skrll  * aieee80211 routines
   5168  1.29.2.2  skrll  */
   5169  1.29.2.2  skrll 
   5170  1.29.2.2  skrll /*
   5171  1.29.2.2  skrll  * Change to AUTH state in 80211 state machine.  Roughly matches what
   5172  1.29.2.2  skrll  * Linux does in bss_info_changed().
   5173  1.29.2.2  skrll  */
   5174  1.29.2.2  skrll static int
   5175  1.29.2.2  skrll iwm_auth(struct iwm_softc *sc)
   5176  1.29.2.2  skrll {
   5177  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5178  1.29.2.2  skrll 	struct iwm_node *in = (void *)ic->ic_bss;
   5179  1.29.2.2  skrll 	uint32_t duration;
   5180  1.29.2.2  skrll 	uint32_t min_duration;
   5181  1.29.2.2  skrll 	int error;
   5182  1.29.2.2  skrll 
   5183  1.29.2.2  skrll 	in->in_assoc = 0;
   5184  1.29.2.2  skrll 
   5185  1.29.2.2  skrll 	if ((error = iwm_allow_mcast(sc)) != 0)
   5186  1.29.2.2  skrll 		return error;
   5187  1.29.2.2  skrll 
   5188  1.29.2.2  skrll 	if ((error = iwm_mvm_mac_ctxt_add(sc, in)) != 0) {
   5189  1.29.2.2  skrll 		DPRINTF(("%s: failed to add MAC\n", DEVNAME(sc)));
   5190  1.29.2.2  skrll 		return error;
   5191  1.29.2.2  skrll 	}
   5192  1.29.2.2  skrll 
   5193  1.29.2.2  skrll 	if ((error = iwm_mvm_phy_ctxt_changed(sc, &sc->sc_phyctxt[0],
   5194  1.29.2.2  skrll 	    in->in_ni.ni_chan, 1, 1)) != 0) {
   5195  1.29.2.2  skrll 		DPRINTF(("%s: failed add phy ctxt\n", DEVNAME(sc)));
   5196  1.29.2.2  skrll 		return error;
   5197  1.29.2.2  skrll 	}
   5198  1.29.2.2  skrll 	in->in_phyctxt = &sc->sc_phyctxt[0];
   5199  1.29.2.2  skrll 
   5200  1.29.2.2  skrll 	if ((error = iwm_mvm_binding_add_vif(sc, in)) != 0) {
   5201  1.29.2.2  skrll 		DPRINTF(("%s: binding cmd\n", DEVNAME(sc)));
   5202  1.29.2.2  skrll 		return error;
   5203  1.29.2.2  skrll 	}
   5204  1.29.2.2  skrll 
   5205  1.29.2.2  skrll 	if ((error = iwm_mvm_add_sta(sc, in)) != 0) {
   5206  1.29.2.2  skrll 		DPRINTF(("%s: failed to add MAC\n", DEVNAME(sc)));
   5207  1.29.2.2  skrll 		return error;
   5208  1.29.2.2  skrll 	}
   5209  1.29.2.2  skrll 
   5210  1.29.2.2  skrll 	/* a bit superfluous? */
   5211  1.29.2.2  skrll 	while (sc->sc_auth_prot)
   5212  1.29.2.2  skrll 		tsleep(&sc->sc_auth_prot, 0, "iwmauth", 0);
   5213  1.29.2.2  skrll 	sc->sc_auth_prot = 1;
   5214  1.29.2.2  skrll 
   5215  1.29.2.2  skrll 	duration = min(IWM_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS,
   5216  1.29.2.2  skrll 	    200 + in->in_ni.ni_intval);
   5217  1.29.2.2  skrll 	min_duration = min(IWM_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS,
   5218  1.29.2.2  skrll 	    100 + in->in_ni.ni_intval);
   5219  1.29.2.2  skrll 	iwm_mvm_protect_session(sc, in, duration, min_duration, 500);
   5220  1.29.2.2  skrll 
   5221  1.29.2.2  skrll 	while (sc->sc_auth_prot != 2) {
   5222  1.29.2.2  skrll 		/*
   5223  1.29.2.2  skrll 		 * well, meh, but if the kernel is sleeping for half a
   5224  1.29.2.2  skrll 		 * second, we have bigger problems
   5225  1.29.2.2  skrll 		 */
   5226  1.29.2.2  skrll 		if (sc->sc_auth_prot == 0) {
   5227  1.29.2.2  skrll 			DPRINTF(("%s: missed auth window!\n", DEVNAME(sc)));
   5228  1.29.2.2  skrll 			return ETIMEDOUT;
   5229  1.29.2.2  skrll 		} else if (sc->sc_auth_prot == -1) {
   5230  1.29.2.2  skrll 			DPRINTF(("%s: no time event, denied!\n", DEVNAME(sc)));
   5231  1.29.2.2  skrll 			sc->sc_auth_prot = 0;
   5232  1.29.2.2  skrll 			return EAUTH;
   5233  1.29.2.2  skrll 		}
   5234  1.29.2.2  skrll 		tsleep(&sc->sc_auth_prot, 0, "iwmau2", 0);
   5235  1.29.2.2  skrll 	}
   5236  1.29.2.2  skrll 
   5237  1.29.2.2  skrll 	return 0;
   5238  1.29.2.2  skrll }
   5239  1.29.2.2  skrll 
   5240  1.29.2.2  skrll static int
   5241  1.29.2.2  skrll iwm_assoc(struct iwm_softc *sc)
   5242  1.29.2.2  skrll {
   5243  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5244  1.29.2.2  skrll 	struct iwm_node *in = (void *)ic->ic_bss;
   5245  1.29.2.2  skrll 	int error;
   5246  1.29.2.2  skrll 
   5247  1.29.2.2  skrll 	if ((error = iwm_mvm_update_sta(sc, in)) != 0) {
   5248  1.29.2.2  skrll 		DPRINTF(("%s: failed to update STA\n", DEVNAME(sc)));
   5249  1.29.2.2  skrll 		return error;
   5250  1.29.2.2  skrll 	}
   5251  1.29.2.2  skrll 
   5252  1.29.2.2  skrll 	in->in_assoc = 1;
   5253  1.29.2.2  skrll 	if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) {
   5254  1.29.2.2  skrll 		DPRINTF(("%s: failed to update MAC\n", DEVNAME(sc)));
   5255  1.29.2.2  skrll 		return error;
   5256  1.29.2.2  skrll 	}
   5257  1.29.2.2  skrll 
   5258  1.29.2.2  skrll 	return 0;
   5259  1.29.2.2  skrll }
   5260  1.29.2.2  skrll 
   5261  1.29.2.2  skrll static int
   5262  1.29.2.2  skrll iwm_release(struct iwm_softc *sc, struct iwm_node *in)
   5263  1.29.2.2  skrll {
   5264  1.29.2.2  skrll 	/*
   5265  1.29.2.2  skrll 	 * Ok, so *technically* the proper set of calls for going
   5266  1.29.2.2  skrll 	 * from RUN back to SCAN is:
   5267  1.29.2.2  skrll 	 *
   5268  1.29.2.2  skrll 	 * iwm_mvm_power_mac_disable(sc, in);
   5269  1.29.2.2  skrll 	 * iwm_mvm_mac_ctxt_changed(sc, in);
   5270  1.29.2.2  skrll 	 * iwm_mvm_rm_sta(sc, in);
   5271  1.29.2.2  skrll 	 * iwm_mvm_update_quotas(sc, NULL);
   5272  1.29.2.2  skrll 	 * iwm_mvm_mac_ctxt_changed(sc, in);
   5273  1.29.2.2  skrll 	 * iwm_mvm_binding_remove_vif(sc, in);
   5274  1.29.2.2  skrll 	 * iwm_mvm_mac_ctxt_remove(sc, in);
   5275  1.29.2.2  skrll 	 *
   5276  1.29.2.2  skrll 	 * However, that freezes the device not matter which permutations
   5277  1.29.2.2  skrll 	 * and modifications are attempted.  Obviously, this driver is missing
   5278  1.29.2.2  skrll 	 * something since it works in the Linux driver, but figuring out what
   5279  1.29.2.2  skrll 	 * is missing is a little more complicated.  Now, since we're going
   5280  1.29.2.2  skrll 	 * back to nothing anyway, we'll just do a complete device reset.
   5281  1.29.2.2  skrll 	 * Up your's, device!
   5282  1.29.2.2  skrll 	 */
   5283  1.29.2.2  skrll 	//iwm_mvm_flush_tx_path(sc, 0xf, 1);
   5284  1.29.2.2  skrll 	iwm_stop_device(sc);
   5285  1.29.2.2  skrll 	iwm_init_hw(sc);
   5286  1.29.2.2  skrll 	if (in)
   5287  1.29.2.2  skrll 		in->in_assoc = 0;
   5288  1.29.2.2  skrll 	return 0;
   5289  1.29.2.2  skrll 
   5290  1.29.2.2  skrll #if 0
   5291  1.29.2.2  skrll 	int error;
   5292  1.29.2.2  skrll 
   5293  1.29.2.2  skrll 	iwm_mvm_power_mac_disable(sc, in);
   5294  1.29.2.2  skrll 
   5295  1.29.2.2  skrll 	if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) {
   5296  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "mac ctxt change fail 1 %d\n",
   5297  1.29.2.2  skrll 		    error);
   5298  1.29.2.2  skrll 		return error;
   5299  1.29.2.2  skrll 	}
   5300  1.29.2.2  skrll 
   5301  1.29.2.2  skrll 	if ((error = iwm_mvm_rm_sta(sc, in)) != 0) {
   5302  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "sta remove fail %d\n", error);
   5303  1.29.2.2  skrll 		return error;
   5304  1.29.2.2  skrll 	}
   5305  1.29.2.2  skrll 	error = iwm_mvm_rm_sta(sc, in);
   5306  1.29.2.2  skrll 	in->in_assoc = 0;
   5307  1.29.2.2  skrll 	iwm_mvm_update_quotas(sc, NULL);
   5308  1.29.2.2  skrll 	if ((error = iwm_mvm_mac_ctxt_changed(sc, in)) != 0) {
   5309  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "mac ctxt change fail 2 %d\n",
   5310  1.29.2.2  skrll 		    error);
   5311  1.29.2.2  skrll 		return error;
   5312  1.29.2.2  skrll 	}
   5313  1.29.2.2  skrll 	iwm_mvm_binding_remove_vif(sc, in);
   5314  1.29.2.2  skrll 
   5315  1.29.2.2  skrll 	iwm_mvm_mac_ctxt_remove(sc, in);
   5316  1.29.2.2  skrll 
   5317  1.29.2.2  skrll 	return error;
   5318  1.29.2.2  skrll #endif
   5319  1.29.2.2  skrll }
   5320  1.29.2.2  skrll 
   5321  1.29.2.2  skrll 
   5322  1.29.2.2  skrll static struct ieee80211_node *
   5323  1.29.2.2  skrll iwm_node_alloc(struct ieee80211_node_table *nt)
   5324  1.29.2.2  skrll {
   5325  1.29.2.2  skrll 	return malloc(sizeof(struct iwm_node), M_80211_NODE, M_NOWAIT | M_ZERO);
   5326  1.29.2.2  skrll }
   5327  1.29.2.2  skrll 
   5328  1.29.2.2  skrll static void
   5329  1.29.2.2  skrll iwm_calib_timeout(void *arg)
   5330  1.29.2.2  skrll {
   5331  1.29.2.2  skrll 	struct iwm_softc *sc = arg;
   5332  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5333  1.29.2.2  skrll 	int s;
   5334  1.29.2.2  skrll 
   5335  1.29.2.2  skrll 	s = splnet();
   5336  1.29.2.2  skrll 	if (ic->ic_fixed_rate == -1
   5337  1.29.2.2  skrll 	    && ic->ic_opmode == IEEE80211_M_STA
   5338  1.29.2.2  skrll 	    && ic->ic_bss) {
   5339  1.29.2.2  skrll 		struct iwm_node *in = (void *)ic->ic_bss;
   5340  1.29.2.2  skrll 		ieee80211_amrr_choose(&sc->sc_amrr, &in->in_ni, &in->in_amn);
   5341  1.29.2.2  skrll 	}
   5342  1.29.2.2  skrll 	splx(s);
   5343  1.29.2.2  skrll 
   5344  1.29.2.2  skrll 	callout_schedule(&sc->sc_calib_to, hz/2);
   5345  1.29.2.2  skrll }
   5346  1.29.2.2  skrll 
   5347  1.29.2.2  skrll static void
   5348  1.29.2.2  skrll iwm_setrates(struct iwm_node *in)
   5349  1.29.2.2  skrll {
   5350  1.29.2.2  skrll 	struct ieee80211_node *ni = &in->in_ni;
   5351  1.29.2.2  skrll 	struct ieee80211com *ic = ni->ni_ic;
   5352  1.29.2.2  skrll 	struct iwm_softc *sc = IC2IFP(ic)->if_softc;
   5353  1.29.2.2  skrll 	struct iwm_lq_cmd *lq = &in->in_lq;
   5354  1.29.2.2  skrll 	int nrates = ni->ni_rates.rs_nrates;
   5355  1.29.2.2  skrll 	int i, ridx, tab = 0;
   5356  1.29.2.2  skrll 	int txant = 0;
   5357  1.29.2.2  skrll 
   5358  1.29.2.2  skrll 	if (nrates > __arraycount(lq->rs_table) ||
   5359  1.29.2.2  skrll 	    nrates > IEEE80211_RATE_MAXSIZE) {
   5360  1.29.2.2  skrll 		DPRINTF(("%s: node supports %d rates, driver handles only "
   5361  1.29.2.2  skrll 		    "%zu\n", DEVNAME(sc), nrates, __arraycount(lq->rs_table)));
   5362  1.29.2.2  skrll 		return;
   5363  1.29.2.2  skrll 	}
   5364  1.29.2.2  skrll 
   5365  1.29.2.2  skrll 	/* first figure out which rates we should support */
   5366  1.29.2.2  skrll 	memset(&in->in_ridx, -1, sizeof(in->in_ridx));
   5367  1.29.2.2  skrll 	for (i = 0; i < nrates; i++) {
   5368  1.29.2.2  skrll 		int rate = ni->ni_rates.rs_rates[i] & IEEE80211_RATE_VAL;
   5369  1.29.2.2  skrll 
   5370  1.29.2.2  skrll 		/* Map 802.11 rate to HW rate index. */
   5371  1.29.2.2  skrll 		for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
   5372  1.29.2.2  skrll 			if (iwm_rates[ridx].rate == rate)
   5373  1.29.2.2  skrll 				break;
   5374  1.29.2.2  skrll 		if (ridx > IWM_RIDX_MAX)
   5375  1.29.2.2  skrll 			DPRINTF(("%s: WARNING: device rate for %d not found!\n",
   5376  1.29.2.2  skrll 			    DEVNAME(sc), rate));
   5377  1.29.2.2  skrll 		else
   5378  1.29.2.2  skrll 			in->in_ridx[i] = ridx;
   5379  1.29.2.2  skrll 	}
   5380  1.29.2.2  skrll 
   5381  1.29.2.2  skrll 	/* then construct a lq_cmd based on those */
   5382  1.29.2.2  skrll 	memset(lq, 0, sizeof(*lq));
   5383  1.29.2.2  skrll 	lq->sta_id = IWM_STATION_ID;
   5384  1.29.2.2  skrll 
   5385  1.29.2.2  skrll 	/*
   5386  1.29.2.2  skrll 	 * are these used? (we don't do SISO or MIMO)
   5387  1.29.2.2  skrll 	 * need to set them to non-zero, though, or we get an error.
   5388  1.29.2.2  skrll 	 */
   5389  1.29.2.2  skrll 	lq->single_stream_ant_msk = 1;
   5390  1.29.2.2  skrll 	lq->dual_stream_ant_msk = 1;
   5391  1.29.2.2  skrll 
   5392  1.29.2.2  skrll 	/*
   5393  1.29.2.2  skrll 	 * Build the actual rate selection table.
   5394  1.29.2.2  skrll 	 * The lowest bits are the rates.  Additionally,
   5395  1.29.2.2  skrll 	 * CCK needs bit 9 to be set.  The rest of the bits
   5396  1.29.2.2  skrll 	 * we add to the table select the tx antenna
   5397  1.29.2.2  skrll 	 * Note that we add the rates in the highest rate first
   5398  1.29.2.2  skrll 	 * (opposite of ni_rates).
   5399  1.29.2.2  skrll 	 */
   5400  1.29.2.2  skrll 	for (i = 0; i < nrates; i++) {
   5401  1.29.2.2  skrll 		int nextant;
   5402  1.29.2.2  skrll 
   5403  1.29.2.2  skrll 		if (txant == 0)
   5404  1.29.2.2  skrll 			txant = IWM_FW_VALID_TX_ANT(sc);
   5405  1.29.2.2  skrll 		nextant = 1<<(ffs(txant)-1);
   5406  1.29.2.2  skrll 		txant &= ~nextant;
   5407  1.29.2.2  skrll 
   5408  1.29.2.2  skrll 		ridx = in->in_ridx[(nrates-1)-i];
   5409  1.29.2.2  skrll 		tab = iwm_rates[ridx].plcp;
   5410  1.29.2.2  skrll 		tab |= nextant << IWM_RATE_MCS_ANT_POS;
   5411  1.29.2.2  skrll 		if (IWM_RIDX_IS_CCK(ridx))
   5412  1.29.2.2  skrll 			tab |= IWM_RATE_MCS_CCK_MSK;
   5413  1.29.2.2  skrll 		DPRINTFN(2, ("station rate %d %x\n", i, tab));
   5414  1.29.2.2  skrll 		lq->rs_table[i] = htole32(tab);
   5415  1.29.2.2  skrll 	}
   5416  1.29.2.2  skrll 	/* then fill the rest with the lowest possible rate */
   5417  1.29.2.2  skrll 	for (i = nrates; i < __arraycount(lq->rs_table); i++) {
   5418  1.29.2.2  skrll 		KASSERT(tab != 0);
   5419  1.29.2.2  skrll 		lq->rs_table[i] = htole32(tab);
   5420  1.29.2.2  skrll 	}
   5421  1.29.2.2  skrll 
   5422  1.29.2.2  skrll 	/* init amrr */
   5423  1.29.2.2  skrll 	ieee80211_amrr_node_init(&sc->sc_amrr, &in->in_amn);
   5424  1.29.2.2  skrll 	/* Start at lowest available bit-rate, AMRR will raise. */
   5425  1.29.2.2  skrll 	ni->ni_txrate = 0;
   5426  1.29.2.2  skrll }
   5427  1.29.2.2  skrll 
   5428  1.29.2.2  skrll static int
   5429  1.29.2.2  skrll iwm_media_change(struct ifnet *ifp)
   5430  1.29.2.2  skrll {
   5431  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5432  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5433  1.29.2.2  skrll 	uint8_t rate, ridx;
   5434  1.29.2.2  skrll 	int error;
   5435  1.29.2.2  skrll 
   5436  1.29.2.2  skrll 	error = ieee80211_media_change(ifp);
   5437  1.29.2.2  skrll 	if (error != ENETRESET)
   5438  1.29.2.2  skrll 		return error;
   5439  1.29.2.2  skrll 
   5440  1.29.2.2  skrll 	if (ic->ic_fixed_rate != -1) {
   5441  1.29.2.2  skrll 		rate = ic->ic_sup_rates[ic->ic_curmode].
   5442  1.29.2.2  skrll 		    rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL;
   5443  1.29.2.2  skrll 		/* Map 802.11 rate to HW rate index. */
   5444  1.29.2.2  skrll 		for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
   5445  1.29.2.2  skrll 			if (iwm_rates[ridx].rate == rate)
   5446  1.29.2.2  skrll 				break;
   5447  1.29.2.2  skrll 		sc->sc_fixed_ridx = ridx;
   5448  1.29.2.2  skrll 	}
   5449  1.29.2.2  skrll 
   5450  1.29.2.2  skrll 	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
   5451  1.29.2.2  skrll 	    (IFF_UP | IFF_RUNNING)) {
   5452  1.29.2.2  skrll 		iwm_stop(ifp, 0);
   5453  1.29.2.2  skrll 		error = iwm_init(ifp);
   5454  1.29.2.2  skrll 	}
   5455  1.29.2.2  skrll 	return error;
   5456  1.29.2.2  skrll }
   5457  1.29.2.2  skrll 
   5458  1.29.2.2  skrll static void
   5459  1.29.2.2  skrll iwm_newstate_cb(struct work *wk, void *v)
   5460  1.29.2.2  skrll {
   5461  1.29.2.2  skrll 	struct iwm_softc *sc = v;
   5462  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5463  1.29.2.2  skrll 	struct iwm_newstate_state *iwmns = (void *)wk;
   5464  1.29.2.2  skrll 	enum ieee80211_state nstate = iwmns->ns_nstate;
   5465  1.29.2.2  skrll 	int generation = iwmns->ns_generation;
   5466  1.29.2.2  skrll 	struct iwm_node *in;
   5467  1.29.2.2  skrll 	int arg = iwmns->ns_arg;
   5468  1.29.2.2  skrll 	int error;
   5469  1.29.2.2  skrll 
   5470  1.29.2.2  skrll 	kmem_free(iwmns, sizeof(*iwmns));
   5471  1.29.2.2  skrll 
   5472  1.29.2.2  skrll 	DPRINTF(("Prepare to switch state %d->%d\n", ic->ic_state, nstate));
   5473  1.29.2.2  skrll 	if (sc->sc_generation != generation) {
   5474  1.29.2.2  skrll 		DPRINTF(("newstate_cb: someone pulled the plug meanwhile\n"));
   5475  1.29.2.2  skrll 		if (nstate == IEEE80211_S_INIT) {
   5476  1.29.2.2  skrll 			DPRINTF(("newstate_cb: nstate == IEEE80211_S_INIT: calling sc_newstate()\n"));
   5477  1.29.2.2  skrll 			sc->sc_newstate(ic, nstate, arg);
   5478  1.29.2.2  skrll 		}
   5479  1.29.2.2  skrll 		return;
   5480  1.29.2.2  skrll 	}
   5481  1.29.2.2  skrll 
   5482  1.29.2.2  skrll 	DPRINTF(("switching state %d->%d\n", ic->ic_state, nstate));
   5483  1.29.2.2  skrll 
   5484  1.29.2.2  skrll 	/* disable beacon filtering if we're hopping out of RUN */
   5485  1.29.2.2  skrll 	if (ic->ic_state == IEEE80211_S_RUN && nstate != ic->ic_state) {
   5486  1.29.2.2  skrll 		iwm_mvm_disable_beacon_filter(sc, (void *)ic->ic_bss);
   5487  1.29.2.2  skrll 
   5488  1.29.2.2  skrll 		if (((in = (void *)ic->ic_bss) != NULL))
   5489  1.29.2.2  skrll 			in->in_assoc = 0;
   5490  1.29.2.2  skrll 		iwm_release(sc, NULL);
   5491  1.29.2.2  skrll 
   5492  1.29.2.2  skrll 		/*
   5493  1.29.2.2  skrll 		 * It's impossible to directly go RUN->SCAN. If we iwm_release()
   5494  1.29.2.2  skrll 		 * above then the card will be completely reinitialized,
   5495  1.29.2.2  skrll 		 * so the driver must do everything necessary to bring the card
   5496  1.29.2.2  skrll 		 * from INIT to SCAN.
   5497  1.29.2.2  skrll 		 *
   5498  1.29.2.2  skrll 		 * Additionally, upon receiving deauth frame from AP,
   5499  1.29.2.2  skrll 		 * OpenBSD 802.11 stack puts the driver in IEEE80211_S_AUTH
   5500  1.29.2.2  skrll 		 * state. This will also fail with this driver, so bring the FSM
   5501  1.29.2.2  skrll 		 * from IEEE80211_S_RUN to IEEE80211_S_SCAN in this case as well.
   5502  1.29.2.2  skrll 		 */
   5503  1.29.2.2  skrll 		if (nstate == IEEE80211_S_SCAN ||
   5504  1.29.2.2  skrll 		    nstate == IEEE80211_S_AUTH ||
   5505  1.29.2.2  skrll 		    nstate == IEEE80211_S_ASSOC) {
   5506  1.29.2.2  skrll 			DPRINTF(("Force transition to INIT; MGT=%d\n", arg));
   5507  1.29.2.2  skrll 			sc->sc_newstate(ic, IEEE80211_S_INIT, arg);
   5508  1.29.2.2  skrll 			DPRINTF(("Going INIT->SCAN\n"));
   5509  1.29.2.2  skrll 			nstate = IEEE80211_S_SCAN;
   5510  1.29.2.2  skrll 		}
   5511  1.29.2.2  skrll 	}
   5512  1.29.2.2  skrll 
   5513  1.29.2.2  skrll 	switch (nstate) {
   5514  1.29.2.2  skrll 	case IEEE80211_S_INIT:
   5515  1.29.2.2  skrll 		sc->sc_scanband = 0;
   5516  1.29.2.2  skrll 		break;
   5517  1.29.2.2  skrll 
   5518  1.29.2.2  skrll 	case IEEE80211_S_SCAN:
   5519  1.29.2.2  skrll 		if (sc->sc_scanband)
   5520  1.29.2.2  skrll 			break;
   5521  1.29.2.2  skrll 
   5522  1.29.2.2  skrll 		if ((error = iwm_mvm_scan_request(sc, IEEE80211_CHAN_2GHZ,
   5523  1.29.2.2  skrll 		    ic->ic_des_esslen != 0,
   5524  1.29.2.2  skrll 		    ic->ic_des_essid, ic->ic_des_esslen)) != 0) {
   5525  1.29.2.2  skrll 			DPRINTF(("%s: could not initiate scan\n", DEVNAME(sc)));
   5526  1.29.2.2  skrll 			return;
   5527  1.29.2.2  skrll 		}
   5528  1.29.2.2  skrll 		ic->ic_state = nstate;
   5529  1.29.2.2  skrll 		return;
   5530  1.29.2.2  skrll 
   5531  1.29.2.2  skrll 	case IEEE80211_S_AUTH:
   5532  1.29.2.2  skrll 		if ((error = iwm_auth(sc)) != 0) {
   5533  1.29.2.2  skrll 			DPRINTF(("%s: could not move to auth state: %d\n",
   5534  1.29.2.2  skrll 			    DEVNAME(sc), error));
   5535  1.29.2.2  skrll 			return;
   5536  1.29.2.2  skrll 		}
   5537  1.29.2.2  skrll 
   5538  1.29.2.2  skrll 		break;
   5539  1.29.2.2  skrll 
   5540  1.29.2.2  skrll 	case IEEE80211_S_ASSOC:
   5541  1.29.2.2  skrll 		if ((error = iwm_assoc(sc)) != 0) {
   5542  1.29.2.2  skrll 			DPRINTF(("%s: failed to associate: %d\n", DEVNAME(sc),
   5543  1.29.2.2  skrll 			    error));
   5544  1.29.2.2  skrll 			return;
   5545  1.29.2.2  skrll 		}
   5546  1.29.2.2  skrll 		break;
   5547  1.29.2.2  skrll 
   5548  1.29.2.2  skrll 	case IEEE80211_S_RUN: {
   5549  1.29.2.2  skrll 		struct iwm_host_cmd cmd = {
   5550  1.29.2.2  skrll 			.id = IWM_LQ_CMD,
   5551  1.29.2.2  skrll 			.len = { sizeof(in->in_lq), },
   5552  1.29.2.2  skrll 			.flags = IWM_CMD_SYNC,
   5553  1.29.2.2  skrll 		};
   5554  1.29.2.2  skrll 
   5555  1.29.2.2  skrll 		in = (struct iwm_node *)ic->ic_bss;
   5556  1.29.2.2  skrll 		iwm_mvm_power_mac_update_mode(sc, in);
   5557  1.29.2.2  skrll 		iwm_mvm_enable_beacon_filter(sc, in);
   5558  1.29.2.2  skrll 		iwm_mvm_update_quotas(sc, in);
   5559  1.29.2.2  skrll 		iwm_setrates(in);
   5560  1.29.2.2  skrll 
   5561  1.29.2.2  skrll 		cmd.data[0] = &in->in_lq;
   5562  1.29.2.2  skrll 		if ((error = iwm_send_cmd(sc, &cmd)) != 0) {
   5563  1.29.2.2  skrll 			DPRINTF(("%s: IWM_LQ_CMD failed\n", DEVNAME(sc)));
   5564  1.29.2.2  skrll 		}
   5565  1.29.2.2  skrll 
   5566  1.29.2.2  skrll 		callout_schedule(&sc->sc_calib_to, hz/2);
   5567  1.29.2.2  skrll 
   5568  1.29.2.2  skrll 		break; }
   5569  1.29.2.2  skrll 
   5570  1.29.2.2  skrll 	default:
   5571  1.29.2.2  skrll 		DPRINTF(("%s: unsupported state %d\n", DEVNAME(sc), nstate));
   5572  1.29.2.2  skrll 		break;
   5573  1.29.2.2  skrll 	}
   5574  1.29.2.2  skrll 
   5575  1.29.2.2  skrll 	sc->sc_newstate(ic, nstate, arg);
   5576  1.29.2.2  skrll }
   5577  1.29.2.2  skrll 
   5578  1.29.2.2  skrll static int
   5579  1.29.2.2  skrll iwm_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
   5580  1.29.2.2  skrll {
   5581  1.29.2.2  skrll 	struct iwm_newstate_state *iwmns;
   5582  1.29.2.2  skrll 	struct ifnet *ifp = IC2IFP(ic);
   5583  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5584  1.29.2.2  skrll 
   5585  1.29.2.2  skrll 	callout_stop(&sc->sc_calib_to);
   5586  1.29.2.2  skrll 
   5587  1.29.2.2  skrll 	iwmns = kmem_intr_alloc(sizeof(*iwmns), KM_NOSLEEP);
   5588  1.29.2.2  skrll 	if (!iwmns) {
   5589  1.29.2.2  skrll 		DPRINTF(("%s: allocating state cb mem failed\n", DEVNAME(sc)));
   5590  1.29.2.2  skrll 		return ENOMEM;
   5591  1.29.2.2  skrll 	}
   5592  1.29.2.2  skrll 
   5593  1.29.2.2  skrll 	iwmns->ns_nstate = nstate;
   5594  1.29.2.2  skrll 	iwmns->ns_arg = arg;
   5595  1.29.2.2  skrll 	iwmns->ns_generation = sc->sc_generation;
   5596  1.29.2.2  skrll 
   5597  1.29.2.2  skrll 	workqueue_enqueue(sc->sc_nswq, &iwmns->ns_wk, NULL);
   5598  1.29.2.2  skrll 
   5599  1.29.2.2  skrll 	return 0;
   5600  1.29.2.2  skrll }
   5601  1.29.2.2  skrll 
   5602  1.29.2.2  skrll static void
   5603  1.29.2.2  skrll iwm_endscan_cb(struct work *work __unused, void *arg)
   5604  1.29.2.2  skrll {
   5605  1.29.2.2  skrll 	struct iwm_softc *sc = arg;
   5606  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5607  1.29.2.2  skrll 	int done;
   5608  1.29.2.2  skrll 
   5609  1.29.2.2  skrll 	DPRINTF(("scan ended\n"));
   5610  1.29.2.2  skrll 
   5611  1.29.2.2  skrll 	if (sc->sc_scanband == IEEE80211_CHAN_2GHZ &&
   5612  1.29.2.2  skrll 	    sc->sc_nvm.sku_cap_band_52GHz_enable) {
   5613  1.29.2.2  skrll 		int error;
   5614  1.29.2.2  skrll 		done = 0;
   5615  1.29.2.2  skrll 		if ((error = iwm_mvm_scan_request(sc,
   5616  1.29.2.2  skrll 		    IEEE80211_CHAN_5GHZ, ic->ic_des_esslen != 0,
   5617  1.29.2.2  skrll 		    ic->ic_des_essid, ic->ic_des_esslen)) != 0) {
   5618  1.29.2.2  skrll 			DPRINTF(("%s: could not initiate scan\n", DEVNAME(sc)));
   5619  1.29.2.2  skrll 			done = 1;
   5620  1.29.2.2  skrll 		}
   5621  1.29.2.2  skrll 	} else {
   5622  1.29.2.2  skrll 		done = 1;
   5623  1.29.2.2  skrll 	}
   5624  1.29.2.2  skrll 
   5625  1.29.2.2  skrll 	if (done) {
   5626  1.29.2.2  skrll 		if (!sc->sc_scanband) {
   5627  1.29.2.2  skrll 			ieee80211_cancel_scan(ic);
   5628  1.29.2.2  skrll 		} else {
   5629  1.29.2.2  skrll 			ieee80211_end_scan(ic);
   5630  1.29.2.2  skrll 		}
   5631  1.29.2.2  skrll 		sc->sc_scanband = 0;
   5632  1.29.2.2  skrll 	}
   5633  1.29.2.2  skrll }
   5634  1.29.2.2  skrll 
   5635  1.29.2.2  skrll static int
   5636  1.29.2.2  skrll iwm_init_hw(struct iwm_softc *sc)
   5637  1.29.2.2  skrll {
   5638  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5639  1.29.2.2  skrll 	int error, i, qid;
   5640  1.29.2.2  skrll 
   5641  1.29.2.2  skrll 	if ((error = iwm_preinit(sc)) != 0)
   5642  1.29.2.2  skrll 		return error;
   5643  1.29.2.2  skrll 
   5644  1.29.2.2  skrll 	if ((error = iwm_start_hw(sc)) != 0)
   5645  1.29.2.2  skrll 		return error;
   5646  1.29.2.2  skrll 
   5647  1.29.2.2  skrll 	if ((error = iwm_run_init_mvm_ucode(sc, 0)) != 0) {
   5648  1.29.2.2  skrll 		return error;
   5649  1.29.2.2  skrll 	}
   5650  1.29.2.2  skrll 
   5651  1.29.2.2  skrll 	/*
   5652  1.29.2.2  skrll 	 * should stop and start HW since that INIT
   5653  1.29.2.2  skrll 	 * image just loaded
   5654  1.29.2.2  skrll 	 */
   5655  1.29.2.2  skrll 	iwm_stop_device(sc);
   5656  1.29.2.2  skrll 	if ((error = iwm_start_hw(sc)) != 0) {
   5657  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
   5658  1.29.2.2  skrll 		return error;
   5659  1.29.2.2  skrll 	}
   5660  1.29.2.2  skrll 
   5661  1.29.2.2  skrll 	/* omstart, this time with the regular firmware */
   5662  1.29.2.2  skrll 	error = iwm_mvm_load_ucode_wait_alive(sc, IWM_UCODE_TYPE_REGULAR);
   5663  1.29.2.2  skrll 	if (error) {
   5664  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "could not load firmware\n");
   5665  1.29.2.2  skrll 		goto error;
   5666  1.29.2.2  skrll 	}
   5667  1.29.2.2  skrll 
   5668  1.29.2.2  skrll 	if ((error = iwm_send_tx_ant_cfg(sc, IWM_FW_VALID_TX_ANT(sc))) != 0)
   5669  1.29.2.2  skrll 		goto error;
   5670  1.29.2.2  skrll 
   5671  1.29.2.2  skrll 	/* Send phy db control command and then phy db calibration*/
   5672  1.29.2.2  skrll 	if ((error = iwm_send_phy_db_data(sc)) != 0)
   5673  1.29.2.2  skrll 		goto error;
   5674  1.29.2.2  skrll 
   5675  1.29.2.2  skrll 	if ((error = iwm_send_phy_cfg_cmd(sc)) != 0)
   5676  1.29.2.2  skrll 		goto error;
   5677  1.29.2.2  skrll 
   5678  1.29.2.2  skrll 	/* Add auxiliary station for scanning */
   5679  1.29.2.2  skrll 	if ((error = iwm_mvm_add_aux_sta(sc)) != 0)
   5680  1.29.2.2  skrll 		goto error;
   5681  1.29.2.2  skrll 
   5682  1.29.2.2  skrll 	for (i = 0; i < IWM_NUM_PHY_CTX; i++) {
   5683  1.29.2.2  skrll 		/*
   5684  1.29.2.2  skrll 		 * The channel used here isn't relevant as it's
   5685  1.29.2.2  skrll 		 * going to be overwritten in the other flows.
   5686  1.29.2.2  skrll 		 * For now use the first channel we have.
   5687  1.29.2.2  skrll 		 */
   5688  1.29.2.2  skrll 		if ((error = iwm_mvm_phy_ctxt_add(sc,
   5689  1.29.2.2  skrll 		    &sc->sc_phyctxt[i], &ic->ic_channels[1], 1, 1)) != 0)
   5690  1.29.2.2  skrll 			goto error;
   5691  1.29.2.2  skrll 	}
   5692  1.29.2.2  skrll 
   5693  1.29.2.2  skrll 	error = iwm_mvm_power_update_device(sc);
   5694  1.29.2.2  skrll 	if (error)
   5695  1.29.2.2  skrll 		goto error;
   5696  1.29.2.2  skrll 
   5697  1.29.2.2  skrll 	/* Mark TX rings as active. */
   5698  1.29.2.2  skrll 	for (qid = 0; qid < 4; qid++) {
   5699  1.29.2.2  skrll 		iwm_enable_txq(sc, qid, qid);
   5700  1.29.2.2  skrll 	}
   5701  1.29.2.2  skrll 
   5702  1.29.2.2  skrll 	return 0;
   5703  1.29.2.2  skrll 
   5704  1.29.2.2  skrll  error:
   5705  1.29.2.2  skrll 	iwm_stop_device(sc);
   5706  1.29.2.2  skrll 	return error;
   5707  1.29.2.2  skrll }
   5708  1.29.2.2  skrll 
   5709  1.29.2.2  skrll /* Allow multicast from our BSSID. */
   5710  1.29.2.2  skrll static int
   5711  1.29.2.2  skrll iwm_allow_mcast(struct iwm_softc *sc)
   5712  1.29.2.2  skrll {
   5713  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5714  1.29.2.2  skrll 	struct ieee80211_node *ni = ic->ic_bss;
   5715  1.29.2.2  skrll 	struct iwm_mcast_filter_cmd *cmd;
   5716  1.29.2.2  skrll 	size_t size;
   5717  1.29.2.2  skrll 	int error;
   5718  1.29.2.2  skrll 
   5719  1.29.2.2  skrll 	size = roundup(sizeof(*cmd), 4);
   5720  1.29.2.2  skrll 	cmd = kmem_intr_zalloc(size, KM_NOSLEEP);
   5721  1.29.2.2  skrll 	if (cmd == NULL)
   5722  1.29.2.2  skrll 		return ENOMEM;
   5723  1.29.2.2  skrll 	cmd->filter_own = 1;
   5724  1.29.2.2  skrll 	cmd->port_id = 0;
   5725  1.29.2.2  skrll 	cmd->count = 0;
   5726  1.29.2.2  skrll 	cmd->pass_all = 1;
   5727  1.29.2.2  skrll 	IEEE80211_ADDR_COPY(cmd->bssid, ni->ni_bssid);
   5728  1.29.2.2  skrll 
   5729  1.29.2.2  skrll 	error = iwm_mvm_send_cmd_pdu(sc, IWM_MCAST_FILTER_CMD,
   5730  1.29.2.2  skrll 	    IWM_CMD_SYNC, size, cmd);
   5731  1.29.2.2  skrll 	kmem_intr_free(cmd, size);
   5732  1.29.2.2  skrll 	return error;
   5733  1.29.2.2  skrll }
   5734  1.29.2.2  skrll 
   5735  1.29.2.2  skrll /*
   5736  1.29.2.2  skrll  * ifnet interfaces
   5737  1.29.2.2  skrll  */
   5738  1.29.2.2  skrll 
   5739  1.29.2.2  skrll static int
   5740  1.29.2.2  skrll iwm_init(struct ifnet *ifp)
   5741  1.29.2.2  skrll {
   5742  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5743  1.29.2.2  skrll 	int error;
   5744  1.29.2.2  skrll 
   5745  1.29.2.2  skrll 	if (sc->sc_flags & IWM_FLAG_HW_INITED) {
   5746  1.29.2.2  skrll 		return 0;
   5747  1.29.2.2  skrll 	}
   5748  1.29.2.2  skrll 	sc->sc_generation++;
   5749  1.29.2.2  skrll 	sc->sc_flags &= ~IWM_FLAG_STOPPED;
   5750  1.29.2.2  skrll 
   5751  1.29.2.2  skrll 	if ((error = iwm_init_hw(sc)) != 0) {
   5752  1.29.2.2  skrll 		iwm_stop(ifp, 1);
   5753  1.29.2.2  skrll 		return error;
   5754  1.29.2.2  skrll 	}
   5755  1.29.2.2  skrll 
   5756  1.29.2.2  skrll 	/*
   5757  1.29.2.5  skrll 	 * Ok, firmware loaded and we are jogging
   5758  1.29.2.2  skrll 	 */
   5759  1.29.2.2  skrll 
   5760  1.29.2.2  skrll 	ifp->if_flags &= ~IFF_OACTIVE;
   5761  1.29.2.2  skrll 	ifp->if_flags |= IFF_RUNNING;
   5762  1.29.2.2  skrll 
   5763  1.29.2.2  skrll 	ieee80211_begin_scan(&sc->sc_ic, 0);
   5764  1.29.2.2  skrll 	sc->sc_flags |= IWM_FLAG_HW_INITED;
   5765  1.29.2.2  skrll 
   5766  1.29.2.2  skrll 	return 0;
   5767  1.29.2.2  skrll }
   5768  1.29.2.2  skrll 
   5769  1.29.2.2  skrll /*
   5770  1.29.2.2  skrll  * Dequeue packets from sendq and call send.
   5771  1.29.2.2  skrll  * mostly from iwn
   5772  1.29.2.2  skrll  */
   5773  1.29.2.2  skrll static void
   5774  1.29.2.2  skrll iwm_start(struct ifnet *ifp)
   5775  1.29.2.2  skrll {
   5776  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5777  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5778  1.29.2.2  skrll 	struct ieee80211_node *ni;
   5779  1.29.2.2  skrll 	struct ether_header *eh;
   5780  1.29.2.2  skrll 	struct mbuf *m;
   5781  1.29.2.2  skrll 	int ac;
   5782  1.29.2.2  skrll 
   5783  1.29.2.2  skrll 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
   5784  1.29.2.2  skrll 		return;
   5785  1.29.2.2  skrll 
   5786  1.29.2.2  skrll 	for (;;) {
   5787  1.29.2.2  skrll 		/* why isn't this done per-queue? */
   5788  1.29.2.2  skrll 		if (sc->qfullmsk != 0) {
   5789  1.29.2.2  skrll 			ifp->if_flags |= IFF_OACTIVE;
   5790  1.29.2.2  skrll 			break;
   5791  1.29.2.2  skrll 		}
   5792  1.29.2.2  skrll 
   5793  1.29.2.2  skrll 		/* need to send management frames even if we're not RUNning */
   5794  1.29.2.2  skrll 		IF_DEQUEUE(&ic->ic_mgtq, m);
   5795  1.29.2.2  skrll 		if (m) {
   5796  1.29.2.7  skrll 			ni = M_GETCTX(m, struct ieee80211_node *);
   5797  1.29.2.2  skrll 			ac = 0;
   5798  1.29.2.2  skrll 			goto sendit;
   5799  1.29.2.2  skrll 		}
   5800  1.29.2.2  skrll 		if (ic->ic_state != IEEE80211_S_RUN) {
   5801  1.29.2.2  skrll 			break;
   5802  1.29.2.2  skrll 		}
   5803  1.29.2.2  skrll 
   5804  1.29.2.2  skrll 		IFQ_DEQUEUE(&ifp->if_snd, m);
   5805  1.29.2.2  skrll 		if (!m)
   5806  1.29.2.2  skrll 			break;
   5807  1.29.2.2  skrll 		if (m->m_len < sizeof (*eh) &&
   5808  1.29.2.2  skrll 		   (m = m_pullup(m, sizeof (*eh))) == NULL) {
   5809  1.29.2.2  skrll 			ifp->if_oerrors++;
   5810  1.29.2.2  skrll 			continue;
   5811  1.29.2.2  skrll 		}
   5812  1.29.2.2  skrll 		if (ifp->if_bpf != NULL)
   5813  1.29.2.2  skrll 			bpf_mtap(ifp, m);
   5814  1.29.2.2  skrll 
   5815  1.29.2.2  skrll 		eh = mtod(m, struct ether_header *);
   5816  1.29.2.2  skrll 		ni = ieee80211_find_txnode(ic, eh->ether_dhost);
   5817  1.29.2.2  skrll 		if (ni == NULL) {
   5818  1.29.2.2  skrll 			m_freem(m);
   5819  1.29.2.2  skrll 			ifp->if_oerrors++;
   5820  1.29.2.2  skrll 			continue;
   5821  1.29.2.2  skrll 		}
   5822  1.29.2.2  skrll 		/* classify mbuf so we can find which tx ring to use */
   5823  1.29.2.2  skrll 		if (ieee80211_classify(ic, m, ni) != 0) {
   5824  1.29.2.2  skrll 			m_freem(m);
   5825  1.29.2.2  skrll 			ieee80211_free_node(ni);
   5826  1.29.2.2  skrll 			ifp->if_oerrors++;
   5827  1.29.2.2  skrll 			continue;
   5828  1.29.2.2  skrll 		}
   5829  1.29.2.2  skrll 
   5830  1.29.2.2  skrll 		/* No QoS encapsulation for EAPOL frames. */
   5831  1.29.2.2  skrll 		ac = (eh->ether_type != htons(ETHERTYPE_PAE)) ?
   5832  1.29.2.2  skrll 		    M_WME_GETAC(m) : WME_AC_BE;
   5833  1.29.2.2  skrll 
   5834  1.29.2.2  skrll 		if ((m = ieee80211_encap(ic, m, ni)) == NULL) {
   5835  1.29.2.2  skrll 			ieee80211_free_node(ni);
   5836  1.29.2.2  skrll 			ifp->if_oerrors++;
   5837  1.29.2.2  skrll 			continue;
   5838  1.29.2.2  skrll 		}
   5839  1.29.2.2  skrll 
   5840  1.29.2.2  skrll  sendit:
   5841  1.29.2.2  skrll 		if (ic->ic_rawbpf != NULL)
   5842  1.29.2.2  skrll 			bpf_mtap3(ic->ic_rawbpf, m);
   5843  1.29.2.2  skrll 		if (iwm_tx(sc, m, ni, ac) != 0) {
   5844  1.29.2.2  skrll 			ieee80211_free_node(ni);
   5845  1.29.2.2  skrll 			ifp->if_oerrors++;
   5846  1.29.2.2  skrll 			continue;
   5847  1.29.2.2  skrll 		}
   5848  1.29.2.2  skrll 
   5849  1.29.2.2  skrll 		if (ifp->if_flags & IFF_UP) {
   5850  1.29.2.2  skrll 			sc->sc_tx_timer = 15;
   5851  1.29.2.2  skrll 			ifp->if_timer = 1;
   5852  1.29.2.2  skrll 		}
   5853  1.29.2.2  skrll 	}
   5854  1.29.2.2  skrll 
   5855  1.29.2.2  skrll 	return;
   5856  1.29.2.2  skrll }
   5857  1.29.2.2  skrll 
   5858  1.29.2.2  skrll static void
   5859  1.29.2.2  skrll iwm_stop(struct ifnet *ifp, int disable)
   5860  1.29.2.2  skrll {
   5861  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5862  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5863  1.29.2.2  skrll 
   5864  1.29.2.2  skrll 	sc->sc_flags &= ~IWM_FLAG_HW_INITED;
   5865  1.29.2.2  skrll 	sc->sc_flags |= IWM_FLAG_STOPPED;
   5866  1.29.2.2  skrll 	sc->sc_generation++;
   5867  1.29.2.2  skrll 	sc->sc_scanband = 0;
   5868  1.29.2.2  skrll 	sc->sc_auth_prot = 0;
   5869  1.29.2.2  skrll 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
   5870  1.29.2.2  skrll 
   5871  1.29.2.2  skrll 	if (ic->ic_state != IEEE80211_S_INIT)
   5872  1.29.2.2  skrll 		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
   5873  1.29.2.2  skrll 
   5874  1.29.2.2  skrll 	callout_stop(&sc->sc_calib_to);
   5875  1.29.2.2  skrll 	ifp->if_timer = sc->sc_tx_timer = 0;
   5876  1.29.2.2  skrll 	iwm_stop_device(sc);
   5877  1.29.2.2  skrll }
   5878  1.29.2.2  skrll 
   5879  1.29.2.2  skrll static void
   5880  1.29.2.2  skrll iwm_watchdog(struct ifnet *ifp)
   5881  1.29.2.2  skrll {
   5882  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5883  1.29.2.2  skrll 
   5884  1.29.2.2  skrll 	ifp->if_timer = 0;
   5885  1.29.2.2  skrll 	if (sc->sc_tx_timer > 0) {
   5886  1.29.2.2  skrll 		if (--sc->sc_tx_timer == 0) {
   5887  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev, "device timeout\n");
   5888  1.29.2.2  skrll #ifdef IWM_DEBUG
   5889  1.29.2.2  skrll 			iwm_nic_error(sc);
   5890  1.29.2.2  skrll #endif
   5891  1.29.2.2  skrll 			ifp->if_flags &= ~IFF_UP;
   5892  1.29.2.2  skrll 			iwm_stop(ifp, 1);
   5893  1.29.2.2  skrll 			ifp->if_oerrors++;
   5894  1.29.2.2  skrll 			return;
   5895  1.29.2.2  skrll 		}
   5896  1.29.2.2  skrll 		ifp->if_timer = 1;
   5897  1.29.2.2  skrll 	}
   5898  1.29.2.2  skrll 
   5899  1.29.2.2  skrll 	ieee80211_watchdog(&sc->sc_ic);
   5900  1.29.2.2  skrll }
   5901  1.29.2.2  skrll 
   5902  1.29.2.2  skrll static int
   5903  1.29.2.2  skrll iwm_ioctl(struct ifnet *ifp, u_long cmd, void *data)
   5904  1.29.2.2  skrll {
   5905  1.29.2.2  skrll 	struct iwm_softc *sc = ifp->if_softc;
   5906  1.29.2.2  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   5907  1.29.2.2  skrll 	const struct sockaddr *sa;
   5908  1.29.2.2  skrll 	int s, error = 0;
   5909  1.29.2.2  skrll 
   5910  1.29.2.2  skrll 	s = splnet();
   5911  1.29.2.2  skrll 
   5912  1.29.2.2  skrll 	switch (cmd) {
   5913  1.29.2.2  skrll 	case SIOCSIFADDR:
   5914  1.29.2.2  skrll 		ifp->if_flags |= IFF_UP;
   5915  1.29.2.2  skrll 		/* FALLTHROUGH */
   5916  1.29.2.2  skrll 	case SIOCSIFFLAGS:
   5917  1.29.2.2  skrll 		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
   5918  1.29.2.2  skrll 			break;
   5919  1.29.2.2  skrll 		if (ifp->if_flags & IFF_UP) {
   5920  1.29.2.2  skrll 			if (!(ifp->if_flags & IFF_RUNNING)) {
   5921  1.29.2.2  skrll 				if ((error = iwm_init(ifp)) != 0)
   5922  1.29.2.2  skrll 					ifp->if_flags &= ~IFF_UP;
   5923  1.29.2.2  skrll 			}
   5924  1.29.2.2  skrll 		} else {
   5925  1.29.2.2  skrll 			if (ifp->if_flags & IFF_RUNNING)
   5926  1.29.2.2  skrll 				iwm_stop(ifp, 1);
   5927  1.29.2.2  skrll 		}
   5928  1.29.2.2  skrll 		break;
   5929  1.29.2.2  skrll 
   5930  1.29.2.2  skrll 	case SIOCADDMULTI:
   5931  1.29.2.2  skrll 	case SIOCDELMULTI:
   5932  1.29.2.4  skrll 		if (!ISSET(sc->sc_flags, IWM_FLAG_ATTACHED)) {
   5933  1.29.2.4  skrll 			error = ENXIO;
   5934  1.29.2.4  skrll 			break;
   5935  1.29.2.4  skrll 		}
   5936  1.29.2.2  skrll 		sa = ifreq_getaddr(SIOCADDMULTI, (struct ifreq *)data);
   5937  1.29.2.2  skrll 		error = (cmd == SIOCADDMULTI) ?
   5938  1.29.2.2  skrll 		    ether_addmulti(sa, &sc->sc_ec) :
   5939  1.29.2.2  skrll 		    ether_delmulti(sa, &sc->sc_ec);
   5940  1.29.2.2  skrll 		if (error == ENETRESET)
   5941  1.29.2.2  skrll 			error = 0;
   5942  1.29.2.2  skrll 		break;
   5943  1.29.2.2  skrll 
   5944  1.29.2.2  skrll 	default:
   5945  1.29.2.4  skrll 		if (!ISSET(sc->sc_flags, IWM_FLAG_ATTACHED)) {
   5946  1.29.2.4  skrll 			error = ether_ioctl(ifp, cmd, data);
   5947  1.29.2.4  skrll 			break;
   5948  1.29.2.4  skrll 		}
   5949  1.29.2.2  skrll 		error = ieee80211_ioctl(ic, cmd, data);
   5950  1.29.2.4  skrll 		break;
   5951  1.29.2.2  skrll 	}
   5952  1.29.2.2  skrll 
   5953  1.29.2.2  skrll 	if (error == ENETRESET) {
   5954  1.29.2.2  skrll 		error = 0;
   5955  1.29.2.2  skrll 		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
   5956  1.29.2.2  skrll 		    (IFF_UP | IFF_RUNNING)) {
   5957  1.29.2.2  skrll 			iwm_stop(ifp, 0);
   5958  1.29.2.2  skrll 			error = iwm_init(ifp);
   5959  1.29.2.2  skrll 		}
   5960  1.29.2.2  skrll 	}
   5961  1.29.2.2  skrll 
   5962  1.29.2.2  skrll 	splx(s);
   5963  1.29.2.2  skrll 	return error;
   5964  1.29.2.2  skrll }
   5965  1.29.2.2  skrll 
   5966  1.29.2.2  skrll /*
   5967  1.29.2.2  skrll  * The interrupt side of things
   5968  1.29.2.2  skrll  */
   5969  1.29.2.2  skrll 
   5970  1.29.2.2  skrll /*
   5971  1.29.2.2  skrll  * error dumping routines are from iwlwifi/mvm/utils.c
   5972  1.29.2.2  skrll  */
   5973  1.29.2.2  skrll 
   5974  1.29.2.2  skrll /*
   5975  1.29.2.2  skrll  * Note: This structure is read from the device with IO accesses,
   5976  1.29.2.2  skrll  * and the reading already does the endian conversion. As it is
   5977  1.29.2.2  skrll  * read with uint32_t-sized accesses, any members with a different size
   5978  1.29.2.2  skrll  * need to be ordered correctly though!
   5979  1.29.2.2  skrll  */
   5980  1.29.2.2  skrll struct iwm_error_event_table {
   5981  1.29.2.2  skrll 	uint32_t valid;		/* (nonzero) valid, (0) log is empty */
   5982  1.29.2.2  skrll 	uint32_t error_id;		/* type of error */
   5983  1.29.2.2  skrll 	uint32_t pc;			/* program counter */
   5984  1.29.2.2  skrll 	uint32_t blink1;		/* branch link */
   5985  1.29.2.2  skrll 	uint32_t blink2;		/* branch link */
   5986  1.29.2.2  skrll 	uint32_t ilink1;		/* interrupt link */
   5987  1.29.2.2  skrll 	uint32_t ilink2;		/* interrupt link */
   5988  1.29.2.2  skrll 	uint32_t data1;		/* error-specific data */
   5989  1.29.2.2  skrll 	uint32_t data2;		/* error-specific data */
   5990  1.29.2.2  skrll 	uint32_t data3;		/* error-specific data */
   5991  1.29.2.2  skrll 	uint32_t bcon_time;		/* beacon timer */
   5992  1.29.2.2  skrll 	uint32_t tsf_low;		/* network timestamp function timer */
   5993  1.29.2.2  skrll 	uint32_t tsf_hi;		/* network timestamp function timer */
   5994  1.29.2.2  skrll 	uint32_t gp1;		/* GP1 timer register */
   5995  1.29.2.2  skrll 	uint32_t gp2;		/* GP2 timer register */
   5996  1.29.2.2  skrll 	uint32_t gp3;		/* GP3 timer register */
   5997  1.29.2.2  skrll 	uint32_t ucode_ver;		/* uCode version */
   5998  1.29.2.2  skrll 	uint32_t hw_ver;		/* HW Silicon version */
   5999  1.29.2.2  skrll 	uint32_t brd_ver;		/* HW board version */
   6000  1.29.2.2  skrll 	uint32_t log_pc;		/* log program counter */
   6001  1.29.2.2  skrll 	uint32_t frame_ptr;		/* frame pointer */
   6002  1.29.2.2  skrll 	uint32_t stack_ptr;		/* stack pointer */
   6003  1.29.2.2  skrll 	uint32_t hcmd;		/* last host command header */
   6004  1.29.2.2  skrll 	uint32_t isr0;		/* isr status register LMPM_NIC_ISR0:
   6005  1.29.2.2  skrll 				 * rxtx_flag */
   6006  1.29.2.2  skrll 	uint32_t isr1;		/* isr status register LMPM_NIC_ISR1:
   6007  1.29.2.2  skrll 				 * host_flag */
   6008  1.29.2.2  skrll 	uint32_t isr2;		/* isr status register LMPM_NIC_ISR2:
   6009  1.29.2.2  skrll 				 * enc_flag */
   6010  1.29.2.2  skrll 	uint32_t isr3;		/* isr status register LMPM_NIC_ISR3:
   6011  1.29.2.2  skrll 				 * time_flag */
   6012  1.29.2.2  skrll 	uint32_t isr4;		/* isr status register LMPM_NIC_ISR4:
   6013  1.29.2.2  skrll 				 * wico interrupt */
   6014  1.29.2.2  skrll 	uint32_t isr_pref;		/* isr status register LMPM_NIC_PREF_STAT */
   6015  1.29.2.2  skrll 	uint32_t wait_event;		/* wait event() caller address */
   6016  1.29.2.2  skrll 	uint32_t l2p_control;	/* L2pControlField */
   6017  1.29.2.2  skrll 	uint32_t l2p_duration;	/* L2pDurationField */
   6018  1.29.2.2  skrll 	uint32_t l2p_mhvalid;	/* L2pMhValidBits */
   6019  1.29.2.2  skrll 	uint32_t l2p_addr_match;	/* L2pAddrMatchStat */
   6020  1.29.2.2  skrll 	uint32_t lmpm_pmg_sel;	/* indicate which clocks are turned on
   6021  1.29.2.2  skrll 				 * (LMPM_PMG_SEL) */
   6022  1.29.2.2  skrll 	uint32_t u_timestamp;	/* indicate when the date and time of the
   6023  1.29.2.2  skrll 				 * compilation */
   6024  1.29.2.2  skrll 	uint32_t flow_handler;	/* FH read/write pointers, RX credit */
   6025  1.29.2.2  skrll } __packed;
   6026  1.29.2.2  skrll 
   6027  1.29.2.2  skrll #define ERROR_START_OFFSET  (1 * sizeof(uint32_t))
   6028  1.29.2.2  skrll #define ERROR_ELEM_SIZE     (7 * sizeof(uint32_t))
   6029  1.29.2.2  skrll 
   6030  1.29.2.2  skrll #ifdef IWM_DEBUG
   6031  1.29.2.2  skrll static const struct {
   6032  1.29.2.2  skrll 	const char *name;
   6033  1.29.2.2  skrll 	uint8_t num;
   6034  1.29.2.2  skrll } advanced_lookup[] = {
   6035  1.29.2.2  skrll 	{ "NMI_INTERRUPT_WDG", 0x34 },
   6036  1.29.2.2  skrll 	{ "SYSASSERT", 0x35 },
   6037  1.29.2.2  skrll 	{ "UCODE_VERSION_MISMATCH", 0x37 },
   6038  1.29.2.2  skrll 	{ "BAD_COMMAND", 0x38 },
   6039  1.29.2.2  skrll 	{ "NMI_INTERRUPT_DATA_ACTION_PT", 0x3C },
   6040  1.29.2.2  skrll 	{ "FATAL_ERROR", 0x3D },
   6041  1.29.2.2  skrll 	{ "NMI_TRM_HW_ERR", 0x46 },
   6042  1.29.2.2  skrll 	{ "NMI_INTERRUPT_TRM", 0x4C },
   6043  1.29.2.2  skrll 	{ "NMI_INTERRUPT_BREAK_POINT", 0x54 },
   6044  1.29.2.2  skrll 	{ "NMI_INTERRUPT_WDG_RXF_FULL", 0x5C },
   6045  1.29.2.2  skrll 	{ "NMI_INTERRUPT_WDG_NO_RBD_RXF_FULL", 0x64 },
   6046  1.29.2.2  skrll 	{ "NMI_INTERRUPT_HOST", 0x66 },
   6047  1.29.2.2  skrll 	{ "NMI_INTERRUPT_ACTION_PT", 0x7C },
   6048  1.29.2.2  skrll 	{ "NMI_INTERRUPT_UNKNOWN", 0x84 },
   6049  1.29.2.2  skrll 	{ "NMI_INTERRUPT_INST_ACTION_PT", 0x86 },
   6050  1.29.2.2  skrll 	{ "ADVANCED_SYSASSERT", 0 },
   6051  1.29.2.2  skrll };
   6052  1.29.2.2  skrll 
   6053  1.29.2.2  skrll static const char *
   6054  1.29.2.2  skrll iwm_desc_lookup(uint32_t num)
   6055  1.29.2.2  skrll {
   6056  1.29.2.2  skrll 	int i;
   6057  1.29.2.2  skrll 
   6058  1.29.2.2  skrll 	for (i = 0; i < __arraycount(advanced_lookup) - 1; i++)
   6059  1.29.2.2  skrll 		if (advanced_lookup[i].num == num)
   6060  1.29.2.2  skrll 			return advanced_lookup[i].name;
   6061  1.29.2.2  skrll 
   6062  1.29.2.2  skrll 	/* No entry matches 'num', so it is the last: ADVANCED_SYSASSERT */
   6063  1.29.2.2  skrll 	return advanced_lookup[i].name;
   6064  1.29.2.2  skrll }
   6065  1.29.2.2  skrll 
   6066  1.29.2.2  skrll /*
   6067  1.29.2.2  skrll  * Support for dumping the error log seemed like a good idea ...
   6068  1.29.2.2  skrll  * but it's mostly hex junk and the only sensible thing is the
   6069  1.29.2.2  skrll  * hw/ucode revision (which we know anyway).  Since it's here,
   6070  1.29.2.2  skrll  * I'll just leave it in, just in case e.g. the Intel guys want to
   6071  1.29.2.2  skrll  * help us decipher some "ADVANCED_SYSASSERT" later.
   6072  1.29.2.2  skrll  */
   6073  1.29.2.2  skrll static void
   6074  1.29.2.2  skrll iwm_nic_error(struct iwm_softc *sc)
   6075  1.29.2.2  skrll {
   6076  1.29.2.2  skrll 	struct iwm_error_event_table table;
   6077  1.29.2.2  skrll 	uint32_t base;
   6078  1.29.2.2  skrll 
   6079  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "dumping device error log\n");
   6080  1.29.2.2  skrll 	base = sc->sc_uc.uc_error_event_table;
   6081  1.29.2.2  skrll 	if (base < 0x800000 || base >= 0x80C000) {
   6082  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   6083  1.29.2.2  skrll 		    "Not valid error log pointer 0x%08x\n", base);
   6084  1.29.2.2  skrll 		return;
   6085  1.29.2.2  skrll 	}
   6086  1.29.2.2  skrll 
   6087  1.29.2.2  skrll 	if (iwm_read_mem(sc, base, &table, sizeof(table)/sizeof(uint32_t)) != 0) {
   6088  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "reading errlog failed\n");
   6089  1.29.2.2  skrll 		return;
   6090  1.29.2.2  skrll 	}
   6091  1.29.2.2  skrll 
   6092  1.29.2.2  skrll 	if (!table.valid) {
   6093  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "errlog not found, skipping\n");
   6094  1.29.2.2  skrll 		return;
   6095  1.29.2.2  skrll 	}
   6096  1.29.2.2  skrll 
   6097  1.29.2.2  skrll 	if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) {
   6098  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "Start IWL Error Log Dump:\n");
   6099  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "Status: 0x%x, count: %d\n",
   6100  1.29.2.2  skrll 		    sc->sc_flags, table.valid);
   6101  1.29.2.2  skrll 	}
   6102  1.29.2.2  skrll 
   6103  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | %-28s\n", table.error_id,
   6104  1.29.2.2  skrll 		iwm_desc_lookup(table.error_id));
   6105  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | uPc\n", table.pc);
   6106  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | branchlink1\n", table.blink1);
   6107  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | branchlink2\n", table.blink2);
   6108  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | interruptlink1\n", table.ilink1);
   6109  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | interruptlink2\n", table.ilink2);
   6110  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | data1\n", table.data1);
   6111  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | data2\n", table.data2);
   6112  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | data3\n", table.data3);
   6113  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | beacon time\n", table.bcon_time);
   6114  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | tsf low\n", table.tsf_low);
   6115  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | tsf hi\n", table.tsf_hi);
   6116  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | time gp1\n", table.gp1);
   6117  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | time gp2\n", table.gp2);
   6118  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | time gp3\n", table.gp3);
   6119  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | uCode version\n", table.ucode_ver);
   6120  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | hw version\n", table.hw_ver);
   6121  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | board version\n", table.brd_ver);
   6122  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | hcmd\n", table.hcmd);
   6123  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | isr0\n", table.isr0);
   6124  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | isr1\n", table.isr1);
   6125  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | isr2\n", table.isr2);
   6126  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | isr3\n", table.isr3);
   6127  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | isr4\n", table.isr4);
   6128  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | isr_pref\n", table.isr_pref);
   6129  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | wait_event\n", table.wait_event);
   6130  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | l2p_control\n", table.l2p_control);
   6131  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | l2p_duration\n",
   6132  1.29.2.2  skrll 	    table.l2p_duration);
   6133  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | l2p_mhvalid\n", table.l2p_mhvalid);
   6134  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | l2p_addr_match\n",
   6135  1.29.2.2  skrll 	    table.l2p_addr_match);
   6136  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | lmpm_pmg_sel\n",
   6137  1.29.2.2  skrll 	    table.lmpm_pmg_sel);
   6138  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | timestamp\n", table.u_timestamp);
   6139  1.29.2.2  skrll 	aprint_error_dev(sc->sc_dev, "%08X | flow_handler\n",
   6140  1.29.2.2  skrll 	    table.flow_handler);
   6141  1.29.2.2  skrll }
   6142  1.29.2.2  skrll #endif
   6143  1.29.2.2  skrll 
   6144  1.29.2.2  skrll #define SYNC_RESP_STRUCT(_var_, _pkt_)					\
   6145  1.29.2.2  skrll do {									\
   6146  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)),	\
   6147  1.29.2.2  skrll 	    sizeof(*(_var_)), BUS_DMASYNC_POSTREAD);			\
   6148  1.29.2.2  skrll 	_var_ = (void *)((_pkt_)+1);					\
   6149  1.29.2.2  skrll } while (/*CONSTCOND*/0)
   6150  1.29.2.2  skrll 
   6151  1.29.2.2  skrll #define SYNC_RESP_PTR(_ptr_, _len_, _pkt_)				\
   6152  1.29.2.2  skrll do {									\
   6153  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, data->map, sizeof(*(_pkt_)),	\
   6154  1.29.2.2  skrll 	    sizeof(len), BUS_DMASYNC_POSTREAD);				\
   6155  1.29.2.2  skrll 	_ptr_ = (void *)((_pkt_)+1);					\
   6156  1.29.2.2  skrll } while (/*CONSTCOND*/0)
   6157  1.29.2.2  skrll 
   6158  1.29.2.2  skrll #define ADVANCE_RXQ(sc) (sc->rxq.cur = (sc->rxq.cur + 1) % IWM_RX_RING_COUNT);
   6159  1.29.2.2  skrll 
   6160  1.29.2.2  skrll /*
   6161  1.29.2.2  skrll  * Process an IWM_CSR_INT_BIT_FH_RX or IWM_CSR_INT_BIT_SW_RX interrupt.
   6162  1.29.2.2  skrll  * Basic structure from if_iwn
   6163  1.29.2.2  skrll  */
   6164  1.29.2.2  skrll static void
   6165  1.29.2.2  skrll iwm_notif_intr(struct iwm_softc *sc)
   6166  1.29.2.2  skrll {
   6167  1.29.2.2  skrll 	uint16_t hw;
   6168  1.29.2.2  skrll 
   6169  1.29.2.2  skrll 	bus_dmamap_sync(sc->sc_dmat, sc->rxq.stat_dma.map,
   6170  1.29.2.2  skrll 	    0, sc->rxq.stat_dma.size, BUS_DMASYNC_POSTREAD);
   6171  1.29.2.2  skrll 
   6172  1.29.2.2  skrll 	hw = le16toh(sc->rxq.stat->closed_rb_num) & 0xfff;
   6173  1.29.2.2  skrll 	while (sc->rxq.cur != hw) {
   6174  1.29.2.2  skrll 		struct iwm_rx_data *data = &sc->rxq.data[sc->rxq.cur];
   6175  1.29.2.2  skrll 		struct iwm_rx_packet *pkt, tmppkt;
   6176  1.29.2.2  skrll 		struct iwm_cmd_response *cresp;
   6177  1.29.2.2  skrll 		int qid, idx;
   6178  1.29.2.2  skrll 
   6179  1.29.2.2  skrll 		bus_dmamap_sync(sc->sc_dmat, data->map, 0, sizeof(*pkt),
   6180  1.29.2.2  skrll 		    BUS_DMASYNC_POSTREAD);
   6181  1.29.2.2  skrll 		pkt = mtod(data->m, struct iwm_rx_packet *);
   6182  1.29.2.2  skrll 
   6183  1.29.2.2  skrll 		qid = pkt->hdr.qid & ~0x80;
   6184  1.29.2.2  skrll 		idx = pkt->hdr.idx;
   6185  1.29.2.2  skrll 
   6186  1.29.2.2  skrll 		DPRINTFN(12, ("rx packet qid=%d idx=%d flags=%x type=%x %d %d\n",
   6187  1.29.2.2  skrll 		    pkt->hdr.qid & ~0x80, pkt->hdr.idx, pkt->hdr.flags,
   6188  1.29.2.2  skrll 		    pkt->hdr.code, sc->rxq.cur, hw));
   6189  1.29.2.2  skrll 
   6190  1.29.2.2  skrll 		/*
   6191  1.29.2.2  skrll 		 * randomly get these from the firmware, no idea why.
   6192  1.29.2.2  skrll 		 * they at least seem harmless, so just ignore them for now
   6193  1.29.2.2  skrll 		 */
   6194  1.29.2.2  skrll 		if (__predict_false((pkt->hdr.code == 0 && qid == 0 && idx == 0)
   6195  1.29.2.2  skrll 		    || pkt->len_n_flags == htole32(0x55550000))) {
   6196  1.29.2.2  skrll 			ADVANCE_RXQ(sc);
   6197  1.29.2.2  skrll 			continue;
   6198  1.29.2.2  skrll 		}
   6199  1.29.2.2  skrll 
   6200  1.29.2.2  skrll 		switch (pkt->hdr.code) {
   6201  1.29.2.2  skrll 		case IWM_REPLY_RX_PHY_CMD:
   6202  1.29.2.2  skrll 			iwm_mvm_rx_rx_phy_cmd(sc, pkt, data);
   6203  1.29.2.2  skrll 			break;
   6204  1.29.2.2  skrll 
   6205  1.29.2.2  skrll 		case IWM_REPLY_RX_MPDU_CMD:
   6206  1.29.2.2  skrll 			tmppkt = *pkt; // XXX m is freed by ieee80211_input()
   6207  1.29.2.2  skrll 			iwm_mvm_rx_rx_mpdu(sc, pkt, data);
   6208  1.29.2.2  skrll 			pkt = &tmppkt;
   6209  1.29.2.2  skrll 			break;
   6210  1.29.2.2  skrll 
   6211  1.29.2.2  skrll 		case IWM_TX_CMD:
   6212  1.29.2.2  skrll 			iwm_mvm_rx_tx_cmd(sc, pkt, data);
   6213  1.29.2.2  skrll 			break;
   6214  1.29.2.2  skrll 
   6215  1.29.2.2  skrll 		case IWM_MISSED_BEACONS_NOTIFICATION:
   6216  1.29.2.2  skrll 			iwm_mvm_rx_missed_beacons_notif(sc, pkt, data);
   6217  1.29.2.2  skrll 			break;
   6218  1.29.2.2  skrll 
   6219  1.29.2.2  skrll 		case IWM_MVM_ALIVE: {
   6220  1.29.2.2  skrll 			struct iwm_mvm_alive_resp *resp;
   6221  1.29.2.2  skrll 			SYNC_RESP_STRUCT(resp, pkt);
   6222  1.29.2.2  skrll 
   6223  1.29.2.2  skrll 			sc->sc_uc.uc_error_event_table
   6224  1.29.2.2  skrll 			    = le32toh(resp->error_event_table_ptr);
   6225  1.29.2.2  skrll 			sc->sc_uc.uc_log_event_table
   6226  1.29.2.2  skrll 			    = le32toh(resp->log_event_table_ptr);
   6227  1.29.2.2  skrll 			sc->sched_base = le32toh(resp->scd_base_ptr);
   6228  1.29.2.2  skrll 			sc->sc_uc.uc_ok = resp->status == IWM_ALIVE_STATUS_OK;
   6229  1.29.2.2  skrll 
   6230  1.29.2.2  skrll 			sc->sc_uc.uc_intr = 1;
   6231  1.29.2.2  skrll 			wakeup(&sc->sc_uc);
   6232  1.29.2.2  skrll 			break; }
   6233  1.29.2.2  skrll 
   6234  1.29.2.2  skrll 		case IWM_CALIB_RES_NOTIF_PHY_DB: {
   6235  1.29.2.2  skrll 			struct iwm_calib_res_notif_phy_db *phy_db_notif;
   6236  1.29.2.2  skrll 			SYNC_RESP_STRUCT(phy_db_notif, pkt);
   6237  1.29.2.2  skrll 
   6238  1.29.2.2  skrll 			uint16_t size = le16toh(phy_db_notif->length);
   6239  1.29.2.2  skrll 			bus_dmamap_sync(sc->sc_dmat, data->map,
   6240  1.29.2.2  skrll 			    sizeof(*pkt) + sizeof(*phy_db_notif),
   6241  1.29.2.2  skrll 			    size, BUS_DMASYNC_POSTREAD);
   6242  1.29.2.2  skrll 			iwm_phy_db_set_section(sc, phy_db_notif, size);
   6243  1.29.2.2  skrll 
   6244  1.29.2.2  skrll 			break; }
   6245  1.29.2.2  skrll 
   6246  1.29.2.2  skrll 		case IWM_STATISTICS_NOTIFICATION: {
   6247  1.29.2.2  skrll 			struct iwm_notif_statistics *stats;
   6248  1.29.2.2  skrll 			SYNC_RESP_STRUCT(stats, pkt);
   6249  1.29.2.2  skrll 			memcpy(&sc->sc_stats, stats, sizeof(sc->sc_stats));
   6250  1.29.2.2  skrll 			sc->sc_noise = iwm_get_noise(&stats->rx.general);
   6251  1.29.2.2  skrll 			break; }
   6252  1.29.2.2  skrll 
   6253  1.29.2.2  skrll 		case IWM_NVM_ACCESS_CMD:
   6254  1.29.2.2  skrll 			if (sc->sc_wantresp == ((qid << 16) | idx)) {
   6255  1.29.2.2  skrll 				bus_dmamap_sync(sc->sc_dmat, data->map, 0,
   6256  1.29.2.2  skrll 				    sizeof(sc->sc_cmd_resp),
   6257  1.29.2.2  skrll 				    BUS_DMASYNC_POSTREAD);
   6258  1.29.2.2  skrll 				memcpy(sc->sc_cmd_resp,
   6259  1.29.2.2  skrll 				    pkt, sizeof(sc->sc_cmd_resp));
   6260  1.29.2.2  skrll 			}
   6261  1.29.2.2  skrll 			break;
   6262  1.29.2.2  skrll 
   6263  1.29.2.2  skrll 		case IWM_PHY_CONFIGURATION_CMD:
   6264  1.29.2.2  skrll 		case IWM_TX_ANT_CONFIGURATION_CMD:
   6265  1.29.2.2  skrll 		case IWM_ADD_STA:
   6266  1.29.2.2  skrll 		case IWM_MAC_CONTEXT_CMD:
   6267  1.29.2.2  skrll 		case IWM_REPLY_SF_CFG_CMD:
   6268  1.29.2.2  skrll 		case IWM_POWER_TABLE_CMD:
   6269  1.29.2.2  skrll 		case IWM_PHY_CONTEXT_CMD:
   6270  1.29.2.2  skrll 		case IWM_BINDING_CONTEXT_CMD:
   6271  1.29.2.2  skrll 		case IWM_TIME_EVENT_CMD:
   6272  1.29.2.2  skrll 		case IWM_SCAN_REQUEST_CMD:
   6273  1.29.2.2  skrll 		case IWM_REPLY_BEACON_FILTERING_CMD:
   6274  1.29.2.2  skrll 		case IWM_MAC_PM_POWER_TABLE:
   6275  1.29.2.2  skrll 		case IWM_TIME_QUOTA_CMD:
   6276  1.29.2.2  skrll 		case IWM_REMOVE_STA:
   6277  1.29.2.2  skrll 		case IWM_TXPATH_FLUSH:
   6278  1.29.2.2  skrll 		case IWM_LQ_CMD:
   6279  1.29.2.2  skrll 			SYNC_RESP_STRUCT(cresp, pkt);
   6280  1.29.2.2  skrll 			if (sc->sc_wantresp == ((qid << 16) | idx)) {
   6281  1.29.2.2  skrll 				memcpy(sc->sc_cmd_resp,
   6282  1.29.2.2  skrll 				    pkt, sizeof(*pkt)+sizeof(*cresp));
   6283  1.29.2.2  skrll 			}
   6284  1.29.2.2  skrll 			break;
   6285  1.29.2.2  skrll 
   6286  1.29.2.2  skrll 		/* ignore */
   6287  1.29.2.2  skrll 		case 0x6c: /* IWM_PHY_DB_CMD, no idea why it's not in fw-api.h */
   6288  1.29.2.2  skrll 			break;
   6289  1.29.2.2  skrll 
   6290  1.29.2.2  skrll 		case IWM_INIT_COMPLETE_NOTIF:
   6291  1.29.2.2  skrll 			sc->sc_init_complete = 1;
   6292  1.29.2.2  skrll 			wakeup(&sc->sc_init_complete);
   6293  1.29.2.2  skrll 			break;
   6294  1.29.2.2  skrll 
   6295  1.29.2.2  skrll 		case IWM_SCAN_COMPLETE_NOTIFICATION: {
   6296  1.29.2.2  skrll 			struct iwm_scan_complete_notif *notif;
   6297  1.29.2.2  skrll 			SYNC_RESP_STRUCT(notif, pkt);
   6298  1.29.2.2  skrll 
   6299  1.29.2.2  skrll 			workqueue_enqueue(sc->sc_eswq, &sc->sc_eswk, NULL);
   6300  1.29.2.2  skrll 			break; }
   6301  1.29.2.2  skrll 
   6302  1.29.2.2  skrll 		case IWM_REPLY_ERROR: {
   6303  1.29.2.2  skrll 			struct iwm_error_resp *resp;
   6304  1.29.2.2  skrll 			SYNC_RESP_STRUCT(resp, pkt);
   6305  1.29.2.2  skrll 
   6306  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   6307  1.29.2.2  skrll 			    "firmware error 0x%x, cmd 0x%x\n",
   6308  1.29.2.2  skrll 			    le32toh(resp->error_type), resp->cmd_id);
   6309  1.29.2.2  skrll 			break; }
   6310  1.29.2.2  skrll 
   6311  1.29.2.2  skrll 		case IWM_TIME_EVENT_NOTIFICATION: {
   6312  1.29.2.2  skrll 			struct iwm_time_event_notif *notif;
   6313  1.29.2.2  skrll 			SYNC_RESP_STRUCT(notif, pkt);
   6314  1.29.2.2  skrll 
   6315  1.29.2.2  skrll 			if (notif->status) {
   6316  1.29.2.2  skrll 				if (le32toh(notif->action) &
   6317  1.29.2.2  skrll 				    IWM_TE_V2_NOTIF_HOST_EVENT_START)
   6318  1.29.2.2  skrll 					sc->sc_auth_prot = 2;
   6319  1.29.2.2  skrll 				else
   6320  1.29.2.2  skrll 					sc->sc_auth_prot = 0;
   6321  1.29.2.2  skrll 			} else {
   6322  1.29.2.2  skrll 				sc->sc_auth_prot = -1;
   6323  1.29.2.2  skrll 			}
   6324  1.29.2.2  skrll 			wakeup(&sc->sc_auth_prot);
   6325  1.29.2.2  skrll 			break; }
   6326  1.29.2.2  skrll 
   6327  1.29.2.2  skrll 		case IWM_MCAST_FILTER_CMD:
   6328  1.29.2.2  skrll 			break;
   6329  1.29.2.2  skrll 
   6330  1.29.2.2  skrll 		default:
   6331  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   6332  1.29.2.2  skrll 			    "code %02x frame %d/%d %x UNHANDLED "
   6333  1.29.2.2  skrll 			    "(this should not happen)\n",
   6334  1.29.2.2  skrll 			    pkt->hdr.code, qid, idx, pkt->len_n_flags);
   6335  1.29.2.2  skrll 			break;
   6336  1.29.2.2  skrll 		}
   6337  1.29.2.2  skrll 
   6338  1.29.2.2  skrll 		/*
   6339  1.29.2.2  skrll 		 * Why test bit 0x80?  The Linux driver:
   6340  1.29.2.2  skrll 		 *
   6341  1.29.2.2  skrll 		 * There is one exception:  uCode sets bit 15 when it
   6342  1.29.2.2  skrll 		 * originates the response/notification, i.e. when the
   6343  1.29.2.2  skrll 		 * response/notification is not a direct response to a
   6344  1.29.2.2  skrll 		 * command sent by the driver.  For example, uCode issues
   6345  1.29.2.2  skrll 		 * IWM_REPLY_RX when it sends a received frame to the driver;
   6346  1.29.2.2  skrll 		 * it is not a direct response to any driver command.
   6347  1.29.2.2  skrll 		 *
   6348  1.29.2.2  skrll 		 * Ok, so since when is 7 == 15?  Well, the Linux driver
   6349  1.29.2.2  skrll 		 * uses a slightly different format for pkt->hdr, and "qid"
   6350  1.29.2.2  skrll 		 * is actually the upper byte of a two-byte field.
   6351  1.29.2.2  skrll 		 */
   6352  1.29.2.2  skrll 		if (!(pkt->hdr.qid & (1 << 7))) {
   6353  1.29.2.2  skrll 			iwm_cmd_done(sc, pkt);
   6354  1.29.2.2  skrll 		}
   6355  1.29.2.2  skrll 
   6356  1.29.2.2  skrll 		ADVANCE_RXQ(sc);
   6357  1.29.2.2  skrll 	}
   6358  1.29.2.2  skrll 
   6359  1.29.2.2  skrll 	IWM_CLRBITS(sc, IWM_CSR_GP_CNTRL,
   6360  1.29.2.2  skrll 	    IWM_CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
   6361  1.29.2.2  skrll 
   6362  1.29.2.2  skrll 	/*
   6363  1.29.2.2  skrll 	 * Tell the firmware what we have processed.
   6364  1.29.2.2  skrll 	 * Seems like the hardware gets upset unless we align
   6365  1.29.2.2  skrll 	 * the write by 8??
   6366  1.29.2.2  skrll 	 */
   6367  1.29.2.2  skrll 	hw = (hw == 0) ? IWM_RX_RING_COUNT - 1 : hw - 1;
   6368  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_FH_RSCSR_CHNL0_WPTR, hw & ~7);
   6369  1.29.2.2  skrll }
   6370  1.29.2.2  skrll 
   6371  1.29.2.2  skrll static int
   6372  1.29.2.2  skrll iwm_intr(void *arg)
   6373  1.29.2.2  skrll {
   6374  1.29.2.2  skrll 	struct iwm_softc *sc = arg;
   6375  1.29.2.2  skrll 	struct ifnet *ifp = IC2IFP(&sc->sc_ic);
   6376  1.29.2.2  skrll 	int handled = 0;
   6377  1.29.2.2  skrll 	int r1, r2, rv = 0;
   6378  1.29.2.2  skrll 	int isperiodic = 0;
   6379  1.29.2.2  skrll 
   6380  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT_MASK, 0);
   6381  1.29.2.2  skrll 
   6382  1.29.2.2  skrll 	if (sc->sc_flags & IWM_FLAG_USE_ICT) {
   6383  1.29.2.2  skrll 		uint32_t *ict = sc->ict_dma.vaddr;
   6384  1.29.2.2  skrll 		int tmp;
   6385  1.29.2.2  skrll 
   6386  1.29.2.2  skrll 		tmp = htole32(ict[sc->ict_cur]);
   6387  1.29.2.2  skrll 		if (!tmp)
   6388  1.29.2.2  skrll 			goto out_ena;
   6389  1.29.2.2  skrll 
   6390  1.29.2.2  skrll 		/*
   6391  1.29.2.2  skrll 		 * ok, there was something.  keep plowing until we have all.
   6392  1.29.2.2  skrll 		 */
   6393  1.29.2.2  skrll 		r1 = r2 = 0;
   6394  1.29.2.2  skrll 		while (tmp) {
   6395  1.29.2.2  skrll 			r1 |= tmp;
   6396  1.29.2.2  skrll 			ict[sc->ict_cur] = 0;
   6397  1.29.2.2  skrll 			sc->ict_cur = (sc->ict_cur+1) % IWM_ICT_COUNT;
   6398  1.29.2.2  skrll 			tmp = htole32(ict[sc->ict_cur]);
   6399  1.29.2.2  skrll 		}
   6400  1.29.2.2  skrll 
   6401  1.29.2.2  skrll 		/* this is where the fun begins.  don't ask */
   6402  1.29.2.2  skrll 		if (r1 == 0xffffffff)
   6403  1.29.2.2  skrll 			r1 = 0;
   6404  1.29.2.2  skrll 
   6405  1.29.2.2  skrll 		/* i am not expected to understand this */
   6406  1.29.2.2  skrll 		if (r1 & 0xc0000)
   6407  1.29.2.2  skrll 			r1 |= 0x8000;
   6408  1.29.2.2  skrll 		r1 = (0xff & r1) | ((0xff00 & r1) << 16);
   6409  1.29.2.2  skrll 	} else {
   6410  1.29.2.2  skrll 		r1 = IWM_READ(sc, IWM_CSR_INT);
   6411  1.29.2.2  skrll 		/* "hardware gone" (where, fishing?) */
   6412  1.29.2.2  skrll 		if (r1 == 0xffffffff || (r1 & 0xfffffff0) == 0xa5a5a5a0)
   6413  1.29.2.2  skrll 			goto out;
   6414  1.29.2.2  skrll 		r2 = IWM_READ(sc, IWM_CSR_FH_INT_STATUS);
   6415  1.29.2.2  skrll 	}
   6416  1.29.2.2  skrll 	if (r1 == 0 && r2 == 0) {
   6417  1.29.2.2  skrll 		goto out_ena;
   6418  1.29.2.2  skrll 	}
   6419  1.29.2.2  skrll 
   6420  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT, r1 | ~sc->sc_intmask);
   6421  1.29.2.2  skrll 
   6422  1.29.2.2  skrll 	/* ignored */
   6423  1.29.2.2  skrll 	handled |= (r1 & (IWM_CSR_INT_BIT_ALIVE /*| IWM_CSR_INT_BIT_SCD*/));
   6424  1.29.2.2  skrll 
   6425  1.29.2.2  skrll 	if (r1 & IWM_CSR_INT_BIT_SW_ERR) {
   6426  1.29.2.2  skrll #ifdef IWM_DEBUG
   6427  1.29.2.2  skrll 		int i;
   6428  1.29.2.2  skrll 
   6429  1.29.2.2  skrll 		iwm_nic_error(sc);
   6430  1.29.2.2  skrll 
   6431  1.29.2.2  skrll 		/* Dump driver status (TX and RX rings) while we're here. */
   6432  1.29.2.2  skrll 		DPRINTF(("driver status:\n"));
   6433  1.29.2.2  skrll 		for (i = 0; i < IWM_MVM_MAX_QUEUES; i++) {
   6434  1.29.2.2  skrll 			struct iwm_tx_ring *ring = &sc->txq[i];
   6435  1.29.2.2  skrll 			DPRINTF(("  tx ring %2d: qid=%-2d cur=%-3d "
   6436  1.29.2.2  skrll 			    "queued=%-3d\n",
   6437  1.29.2.2  skrll 			    i, ring->qid, ring->cur, ring->queued));
   6438  1.29.2.2  skrll 		}
   6439  1.29.2.2  skrll 		DPRINTF(("  rx ring: cur=%d\n", sc->rxq.cur));
   6440  1.29.2.2  skrll 		DPRINTF(("  802.11 state %d\n", sc->sc_ic.ic_state));
   6441  1.29.2.2  skrll #endif
   6442  1.29.2.2  skrll 
   6443  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "fatal firmware error\n");
   6444  1.29.2.2  skrll 		ifp->if_flags &= ~IFF_UP;
   6445  1.29.2.2  skrll 		iwm_stop(ifp, 1);
   6446  1.29.2.2  skrll 		rv = 1;
   6447  1.29.2.2  skrll 		goto out;
   6448  1.29.2.2  skrll 
   6449  1.29.2.2  skrll 	}
   6450  1.29.2.2  skrll 
   6451  1.29.2.2  skrll 	if (r1 & IWM_CSR_INT_BIT_HW_ERR) {
   6452  1.29.2.2  skrll 		handled |= IWM_CSR_INT_BIT_HW_ERR;
   6453  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   6454  1.29.2.2  skrll 		    "hardware error, stopping device\n");
   6455  1.29.2.2  skrll 		ifp->if_flags &= ~IFF_UP;
   6456  1.29.2.2  skrll 		iwm_stop(ifp, 1);
   6457  1.29.2.2  skrll 		rv = 1;
   6458  1.29.2.2  skrll 		goto out;
   6459  1.29.2.2  skrll 	}
   6460  1.29.2.2  skrll 
   6461  1.29.2.2  skrll 	/* firmware chunk loaded */
   6462  1.29.2.2  skrll 	if (r1 & IWM_CSR_INT_BIT_FH_TX) {
   6463  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_TX_MASK);
   6464  1.29.2.2  skrll 		handled |= IWM_CSR_INT_BIT_FH_TX;
   6465  1.29.2.2  skrll 
   6466  1.29.2.2  skrll 		sc->sc_fw_chunk_done = 1;
   6467  1.29.2.2  skrll 		wakeup(&sc->sc_fw);
   6468  1.29.2.2  skrll 	}
   6469  1.29.2.2  skrll 
   6470  1.29.2.2  skrll 	if (r1 & IWM_CSR_INT_BIT_RF_KILL) {
   6471  1.29.2.2  skrll 		handled |= IWM_CSR_INT_BIT_RF_KILL;
   6472  1.29.2.2  skrll 		if (iwm_check_rfkill(sc) && (ifp->if_flags & IFF_UP)) {
   6473  1.29.2.2  skrll 			DPRINTF(("%s: rfkill switch, disabling interface\n",
   6474  1.29.2.2  skrll 			    DEVNAME(sc)));
   6475  1.29.2.2  skrll 			ifp->if_flags &= ~IFF_UP;
   6476  1.29.2.2  skrll 			iwm_stop(ifp, 1);
   6477  1.29.2.2  skrll 		}
   6478  1.29.2.2  skrll 	}
   6479  1.29.2.2  skrll 
   6480  1.29.2.2  skrll 	/*
   6481  1.29.2.2  skrll 	 * The Linux driver uses periodic interrupts to avoid races.
   6482  1.29.2.2  skrll 	 * We cargo-cult like it's going out of fashion.
   6483  1.29.2.2  skrll 	 */
   6484  1.29.2.2  skrll 	if (r1 & IWM_CSR_INT_BIT_RX_PERIODIC) {
   6485  1.29.2.2  skrll 		handled |= IWM_CSR_INT_BIT_RX_PERIODIC;
   6486  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_CSR_INT, IWM_CSR_INT_BIT_RX_PERIODIC);
   6487  1.29.2.2  skrll 		if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) == 0)
   6488  1.29.2.2  skrll 			IWM_WRITE_1(sc,
   6489  1.29.2.2  skrll 			    IWM_CSR_INT_PERIODIC_REG, IWM_CSR_INT_PERIODIC_DIS);
   6490  1.29.2.2  skrll 		isperiodic = 1;
   6491  1.29.2.2  skrll 	}
   6492  1.29.2.2  skrll 
   6493  1.29.2.2  skrll 	if ((r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX)) || isperiodic) {
   6494  1.29.2.2  skrll 		handled |= (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX);
   6495  1.29.2.2  skrll 		IWM_WRITE(sc, IWM_CSR_FH_INT_STATUS, IWM_CSR_FH_INT_RX_MASK);
   6496  1.29.2.2  skrll 
   6497  1.29.2.2  skrll 		iwm_notif_intr(sc);
   6498  1.29.2.2  skrll 
   6499  1.29.2.2  skrll 		/* enable periodic interrupt, see above */
   6500  1.29.2.2  skrll 		if (r1 & (IWM_CSR_INT_BIT_FH_RX | IWM_CSR_INT_BIT_SW_RX) && !isperiodic)
   6501  1.29.2.2  skrll 			IWM_WRITE_1(sc, IWM_CSR_INT_PERIODIC_REG,
   6502  1.29.2.2  skrll 			    IWM_CSR_INT_PERIODIC_ENA);
   6503  1.29.2.2  skrll 	}
   6504  1.29.2.2  skrll 
   6505  1.29.2.2  skrll 	if (__predict_false(r1 & ~handled))
   6506  1.29.2.2  skrll 		DPRINTF(("%s: unhandled interrupts: %x\n", DEVNAME(sc), r1));
   6507  1.29.2.2  skrll 	rv = 1;
   6508  1.29.2.2  skrll 
   6509  1.29.2.2  skrll  out_ena:
   6510  1.29.2.2  skrll 	iwm_restore_interrupts(sc);
   6511  1.29.2.2  skrll  out:
   6512  1.29.2.2  skrll 	return rv;
   6513  1.29.2.2  skrll }
   6514  1.29.2.2  skrll 
   6515  1.29.2.2  skrll /*
   6516  1.29.2.2  skrll  * Autoconf glue-sniffing
   6517  1.29.2.2  skrll  */
   6518  1.29.2.2  skrll 
   6519  1.29.2.2  skrll static const pci_product_id_t iwm_devices[] = {
   6520  1.29.2.2  skrll 	PCI_PRODUCT_INTEL_WIFI_LINK_7260_1,
   6521  1.29.2.2  skrll 	PCI_PRODUCT_INTEL_WIFI_LINK_7260_2,
   6522  1.29.2.2  skrll 	PCI_PRODUCT_INTEL_WIFI_LINK_3160_1,
   6523  1.29.2.2  skrll 	PCI_PRODUCT_INTEL_WIFI_LINK_3160_2,
   6524  1.29.2.2  skrll 	PCI_PRODUCT_INTEL_WIFI_LINK_7265_1,
   6525  1.29.2.2  skrll 	PCI_PRODUCT_INTEL_WIFI_LINK_7265_2,
   6526  1.29.2.2  skrll };
   6527  1.29.2.2  skrll 
   6528  1.29.2.2  skrll static int
   6529  1.29.2.2  skrll iwm_match(device_t parent, cfdata_t match __unused, void *aux)
   6530  1.29.2.2  skrll {
   6531  1.29.2.2  skrll 	struct pci_attach_args *pa = aux;
   6532  1.29.2.2  skrll 
   6533  1.29.2.2  skrll 	if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
   6534  1.29.2.2  skrll 		return 0;
   6535  1.29.2.2  skrll 
   6536  1.29.2.2  skrll 	for (size_t i = 0; i < __arraycount(iwm_devices); i++)
   6537  1.29.2.2  skrll 		if (PCI_PRODUCT(pa->pa_id) == iwm_devices[i])
   6538  1.29.2.2  skrll 			return 1;
   6539  1.29.2.2  skrll 
   6540  1.29.2.2  skrll 	return 0;
   6541  1.29.2.2  skrll }
   6542  1.29.2.2  skrll 
   6543  1.29.2.2  skrll static int
   6544  1.29.2.2  skrll iwm_preinit(struct iwm_softc *sc)
   6545  1.29.2.2  skrll {
   6546  1.29.2.4  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   6547  1.29.2.2  skrll 	int error;
   6548  1.29.2.2  skrll 
   6549  1.29.2.2  skrll 	if (sc->sc_flags & IWM_FLAG_ATTACHED)
   6550  1.29.2.2  skrll 		return 0;
   6551  1.29.2.2  skrll 
   6552  1.29.2.2  skrll 	if ((error = iwm_start_hw(sc)) != 0) {
   6553  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
   6554  1.29.2.2  skrll 		return error;
   6555  1.29.2.2  skrll 	}
   6556  1.29.2.2  skrll 
   6557  1.29.2.2  skrll 	error = iwm_run_init_mvm_ucode(sc, 1);
   6558  1.29.2.2  skrll 	iwm_stop_device(sc);
   6559  1.29.2.4  skrll 	if (error)
   6560  1.29.2.4  skrll 		return error;
   6561  1.29.2.2  skrll 
   6562  1.29.2.2  skrll 	sc->sc_flags |= IWM_FLAG_ATTACHED;
   6563  1.29.2.2  skrll 
   6564  1.29.2.2  skrll 	aprint_normal_dev(sc->sc_dev,
   6565  1.29.2.2  skrll 	    "hw rev: 0x%x, fw ver %d.%d (API ver %d), address %s\n",
   6566  1.29.2.2  skrll 	    sc->sc_hw_rev & IWM_CSR_HW_REV_TYPE_MSK,
   6567  1.29.2.2  skrll 	    IWM_UCODE_MAJOR(sc->sc_fwver),
   6568  1.29.2.2  skrll 	    IWM_UCODE_MINOR(sc->sc_fwver),
   6569  1.29.2.2  skrll 	    IWM_UCODE_API(sc->sc_fwver),
   6570  1.29.2.2  skrll 	    ether_sprintf(sc->sc_nvm.hw_addr));
   6571  1.29.2.2  skrll 
   6572  1.29.2.2  skrll 	/* not all hardware can do 5GHz band */
   6573  1.29.2.2  skrll 	if (sc->sc_nvm.sku_cap_band_52GHz_enable)
   6574  1.29.2.2  skrll 		ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
   6575  1.29.2.2  skrll 
   6576  1.29.2.2  skrll 	ieee80211_ifattach(ic);
   6577  1.29.2.2  skrll 
   6578  1.29.2.2  skrll 	ic->ic_node_alloc = iwm_node_alloc;
   6579  1.29.2.2  skrll 
   6580  1.29.2.2  skrll 	/* Override 802.11 state transition machine. */
   6581  1.29.2.2  skrll 	sc->sc_newstate = ic->ic_newstate;
   6582  1.29.2.2  skrll 	ic->ic_newstate = iwm_newstate;
   6583  1.29.2.2  skrll 	ieee80211_media_init(ic, iwm_media_change, ieee80211_media_status);
   6584  1.29.2.2  skrll 	ieee80211_announce(ic);
   6585  1.29.2.2  skrll 
   6586  1.29.2.2  skrll 	iwm_radiotap_attach(sc);
   6587  1.29.2.2  skrll 
   6588  1.29.2.4  skrll 	return 0;
   6589  1.29.2.4  skrll }
   6590  1.29.2.3  skrll 
   6591  1.29.2.4  skrll static void
   6592  1.29.2.4  skrll iwm_attach_hook(device_t dev)
   6593  1.29.2.4  skrll {
   6594  1.29.2.4  skrll 	struct iwm_softc *sc = device_private(dev);
   6595  1.29.2.4  skrll 
   6596  1.29.2.4  skrll 	iwm_preinit(sc);
   6597  1.29.2.2  skrll }
   6598  1.29.2.2  skrll 
   6599  1.29.2.2  skrll static void
   6600  1.29.2.2  skrll iwm_attach(device_t parent, device_t self, void *aux)
   6601  1.29.2.2  skrll {
   6602  1.29.2.2  skrll 	struct iwm_softc *sc = device_private(self);
   6603  1.29.2.2  skrll 	struct pci_attach_args *pa = aux;
   6604  1.29.2.4  skrll 	struct ieee80211com *ic = &sc->sc_ic;
   6605  1.29.2.4  skrll 	struct ifnet *ifp = &sc->sc_ec.ec_if;
   6606  1.29.2.2  skrll 	pcireg_t reg, memtype;
   6607  1.29.2.4  skrll 	char intrbuf[PCI_INTRSTR_LEN];
   6608  1.29.2.2  skrll 	const char *intrstr;
   6609  1.29.2.2  skrll 	int error;
   6610  1.29.2.2  skrll 	int txq_i;
   6611  1.29.2.4  skrll 	const struct sysctlnode *node;
   6612  1.29.2.2  skrll 
   6613  1.29.2.2  skrll 	sc->sc_dev = self;
   6614  1.29.2.2  skrll 	sc->sc_pct = pa->pa_pc;
   6615  1.29.2.2  skrll 	sc->sc_pcitag = pa->pa_tag;
   6616  1.29.2.2  skrll 	sc->sc_dmat = pa->pa_dmat;
   6617  1.29.2.2  skrll 	sc->sc_pciid = pa->pa_id;
   6618  1.29.2.2  skrll 
   6619  1.29.2.2  skrll 	pci_aprint_devinfo(pa, NULL);
   6620  1.29.2.2  skrll 
   6621  1.29.2.2  skrll 	/*
   6622  1.29.2.2  skrll 	 * Get the offset of the PCI Express Capability Structure in PCI
   6623  1.29.2.2  skrll 	 * Configuration Space.
   6624  1.29.2.2  skrll 	 */
   6625  1.29.2.2  skrll 	error = pci_get_capability(sc->sc_pct, sc->sc_pcitag,
   6626  1.29.2.2  skrll 	    PCI_CAP_PCIEXPRESS, &sc->sc_cap_off, NULL);
   6627  1.29.2.2  skrll 	if (error == 0) {
   6628  1.29.2.2  skrll 		aprint_error_dev(self,
   6629  1.29.2.2  skrll 		    "PCIe capability structure not found!\n");
   6630  1.29.2.2  skrll 		return;
   6631  1.29.2.2  skrll 	}
   6632  1.29.2.2  skrll 
   6633  1.29.2.2  skrll 	/* Clear device-specific "PCI retry timeout" register (41h). */
   6634  1.29.2.2  skrll 	reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
   6635  1.29.2.2  skrll 	pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
   6636  1.29.2.2  skrll 
   6637  1.29.2.2  skrll 	/* Enable bus-mastering and hardware bug workaround. */
   6638  1.29.2.2  skrll 	reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG);
   6639  1.29.2.2  skrll 	reg |= PCI_COMMAND_MASTER_ENABLE;
   6640  1.29.2.2  skrll 	/* if !MSI */
   6641  1.29.2.2  skrll 	if (reg & PCI_COMMAND_INTERRUPT_DISABLE) {
   6642  1.29.2.2  skrll 		reg &= ~PCI_COMMAND_INTERRUPT_DISABLE;
   6643  1.29.2.2  skrll 	}
   6644  1.29.2.2  skrll 	pci_conf_write(sc->sc_pct, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, reg);
   6645  1.29.2.2  skrll 
   6646  1.29.2.2  skrll 	memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_MAPREG_START);
   6647  1.29.2.2  skrll 	error = pci_mapreg_map(pa, PCI_MAPREG_START, memtype, 0,
   6648  1.29.2.2  skrll 	    &sc->sc_st, &sc->sc_sh, NULL, &sc->sc_sz);
   6649  1.29.2.2  skrll 	if (error != 0) {
   6650  1.29.2.2  skrll 		aprint_error_dev(self, "can't map mem space\n");
   6651  1.29.2.2  skrll 		return;
   6652  1.29.2.2  skrll 	}
   6653  1.29.2.2  skrll 
   6654  1.29.2.2  skrll 	/* Install interrupt handler. */
   6655  1.29.2.4  skrll 	error = pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0);
   6656  1.29.2.3  skrll 	if (error != 0) {
   6657  1.29.2.4  skrll 		aprint_error_dev(self, "can't allocate interrupt\n");
   6658  1.29.2.2  skrll 		return;
   6659  1.29.2.2  skrll 	}
   6660  1.29.2.3  skrll 	intrstr = pci_intr_string(sc->sc_pct, sc->sc_pihp[0], intrbuf,
   6661  1.29.2.3  skrll 	    sizeof(intrbuf));
   6662  1.29.2.3  skrll 	sc->sc_ih = pci_intr_establish(sc->sc_pct, sc->sc_pihp[0], IPL_NET,
   6663  1.29.2.3  skrll 	    iwm_intr, sc);
   6664  1.29.2.2  skrll 	if (sc->sc_ih == NULL) {
   6665  1.29.2.2  skrll 		aprint_error_dev(self, "can't establish interrupt");
   6666  1.29.2.2  skrll 		if (intrstr != NULL)
   6667  1.29.2.2  skrll 			aprint_error(" at %s", intrstr);
   6668  1.29.2.2  skrll 		aprint_error("\n");
   6669  1.29.2.2  skrll 		return;
   6670  1.29.2.2  skrll 	}
   6671  1.29.2.2  skrll 	aprint_normal_dev(self, "interrupting at %s\n", intrstr);
   6672  1.29.2.2  skrll 
   6673  1.29.2.2  skrll 	sc->sc_wantresp = -1;
   6674  1.29.2.2  skrll 
   6675  1.29.2.2  skrll 	switch (PCI_PRODUCT(sc->sc_pciid)) {
   6676  1.29.2.2  skrll 	case PCI_PRODUCT_INTEL_WIFI_LINK_7260_1:
   6677  1.29.2.2  skrll 	case PCI_PRODUCT_INTEL_WIFI_LINK_7260_2:
   6678  1.29.2.2  skrll 		sc->sc_fwname = "iwlwifi-7260-9.ucode";
   6679  1.29.2.2  skrll 		sc->host_interrupt_operation_mode = 1;
   6680  1.29.2.2  skrll 		break;
   6681  1.29.2.2  skrll 	case PCI_PRODUCT_INTEL_WIFI_LINK_3160_1:
   6682  1.29.2.2  skrll 	case PCI_PRODUCT_INTEL_WIFI_LINK_3160_2:
   6683  1.29.2.2  skrll 		sc->sc_fwname = "iwlwifi-3160-9.ucode";
   6684  1.29.2.2  skrll 		sc->host_interrupt_operation_mode = 1;
   6685  1.29.2.2  skrll 		break;
   6686  1.29.2.2  skrll 	case PCI_PRODUCT_INTEL_WIFI_LINK_7265_1:
   6687  1.29.2.2  skrll 	case PCI_PRODUCT_INTEL_WIFI_LINK_7265_2:
   6688  1.29.2.2  skrll 		sc->sc_fwname = "iwlwifi-7265-9.ucode";
   6689  1.29.2.2  skrll 		sc->host_interrupt_operation_mode = 0;
   6690  1.29.2.2  skrll 		break;
   6691  1.29.2.2  skrll 	default:
   6692  1.29.2.2  skrll 		aprint_error_dev(self, "unknown product %#x",
   6693  1.29.2.2  skrll 		    PCI_PRODUCT(sc->sc_pciid));
   6694  1.29.2.2  skrll 		return;
   6695  1.29.2.2  skrll 	}
   6696  1.29.2.2  skrll 	DPRINTF(("%s: firmware=%s\n", DEVNAME(sc), sc->sc_fwname));
   6697  1.29.2.2  skrll 	sc->sc_fwdmasegsz = IWM_FWDMASEGSZ;
   6698  1.29.2.2  skrll 
   6699  1.29.2.2  skrll 	/*
   6700  1.29.2.2  skrll 	 * We now start fiddling with the hardware
   6701  1.29.2.2  skrll 	 */
   6702  1.29.2.2  skrll 
   6703  1.29.2.2  skrll 	sc->sc_hw_rev = IWM_READ(sc, IWM_CSR_HW_REV);
   6704  1.29.2.2  skrll 	if (iwm_prepare_card_hw(sc) != 0) {
   6705  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "could not initialize hardware\n");
   6706  1.29.2.2  skrll 		return;
   6707  1.29.2.2  skrll 	}
   6708  1.29.2.2  skrll 
   6709  1.29.2.2  skrll 	/* Allocate DMA memory for firmware transfers. */
   6710  1.29.2.2  skrll 	if ((error = iwm_alloc_fwmem(sc)) != 0) {
   6711  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   6712  1.29.2.2  skrll 		    "could not allocate memory for firmware\n");
   6713  1.29.2.2  skrll 		return;
   6714  1.29.2.2  skrll 	}
   6715  1.29.2.2  skrll 
   6716  1.29.2.2  skrll 	/* Allocate "Keep Warm" page. */
   6717  1.29.2.2  skrll 	if ((error = iwm_alloc_kw(sc)) != 0) {
   6718  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   6719  1.29.2.2  skrll 		    "could not allocate keep warm page\n");
   6720  1.29.2.2  skrll 		goto fail1;
   6721  1.29.2.2  skrll 	}
   6722  1.29.2.2  skrll 
   6723  1.29.2.2  skrll 	/* We use ICT interrupts */
   6724  1.29.2.2  skrll 	if ((error = iwm_alloc_ict(sc)) != 0) {
   6725  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "could not allocate ICT table\n");
   6726  1.29.2.2  skrll 		goto fail2;
   6727  1.29.2.2  skrll 	}
   6728  1.29.2.2  skrll 
   6729  1.29.2.2  skrll 	/* Allocate TX scheduler "rings". */
   6730  1.29.2.2  skrll 	if ((error = iwm_alloc_sched(sc)) != 0) {
   6731  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev,
   6732  1.29.2.2  skrll 		    "could not allocate TX scheduler rings\n");
   6733  1.29.2.2  skrll 		goto fail3;
   6734  1.29.2.2  skrll 	}
   6735  1.29.2.2  skrll 
   6736  1.29.2.2  skrll 	/* Allocate TX rings */
   6737  1.29.2.2  skrll 	for (txq_i = 0; txq_i < __arraycount(sc->txq); txq_i++) {
   6738  1.29.2.2  skrll 		if ((error = iwm_alloc_tx_ring(sc,
   6739  1.29.2.2  skrll 		    &sc->txq[txq_i], txq_i)) != 0) {
   6740  1.29.2.2  skrll 			aprint_error_dev(sc->sc_dev,
   6741  1.29.2.2  skrll 			    "could not allocate TX ring %d\n", txq_i);
   6742  1.29.2.2  skrll 			goto fail4;
   6743  1.29.2.2  skrll 		}
   6744  1.29.2.2  skrll 	}
   6745  1.29.2.2  skrll 
   6746  1.29.2.2  skrll 	/* Allocate RX ring. */
   6747  1.29.2.2  skrll 	if ((error = iwm_alloc_rx_ring(sc, &sc->rxq)) != 0) {
   6748  1.29.2.2  skrll 		aprint_error_dev(sc->sc_dev, "could not allocate RX ring\n");
   6749  1.29.2.2  skrll 		goto fail4;
   6750  1.29.2.2  skrll 	}
   6751  1.29.2.2  skrll 
   6752  1.29.2.2  skrll 	workqueue_create(&sc->sc_eswq, "iwmes",
   6753  1.29.2.2  skrll 	    iwm_endscan_cb, sc, PRI_NONE, IPL_NET, 0);
   6754  1.29.2.2  skrll 	workqueue_create(&sc->sc_nswq, "iwmns",
   6755  1.29.2.2  skrll 	    iwm_newstate_cb, sc, PRI_NONE, IPL_NET, 0);
   6756  1.29.2.2  skrll 
   6757  1.29.2.2  skrll 	/* Clear pending interrupts. */
   6758  1.29.2.2  skrll 	IWM_WRITE(sc, IWM_CSR_INT, 0xffffffff);
   6759  1.29.2.2  skrll 
   6760  1.29.2.4  skrll 	if ((error = sysctl_createv(&sc->sc_clog, 0, NULL, &node,
   6761  1.29.2.4  skrll 	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
   6762  1.29.2.4  skrll 	    SYSCTL_DESCR("iwm per-controller controls"),
   6763  1.29.2.4  skrll 	    NULL, 0, NULL, 0,
   6764  1.29.2.4  skrll 	    CTL_HW, iwm_sysctl_root_num, CTL_CREATE,
   6765  1.29.2.4  skrll 	    CTL_EOL)) != 0) {
   6766  1.29.2.4  skrll 		aprint_normal_dev(sc->sc_dev,
   6767  1.29.2.4  skrll 		    "couldn't create iwm per-controller sysctl node\n");
   6768  1.29.2.4  skrll 	}
   6769  1.29.2.4  skrll 	if (error == 0) {
   6770  1.29.2.4  skrll 		int iwm_nodenum = node->sysctl_num;
   6771  1.29.2.4  skrll 
   6772  1.29.2.4  skrll 		/* Reload firmware sysctl node */
   6773  1.29.2.4  skrll 		if ((error = sysctl_createv(&sc->sc_clog, 0, NULL, &node,
   6774  1.29.2.4  skrll 		    CTLFLAG_READWRITE, CTLTYPE_INT, "fw_loaded",
   6775  1.29.2.4  skrll 		    SYSCTL_DESCR("Reload firmware"),
   6776  1.29.2.4  skrll 		    iwm_sysctl_fw_loaded_handler, 0, (void *)sc, 0,
   6777  1.29.2.4  skrll 		    CTL_HW, iwm_sysctl_root_num, iwm_nodenum, CTL_CREATE,
   6778  1.29.2.4  skrll 		    CTL_EOL)) != 0) {
   6779  1.29.2.4  skrll 			aprint_normal_dev(sc->sc_dev,
   6780  1.29.2.4  skrll 			    "couldn't create load_fw sysctl node\n");
   6781  1.29.2.4  skrll 		}
   6782  1.29.2.4  skrll 	}
   6783  1.29.2.4  skrll 
   6784  1.29.2.4  skrll 	/*
   6785  1.29.2.4  skrll 	 * Attach interface
   6786  1.29.2.4  skrll 	 */
   6787  1.29.2.4  skrll 	ic->ic_ifp = ifp;
   6788  1.29.2.4  skrll 	ic->ic_phytype = IEEE80211_T_OFDM;	/* not only, but not used */
   6789  1.29.2.4  skrll 	ic->ic_opmode = IEEE80211_M_STA;	/* default to BSS mode */
   6790  1.29.2.4  skrll 	ic->ic_state = IEEE80211_S_INIT;
   6791  1.29.2.4  skrll 
   6792  1.29.2.4  skrll 	/* Set device capabilities. */
   6793  1.29.2.4  skrll 	ic->ic_caps =
   6794  1.29.2.4  skrll 	    IEEE80211_C_WEP |		/* WEP */
   6795  1.29.2.4  skrll 	    IEEE80211_C_WPA |		/* 802.11i */
   6796  1.29.2.4  skrll 	    IEEE80211_C_SHSLOT |	/* short slot time supported */
   6797  1.29.2.4  skrll 	    IEEE80211_C_SHPREAMBLE;	/* short preamble supported */
   6798  1.29.2.4  skrll 
   6799  1.29.2.4  skrll 	/* all hardware can do 2.4GHz band */
   6800  1.29.2.4  skrll 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
   6801  1.29.2.4  skrll 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
   6802  1.29.2.4  skrll 
   6803  1.29.2.4  skrll 	for (int i = 0; i < __arraycount(sc->sc_phyctxt); i++) {
   6804  1.29.2.4  skrll 		sc->sc_phyctxt[i].id = i;
   6805  1.29.2.4  skrll 	}
   6806  1.29.2.4  skrll 
   6807  1.29.2.4  skrll 	sc->sc_amrr.amrr_min_success_threshold =  1;
   6808  1.29.2.4  skrll 	sc->sc_amrr.amrr_max_success_threshold = 15;
   6809  1.29.2.4  skrll 
   6810  1.29.2.4  skrll 	/* IBSS channel undefined for now. */
   6811  1.29.2.4  skrll 	ic->ic_ibss_chan = &ic->ic_channels[1];
   6812  1.29.2.4  skrll 
   6813  1.29.2.4  skrll #if 0
   6814  1.29.2.4  skrll 	/* Max RSSI */
   6815  1.29.2.4  skrll 	ic->ic_max_rssi = IWM_MAX_DBM - IWM_MIN_DBM;
   6816  1.29.2.4  skrll #endif
   6817  1.29.2.4  skrll 
   6818  1.29.2.4  skrll 	ifp->if_softc = sc;
   6819  1.29.2.4  skrll 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
   6820  1.29.2.4  skrll 	ifp->if_init = iwm_init;
   6821  1.29.2.4  skrll 	ifp->if_stop = iwm_stop;
   6822  1.29.2.4  skrll 	ifp->if_ioctl = iwm_ioctl;
   6823  1.29.2.4  skrll 	ifp->if_start = iwm_start;
   6824  1.29.2.4  skrll 	ifp->if_watchdog = iwm_watchdog;
   6825  1.29.2.4  skrll 	IFQ_SET_READY(&ifp->if_snd);
   6826  1.29.2.4  skrll 	memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
   6827  1.29.2.4  skrll 
   6828  1.29.2.4  skrll 	if_initialize(ifp);
   6829  1.29.2.4  skrll #if 0
   6830  1.29.2.4  skrll 	ieee80211_ifattach(ic);
   6831  1.29.2.4  skrll #else
   6832  1.29.2.4  skrll 	ether_ifattach(ifp, ic->ic_myaddr);	/* XXX */
   6833  1.29.2.4  skrll #endif
   6834  1.29.2.4  skrll 	if_register(ifp);
   6835  1.29.2.6  skrll 	/* Use common softint-based if_input */
   6836  1.29.2.6  skrll 	ifp->if_percpuq = if_percpuq_create(ifp);
   6837  1.29.2.4  skrll 
   6838  1.29.2.4  skrll 	callout_init(&sc->sc_calib_to, 0);
   6839  1.29.2.4  skrll 	callout_setfunc(&sc->sc_calib_to, iwm_calib_timeout, sc);
   6840  1.29.2.4  skrll 
   6841  1.29.2.4  skrll 	//task_set(&sc->init_task, iwm_init_task, sc);
   6842  1.29.2.4  skrll 
   6843  1.29.2.4  skrll 	if (pmf_device_register(self, NULL, NULL))
   6844  1.29.2.4  skrll 		pmf_class_network_register(self, ifp);
   6845  1.29.2.4  skrll 	else
   6846  1.29.2.4  skrll 		aprint_error_dev(self, "couldn't establish power handler\n");
   6847  1.29.2.4  skrll 
   6848  1.29.2.2  skrll 	/*
   6849  1.29.2.2  skrll 	 * We can't do normal attach before the file system is mounted
   6850  1.29.2.2  skrll 	 * because we cannot read the MAC address without loading the
   6851  1.29.2.2  skrll 	 * firmware from disk.  So we postpone until mountroot is done.
   6852  1.29.2.2  skrll 	 * Notably, this will require a full driver unload/load cycle
   6853  1.29.2.2  skrll 	 * (or reboot) in case the firmware is not present when the
   6854  1.29.2.2  skrll 	 * hook runs.
   6855  1.29.2.2  skrll 	 */
   6856  1.29.2.2  skrll 	config_mountroot(self, iwm_attach_hook);
   6857  1.29.2.2  skrll 
   6858  1.29.2.2  skrll 	return;
   6859  1.29.2.2  skrll 
   6860  1.29.2.2  skrll 	/* Free allocated memory if something failed during attachment. */
   6861  1.29.2.2  skrll fail4:	while (--txq_i >= 0)
   6862  1.29.2.2  skrll 		iwm_free_tx_ring(sc, &sc->txq[txq_i]);
   6863  1.29.2.2  skrll 	iwm_free_sched(sc);
   6864  1.29.2.2  skrll fail3:	if (sc->ict_dma.vaddr != NULL)
   6865  1.29.2.2  skrll 		iwm_free_ict(sc);
   6866  1.29.2.2  skrll fail2:	iwm_free_kw(sc);
   6867  1.29.2.2  skrll fail1:	iwm_free_fwmem(sc);
   6868  1.29.2.2  skrll }
   6869  1.29.2.2  skrll 
   6870  1.29.2.2  skrll /*
   6871  1.29.2.2  skrll  * Attach the interface to 802.11 radiotap.
   6872  1.29.2.2  skrll  */
   6873  1.29.2.2  skrll void
   6874  1.29.2.2  skrll iwm_radiotap_attach(struct iwm_softc *sc)
   6875  1.29.2.2  skrll {
   6876  1.29.2.2  skrll 	struct ifnet *ifp = sc->sc_ic.ic_ifp;
   6877  1.29.2.2  skrll 
   6878  1.29.2.2  skrll 	bpf_attach2(ifp, DLT_IEEE802_11_RADIO,
   6879  1.29.2.2  skrll 	    sizeof (struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN,
   6880  1.29.2.2  skrll 	    &sc->sc_drvbpf);
   6881  1.29.2.2  skrll 
   6882  1.29.2.2  skrll 	sc->sc_rxtap_len = sizeof sc->sc_rxtapu;
   6883  1.29.2.2  skrll 	sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len);
   6884  1.29.2.2  skrll 	sc->sc_rxtap.wr_ihdr.it_present = htole32(IWM_RX_RADIOTAP_PRESENT);
   6885  1.29.2.2  skrll 
   6886  1.29.2.2  skrll 	sc->sc_txtap_len = sizeof sc->sc_txtapu;
   6887  1.29.2.2  skrll 	sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len);
   6888  1.29.2.2  skrll 	sc->sc_txtap.wt_ihdr.it_present = htole32(IWM_TX_RADIOTAP_PRESENT);
   6889  1.29.2.2  skrll }
   6890  1.29.2.2  skrll 
   6891  1.29.2.2  skrll #if 0
   6892  1.29.2.2  skrll static void
   6893  1.29.2.2  skrll iwm_init_task(void *arg1)
   6894  1.29.2.2  skrll {
   6895  1.29.2.2  skrll 	struct iwm_softc *sc = arg1;
   6896  1.29.2.2  skrll 	struct ifnet *ifp = &sc->sc_ic.ic_if;
   6897  1.29.2.2  skrll 	int s;
   6898  1.29.2.2  skrll 
   6899  1.29.2.2  skrll 	s = splnet();
   6900  1.29.2.2  skrll 	while (sc->sc_flags & IWM_FLAG_BUSY)
   6901  1.29.2.2  skrll 		tsleep(&sc->sc_flags, 0, "iwmpwr", 0);
   6902  1.29.2.2  skrll 	sc->sc_flags |= IWM_FLAG_BUSY;
   6903  1.29.2.2  skrll 
   6904  1.29.2.2  skrll 	iwm_stop(ifp, 0);
   6905  1.29.2.2  skrll 	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == IFF_UP)
   6906  1.29.2.2  skrll 		iwm_init(ifp);
   6907  1.29.2.2  skrll 
   6908  1.29.2.2  skrll 	sc->sc_flags &= ~IWM_FLAG_BUSY;
   6909  1.29.2.2  skrll 	wakeup(&sc->sc_flags);
   6910  1.29.2.2  skrll 	splx(s);
   6911  1.29.2.2  skrll }
   6912  1.29.2.2  skrll 
   6913  1.29.2.2  skrll static void
   6914  1.29.2.2  skrll iwm_wakeup(struct iwm_softc *sc)
   6915  1.29.2.2  skrll {
   6916  1.29.2.2  skrll 	pcireg_t reg;
   6917  1.29.2.2  skrll 
   6918  1.29.2.2  skrll 	/* Clear device-specific "PCI retry timeout" register (41h). */
   6919  1.29.2.2  skrll 	reg = pci_conf_read(sc->sc_pct, sc->sc_pcitag, 0x40);
   6920  1.29.2.2  skrll 	pci_conf_write(sc->sc_pct, sc->sc_pcitag, 0x40, reg & ~0xff00);
   6921  1.29.2.2  skrll 
   6922  1.29.2.2  skrll 	iwm_init_task(sc);
   6923  1.29.2.2  skrll }
   6924  1.29.2.2  skrll 
   6925  1.29.2.2  skrll static int
   6926  1.29.2.2  skrll iwm_activate(device_t self, enum devact act)
   6927  1.29.2.2  skrll {
   6928  1.29.2.2  skrll 	struct iwm_softc *sc = device_private(self);
   6929  1.29.2.2  skrll 	struct ifnet *ifp = IC2IFP(&sc->sc_ic);
   6930  1.29.2.2  skrll 
   6931  1.29.2.2  skrll 	switch (act) {
   6932  1.29.2.2  skrll 	case DVACT_DEACTIVATE:
   6933  1.29.2.2  skrll 		if (ifp->if_flags & IFF_RUNNING)
   6934  1.29.2.2  skrll 			iwm_stop(ifp, 0);
   6935  1.29.2.2  skrll 		return 0;
   6936  1.29.2.2  skrll 	default:
   6937  1.29.2.2  skrll 		return EOPNOTSUPP;
   6938  1.29.2.2  skrll 	}
   6939  1.29.2.2  skrll }
   6940  1.29.2.2  skrll #endif
   6941  1.29.2.2  skrll 
   6942  1.29.2.2  skrll CFATTACH_DECL_NEW(iwm, sizeof(struct iwm_softc), iwm_match, iwm_attach,
   6943  1.29.2.2  skrll 	NULL, NULL);
   6944  1.29.2.3  skrll 
   6945  1.29.2.4  skrll static int
   6946  1.29.2.4  skrll iwm_sysctl_fw_loaded_handler(SYSCTLFN_ARGS)
   6947  1.29.2.4  skrll {
   6948  1.29.2.4  skrll 	struct sysctlnode node;
   6949  1.29.2.4  skrll 	struct iwm_softc *sc;
   6950  1.29.2.4  skrll 	int error, t;
   6951  1.29.2.4  skrll 
   6952  1.29.2.4  skrll 	node = *rnode;
   6953  1.29.2.4  skrll 	sc = node.sysctl_data;
   6954  1.29.2.4  skrll 	t = ISSET(sc->sc_flags, IWM_FLAG_FW_LOADED) ? 1 : 0;
   6955  1.29.2.4  skrll 	node.sysctl_data = &t;
   6956  1.29.2.4  skrll 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
   6957  1.29.2.4  skrll 	if (error || newp == NULL)
   6958  1.29.2.4  skrll 		return error;
   6959  1.29.2.4  skrll 
   6960  1.29.2.4  skrll 	if (t == 0)
   6961  1.29.2.4  skrll 		CLR(sc->sc_flags, IWM_FLAG_FW_LOADED);
   6962  1.29.2.4  skrll 	return 0;
   6963  1.29.2.4  skrll }
   6964  1.29.2.4  skrll 
   6965  1.29.2.3  skrll SYSCTL_SETUP(sysctl_iwm, "sysctl iwm(4) subtree setup")
   6966  1.29.2.3  skrll {
   6967  1.29.2.4  skrll 	const struct sysctlnode *rnode;
   6968  1.29.2.4  skrll #ifdef IWM_DEBUG
   6969  1.29.2.4  skrll 	const struct sysctlnode *cnode;
   6970  1.29.2.4  skrll #endif /* IWM_DEBUG */
   6971  1.29.2.3  skrll 	int rc;
   6972  1.29.2.3  skrll 
   6973  1.29.2.3  skrll 	if ((rc = sysctl_createv(clog, 0, NULL, &rnode,
   6974  1.29.2.3  skrll 	    CTLFLAG_PERMANENT, CTLTYPE_NODE, "iwm",
   6975  1.29.2.3  skrll 	    SYSCTL_DESCR("iwm global controls"),
   6976  1.29.2.3  skrll 	    NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0)
   6977  1.29.2.3  skrll 		goto err;
   6978  1.29.2.3  skrll 
   6979  1.29.2.4  skrll 	iwm_sysctl_root_num = rnode->sysctl_num;
   6980  1.29.2.4  skrll 
   6981  1.29.2.4  skrll #ifdef IWM_DEBUG
   6982  1.29.2.3  skrll 	/* control debugging printfs */
   6983  1.29.2.3  skrll 	if ((rc = sysctl_createv(clog, 0, &rnode, &cnode,
   6984  1.29.2.3  skrll 	    CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT,
   6985  1.29.2.3  skrll 	    "debug", SYSCTL_DESCR("Enable debugging output"),
   6986  1.29.2.3  skrll 	    NULL, 0, &iwm_debug, 0, CTL_CREATE, CTL_EOL)) != 0)
   6987  1.29.2.3  skrll 		goto err;
   6988  1.29.2.4  skrll #endif /* IWM_DEBUG */
   6989  1.29.2.3  skrll 
   6990  1.29.2.3  skrll 	return;
   6991  1.29.2.3  skrll 
   6992  1.29.2.3  skrll  err:
   6993  1.29.2.3  skrll 	aprint_error("%s: sysctl_createv failed (rc = %d)\n", __func__, rc);
   6994  1.29.2.3  skrll }
   6995