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/ice/ice_osdep.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 /* SPDX-License-Identifier: BSD-3-Clause */
    2 /*  Copyright (c) 2021, Intel Corporation
    3  *  All rights reserved.
    4  *
    5  *  Redistribution and use in source and binary forms, with or without
    6  *  modification, are permitted provided that the following conditions are met:
    7  *
    8  *   1. Redistributions of source code must retain the above copyright notice,
    9  *      this list of conditions and the following disclaimer.
   10  *
   11  *   2. Redistributions in binary form must reproduce the above copyright
   12  *      notice, this list of conditions and the following disclaimer in the
   13  *      documentation and/or other materials provided with the distribution.
   14  *
   15  *   3. Neither the name of the Intel Corporation nor the names of its
   16  *      contributors may be used to endorse or promote products derived from
   17  *      this software without specific prior written permission.
   18  *
   19  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   20  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   23  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  *  POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 /*$FreeBSD$*/
   32 
   33 /**
   34  * @file ice_osdep.c
   35  * @brief Functions used to implement OS compatibility layer
   36  *
   37  * Contains functions used by ice_osdep.h to implement the OS compatibility
   38  * layer used by some of the hardware files. Specifically, it is for the bits
   39  * of OS compatibility which don't make sense as macros or inline functions.
   40  */
   41 
   42 #include "ice_common.h"
   43 #include "ice_iflib.h"
   44 #include <machine/stdarg.h>
   45 #include <sys/time.h>
   46 
   47 /**
   48  * @var M_ICE_OSDEP
   49  * @brief OS compatibility layer allocation type
   50  *
   51  * malloc(9) allocation type used by the OS compatibility layer for
   52  * distinguishing allocations by this layer from those of the rest of the
   53  * driver.
   54  */
   55 MALLOC_DEFINE(M_ICE_OSDEP, "ice-osdep", "Intel(R) 100Gb Network Driver osdep allocations");
   56 
   57 /**
   58  * @var ice_lock_count
   59  * @brief Global count of # of ice_lock mutexes initialized
   60  *
   61  * A global count of the total number of times that ice_init_lock has been
   62  * called. This is used to generate unique lock names for each ice_lock, to
   63  * aid in witness lock checking.
   64  */
   65 u16 ice_lock_count = 0;
   66 
   67 static void ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error);
   68 
   69 /**
   70  * ice_hw_to_dev - Given a hw private struct, find the associated device_t
   71  * @hw: the hardware private structure
   72  *
   73  * Given a hw structure pointer, lookup the softc and extract the device
   74  * pointer. Assumes that hw is embedded within the ice_softc, instead of being
   75  * allocated separately, so that __containerof math will work.
   76  *
   77  * This can't be defined in ice_osdep.h as it depends on the complete
   78  * definition of struct ice_softc. That can't be easily included in
   79  * ice_osdep.h without creating circular header dependencies.
   80  */
   81 device_t
   82 ice_hw_to_dev(struct ice_hw *hw) {
   83         struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
   84 
   85         return sc->dev;
   86 }
   87 
   88 /**
   89  * ice_debug - Log a debug message if the type is enabled
   90  * @hw: device private hardware structure
   91  * @mask: the debug message type
   92  * @fmt: printf format specifier
   93  *
   94  * Check if hw->debug_mask has enabled the given message type. If so, log the
   95  * message to the console using vprintf. Mimic the output of device_printf by
   96  * using device_print_prettyname().
   97  */
   98 void
   99 ice_debug(struct ice_hw *hw, uint64_t mask, char *fmt, ...)
  100 {
  101         device_t dev = ice_hw_to_dev(hw);
  102         va_list args;
  103 
  104         if (!(mask & hw->debug_mask))
  105                 return;
  106 
  107         device_print_prettyname(dev);
  108         va_start(args, fmt);
  109         vprintf(fmt, args);
  110         va_end(args);
  111 }
  112 
  113 /**
  114  * ice_debug_array - Format and print an array of values to the console
  115  * @hw: private hardware structure
  116  * @mask: the debug message type
  117  * @rowsize: preferred number of rows to use
  118  * @groupsize: preferred size in bytes to print each chunk
  119  * @buf: the array buffer to print
  120  * @len: size of the array buffer
  121  *
  122  * Format the given array as a series of uint8_t values with hexadecimal
  123  * notation and log the contents to the console log.
  124  *
  125  * TODO: Currently only supports a group size of 1, due to the way hexdump is
  126  * implemented.
  127  */
  128 void
  129 ice_debug_array(struct ice_hw *hw, uint64_t mask, uint32_t rowsize,
  130                 uint32_t __unused groupsize, uint8_t *buf, size_t len)
  131 {
  132         device_t dev = ice_hw_to_dev(hw);
  133         char prettyname[20];
  134 
  135         if (!(mask & hw->debug_mask))
  136                 return;
  137 
  138         /* Format the device header to a string */
  139         snprintf(prettyname, sizeof(prettyname), "%s: ", device_get_nameunit(dev));
  140 
  141         /* Make sure the row-size isn't too large */
  142         if (rowsize > 0xFF)
  143                 rowsize = 0xFF;
  144 
  145         hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
  146 }
  147 
  148 /**
  149  * ice_info_fwlog - Format and print an array of values to the console
  150  * @hw: private hardware structure
  151  * @rowsize: preferred number of rows to use
  152  * @groupsize: preferred size in bytes to print each chunk
  153  * @buf: the array buffer to print
  154  * @len: size of the array buffer
  155  *
  156  * Format the given array as a series of uint8_t values with hexadecimal
  157  * notation and log the contents to the console log.  This variation is
  158  * specific to firmware logging.
  159  *
  160  * TODO: Currently only supports a group size of 1, due to the way hexdump is
  161  * implemented.
  162  */
  163 void
  164 ice_info_fwlog(struct ice_hw *hw, uint32_t rowsize, uint32_t __unused groupsize,
  165                uint8_t *buf, size_t len)
  166 {
  167         device_t dev = ice_hw_to_dev(hw);
  168         char prettyname[20];
  169 
  170         if (!ice_fwlog_supported(hw))
  171                 return;
  172 
  173         /* Format the device header to a string */
  174         snprintf(prettyname, sizeof(prettyname), "%s: FWLOG: ",
  175             device_get_nameunit(dev));
  176 
  177         /* Make sure the row-size isn't too large */
  178         if (rowsize > 0xFF)
  179                 rowsize = 0xFF;
  180 
  181         hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
  182 }
  183 
  184 /**
  185  * rd32 - Read a 32bit hardware register value
  186  * @hw: the private hardware structure
  187  * @reg: register address to read
  188  *
  189  * Read the specified 32bit register value from BAR0 and return its contents.
  190  */
  191 uint32_t
  192 rd32(struct ice_hw *hw, uint32_t reg)
  193 {
  194         struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
  195 
  196         return bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
  197 }
  198 
  199 /**
  200  * rd64 - Read a 64bit hardware register value
  201  * @hw: the private hardware structure
  202  * @reg: register address to read
  203  *
  204  * Read the specified 64bit register value from BAR0 and return its contents.
  205  *
  206  * @pre For 32-bit builds, assumes that the 64bit register read can be
  207  * safely broken up into two 32-bit register reads.
  208  */
  209 uint64_t
  210 rd64(struct ice_hw *hw, uint32_t reg)
  211 {
  212         struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
  213         uint64_t data;
  214 
  215 #ifdef __amd64__
  216         data = bus_space_read_8(sc->bar0.tag, sc->bar0.handle, reg);
  217 #else
  218         /*
  219          * bus_space_read_8 isn't supported on 32bit platforms, so we fall
  220          * back to using two bus_space_read_4 calls.
  221          */
  222         data = bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
  223         data |= ((uint64_t)bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg + 4)) << 32;
  224 #endif
  225 
  226         return data;
  227 }
  228 
  229 /**
  230  * wr32 - Write a 32bit hardware register
  231  * @hw: the private hardware structure
  232  * @reg: the register address to write to
  233  * @val: the 32bit value to write
  234  *
  235  * Write the specified 32bit value to a register address in BAR0.
  236  */
  237 void
  238 wr32(struct ice_hw *hw, uint32_t reg, uint32_t val)
  239 {
  240         struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
  241 
  242         bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, val);
  243 }
  244 
  245 /**
  246  * wr64 - Write a 64bit hardware register
  247  * @hw: the private hardware structure
  248  * @reg: the register address to write to
  249  * @val: the 64bit value to write
  250  *
  251  * Write the specified 64bit value to a register address in BAR0.
  252  *
  253  * @pre For 32-bit builds, assumes that the 64bit register write can be safely
  254  * broken up into two 32-bit register writes.
  255  */
  256 void
  257 wr64(struct ice_hw *hw, uint32_t reg, uint64_t val)
  258 {
  259         struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
  260 
  261 #ifdef __amd64__
  262         bus_space_write_8(sc->bar0.tag, sc->bar0.handle, reg, val);
  263 #else
  264         uint32_t lo_val, hi_val;
  265 
  266         /*
  267          * bus_space_write_8 isn't supported on 32bit platforms, so we fall
  268          * back to using two bus_space_write_4 calls.
  269          */
  270         lo_val = (uint32_t)val;
  271         hi_val = (uint32_t)(val >> 32);
  272         bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, lo_val);
  273         bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg + 4, hi_val);
  274 #endif
  275 }
  276 
  277 /**
  278  * ice_usec_delay - Delay for the specified number of microseconds
  279  * @time: microseconds to delay
  280  * @sleep: if true, sleep where possible
  281  *
  282  * If sleep is true, and if the current thread is allowed to sleep, pause so
  283  * that another thread can execute. Otherwise, use DELAY to spin the thread
  284  * instead.
  285  */
  286 void
  287 ice_usec_delay(uint32_t time, bool sleep)
  288 {
  289         if (sleep && THREAD_CAN_SLEEP())
  290                 pause("ice_usec_delay", USEC_2_TICKS(time));
  291         else
  292                 DELAY(time);
  293 }
  294 
  295 /**
  296  * ice_msec_delay - Delay for the specified number of milliseconds
  297  * @time: milliseconds to delay
  298  * @sleep: if true, sleep where possible
  299  *
  300  * If sleep is true, and if the current thread is allowed to sleep, pause so
  301  * that another thread can execute. Otherwise, use DELAY to spin the thread
  302  * instead.
  303  */
  304 void
  305 ice_msec_delay(uint32_t time, bool sleep)
  306 {
  307         if (sleep && THREAD_CAN_SLEEP())
  308                 pause("ice_msec_delay", MSEC_2_TICKS(time));
  309         else
  310                 DELAY(time * 1000);
  311 }
  312 
  313 /**
  314  * ice_msec_pause - pause (sleep) the thread for a time in milliseconds
  315  * @time: milliseconds to sleep
  316  *
  317  * Wrapper for ice_msec_delay with sleep set to true.
  318  */
  319 void
  320 ice_msec_pause(uint32_t time)
  321 {
  322         ice_msec_delay(time, true);
  323 }
  324 
  325 /**
  326  * ice_msec_spin - Spin the thread for a time in milliseconds
  327  * @time: milliseconds to delay
  328  *
  329  * Wrapper for ice_msec_delay with sleep sent to false.
  330  */
  331 void
  332 ice_msec_spin(uint32_t time)
  333 {
  334         ice_msec_delay(time, false);
  335 }
  336 
  337 /********************************************************************
  338  * Manage DMA'able memory.
  339  *******************************************************************/
  340 
  341 /**
  342  * ice_dmamap_cb - Callback function DMA maps
  343  * @arg: pointer to return the segment address
  344  * @segs: the segments array
  345  * @nseg: number of segments in the array
  346  * @error: error code
  347  *
  348  * Callback used by the bus DMA code to obtain the segment address.
  349  */
  350 static void
  351 ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error)
  352 {
  353         if (error)
  354                 return;
  355         *(bus_addr_t *) arg = segs->ds_addr;
  356         return;
  357 }
  358 
  359 /**
  360  * ice_alloc_dma_mem - Request OS to allocate DMA memory
  361  * @hw: private hardware structure
  362  * @mem: structure defining the DMA memory request
  363  * @size: the allocation size
  364  *
  365  * Allocates some memory for DMA use. Use the FreeBSD bus DMA interface to
  366  * track this memory using a bus DMA tag and map.
  367  *
  368  * Returns a pointer to the DMA memory address.
  369  */
  370 void *
  371 ice_alloc_dma_mem(struct ice_hw *hw, struct ice_dma_mem *mem, u64 size)
  372 {
  373         device_t dev = ice_hw_to_dev(hw);
  374         int err;
  375 
  376         err = bus_dma_tag_create(bus_get_dma_tag(dev),  /* parent */
  377                                  1, 0,                  /* alignment, boundary */
  378                                  BUS_SPACE_MAXADDR,     /* lowaddr */
  379                                  BUS_SPACE_MAXADDR,     /* highaddr */
  380                                  NULL, NULL,            /* filtfunc, filtfuncarg */
  381                                  size,                  /* maxsize */
  382                                  1,                     /* nsegments */
  383                                  size,                  /* maxsegsz */
  384                                  BUS_DMA_ALLOCNOW,      /* flags */
  385                                  NULL,                  /* lockfunc */
  386                                  NULL,                  /* lockfuncarg */
  387                                  &mem->tag);
  388         if (err != 0) {
  389                 device_printf(dev,
  390                     "ice_alloc_dma: bus_dma_tag_create failed, "
  391                     "error %s\n", ice_err_str(err));
  392                 goto fail_0;
  393         }
  394         err = bus_dmamem_alloc(mem->tag, (void **)&mem->va,
  395                              BUS_DMA_NOWAIT | BUS_DMA_ZERO, &mem->map);
  396         if (err != 0) {
  397                 device_printf(dev,
  398                     "ice_alloc_dma: bus_dmamem_alloc failed, "
  399                     "error %s\n", ice_err_str(err));
  400                 goto fail_1;
  401         }
  402         err = bus_dmamap_load(mem->tag, mem->map, mem->va,
  403                             size,
  404                             ice_dmamap_cb,
  405                             &mem->pa,
  406                             BUS_DMA_NOWAIT);
  407         if (err != 0) {
  408                 device_printf(dev,
  409                     "ice_alloc_dma: bus_dmamap_load failed, "
  410                     "error %s\n", ice_err_str(err));
  411                 goto fail_2;
  412         }
  413         mem->size = size;
  414         bus_dmamap_sync(mem->tag, mem->map,
  415             BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
  416         return (mem->va);
  417 fail_2:
  418         bus_dmamem_free(mem->tag, mem->va, mem->map);
  419 fail_1:
  420         bus_dma_tag_destroy(mem->tag);
  421 fail_0:
  422         mem->map = NULL;
  423         mem->tag = NULL;
  424         return (NULL);
  425 }
  426 
  427 /**
  428  * ice_free_dma_mem - Free DMA memory allocated by ice_alloc_dma_mem
  429  * @hw: the hardware private structure
  430  * @mem: DMA memory to free
  431  *
  432  * Release the bus DMA tag and map, and free the DMA memory associated with
  433  * it.
  434  */
  435 void
  436 ice_free_dma_mem(struct ice_hw __unused *hw, struct ice_dma_mem *mem)
  437 {
  438         bus_dmamap_sync(mem->tag, mem->map,
  439             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  440         bus_dmamap_unload(mem->tag, mem->map);
  441         bus_dmamem_free(mem->tag, mem->va, mem->map);
  442         bus_dma_tag_destroy(mem->tag);
  443         mem->map = NULL;
  444         mem->tag = NULL;
  445 }

Cache object: 27d90302582a536c1b6143eaf192c66b


[ 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.