The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/iwm/if_iwm_fw.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Based on BSD-licensed source modules in the Linux iwlwifi driver,
    3  * which were used as the reference documentation for this implementation.
    4  *
    5  * Driver version we are currently based off of is
    6  * Linux 4.7.3 (tag id d7f6728f57e3ecbb7ef34eb7d9f564d514775d75)
    7  *
    8  ***********************************************************************
    9  *
   10  * This file is provided under a dual BSD/GPLv2 license.  When using or
   11  * redistributing this file, you may do so under either license.
   12  *
   13  * GPL LICENSE SUMMARY
   14  *
   15  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
   16  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
   17  * Copyright(c) 2016 Intel Deutschland GmbH
   18  *
   19  * This program is free software; you can redistribute it and/or modify
   20  * it under the terms of version 2 of the GNU General Public License as
   21  * published by the Free Software Foundation.
   22  *
   23  * This program is distributed in the hope that it will be useful, but
   24  * WITHOUT ANY WARRANTY; without even the implied warranty of
   25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   26  * General Public License for more details.
   27  *
   28  * You should have received a copy of the GNU General Public License
   29  * along with this program; if not, write to the Free Software
   30  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
   31  * USA
   32  *
   33  * The full GNU General Public License is included in this distribution
   34  * in the file called COPYING.
   35  *
   36  * Contact Information:
   37  *  Intel Linux Wireless <linuxwifi@intel.com>
   38  * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
   39  *
   40  * BSD LICENSE
   41  *
   42  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
   43  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
   44  * All rights reserved.
   45  *
   46  * Redistribution and use in source and binary forms, with or without
   47  * modification, are permitted provided that the following conditions
   48  * are met:
   49  *
   50  *  * Redistributions of source code must retain the above copyright
   51  *    notice, this list of conditions and the following disclaimer.
   52  *  * Redistributions in binary form must reproduce the above copyright
   53  *    notice, this list of conditions and the following disclaimer in
   54  *    the documentation and/or other materials provided with the
   55  *    distribution.
   56  *  * Neither the name Intel Corporation nor the names of its
   57  *    contributors may be used to endorse or promote products derived
   58  *    from this software without specific prior written permission.
   59  *
   60  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   61  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   62  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   63  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   64  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   65  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   66  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   67  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   68  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   69  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   70  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   71  */
   72 
   73 #include <sys/cdefs.h>
   74 __FBSDID("$FreeBSD$");
   75 
   76 #include "opt_wlan.h"
   77 #include "opt_iwm.h"
   78 
   79 #include <sys/param.h>
   80 #include <sys/bus.h>
   81 #include <sys/conf.h>
   82 #include <sys/endian.h>
   83 #include <sys/firmware.h>
   84 #include <sys/kernel.h>
   85 #include <sys/malloc.h>
   86 #include <sys/mbuf.h>
   87 #include <sys/mutex.h>
   88 #include <sys/module.h>
   89 #include <sys/proc.h>
   90 #include <sys/rman.h>
   91 #include <sys/socket.h>
   92 #include <sys/sockio.h>
   93 #include <sys/sysctl.h>
   94 #include <sys/linker.h>
   95 
   96 #include <machine/bus.h>
   97 #include <machine/endian.h>
   98 #include <machine/resource.h>
   99 
  100 #include <dev/pci/pcivar.h>
  101 #include <dev/pci/pcireg.h>
  102 
  103 #include <net/bpf.h>
  104 
  105 #include <net/if.h>
  106 #include <net/if_var.h>
  107 #include <net/if_arp.h>
  108 #include <net/if_dl.h>
  109 #include <net/if_media.h>
  110 #include <net/if_types.h>
  111 
  112 #include <netinet/in.h>
  113 #include <netinet/in_systm.h>
  114 #include <netinet/if_ether.h>
  115 #include <netinet/ip.h>
  116 
  117 #include <net80211/ieee80211_var.h>
  118 #include <net80211/ieee80211_regdomain.h>
  119 #include <net80211/ieee80211_ratectl.h>
  120 #include <net80211/ieee80211_radiotap.h>
  121 
  122 #include <dev/iwm/if_iwmreg.h>
  123 #include <dev/iwm/if_iwmvar.h>
  124 #include <dev/iwm/if_iwm_debug.h>
  125 #include <dev/iwm/if_iwm_util.h>
  126 #include <dev/iwm/if_iwm_fw.h>
  127 
  128 void
  129 iwm_free_fw_paging(struct iwm_softc *sc)
  130 {
  131         int i;
  132 
  133         if (sc->fw_paging_db[0].fw_paging_block.vaddr == NULL)
  134                 return;
  135 
  136         for (i = 0; i < IWM_NUM_OF_FW_PAGING_BLOCKS; i++) {
  137                 iwm_dma_contig_free(&sc->fw_paging_db[i].fw_paging_block);
  138         }
  139 
  140         memset(sc->fw_paging_db, 0, sizeof(sc->fw_paging_db));
  141 }
  142 
  143 static int
  144 iwm_fill_paging_mem(struct iwm_softc *sc, const struct iwm_fw_img *image)
  145 {
  146         int sec_idx, idx;
  147         uint32_t offset = 0;
  148 
  149         /*
  150          * find where is the paging image start point:
  151          * if CPU2 exist and it's in paging format, then the image looks like:
  152          * CPU1 sections (2 or more)
  153          * CPU1_CPU2_SEPARATOR_SECTION delimiter - separate between CPU1 to CPU2
  154          * CPU2 sections (not paged)
  155          * PAGING_SEPARATOR_SECTION delimiter - separate between CPU2
  156          * non paged to CPU2 paging sec
  157          * CPU2 paging CSS
  158          * CPU2 paging image (including instruction and data)
  159          */
  160         for (sec_idx = 0; sec_idx < IWM_UCODE_SECTION_MAX; sec_idx++) {
  161                 if (image->sec[sec_idx].offset == IWM_PAGING_SEPARATOR_SECTION) {
  162                         sec_idx++;
  163                         break;
  164                 }
  165         }
  166 
  167         /*
  168          * If paging is enabled there should be at least 2 more sections left
  169          * (one for CSS and one for Paging data)
  170          */
  171         if (sec_idx >= nitems(image->sec) - 1) {
  172                 device_printf(sc->sc_dev,
  173                     "Paging: Missing CSS and/or paging sections\n");
  174                 iwm_free_fw_paging(sc);
  175                 return EINVAL;
  176         }
  177 
  178         /* copy the CSS block to the dram */
  179         IWM_DPRINTF(sc, IWM_DEBUG_FW,
  180                     "Paging: load paging CSS to FW, sec = %d\n",
  181                     sec_idx);
  182 
  183         memcpy(sc->fw_paging_db[0].fw_paging_block.vaddr,
  184                image->sec[sec_idx].data,
  185                sc->fw_paging_db[0].fw_paging_size);
  186 
  187         IWM_DPRINTF(sc, IWM_DEBUG_FW,
  188                     "Paging: copied %d CSS bytes to first block\n",
  189                     sc->fw_paging_db[0].fw_paging_size);
  190 
  191         sec_idx++;
  192 
  193         /*
  194          * copy the paging blocks to the dram
  195          * loop index start from 1 since that CSS block already copied to dram
  196          * and CSS index is 0.
  197          * loop stop at num_of_paging_blk since that last block is not full.
  198          */
  199         for (idx = 1; idx < sc->num_of_paging_blk; idx++) {
  200                 memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr,
  201                        (const char *)image->sec[sec_idx].data + offset,
  202                        sc->fw_paging_db[idx].fw_paging_size);
  203 
  204                 IWM_DPRINTF(sc, IWM_DEBUG_FW,
  205                             "Paging: copied %d paging bytes to block %d\n",
  206                             sc->fw_paging_db[idx].fw_paging_size,
  207                             idx);
  208 
  209                 offset += sc->fw_paging_db[idx].fw_paging_size;
  210         }
  211 
  212         /* copy the last paging block */
  213         if (sc->num_of_pages_in_last_blk > 0) {
  214                 memcpy(sc->fw_paging_db[idx].fw_paging_block.vaddr,
  215                        (const char *)image->sec[sec_idx].data + offset,
  216                        IWM_FW_PAGING_SIZE * sc->num_of_pages_in_last_blk);
  217 
  218                 IWM_DPRINTF(sc, IWM_DEBUG_FW,
  219                             "Paging: copied %d pages in the last block %d\n",
  220                             sc->num_of_pages_in_last_blk, idx);
  221         }
  222 
  223         return 0;
  224 }
  225 
  226 static int
  227 iwm_alloc_fw_paging_mem(struct iwm_softc *sc, const struct iwm_fw_img *image)
  228 {
  229         int blk_idx = 0;
  230         int error, num_of_pages;
  231 
  232         if (sc->fw_paging_db[0].fw_paging_block.vaddr != NULL) {
  233                 int i;
  234                 /* Device got reset, and we setup firmware paging again */
  235                 for (i = 0; i < sc->num_of_paging_blk + 1; i++) {
  236                         bus_dmamap_sync(sc->sc_dmat,
  237                             sc->fw_paging_db[i].fw_paging_block.map,
  238                             BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
  239                 }
  240                 return 0;
  241         }
  242 
  243         /* ensure IWM_BLOCK_2_EXP_SIZE is power of 2 of IWM_PAGING_BLOCK_SIZE */
  244         _Static_assert((1 << IWM_BLOCK_2_EXP_SIZE) == IWM_PAGING_BLOCK_SIZE,
  245             "IWM_BLOCK_2_EXP_SIZE must be power of 2 of IWM_PAGING_BLOCK_SIZE");
  246 
  247         num_of_pages = image->paging_mem_size / IWM_FW_PAGING_SIZE;
  248         sc->num_of_paging_blk = ((num_of_pages - 1) /
  249                                     IWM_NUM_OF_PAGE_PER_GROUP) + 1;
  250 
  251         sc->num_of_pages_in_last_blk =
  252                 num_of_pages -
  253                 IWM_NUM_OF_PAGE_PER_GROUP * (sc->num_of_paging_blk - 1);
  254 
  255         IWM_DPRINTF(sc, IWM_DEBUG_FW,
  256                     "Paging: allocating mem for %d paging blocks, each block holds 8 pages, last block holds %d pages\n",
  257                     sc->num_of_paging_blk,
  258                     sc->num_of_pages_in_last_blk);
  259 
  260         /* allocate block of 4Kbytes for paging CSS */
  261         error = iwm_dma_contig_alloc(sc->sc_dmat,
  262             &sc->fw_paging_db[blk_idx].fw_paging_block, IWM_FW_PAGING_SIZE,
  263             4096);
  264         if (error) {
  265                 /* free all the previous pages since we failed */
  266                 iwm_free_fw_paging(sc);
  267                 return ENOMEM;
  268         }
  269 
  270         sc->fw_paging_db[blk_idx].fw_paging_size = IWM_FW_PAGING_SIZE;
  271 
  272         IWM_DPRINTF(sc, IWM_DEBUG_FW,
  273                     "Paging: allocated 4K(CSS) bytes for firmware paging.\n");
  274 
  275         /*
  276          * allocate blocks in dram.
  277          * since that CSS allocated in fw_paging_db[0] loop start from index 1
  278          */
  279         for (blk_idx = 1; blk_idx < sc->num_of_paging_blk + 1; blk_idx++) {
  280                 /* allocate block of IWM_PAGING_BLOCK_SIZE (32K) */
  281                 /* XXX Use iwm_dma_contig_alloc for allocating */
  282                 error = iwm_dma_contig_alloc(sc->sc_dmat,
  283                      &sc->fw_paging_db[blk_idx].fw_paging_block,
  284                     IWM_PAGING_BLOCK_SIZE, 4096);
  285                 if (error) {
  286                         /* free all the previous pages since we failed */
  287                         iwm_free_fw_paging(sc);
  288                         return ENOMEM;
  289                 }
  290 
  291                 sc->fw_paging_db[blk_idx].fw_paging_size = IWM_PAGING_BLOCK_SIZE;
  292 
  293                 IWM_DPRINTF(sc, IWM_DEBUG_FW,
  294                             "Paging: allocated 32K bytes for firmware paging.\n");
  295         }
  296 
  297         return 0;
  298 }
  299 
  300 int
  301 iwm_save_fw_paging(struct iwm_softc *sc, const struct iwm_fw_img *fw)
  302 {
  303         int ret;
  304 
  305         ret = iwm_alloc_fw_paging_mem(sc, fw);
  306         if (ret)
  307                 return ret;
  308 
  309         return iwm_fill_paging_mem(sc, fw);
  310 }
  311 
  312 /* send paging cmd to FW in case CPU2 has paging image */
  313 int
  314 iwm_send_paging_cmd(struct iwm_softc *sc, const struct iwm_fw_img *fw)
  315 {
  316         int blk_idx;
  317         uint32_t dev_phy_addr;
  318         struct iwm_fw_paging_cmd fw_paging_cmd = {
  319                 .flags =
  320                         htole32(IWM_PAGING_CMD_IS_SECURED |
  321                                 IWM_PAGING_CMD_IS_ENABLED |
  322                                 (sc->num_of_pages_in_last_blk <<
  323                                 IWM_PAGING_CMD_NUM_OF_PAGES_IN_LAST_GRP_POS)),
  324                 .block_size = htole32(IWM_BLOCK_2_EXP_SIZE),
  325                 .block_num = htole32(sc->num_of_paging_blk),
  326         };
  327 
  328         /* loop for all paging blocks + CSS block */
  329         for (blk_idx = 0; blk_idx < sc->num_of_paging_blk + 1; blk_idx++) {
  330                 dev_phy_addr = htole32(
  331                     sc->fw_paging_db[blk_idx].fw_paging_block.paddr >>
  332                     IWM_PAGE_2_EXP_SIZE);
  333                 fw_paging_cmd.device_phy_addr[blk_idx] = dev_phy_addr;
  334                 bus_dmamap_sync(sc->sc_dmat,
  335                     sc->fw_paging_db[blk_idx].fw_paging_block.map,
  336                     BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
  337         }
  338 
  339         return iwm_send_cmd_pdu(sc, iwm_cmd_id(IWM_FW_PAGING_BLOCK_CMD,
  340                                                    IWM_ALWAYS_LONG_GROUP, 0),
  341                                     0, sizeof(fw_paging_cmd), &fw_paging_cmd);
  342 }

Cache object: b919fc1e12d5c1b91bf10ca50897b61f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.