git: 2ad0f7e91582 - main - Import iwx as ported from OpenBSD by Future Crew.
Date: Mon, 31 Mar 2025 12:43:09 UTC
The branch main has been updated by thj: URL: https://cgit.FreeBSD.org/src/commit/?id=2ad0f7e91582dde5475ceb1a1942930549e5c628 commit 2ad0f7e91582dde5475ceb1a1942930549e5c628 Author: Tom Jones <thj@FreeBSD.org> AuthorDate: 2025-03-31 12:24:15 +0000 Commit: Tom Jones <thj@FreeBSD.org> CommitDate: 2025-03-31 12:42:31 +0000 Import iwx as ported from OpenBSD by Future Crew. This driver originates from OpenBSD and was ported to FreeBSD by Future Crew LLC who kindly provided a source release. iwx supports many recent Intel WiFi card and this driver should support running these cards with legacy, HT and VHT rates. There are some issues remaining in the port, but at this point wider testing is sought. To avoid breaking deployed WiFi configurations iwx probes with a lower priority than iwlwifi. This can be changed by blocking iwlwifi with devmatch. Reviewed by: adrian Obtained from: Future Crew LLC Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D49259 --- sys/dev/iwx/if_iwx.c | 11016 +++++++++++++++++++++++++++++++++++++++++++ sys/dev/iwx/if_iwx_debug.c | 321 ++ sys/dev/iwx/if_iwx_debug.h | 265 ++ sys/dev/iwx/if_iwxreg.h | 7922 +++++++++++++++++++++++++++++++ sys/dev/iwx/if_iwxvar.h | 924 ++++ sys/modules/Makefile | 2 + sys/modules/iwx/Makefile | 10 + 7 files changed, 20460 insertions(+) diff --git a/sys/dev/iwx/if_iwx.c b/sys/dev/iwx/if_iwx.c new file mode 100644 index 000000000000..9e5d5a9569d5 --- /dev/null +++ b/sys/dev/iwx/if_iwx.c @@ -0,0 +1,11016 @@ +/*- + * SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) AND ISC + */ + +/* $OpenBSD: if_iwx.c,v 1.175 2023/07/05 15:07:28 stsp Exp $ */ + +/* + * + * Copyright (c) 2025 The FreeBSD Foundation + * + * Portions of this software were developed by Tom Jones <thj@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/*- + * Copyright (c) 2024 Future Crew, LLC + * Author: Mikhail Pchelin <misha@FreeBSD.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Copyright (c) 2014, 2016 genua gmbh <info@genua.de> + * Author: Stefan Sperling <stsp@openbsd.org> + * Copyright (c) 2014 Fixup Software Ltd. + * Copyright (c) 2017, 2019, 2020 Stefan Sperling <stsp@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*- + * Based on BSD-licensed source modules in the Linux iwlwifi driver, + * which were used as the reference documentation for this implementation. + * + ****************************************************************************** + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 - 2019 Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ***************************************************************************** + */ + +/*- + * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/mutex.h> +#include <sys/proc.h> +#include <sys/rman.h> +#include <sys/rwlock.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/systm.h> +#include <sys/endian.h> +#include <sys/linker.h> +#include <sys/firmware.h> +#include <sys/epoch.h> +#include <sys/kdb.h> + +#include <machine/bus.h> +#include <machine/endian.h> +#include <machine/resource.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> + +#include <net/bpf.h> + +#include <net/if.h> +#include <net/if_var.h> +#include <net/if_dl.h> +#include <net/if_media.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#include <net80211/ieee80211_var.h> +#include <net80211/ieee80211_radiotap.h> +#include <net80211/ieee80211_regdomain.h> +#include <net80211/ieee80211_ratectl.h> +#include <net80211/ieee80211_vht.h> + +int iwx_himark = 224; +int iwx_lomark = 192; + +#define IWX_FBSD_RSP_V3 3 +#define IWX_FBSD_RSP_V4 4 + +#define DEVNAME(_sc) (device_get_nameunit((_sc)->sc_dev)) +#define IC2IFP(ic) (((struct ieee80211vap *)TAILQ_FIRST(&(ic)->ic_vaps))->iv_ifp) + +#define le16_to_cpup(_a_) (le16toh(*(const uint16_t *)(_a_))) +#define le32_to_cpup(_a_) (le32toh(*(const uint32_t *)(_a_))) + +#include <dev/iwx/if_iwxreg.h> +#include <dev/iwx/if_iwxvar.h> + +#include <dev/iwx/if_iwx_debug.h> + +#define PCI_VENDOR_INTEL 0x8086 +#define PCI_PRODUCT_INTEL_WL_22500_1 0x2723 /* Wi-Fi 6 AX200 */ +#define PCI_PRODUCT_INTEL_WL_22500_2 0x02f0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_3 0xa0f0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_4 0x34f0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_5 0x06f0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_6 0x43f0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_7 0x3df0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_8 0x4df0 /* Wi-Fi 6 AX201 */ +#define PCI_PRODUCT_INTEL_WL_22500_9 0x2725 /* Wi-Fi 6 AX210 */ +#define PCI_PRODUCT_INTEL_WL_22500_10 0x2726 /* Wi-Fi 6 AX211 */ +#define PCI_PRODUCT_INTEL_WL_22500_11 0x51f0 /* Wi-Fi 6 AX211 */ +#define PCI_PRODUCT_INTEL_WL_22500_12 0x7a70 /* Wi-Fi 6 AX211 */ +#define PCI_PRODUCT_INTEL_WL_22500_13 0x7af0 /* Wi-Fi 6 AX211 */ +#define PCI_PRODUCT_INTEL_WL_22500_14 0x7e40 /* Wi-Fi 6 AX210 */ +#define PCI_PRODUCT_INTEL_WL_22500_15 0x7f70 /* Wi-Fi 6 AX211 */ +#define PCI_PRODUCT_INTEL_WL_22500_16 0x54f0 /* Wi-Fi 6 AX211 */ +#define PCI_PRODUCT_INTEL_WL_22500_17 0x51f1 /* Wi-Fi 6 AX211 */ + +static const struct iwx_devices { + uint16_t device; + char *name; +} iwx_devices[] = { + { PCI_PRODUCT_INTEL_WL_22500_1, "Wi-Fi 6 AX200" }, + { PCI_PRODUCT_INTEL_WL_22500_2, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_3, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_4, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_5, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_6, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_7, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_8, "Wi-Fi 6 AX201" }, + { PCI_PRODUCT_INTEL_WL_22500_9, "Wi-Fi 6 AX210" }, + { PCI_PRODUCT_INTEL_WL_22500_10, "Wi-Fi 6 AX211" }, + { PCI_PRODUCT_INTEL_WL_22500_11, "Wi-Fi 6 AX211" }, + { PCI_PRODUCT_INTEL_WL_22500_12, "Wi-Fi 6 AX211" }, + { PCI_PRODUCT_INTEL_WL_22500_13, "Wi-Fi 6 AX211" }, + { PCI_PRODUCT_INTEL_WL_22500_14, "Wi-Fi 6 AX210" }, + { PCI_PRODUCT_INTEL_WL_22500_15, "Wi-Fi 6 AX211" }, + { PCI_PRODUCT_INTEL_WL_22500_16, "Wi-Fi 6 AX211" }, + { PCI_PRODUCT_INTEL_WL_22500_17, "Wi-Fi 6 AX211" }, +}; + +static const uint8_t iwx_nvm_channels_8000[] = { + /* 2.4 GHz */ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + /* 5 GHz */ + 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, + 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161, 165, 169, 173, 177, 181 +}; + +static const uint8_t iwx_nvm_channels_uhb[] = { + /* 2.4 GHz */ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + /* 5 GHz */ + 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, 84, 88, 92, + 96, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 144, + 149, 153, 157, 161, 165, 169, 173, 177, 181, + /* 6-7 GHz */ + 1, 5, 9, 13, 17, 21, 25, 29, 33, 37, 41, 45, 49, 53, 57, 61, 65, 69, + 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125, 129, + 133, 137, 141, 145, 149, 153, 157, 161, 165, 169, 173, 177, 181, 185, + 189, 193, 197, 201, 205, 209, 213, 217, 221, 225, 229, 233 +}; + +#define IWX_NUM_2GHZ_CHANNELS 14 +#define IWX_NUM_5GHZ_CHANNELS 37 + +const struct iwx_rate { + uint16_t rate; + uint8_t plcp; + uint8_t ht_plcp; +} iwx_rates[] = { + /* Legacy */ /* HT */ + { 2, IWX_RATE_1M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, + { 4, IWX_RATE_2M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, + { 11, IWX_RATE_5M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, + { 22, IWX_RATE_11M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, + { 12, IWX_RATE_6M_PLCP, IWX_RATE_HT_SISO_MCS_0_PLCP }, + { 18, IWX_RATE_9M_PLCP, IWX_RATE_HT_SISO_MCS_INV_PLCP }, + { 24, IWX_RATE_12M_PLCP, IWX_RATE_HT_SISO_MCS_1_PLCP }, + { 26, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_8_PLCP }, + { 36, IWX_RATE_18M_PLCP, IWX_RATE_HT_SISO_MCS_2_PLCP }, + { 48, IWX_RATE_24M_PLCP, IWX_RATE_HT_SISO_MCS_3_PLCP }, + { 52, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_9_PLCP }, + { 72, IWX_RATE_36M_PLCP, IWX_RATE_HT_SISO_MCS_4_PLCP }, + { 78, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_10_PLCP }, + { 96, IWX_RATE_48M_PLCP, IWX_RATE_HT_SISO_MCS_5_PLCP }, + { 104, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_11_PLCP }, + { 108, IWX_RATE_54M_PLCP, IWX_RATE_HT_SISO_MCS_6_PLCP }, + { 128, IWX_RATE_INVM_PLCP, IWX_RATE_HT_SISO_MCS_7_PLCP }, + { 156, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_12_PLCP }, + { 208, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_13_PLCP }, + { 234, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_14_PLCP }, + { 260, IWX_RATE_INVM_PLCP, IWX_RATE_HT_MIMO2_MCS_15_PLCP }, +}; +#define IWX_RIDX_CCK 0 +#define IWX_RIDX_OFDM 4 +#define IWX_RIDX_MAX (nitems(iwx_rates)-1) +#define IWX_RIDX_IS_CCK(_i_) ((_i_) < IWX_RIDX_OFDM) +#define IWX_RIDX_IS_OFDM(_i_) ((_i_) >= IWX_RIDX_OFDM) +#define IWX_RVAL_IS_OFDM(_i_) ((_i_) >= 12 && (_i_) != 22) + +/* Convert an MCS index into an iwx_rates[] index. */ +const int iwx_mcs2ridx[] = { + IWX_RATE_MCS_0_INDEX, + IWX_RATE_MCS_1_INDEX, + IWX_RATE_MCS_2_INDEX, + IWX_RATE_MCS_3_INDEX, + IWX_RATE_MCS_4_INDEX, + IWX_RATE_MCS_5_INDEX, + IWX_RATE_MCS_6_INDEX, + IWX_RATE_MCS_7_INDEX, + IWX_RATE_MCS_8_INDEX, + IWX_RATE_MCS_9_INDEX, + IWX_RATE_MCS_10_INDEX, + IWX_RATE_MCS_11_INDEX, + IWX_RATE_MCS_12_INDEX, + IWX_RATE_MCS_13_INDEX, + IWX_RATE_MCS_14_INDEX, + IWX_RATE_MCS_15_INDEX, +}; + +static uint8_t iwx_lookup_cmd_ver(struct iwx_softc *, uint8_t, uint8_t); +static uint8_t iwx_lookup_notif_ver(struct iwx_softc *, uint8_t, uint8_t); +static int iwx_store_cscheme(struct iwx_softc *, const uint8_t *, size_t); +#if 0 +static int iwx_alloc_fw_monitor_block(struct iwx_softc *, uint8_t, uint8_t); +static int iwx_alloc_fw_monitor(struct iwx_softc *, uint8_t); +#endif +static int iwx_apply_debug_destination(struct iwx_softc *); +static void iwx_set_ltr(struct iwx_softc *); +static int iwx_ctxt_info_init(struct iwx_softc *, const struct iwx_fw_sects *); +static int iwx_ctxt_info_gen3_init(struct iwx_softc *, + const struct iwx_fw_sects *); +static void iwx_ctxt_info_free_fw_img(struct iwx_softc *); +static void iwx_ctxt_info_free_paging(struct iwx_softc *); +static int iwx_init_fw_sec(struct iwx_softc *, const struct iwx_fw_sects *, + struct iwx_context_info_dram *); +static void iwx_fw_version_str(char *, size_t, uint32_t, uint32_t, uint32_t); +static int iwx_firmware_store_section(struct iwx_softc *, enum iwx_ucode_type, + const uint8_t *, size_t); +static int iwx_set_default_calib(struct iwx_softc *, const void *); +static void iwx_fw_info_free(struct iwx_fw_info *); +static int iwx_read_firmware(struct iwx_softc *); +static uint32_t iwx_prph_addr_mask(struct iwx_softc *); +static uint32_t iwx_read_prph_unlocked(struct iwx_softc *, uint32_t); +static uint32_t iwx_read_prph(struct iwx_softc *, uint32_t); +static void iwx_write_prph_unlocked(struct iwx_softc *, uint32_t, uint32_t); +static void iwx_write_prph(struct iwx_softc *, uint32_t, uint32_t); +static uint32_t iwx_read_umac_prph(struct iwx_softc *, uint32_t); +static void iwx_write_umac_prph(struct iwx_softc *, uint32_t, uint32_t); +static int iwx_read_mem(struct iwx_softc *, uint32_t, void *, int); +static int iwx_poll_bit(struct iwx_softc *, int, uint32_t, uint32_t, int); +static int iwx_nic_lock(struct iwx_softc *); +static void iwx_nic_assert_locked(struct iwx_softc *); +static void iwx_nic_unlock(struct iwx_softc *); +static int iwx_set_bits_mask_prph(struct iwx_softc *, uint32_t, uint32_t, + uint32_t); +static int iwx_set_bits_prph(struct iwx_softc *, uint32_t, uint32_t); +static int iwx_clear_bits_prph(struct iwx_softc *, uint32_t, uint32_t); +static void iwx_dma_map_addr(void *, bus_dma_segment_t *, int, int); +static int iwx_dma_contig_alloc(bus_dma_tag_t, struct iwx_dma_info *, + bus_size_t, bus_size_t); +static void iwx_dma_contig_free(struct iwx_dma_info *); +static int iwx_alloc_rx_ring(struct iwx_softc *, struct iwx_rx_ring *); +static void iwx_disable_rx_dma(struct iwx_softc *); +static void iwx_reset_rx_ring(struct iwx_softc *, struct iwx_rx_ring *); +static void iwx_free_rx_ring(struct iwx_softc *, struct iwx_rx_ring *); +static int iwx_alloc_tx_ring(struct iwx_softc *, struct iwx_tx_ring *, int); +static void iwx_reset_tx_ring(struct iwx_softc *, struct iwx_tx_ring *); +static void iwx_free_tx_ring(struct iwx_softc *, struct iwx_tx_ring *); +static void iwx_enable_rfkill_int(struct iwx_softc *); +static int iwx_check_rfkill(struct iwx_softc *); +static void iwx_enable_interrupts(struct iwx_softc *); +static void iwx_enable_fwload_interrupt(struct iwx_softc *); +#if 0 +static void iwx_restore_interrupts(struct iwx_softc *); +#endif +static void iwx_disable_interrupts(struct iwx_softc *); +static void iwx_ict_reset(struct iwx_softc *); +static int iwx_set_hw_ready(struct iwx_softc *); +static int iwx_prepare_card_hw(struct iwx_softc *); +static int iwx_force_power_gating(struct iwx_softc *); +static void iwx_apm_config(struct iwx_softc *); +static int iwx_apm_init(struct iwx_softc *); +static void iwx_apm_stop(struct iwx_softc *); +static int iwx_allow_mcast(struct iwx_softc *); +static void iwx_init_msix_hw(struct iwx_softc *); +static void iwx_conf_msix_hw(struct iwx_softc *, int); +static int iwx_clear_persistence_bit(struct iwx_softc *); +static int iwx_start_hw(struct iwx_softc *); +static void iwx_stop_device(struct iwx_softc *); +static void iwx_nic_config(struct iwx_softc *); +static int iwx_nic_rx_init(struct iwx_softc *); +static int iwx_nic_init(struct iwx_softc *); +static int iwx_enable_txq(struct iwx_softc *, int, int, int, int); +static int iwx_disable_txq(struct iwx_softc *sc, int, int, uint8_t); +static void iwx_post_alive(struct iwx_softc *); +static int iwx_schedule_session_protection(struct iwx_softc *, + struct iwx_node *, uint32_t); +static void iwx_unprotect_session(struct iwx_softc *, struct iwx_node *); +static void iwx_init_channel_map(struct ieee80211com *, int, int *, + struct ieee80211_channel[]); +static int iwx_mimo_enabled(struct iwx_softc *); +static void iwx_init_reorder_buffer(struct iwx_reorder_buffer *, uint16_t, + uint16_t); +static void iwx_clear_reorder_buffer(struct iwx_softc *, struct iwx_rxba_data *); +static void iwx_sta_rx_agg(struct iwx_softc *, struct ieee80211_node *, uint8_t, + uint16_t, uint16_t, int, int); +static void iwx_sta_tx_agg_start(struct iwx_softc *, + struct ieee80211_node *, uint8_t); +static void iwx_ba_rx_task(void *, int); +static void iwx_ba_tx_task(void *, int); +static void iwx_set_mac_addr_from_csr(struct iwx_softc *, struct iwx_nvm_data *); +static int iwx_is_valid_mac_addr(const uint8_t *); +static void iwx_flip_hw_address(uint32_t, uint32_t, uint8_t *); +static int iwx_nvm_get(struct iwx_softc *); +static int iwx_load_firmware(struct iwx_softc *); +static int iwx_start_fw(struct iwx_softc *); +static int iwx_pnvm_handle_section(struct iwx_softc *, const uint8_t *, size_t); +static int iwx_pnvm_parse(struct iwx_softc *, const uint8_t *, size_t); +static void iwx_ctxt_info_gen3_set_pnvm(struct iwx_softc *); +static int iwx_load_pnvm(struct iwx_softc *); +static int iwx_send_tx_ant_cfg(struct iwx_softc *, uint8_t); +static int iwx_send_phy_cfg_cmd(struct iwx_softc *); +static int iwx_load_ucode_wait_alive(struct iwx_softc *); +static int iwx_send_dqa_cmd(struct iwx_softc *); +static int iwx_run_init_mvm_ucode(struct iwx_softc *, int); +static int iwx_config_ltr(struct iwx_softc *); +static void iwx_update_rx_desc(struct iwx_softc *, struct iwx_rx_ring *, int, bus_dma_segment_t *); +static int iwx_rx_addbuf(struct iwx_softc *, int, int); +static int iwx_rxmq_get_signal_strength(struct iwx_softc *, struct iwx_rx_mpdu_desc *); +static void iwx_rx_rx_phy_cmd(struct iwx_softc *, struct iwx_rx_packet *, + struct iwx_rx_data *); +static int iwx_get_noise(const struct iwx_statistics_rx_non_phy *); +static int iwx_rx_hwdecrypt(struct iwx_softc *, struct mbuf *, uint32_t); +#if 0 +int iwx_ccmp_decap(struct iwx_softc *, struct mbuf *, + struct ieee80211_node *, struct ieee80211_rxinfo *); +#endif +static void iwx_rx_frame(struct iwx_softc *, struct mbuf *, int, uint32_t, + int, int, uint32_t, uint8_t); +static void iwx_clear_tx_desc(struct iwx_softc *, struct iwx_tx_ring *, int); +static void iwx_txd_done(struct iwx_softc *, struct iwx_tx_ring *, + struct iwx_tx_data *); +static void iwx_txq_advance(struct iwx_softc *, struct iwx_tx_ring *, uint16_t); +static void iwx_rx_tx_cmd(struct iwx_softc *, struct iwx_rx_packet *, + struct iwx_rx_data *); +static void iwx_clear_oactive(struct iwx_softc *, struct iwx_tx_ring *); +static void iwx_rx_bmiss(struct iwx_softc *, struct iwx_rx_packet *, + struct iwx_rx_data *); +static int iwx_binding_cmd(struct iwx_softc *, struct iwx_node *, uint32_t); +static uint8_t iwx_get_vht_ctrl_pos(struct ieee80211com *, struct ieee80211_channel *); +static int iwx_phy_ctxt_cmd_uhb_v3_v4(struct iwx_softc *, + struct iwx_phy_ctxt *, uint8_t, uint8_t, uint32_t, uint8_t, uint8_t, int); +#if 0 +static int iwx_phy_ctxt_cmd_v3_v4(struct iwx_softc *, struct iwx_phy_ctxt *, + uint8_t, uint8_t, uint32_t, uint8_t, uint8_t, int); +#endif +static int iwx_phy_ctxt_cmd(struct iwx_softc *, struct iwx_phy_ctxt *, + uint8_t, uint8_t, uint32_t, uint32_t, uint8_t, uint8_t); +static int iwx_send_cmd(struct iwx_softc *, struct iwx_host_cmd *); +static int iwx_send_cmd_pdu(struct iwx_softc *, uint32_t, uint32_t, uint16_t, + const void *); +static int iwx_send_cmd_status(struct iwx_softc *, struct iwx_host_cmd *, + uint32_t *); +static int iwx_send_cmd_pdu_status(struct iwx_softc *, uint32_t, uint16_t, + const void *, uint32_t *); +static void iwx_free_resp(struct iwx_softc *, struct iwx_host_cmd *); +static void iwx_cmd_done(struct iwx_softc *, int, int, int); +static uint32_t iwx_fw_rateidx_ofdm(uint8_t); +static uint32_t iwx_fw_rateidx_cck(uint8_t); +static const struct iwx_rate *iwx_tx_fill_cmd(struct iwx_softc *, + struct iwx_node *, struct ieee80211_frame *, uint16_t *, uint32_t *, + struct mbuf *); +static void iwx_tx_update_byte_tbl(struct iwx_softc *, struct iwx_tx_ring *, int, + uint16_t, uint16_t); +static int iwx_tx(struct iwx_softc *, struct mbuf *, + struct ieee80211_node *); +static int iwx_flush_sta_tids(struct iwx_softc *, int, uint16_t); +static int iwx_drain_sta(struct iwx_softc *sc, struct iwx_node *, int); +static int iwx_flush_sta(struct iwx_softc *, struct iwx_node *); +static int iwx_beacon_filter_send_cmd(struct iwx_softc *, + struct iwx_beacon_filter_cmd *); +static int iwx_update_beacon_abort(struct iwx_softc *, struct iwx_node *, + int); +static void iwx_power_build_cmd(struct iwx_softc *, struct iwx_node *, + struct iwx_mac_power_cmd *); +static int iwx_power_mac_update_mode(struct iwx_softc *, struct iwx_node *); +static int iwx_power_update_device(struct iwx_softc *); +#if 0 +static int iwx_enable_beacon_filter(struct iwx_softc *, struct iwx_node *); +#endif +static int iwx_disable_beacon_filter(struct iwx_softc *); +static int iwx_add_sta_cmd(struct iwx_softc *, struct iwx_node *, int); +static int iwx_rm_sta_cmd(struct iwx_softc *, struct iwx_node *); +static int iwx_rm_sta(struct iwx_softc *, struct iwx_node *); +static int iwx_fill_probe_req(struct iwx_softc *, + struct iwx_scan_probe_req *); +static int iwx_config_umac_scan_reduced(struct iwx_softc *); +static uint16_t iwx_scan_umac_flags_v2(struct iwx_softc *, int); +static void iwx_scan_umac_dwell_v10(struct iwx_softc *, + struct iwx_scan_general_params_v10 *, int); +static void iwx_scan_umac_fill_general_p_v10(struct iwx_softc *, + struct iwx_scan_general_params_v10 *, uint16_t, int); +static void iwx_scan_umac_fill_ch_p_v6(struct iwx_softc *, + struct iwx_scan_channel_params_v6 *, uint32_t, int); +static int iwx_umac_scan_v14(struct iwx_softc *, int); +static void iwx_mcc_update(struct iwx_softc *, struct iwx_mcc_chub_notif *); +static uint8_t iwx_ridx2rate(struct ieee80211_rateset *, int); +static int iwx_rval2ridx(int); +static void iwx_ack_rates(struct iwx_softc *, struct iwx_node *, int *, + int *); +static void iwx_mac_ctxt_cmd_common(struct iwx_softc *, struct iwx_node *, + struct iwx_mac_ctx_cmd *, uint32_t); +static void iwx_mac_ctxt_cmd_fill_sta(struct iwx_softc *, struct iwx_node *, + struct iwx_mac_data_sta *, int); +static int iwx_mac_ctxt_cmd(struct iwx_softc *, struct iwx_node *, + uint32_t, int); +static int iwx_clear_statistics(struct iwx_softc *); +static int iwx_scan(struct iwx_softc *); +static int iwx_bgscan(struct ieee80211com *); +static int iwx_enable_mgmt_queue(struct iwx_softc *); +static int iwx_disable_mgmt_queue(struct iwx_softc *); +static int iwx_rs_rval2idx(uint8_t); +static uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, + int); +static uint16_t iwx_rs_vht_rates(struct iwx_softc *, struct ieee80211_node *, int); +static int iwx_rs_init_v3(struct iwx_softc *, struct iwx_node *); +static int iwx_rs_init_v4(struct iwx_softc *, struct iwx_node *); +static int iwx_rs_init(struct iwx_softc *, struct iwx_node *); +static int iwx_phy_send_rlc(struct iwx_softc *, struct iwx_phy_ctxt *, + uint8_t, uint8_t); +static int iwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *, + struct ieee80211_channel *, uint8_t, uint8_t, uint32_t, uint8_t, + uint8_t); +static int iwx_auth(struct ieee80211vap *, struct iwx_softc *); +static int iwx_deauth(struct iwx_softc *); +static int iwx_run(struct ieee80211vap *, struct iwx_softc *); +static int iwx_run_stop(struct iwx_softc *); +static struct ieee80211_node * iwx_node_alloc(struct ieee80211vap *, + const uint8_t[IEEE80211_ADDR_LEN]); +#if 0 +int iwx_set_key(struct ieee80211com *, struct ieee80211_node *, + struct ieee80211_key *); +void iwx_setkey_task(void *); +void iwx_delete_key(struct ieee80211com *, + struct ieee80211_node *, struct ieee80211_key *); +#endif +static int iwx_newstate(struct ieee80211vap *, enum ieee80211_state, int); +static void iwx_endscan(struct iwx_softc *); +static void iwx_fill_sf_command(struct iwx_softc *, struct iwx_sf_cfg_cmd *, + struct ieee80211_node *); +static int iwx_sf_config(struct iwx_softc *, int); +static int iwx_send_bt_init_conf(struct iwx_softc *); +static int iwx_send_soc_conf(struct iwx_softc *); +static int iwx_send_update_mcc_cmd(struct iwx_softc *, const char *); +static int iwx_send_temp_report_ths_cmd(struct iwx_softc *); +static int iwx_init_hw(struct iwx_softc *); +static int iwx_init(struct iwx_softc *); +static void iwx_stop(struct iwx_softc *); +static void iwx_watchdog(void *); +static const char *iwx_desc_lookup(uint32_t); +static void iwx_nic_error(struct iwx_softc *); +static void iwx_dump_driver_status(struct iwx_softc *); +static void iwx_nic_umac_error(struct iwx_softc *); +static void iwx_rx_mpdu_mq(struct iwx_softc *, struct mbuf *, void *, size_t); +static int iwx_rx_pkt_valid(struct iwx_rx_packet *); +static void iwx_rx_pkt(struct iwx_softc *, struct iwx_rx_data *, + struct mbuf *); +static void iwx_notif_intr(struct iwx_softc *); +#if 0 +/* XXX-THJ - I don't have hardware for this */ +static int iwx_intr(void *); +#endif +static void iwx_intr_msix(void *); +static int iwx_preinit(struct iwx_softc *); +static void iwx_attach_hook(void *); +static const struct iwx_device_cfg *iwx_find_device_cfg(struct iwx_softc *); +static int iwx_probe(device_t); +static int iwx_attach(device_t); +static int iwx_detach(device_t); + +/* FreeBSD specific glue */ +u_int8_t etherbroadcastaddr[ETHER_ADDR_LEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +u_int8_t etheranyaddr[ETHER_ADDR_LEN] = + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +#if IWX_DEBUG +#define DPRINTF(x) do { if (sc->sc_debug == IWX_DEBUG_ANY) { printf x; } } while (0) +#else +#define DPRINTF(x) do { ; } while (0) +#endif + +/* FreeBSD specific functions */ +static struct ieee80211vap * iwx_vap_create(struct ieee80211com *, + const char[IFNAMSIZ], int, enum ieee80211_opmode, int, + const uint8_t[IEEE80211_ADDR_LEN], const uint8_t[IEEE80211_ADDR_LEN]); +static void iwx_vap_delete(struct ieee80211vap *); +static void iwx_parent(struct ieee80211com *); +static void iwx_scan_start(struct ieee80211com *); +static void iwx_scan_end(struct ieee80211com *); +static void iwx_update_mcast(struct ieee80211com *ic); +static void iwx_scan_curchan(struct ieee80211_scan_state *, unsigned long); +static void iwx_scan_mindwell(struct ieee80211_scan_state *); +static void iwx_set_channel(struct ieee80211com *); +static void iwx_endscan_cb(void *, int ); +static int iwx_wme_update(struct ieee80211com *); +static int iwx_raw_xmit(struct ieee80211_node *, struct mbuf *, + const struct ieee80211_bpf_params *); +static int iwx_transmit(struct ieee80211com *, struct mbuf *); +static void iwx_start(struct iwx_softc *); +static int iwx_ampdu_rx_start(struct ieee80211_node *, + struct ieee80211_rx_ampdu *, int, int, int); +static void iwx_ampdu_rx_stop(struct ieee80211_node *, + struct ieee80211_rx_ampdu *); +static int iwx_addba_request(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int, int, int); +static int iwx_addba_response(struct ieee80211_node *, + struct ieee80211_tx_ampdu *, int, int, int); +static void iwx_key_update_begin(struct ieee80211vap *); +static void iwx_key_update_end(struct ieee80211vap *); +static int iwx_key_alloc(struct ieee80211vap *, struct ieee80211_key *, + ieee80211_keyix *,ieee80211_keyix *); +static int iwx_key_set(struct ieee80211vap *, const struct ieee80211_key *); +static int iwx_key_delete(struct ieee80211vap *, + const struct ieee80211_key *); +static int iwx_suspend(device_t); +static int iwx_resume(device_t); +static void iwx_radiotap_attach(struct iwx_softc *); + +/* OpenBSD compat defines */ +#define IEEE80211_HTOP0_SCO_SCN 0 +#define IEEE80211_VHTOP0_CHAN_WIDTH_HT 0 +#define IEEE80211_VHTOP0_CHAN_WIDTH_80 1 + +#define IEEE80211_HT_RATESET_SISO 0 +#define IEEE80211_HT_RATESET_MIMO2 2 + +const struct ieee80211_rateset ieee80211_std_rateset_11a = + { 8, { 12, 18, 24, 36, 48, 72, 96, 108 } }; + +const struct ieee80211_rateset ieee80211_std_rateset_11b = + { 4, { 2, 4, 11, 22 } }; + +const struct ieee80211_rateset ieee80211_std_rateset_11g = + { 12, { 2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108 } }; + +inline int +ieee80211_has_addr4(const struct ieee80211_frame *wh) +{ + return (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS; +} + +static uint8_t +iwx_lookup_cmd_ver(struct iwx_softc *sc, uint8_t grp, uint8_t cmd) +{ + const struct iwx_fw_cmd_version *entry; + int i; + + for (i = 0; i < sc->n_cmd_versions; i++) { + entry = &sc->cmd_versions[i]; + if (entry->group == grp && entry->cmd == cmd) + return entry->cmd_ver; + } + + return IWX_FW_CMD_VER_UNKNOWN; +} + +uint8_t +iwx_lookup_notif_ver(struct iwx_softc *sc, uint8_t grp, uint8_t cmd) +{ + const struct iwx_fw_cmd_version *entry; + int i; + + for (i = 0; i < sc->n_cmd_versions; i++) { + entry = &sc->cmd_versions[i]; + if (entry->group == grp && entry->cmd == cmd) + return entry->notif_ver; + } + + return IWX_FW_CMD_VER_UNKNOWN; +} + +static int +iwx_store_cscheme(struct iwx_softc *sc, const uint8_t *data, size_t dlen) +{ + const struct iwx_fw_cscheme_list *l = (const void *)data; + + if (dlen < sizeof(*l) || + dlen < sizeof(l->size) + l->size * sizeof(*l->cs)) + return EINVAL; + + /* we don't actually store anything for now, always use s/w crypto */ + + return 0; +} + +static int +iwx_ctxt_info_alloc_dma(struct iwx_softc *sc, + const struct iwx_fw_onesect *sec, struct iwx_dma_info *dram) +{ + int err = iwx_dma_contig_alloc(sc->sc_dmat, dram, sec->fws_len, 1); + if (err) { + printf("%s: could not allocate context info DMA memory\n", + DEVNAME(sc)); + return err; + } + + memcpy(dram->vaddr, sec->fws_data, sec->fws_len); + + return 0; +} + +static void +iwx_ctxt_info_free_paging(struct iwx_softc *sc) +{ + struct iwx_self_init_dram *dram = &sc->init_dram; + int i; + + if (!dram->paging) + return; + + /* free paging*/ + for (i = 0; i < dram->paging_cnt; i++) + iwx_dma_contig_free(&dram->paging[i]); + + free(dram->paging, M_DEVBUF); + dram->paging_cnt = 0; + dram->paging = NULL; +} + +static int +iwx_get_num_sections(const struct iwx_fw_sects *fws, int start) +{ + int i = 0; + + while (start < fws->fw_count && + fws->fw_sect[start].fws_devoff != IWX_CPU1_CPU2_SEPARATOR_SECTION && + fws->fw_sect[start].fws_devoff != IWX_PAGING_SEPARATOR_SECTION) { + start++; + i++; + } + + return i; +} + +static int +iwx_init_fw_sec(struct iwx_softc *sc, const struct iwx_fw_sects *fws, + struct iwx_context_info_dram *ctxt_dram) +{ + struct iwx_self_init_dram *dram = &sc->init_dram; + int i, ret, fw_cnt = 0; + + KASSERT(dram->paging == NULL, ("iwx_init_fw_sec")); + + dram->lmac_cnt = iwx_get_num_sections(fws, 0); + /* add 1 due to separator */ + dram->umac_cnt = iwx_get_num_sections(fws, dram->lmac_cnt + 1); + /* add 2 due to separators */ + dram->paging_cnt = iwx_get_num_sections(fws, + dram->lmac_cnt + dram->umac_cnt + 2); + + IWX_UNLOCK(sc); + dram->fw = mallocarray(dram->umac_cnt + dram->lmac_cnt, + sizeof(*dram->fw), M_DEVBUF, M_ZERO | M_NOWAIT); + if (!dram->fw) { + printf("%s: could not allocate memory for firmware sections\n", + DEVNAME(sc)); + IWX_LOCK(sc); + return ENOMEM; + } + + dram->paging = mallocarray(dram->paging_cnt, sizeof(*dram->paging), + M_DEVBUF, M_ZERO | M_WAITOK); + IWX_LOCK(sc); + if (!dram->paging) { + printf("%s: could not allocate memory for firmware paging\n", + DEVNAME(sc)); + return ENOMEM; + } + + /* initialize lmac sections */ + for (i = 0; i < dram->lmac_cnt; i++) { + ret = iwx_ctxt_info_alloc_dma(sc, &fws->fw_sect[i], + &dram->fw[fw_cnt]); + if (ret) + return ret; + ctxt_dram->lmac_img[i] = + htole64(dram->fw[fw_cnt].paddr); + IWX_DPRINTF(sc, IWX_DEBUG_FIRMWARE_TLV, + "%s: firmware LMAC section %d at 0x%llx size %lld\n", + __func__, i, + (unsigned long long)dram->fw[fw_cnt].paddr, + (unsigned long long)dram->fw[fw_cnt].size); + fw_cnt++; + } + + /* initialize umac sections */ + for (i = 0; i < dram->umac_cnt; i++) { + /* access FW with +1 to make up for lmac separator */ + ret = iwx_ctxt_info_alloc_dma(sc, + &fws->fw_sect[fw_cnt + 1], &dram->fw[fw_cnt]); + if (ret) + return ret; + ctxt_dram->umac_img[i] = + htole64(dram->fw[fw_cnt].paddr); + IWX_DPRINTF(sc, IWX_DEBUG_FIRMWARE_TLV, + "%s: firmware UMAC section %d at 0x%llx size %lld\n", + __func__, i, + (unsigned long long)dram->fw[fw_cnt].paddr, + (unsigned long long)dram->fw[fw_cnt].size); + fw_cnt++; + } + + /* + * Initialize paging. + * Paging memory isn't stored in dram->fw as the umac and lmac - it is + * stored separately. + * This is since the timing of its release is different - + * while fw memory can be released on alive, the paging memory can be + * freed only when the device goes down. + * Given that, the logic here in accessing the fw image is a bit + * different - fw_cnt isn't changing so loop counter is added to it. + */ + for (i = 0; i < dram->paging_cnt; i++) { + /* access FW with +2 to make up for lmac & umac separators */ + int fw_idx = fw_cnt + i + 2; + + ret = iwx_ctxt_info_alloc_dma(sc, + &fws->fw_sect[fw_idx], &dram->paging[i]); + if (ret) + return ret; + + ctxt_dram->virtual_img[i] = htole64(dram->paging[i].paddr); + IWX_DPRINTF(sc, IWX_DEBUG_FIRMWARE_TLV, + "%s: firmware paging section %d at 0x%llx size %lld\n", + __func__, i, + (unsigned long long)dram->paging[i].paddr, + (unsigned long long)dram->paging[i].size); + } + + return 0; +} + +static void +iwx_fw_version_str(char *buf, size_t bufsize, + uint32_t major, uint32_t minor, uint32_t api) +{ + /* + * Starting with major version 35 the Linux driver prints the minor + * version in hexadecimal. + */ + if (major >= 35) + snprintf(buf, bufsize, "%u.%08x.%u", major, minor, api); + else + snprintf(buf, bufsize, "%u.%u.%u", major, minor, api); +} +#if 0 +static int +iwx_alloc_fw_monitor_block(struct iwx_softc *sc, uint8_t max_power, + uint8_t min_power) +{ + struct iwx_dma_info *fw_mon = &sc->fw_mon; + uint32_t size = 0; + uint8_t power; + int err; + + if (fw_mon->size) + return 0; + + for (power = max_power; power >= min_power; power--) { + size = (1 << power); + + err = iwx_dma_contig_alloc(sc->sc_dmat, fw_mon, size, 0); + if (err) + continue; + + IWX_DPRINTF(sc, IWX_DEBUG_FIRMWARE_TLV, + "%s: allocated 0x%08x bytes for firmware monitor.\n", + DEVNAME(sc), size); + break; + } + + if (err) { + fw_mon->size = 0; + return err; + } + + if (power != max_power) + IWX_DPRINTF(sc, IWX_DEBUG_FIRMWARE_TLV, + "%s: Sorry - debug buffer is only %luK while you requested %luK\n", + DEVNAME(sc), (unsigned long)(1 << (power - 10)), + (unsigned long)(1 << (max_power - 10))); + + return 0; +} + +static int +iwx_alloc_fw_monitor(struct iwx_softc *sc, uint8_t max_power) +{ + if (!max_power) { + /* default max_power is maximum */ + max_power = 26; + } else { + max_power += 11; + } + + if (max_power > 26) { + IWX_DPRINTF(sc, IWX_DEBUG_FIRMWARE_TLV, + "%s: External buffer size for monitor is too big %d, " + "check the FW TLV\n", DEVNAME(sc), max_power); + return 0; + } + + if (sc->fw_mon.size) + return 0; + + return iwx_alloc_fw_monitor_block(sc, max_power, 11); +} +#endif + +static int +iwx_apply_debug_destination(struct iwx_softc *sc) +{ +#if 0 + struct iwx_fw_dbg_dest_tlv_v1 *dest_v1; + int i, err; + uint8_t mon_mode, size_power, base_shift, end_shift; + uint32_t base_reg, end_reg; + + dest_v1 = sc->sc_fw.dbg_dest_tlv_v1; + mon_mode = dest_v1->monitor_mode; + size_power = dest_v1->size_power; + base_reg = le32toh(dest_v1->base_reg); + end_reg = le32toh(dest_v1->end_reg); + base_shift = dest_v1->base_shift; + end_shift = dest_v1->end_shift; + + DPRINTF(("%s: applying debug destination %d\n", DEVNAME(sc), mon_mode)); + + if (mon_mode == EXTERNAL_MODE) { *** 19565 LINES SKIPPED ***