19c8efa1dSAdrian Chadd /*- 29c8efa1dSAdrian Chadd * Based on BSD-licensed source modules in the Linux iwlwifi driver, 39c8efa1dSAdrian Chadd * which were used as the reference documentation for this implementation. 49c8efa1dSAdrian Chadd * 59c8efa1dSAdrian Chadd * Driver version we are currently based off of is 69c8efa1dSAdrian Chadd * Linux 4.7.3 (tag id d7f6728f57e3ecbb7ef34eb7d9f564d514775d75) 79c8efa1dSAdrian Chadd * 89c8efa1dSAdrian Chadd *********************************************************************** 99c8efa1dSAdrian Chadd * 109c8efa1dSAdrian Chadd * This file is provided under a dual BSD/GPLv2 license. When using or 119c8efa1dSAdrian Chadd * redistributing this file, you may do so under either license. 129c8efa1dSAdrian Chadd * 139c8efa1dSAdrian Chadd * GPL LICENSE SUMMARY 149c8efa1dSAdrian Chadd * 159c8efa1dSAdrian Chadd * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 169c8efa1dSAdrian Chadd * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 179c8efa1dSAdrian Chadd * Copyright(c) 2016 Intel Deutschland GmbH 189c8efa1dSAdrian Chadd * 199c8efa1dSAdrian Chadd * This program is free software; you can redistribute it and/or modify 209c8efa1dSAdrian Chadd * it under the terms of version 2 of the GNU General Public License as 219c8efa1dSAdrian Chadd * published by the Free Software Foundation. 229c8efa1dSAdrian Chadd * 239c8efa1dSAdrian Chadd * This program is distributed in the hope that it will be useful, but 249c8efa1dSAdrian Chadd * WITHOUT ANY WARRANTY; without even the implied warranty of 259c8efa1dSAdrian Chadd * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 269c8efa1dSAdrian Chadd * General Public License for more details. 279c8efa1dSAdrian Chadd * 289c8efa1dSAdrian Chadd * You should have received a copy of the GNU General Public License 299c8efa1dSAdrian Chadd * along with this program; if not, write to the Free Software 309c8efa1dSAdrian Chadd * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, 319c8efa1dSAdrian Chadd * USA 329c8efa1dSAdrian Chadd * 339c8efa1dSAdrian Chadd * The full GNU General Public License is included in this distribution 349c8efa1dSAdrian Chadd * in the file called COPYING. 359c8efa1dSAdrian Chadd * 369c8efa1dSAdrian Chadd * Contact Information: 379c8efa1dSAdrian Chadd * Intel Linux Wireless <linuxwifi@intel.com> 389c8efa1dSAdrian Chadd * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 399c8efa1dSAdrian Chadd * 409c8efa1dSAdrian Chadd * BSD LICENSE 419c8efa1dSAdrian Chadd * 429c8efa1dSAdrian Chadd * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 439c8efa1dSAdrian Chadd * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 449c8efa1dSAdrian Chadd * All rights reserved. 459c8efa1dSAdrian Chadd * 469c8efa1dSAdrian Chadd * Redistribution and use in source and binary forms, with or without 479c8efa1dSAdrian Chadd * modification, are permitted provided that the following conditions 489c8efa1dSAdrian Chadd * are met: 499c8efa1dSAdrian Chadd * 509c8efa1dSAdrian Chadd * * Redistributions of source code must retain the above copyright 519c8efa1dSAdrian Chadd * notice, this list of conditions and the following disclaimer. 529c8efa1dSAdrian Chadd * * Redistributions in binary form must reproduce the above copyright 539c8efa1dSAdrian Chadd * notice, this list of conditions and the following disclaimer in 549c8efa1dSAdrian Chadd * the documentation and/or other materials provided with the 559c8efa1dSAdrian Chadd * distribution. 569c8efa1dSAdrian Chadd * * Neither the name Intel Corporation nor the names of its 579c8efa1dSAdrian Chadd * contributors may be used to endorse or promote products derived 589c8efa1dSAdrian Chadd * from this software without specific prior written permission. 599c8efa1dSAdrian Chadd * 609c8efa1dSAdrian Chadd * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 619c8efa1dSAdrian Chadd * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 629c8efa1dSAdrian Chadd * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 639c8efa1dSAdrian Chadd * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 649c8efa1dSAdrian Chadd * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 659c8efa1dSAdrian Chadd * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 669c8efa1dSAdrian Chadd * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 679c8efa1dSAdrian Chadd * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 689c8efa1dSAdrian Chadd * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 699c8efa1dSAdrian Chadd * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 709c8efa1dSAdrian Chadd * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 719c8efa1dSAdrian Chadd */ 729c8efa1dSAdrian Chadd 739c8efa1dSAdrian Chadd #include <sys/cdefs.h> 749c8efa1dSAdrian Chadd __FBSDID("$FreeBSD$"); 759c8efa1dSAdrian Chadd 769c8efa1dSAdrian Chadd #include "opt_wlan.h" 77616201d1SAdrian Chadd #include "opt_iwm.h" 789c8efa1dSAdrian Chadd 799c8efa1dSAdrian Chadd #include <sys/param.h> 809c8efa1dSAdrian Chadd #include <sys/bus.h> 819c8efa1dSAdrian Chadd #include <sys/conf.h> 829c8efa1dSAdrian Chadd #include <sys/endian.h> 839c8efa1dSAdrian Chadd #include <sys/firmware.h> 849c8efa1dSAdrian Chadd #include <sys/kernel.h> 859c8efa1dSAdrian Chadd #include <sys/malloc.h> 869c8efa1dSAdrian Chadd #include <sys/mbuf.h> 879c8efa1dSAdrian Chadd #include <sys/mutex.h> 889c8efa1dSAdrian Chadd #include <sys/module.h> 899c8efa1dSAdrian Chadd #include <sys/proc.h> 909c8efa1dSAdrian Chadd #include <sys/rman.h> 919c8efa1dSAdrian Chadd #include <sys/socket.h> 929c8efa1dSAdrian Chadd #include <sys/sockio.h> 939c8efa1dSAdrian Chadd #include <sys/sysctl.h> 949c8efa1dSAdrian Chadd #include <sys/linker.h> 959c8efa1dSAdrian Chadd 969c8efa1dSAdrian Chadd #include <machine/bus.h> 979c8efa1dSAdrian Chadd #include <machine/endian.h> 989c8efa1dSAdrian Chadd #include <machine/resource.h> 999c8efa1dSAdrian Chadd 1009c8efa1dSAdrian Chadd #include <dev/pci/pcivar.h> 1019c8efa1dSAdrian Chadd #include <dev/pci/pcireg.h> 1029c8efa1dSAdrian Chadd 1039c8efa1dSAdrian Chadd #include <net/bpf.h> 1049c8efa1dSAdrian Chadd 1059c8efa1dSAdrian Chadd #include <net/if.h> 1069c8efa1dSAdrian Chadd #include <net/if_var.h> 1079c8efa1dSAdrian Chadd #include <net/if_arp.h> 1089c8efa1dSAdrian Chadd #include <net/if_dl.h> 1099c8efa1dSAdrian Chadd #include <net/if_media.h> 1109c8efa1dSAdrian Chadd #include <net/if_types.h> 1119c8efa1dSAdrian Chadd 1129c8efa1dSAdrian Chadd #include <netinet/in.h> 1139c8efa1dSAdrian Chadd #include <netinet/in_systm.h> 1149c8efa1dSAdrian Chadd #include <netinet/if_ether.h> 1159c8efa1dSAdrian Chadd #include <netinet/ip.h> 1169c8efa1dSAdrian Chadd 1179c8efa1dSAdrian Chadd #include <net80211/ieee80211_var.h> 1189c8efa1dSAdrian Chadd #include <net80211/ieee80211_regdomain.h> 1199c8efa1dSAdrian Chadd #include <net80211/ieee80211_ratectl.h> 1209c8efa1dSAdrian Chadd #include <net80211/ieee80211_radiotap.h> 1219c8efa1dSAdrian Chadd 1229c8efa1dSAdrian Chadd #include <dev/iwm/if_iwmreg.h> 1239c8efa1dSAdrian Chadd #include <dev/iwm/if_iwmvar.h> 1249c8efa1dSAdrian Chadd #include <dev/iwm/if_iwm_debug.h> 1259c8efa1dSAdrian Chadd #include <dev/iwm/if_iwm_util.h> 1269c8efa1dSAdrian Chadd #include <dev/iwm/if_iwm_fw.h> 1279c8efa1dSAdrian Chadd 1289c8efa1dSAdrian Chadd void 1299c8efa1dSAdrian Chadd iwm_free_fw_paging(struct iwm_softc *sc) 1309c8efa1dSAdrian Chadd { 1319c8efa1dSAdrian Chadd int i; 1329c8efa1dSAdrian Chadd 1339c8efa1dSAdrian Chadd if (sc->fw_paging_db[0].fw_paging_block.vaddr == NULL) 1349c8efa1dSAdrian Chadd return; 1359c8efa1dSAdrian Chadd 1369c8efa1dSAdrian Chadd for (i = 0; i < IWM_NUM_OF_FW_PAGING_BLOCKS; i++) { 1379c8efa1dSAdrian Chadd iwm_dma_contig_free(&sc->fw_paging_db[i].fw_paging_block); 1389c8efa1dSAdrian Chadd } 1399c8efa1dSAdrian Chadd 1409c8efa1dSAdrian Chadd memset(sc->fw_paging_db, 0, sizeof(sc->fw_paging_db)); 1419c8efa1dSAdrian Chadd } 1429c8efa1dSAdrian Chadd 1439c8efa1dSAdrian Chadd static int 144f33c8309SKyle Evans iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_img *image) 1459c8efa1dSAdrian Chadd { 1469c8efa1dSAdrian Chadd int sec_idx, idx; 1479c8efa1dSAdrian Chadd uint32_t offset = 0; 1489c8efa1dSAdrian Chadd 1499c8efa1dSAdrian Chadd /* 1509c8efa1dSAdrian Chadd * find where is the paging image start point: 1519c8efa1dSAdrian Chadd * if CPU2 exist and it's in paging format, then the image looks like: 1529c8efa1dSAdrian Chadd * CPU1 sections (2 or more) 1539c8efa1dSAdrian Chadd * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2 1549c8efa1dSAdrian Chadd * CPU2 sections (not paged) 1559c8efa1dSAdrian Chadd * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2 1569c8efa1dSAdrian Chadd * non paged to CPU2 paging sec 1579c8efa1dSAdrian Chadd * CPU2 paging CSS 1589c8efa1dSAdrian Chadd * CPU2 paging image (including instruction and data) 1599c8efa1dSAdrian Chadd */ 1609c8efa1dSAdrian Chadd for (sec_idx = 0; sec_idx < IWM_UCODE_SECTION_MAX; sec_idx++) { 161f33c8309SKyle Evans if (image->sec[sec_idx].offset == IWM_PAGING_SEPARATOR_SECTION) { 1629c8efa1dSAdrian Chadd sec_idx++; 1639c8efa1dSAdrian Chadd break; 1649c8efa1dSAdrian Chadd } 1659c8efa1dSAdrian Chadd } 1669c8efa1dSAdrian Chadd 1679c8efa1dSAdrian Chadd /* 1689c8efa1dSAdrian Chadd * If paging is enabled there should be at least 2 more sections left 1699c8efa1dSAdrian Chadd * (one for CSS and one for Paging data) 1709c8efa1dSAdrian Chadd */ 171f33c8309SKyle Evans if (sec_idx >= nitems(image->sec) - 1) { 1729c8efa1dSAdrian Chadd device_printf(sc->sc_dev, 1739c8efa1dSAdrian Chadd "Paging: Missing CSS and/or paging sections\n"); 1749c8efa1dSAdrian Chadd iwm_free_fw_paging(sc); 1759c8efa1dSAdrian Chadd return EINVAL; 1769c8efa1dSAdrian Chadd } 1779c8efa1dSAdrian Chadd 1789c8efa1dSAdrian Chadd /* copy the CSS block to the dram */ 1799c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 1809c8efa1dSAdrian Chadd "Paging: load paging CSS to FW, sec = %d\n", 1819c8efa1dSAdrian Chadd sec_idx); 1829c8efa1dSAdrian Chadd 1839c8efa1dSAdrian Chadd memcpy(sc->fw_paging_db[0].fw_paging_block.vaddr, 184f33c8309SKyle Evans image->sec[sec_idx].data, 1859c8efa1dSAdrian Chadd sc->fw_paging_db[0].fw_paging_size); 1869c8efa1dSAdrian Chadd 1879c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 1889c8efa1dSAdrian Chadd "Paging: copied %d CSS bytes to first block\n", 1899c8efa1dSAdrian Chadd sc->fw_paging_db[0].fw_paging_size); 1909c8efa1dSAdrian Chadd 1919c8efa1dSAdrian Chadd sec_idx++; 1929c8efa1dSAdrian Chadd 1939c8efa1dSAdrian Chadd /* 1949c8efa1dSAdrian Chadd * copy the paging blocks to the dram 1959c8efa1dSAdrian Chadd * loop index start from 1 since that CSS block already copied to dram 1969c8efa1dSAdrian Chadd * and CSS index is 0. 1979c8efa1dSAdrian Chadd * loop stop at num_of_paging_blk since that last block is not full. 1989c8efa1dSAdrian Chadd */ 1999c8efa1dSAdrian Chadd for (idx = 1; idx < sc->num_of_paging_blk; idx++) { 2009c8efa1dSAdrian Chadd memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr, 201f33c8309SKyle Evans (const char *)image->sec[sec_idx].data + offset, 2029c8efa1dSAdrian Chadd sc->fw_paging_db[idx].fw_paging_size); 2039c8efa1dSAdrian Chadd 2049c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 2059c8efa1dSAdrian Chadd "Paging: copied %d paging bytes to block %d\n", 2069c8efa1dSAdrian Chadd sc->fw_paging_db[idx].fw_paging_size, 2079c8efa1dSAdrian Chadd idx); 2089c8efa1dSAdrian Chadd 2099c8efa1dSAdrian Chadd offset += sc->fw_paging_db[idx].fw_paging_size; 2109c8efa1dSAdrian Chadd } 2119c8efa1dSAdrian Chadd 2129c8efa1dSAdrian Chadd /* copy the last paging block */ 2139c8efa1dSAdrian Chadd if (sc->num_of_pages_in_last_blk > 0) { 2149c8efa1dSAdrian Chadd memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr, 215f33c8309SKyle Evans (const char *)image->sec[sec_idx].data + offset, 2169c8efa1dSAdrian Chadd IWM_FW_PAGING_SIZE * sc->num_of_pages_in_last_blk); 2179c8efa1dSAdrian Chadd 2189c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 2199c8efa1dSAdrian Chadd "Paging: copied %d pages in the last block %d\n", 2209c8efa1dSAdrian Chadd sc->num_of_pages_in_last_blk, idx); 2219c8efa1dSAdrian Chadd } 2229c8efa1dSAdrian Chadd 2239c8efa1dSAdrian Chadd return 0; 2249c8efa1dSAdrian Chadd } 2259c8efa1dSAdrian Chadd 2269c8efa1dSAdrian Chadd static int 227f33c8309SKyle Evans iwm_alloc_fw_paging_mem(struct iwm_softc *sc, const struct iwm_fw_img *image) 2289c8efa1dSAdrian Chadd { 2299c8efa1dSAdrian Chadd int blk_idx = 0; 2309c8efa1dSAdrian Chadd int error, num_of_pages; 2319c8efa1dSAdrian Chadd 2329c8efa1dSAdrian Chadd if (sc->fw_paging_db[0].fw_paging_block.vaddr != NULL) { 2339c8efa1dSAdrian Chadd int i; 2349c8efa1dSAdrian Chadd /* Device got reset, and we setup firmware paging again */ 2359c8efa1dSAdrian Chadd for (i = 0; i < sc->num_of_paging_blk + 1; i++) { 2369c8efa1dSAdrian Chadd bus_dmamap_sync(sc->sc_dmat, 2379c8efa1dSAdrian Chadd sc->fw_paging_db[i].fw_paging_block.map, 2389c8efa1dSAdrian Chadd BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 2399c8efa1dSAdrian Chadd } 2409c8efa1dSAdrian Chadd return 0; 2419c8efa1dSAdrian Chadd } 2429c8efa1dSAdrian Chadd 2439c8efa1dSAdrian Chadd /* ensure IWM_BLOCK_2_EXP_SIZE is power of 2 of IWM_PAGING_BLOCK_SIZE */ 2449c8efa1dSAdrian Chadd _Static_assert((1 << IWM_BLOCK_2_EXP_SIZE) == IWM_PAGING_BLOCK_SIZE, 2459c8efa1dSAdrian Chadd "IWM_BLOCK_2_EXP_SIZE must be power of 2 of IWM_PAGING_BLOCK_SIZE"); 2469c8efa1dSAdrian Chadd 2479c8efa1dSAdrian Chadd num_of_pages = image->paging_mem_size / IWM_FW_PAGING_SIZE; 2489c8efa1dSAdrian Chadd sc->num_of_paging_blk = ((num_of_pages - 1) / 2499c8efa1dSAdrian Chadd IWM_NUM_OF_PAGE_PER_GROUP) + 1; 2509c8efa1dSAdrian Chadd 2519c8efa1dSAdrian Chadd sc->num_of_pages_in_last_blk = 2529c8efa1dSAdrian Chadd num_of_pages - 2539c8efa1dSAdrian Chadd IWM_NUM_OF_PAGE_PER_GROUP * (sc->num_of_paging_blk - 1); 2549c8efa1dSAdrian Chadd 2559c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 2569c8efa1dSAdrian Chadd "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n", 2579c8efa1dSAdrian Chadd sc->num_of_paging_blk, 2589c8efa1dSAdrian Chadd sc->num_of_pages_in_last_blk); 2599c8efa1dSAdrian Chadd 2609c8efa1dSAdrian Chadd /* allocate block of 4Kbytes for paging CSS */ 2619c8efa1dSAdrian Chadd error = iwm_dma_contig_alloc(sc->sc_dmat, 2629c8efa1dSAdrian Chadd &sc->fw_paging_db[blk_idx].fw_paging_block, IWM_FW_PAGING_SIZE, 2639c8efa1dSAdrian Chadd 4096); 2649c8efa1dSAdrian Chadd if (error) { 2659c8efa1dSAdrian Chadd /* free all the previous pages since we failed */ 2669c8efa1dSAdrian Chadd iwm_free_fw_paging(sc); 2679c8efa1dSAdrian Chadd return ENOMEM; 2689c8efa1dSAdrian Chadd } 2699c8efa1dSAdrian Chadd 2709c8efa1dSAdrian Chadd sc->fw_paging_db[blk_idx].fw_paging_size = IWM_FW_PAGING_SIZE; 2719c8efa1dSAdrian Chadd 2729c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 2739c8efa1dSAdrian Chadd "Paging: allocated 4K(CSS) bytes for firmware paging.\n"); 2749c8efa1dSAdrian Chadd 2759c8efa1dSAdrian Chadd /* 2769c8efa1dSAdrian Chadd * allocate blocks in dram. 2779c8efa1dSAdrian Chadd * since that CSS allocated in fw_paging_db[0] loop start from index 1 2789c8efa1dSAdrian Chadd */ 2799c8efa1dSAdrian Chadd for (blk_idx = 1; blk_idx < sc->num_of_paging_blk + 1; blk_idx++) { 2809c8efa1dSAdrian Chadd /* allocate block of IWM_PAGING_BLOCK_SIZE (32K) */ 2819c8efa1dSAdrian Chadd /* XXX Use iwm_dma_contig_alloc for allocating */ 2829c8efa1dSAdrian Chadd error = iwm_dma_contig_alloc(sc->sc_dmat, 2839c8efa1dSAdrian Chadd &sc->fw_paging_db[blk_idx].fw_paging_block, 2849c8efa1dSAdrian Chadd IWM_PAGING_BLOCK_SIZE, 4096); 2859c8efa1dSAdrian Chadd if (error) { 2869c8efa1dSAdrian Chadd /* free all the previous pages since we failed */ 2879c8efa1dSAdrian Chadd iwm_free_fw_paging(sc); 2889c8efa1dSAdrian Chadd return ENOMEM; 2899c8efa1dSAdrian Chadd } 2909c8efa1dSAdrian Chadd 2919c8efa1dSAdrian Chadd sc->fw_paging_db[blk_idx].fw_paging_size = IWM_PAGING_BLOCK_SIZE; 2929c8efa1dSAdrian Chadd 2939c8efa1dSAdrian Chadd IWM_DPRINTF(sc, IWM_DEBUG_FW, 2949c8efa1dSAdrian Chadd "Paging: allocated 32K bytes for firmware paging.\n"); 2959c8efa1dSAdrian Chadd } 2969c8efa1dSAdrian Chadd 2979c8efa1dSAdrian Chadd return 0; 2989c8efa1dSAdrian Chadd } 2999c8efa1dSAdrian Chadd 3009c8efa1dSAdrian Chadd int 301f33c8309SKyle Evans iwm_save_fw_paging(struct iwm_softc *sc, const struct iwm_fw_img *fw) 3029c8efa1dSAdrian Chadd { 3039c8efa1dSAdrian Chadd int ret; 3049c8efa1dSAdrian Chadd 3059c8efa1dSAdrian Chadd ret = iwm_alloc_fw_paging_mem(sc, fw); 3069c8efa1dSAdrian Chadd if (ret) 3079c8efa1dSAdrian Chadd return ret; 3089c8efa1dSAdrian Chadd 3099c8efa1dSAdrian Chadd return iwm_fill_paging_mem(sc, fw); 3109c8efa1dSAdrian Chadd } 3119c8efa1dSAdrian Chadd 3129c8efa1dSAdrian Chadd /* send paging cmd to FW in case CPU2 has paging image */ 3139c8efa1dSAdrian Chadd int 314f33c8309SKyle Evans iwm_send_paging_cmd(struct iwm_softc *sc, const struct iwm_fw_img *fw) 3159c8efa1dSAdrian Chadd { 3169c8efa1dSAdrian Chadd int blk_idx; 3179c8efa1dSAdrian Chadd uint32_t dev_phy_addr; 3189c8efa1dSAdrian Chadd struct iwm_fw_paging_cmd fw_paging_cmd = { 3199c8efa1dSAdrian Chadd .flags = 3209c8efa1dSAdrian Chadd htole32(IWM_PAGING_CMD_IS_SECURED | 3219c8efa1dSAdrian Chadd IWM_PAGING_CMD_IS_ENABLED | 3229c8efa1dSAdrian Chadd (sc->num_of_pages_in_last_blk << 3239c8efa1dSAdrian Chadd IWM_PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)), 3249c8efa1dSAdrian Chadd .block_size = htole32(IWM_BLOCK_2_EXP_SIZE), 3259c8efa1dSAdrian Chadd .block_num = htole32(sc->num_of_paging_blk), 3269c8efa1dSAdrian Chadd }; 3279c8efa1dSAdrian Chadd 3289c8efa1dSAdrian Chadd /* loop for for all paging blocks + CSS block */ 3299c8efa1dSAdrian Chadd for (blk_idx = 0; blk_idx < sc->num_of_paging_blk + 1; blk_idx++) { 3309c8efa1dSAdrian Chadd dev_phy_addr = htole32( 3319c8efa1dSAdrian Chadd sc->fw_paging_db[blk_idx].fw_paging_block.paddr >> 3329c8efa1dSAdrian Chadd IWM_PAGE_2_EXP_SIZE); 3339c8efa1dSAdrian Chadd fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr; 3349c8efa1dSAdrian Chadd bus_dmamap_sync(sc->sc_dmat, 3359c8efa1dSAdrian Chadd sc->fw_paging_db[blk_idx].fw_paging_block.map, 3369c8efa1dSAdrian Chadd BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 3379c8efa1dSAdrian Chadd } 3389c8efa1dSAdrian Chadd 339*e7065dd1SMark Johnston return iwm_send_cmd_pdu(sc, iwm_cmd_id(IWM_FW_PAGING_BLOCK_CMD, 3409c8efa1dSAdrian Chadd IWM_ALWAYS_LONG_GROUP, 0), 3419c8efa1dSAdrian Chadd 0, sizeof(fw_paging_cmd), &fw_paging_cmd); 3429c8efa1dSAdrian Chadd } 343