aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/ice/ice_osdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ice/ice_osdep.c')
-rw-r--r--sys/dev/ice/ice_osdep.c409
1 files changed, 409 insertions, 0 deletions
diff --git a/sys/dev/ice/ice_osdep.c b/sys/dev/ice/ice_osdep.c
new file mode 100644
index 000000000000..1e26b713ab13
--- /dev/null
+++ b/sys/dev/ice/ice_osdep.c
@@ -0,0 +1,409 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2020, 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:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of the 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.
+ */
+/*$FreeBSD$*/
+
+/**
+ * @file ice_osdep.c
+ * @brief Functions used to implement OS compatibility layer
+ *
+ * Contains functions used by ice_osdep.h to implement the OS compatibility
+ * layer used by some of the hardware files. Specifically, it is for the bits
+ * of OS compatibility which don't make sense as macros or inline functions.
+ */
+
+#include "ice_common.h"
+#include "ice_iflib.h"
+#include <machine/stdarg.h>
+#include <sys/time.h>
+
+/**
+ * @var M_ICE_OSDEP
+ * @brief OS compatibility layer allocation type
+ *
+ * malloc(9) allocation type used by the OS compatibility layer for
+ * distinguishing allocations by this layer from those of the rest of the
+ * driver.
+ */
+MALLOC_DEFINE(M_ICE_OSDEP, "ice-osdep", "Intel(R) 100Gb Network Driver osdep allocations");
+
+/**
+ * @var ice_lock_count
+ * @brief Global count of # of ice_lock mutexes initialized
+ *
+ * A global count of the total number of times that ice_init_lock has been
+ * called. This is used to generate unique lock names for each ice_lock, to
+ * aid in witness lock checking.
+ */
+u16 ice_lock_count = 0;
+
+static void ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error);
+
+/**
+ * ice_hw_to_dev - Given a hw private struct, find the associated device_t
+ * @hw: the hardware private structure
+ *
+ * Given a hw structure pointer, lookup the softc and extract the device
+ * pointer. Assumes that hw is embedded within the ice_softc, instead of being
+ * allocated separately, so that __containerof math will work.
+ *
+ * This can't be defined in ice_osdep.h as it depends on the complete
+ * definition of struct ice_softc. That can't be easily included in
+ * ice_osdep.h without creating circular header dependencies.
+ */
+device_t
+ice_hw_to_dev(struct ice_hw *hw) {
+ struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
+
+ return sc->dev;
+}
+
+/**
+ * ice_debug - Log a debug message if the type is enabled
+ * @hw: device private hardware structure
+ * @mask: the debug message type
+ * @fmt: printf format specifier
+ *
+ * Check if hw->debug_mask has enabled the given message type. If so, log the
+ * message to the console using vprintf. Mimic the output of device_printf by
+ * using device_print_prettyname().
+ */
+void
+ice_debug(struct ice_hw *hw, uint64_t mask, char *fmt, ...)
+{
+ device_t dev = ice_hw_to_dev(hw);
+ va_list args;
+
+ if (!(mask & hw->debug_mask))
+ return;
+
+ device_print_prettyname(dev);
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+/**
+ * ice_debug_array - Format and print an array of values to the console
+ * @hw: private hardware structure
+ * @mask: the debug message type
+ * @rowsize: preferred number of rows to use
+ * @groupsize: preferred size in bytes to print each chunk
+ * @buf: the array buffer to print
+ * @len: size of the array buffer
+ *
+ * Format the given array as a series of uint8_t values with hexadecimal
+ * notation and log the contents to the console log.
+ *
+ * TODO: Currently only supports a group size of 1, due to the way hexdump is
+ * implemented.
+ */
+void
+ice_debug_array(struct ice_hw *hw, uint64_t mask, uint32_t rowsize,
+ uint32_t __unused groupsize, uint8_t *buf, size_t len)
+{
+ device_t dev = ice_hw_to_dev(hw);
+ char prettyname[20];
+
+ if (!(mask & hw->debug_mask))
+ return;
+
+ /* Format the device header to a string */
+ snprintf(prettyname, sizeof(prettyname), "%s: ", device_get_nameunit(dev));
+
+ /* Make sure the row-size isn't too large */
+ if (rowsize > 0xFF)
+ rowsize = 0xFF;
+
+ hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
+}
+
+/**
+ * rd32 - Read a 32bit hardware register value
+ * @hw: the private hardware structure
+ * @reg: register address to read
+ *
+ * Read the specified 32bit register value from BAR0 and return its contents.
+ */
+uint32_t
+rd32(struct ice_hw *hw, uint32_t reg)
+{
+ struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
+
+ return bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
+}
+
+/**
+ * rd64 - Read a 64bit hardware register value
+ * @hw: the private hardware structure
+ * @reg: register address to read
+ *
+ * Read the specified 64bit register value from BAR0 and return its contents.
+ *
+ * @pre For 32-bit builds, assumes that the 64bit register read can be
+ * safely broken up into two 32-bit register reads.
+ */
+uint64_t
+rd64(struct ice_hw *hw, uint32_t reg)
+{
+ struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
+ uint64_t data;
+
+#ifdef __amd64__
+ data = bus_space_read_8(sc->bar0.tag, sc->bar0.handle, reg);
+#else
+ /*
+ * bus_space_read_8 isn't supported on 32bit platforms, so we fall
+ * back to using two bus_space_read_4 calls.
+ */
+ data = bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
+ data |= ((uint64_t)bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg + 4)) << 32;
+#endif
+
+ return data;
+}
+
+/**
+ * wr32 - Write a 32bit hardware register
+ * @hw: the private hardware structure
+ * @reg: the register address to write to
+ * @val: the 32bit value to write
+ *
+ * Write the specified 32bit value to a register address in BAR0.
+ */
+void
+wr32(struct ice_hw *hw, uint32_t reg, uint32_t val)
+{
+ struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
+
+ bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, val);
+}
+
+/**
+ * wr64 - Write a 64bit hardware register
+ * @hw: the private hardware structure
+ * @reg: the register address to write to
+ * @val: the 64bit value to write
+ *
+ * Write the specified 64bit value to a register address in BAR0.
+ *
+ * @pre For 32-bit builds, assumes that the 64bit register write can be safely
+ * broken up into two 32-bit register writes.
+ */
+void
+wr64(struct ice_hw *hw, uint32_t reg, uint64_t val)
+{
+ struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
+
+#ifdef __amd64__
+ bus_space_write_8(sc->bar0.tag, sc->bar0.handle, reg, val);
+#else
+ uint32_t lo_val, hi_val;
+
+ /*
+ * bus_space_write_8 isn't supported on 32bit platforms, so we fall
+ * back to using two bus_space_write_4 calls.
+ */
+ lo_val = (uint32_t)val;
+ hi_val = (uint32_t)(val >> 32);
+ bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, lo_val);
+ bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg + 4, hi_val);
+#endif
+}
+
+/**
+ * ice_usec_delay - Delay for the specified number of microseconds
+ * @time: microseconds to delay
+ * @sleep: if true, sleep where possible
+ *
+ * If sleep is true, and if the current thread is allowed to sleep, pause so
+ * that another thread can execute. Otherwise, use DELAY to spin the thread
+ * instead.
+ */
+void
+ice_usec_delay(uint32_t time, bool sleep)
+{
+ if (sleep && THREAD_CAN_SLEEP())
+ pause("ice_usec_delay", USEC_2_TICKS(time));
+ else
+ DELAY(time);
+}
+
+/**
+ * ice_msec_delay - Delay for the specified number of milliseconds
+ * @time: milliseconds to delay
+ * @sleep: if true, sleep where possible
+ *
+ * If sleep is true, and if the current thread is allowed to sleep, pause so
+ * that another thread can execute. Otherwise, use DELAY to spin the thread
+ * instead.
+ */
+void
+ice_msec_delay(uint32_t time, bool sleep)
+{
+ if (sleep && THREAD_CAN_SLEEP())
+ pause("ice_msec_delay", MSEC_2_TICKS(time));
+ else
+ DELAY(time * 1000);
+}
+
+/**
+ * ice_msec_pause - pause (sleep) the thread for a time in milliseconds
+ * @time: milliseconds to sleep
+ *
+ * Wrapper for ice_msec_delay with sleep set to true.
+ */
+void
+ice_msec_pause(uint32_t time)
+{
+ ice_msec_delay(time, true);
+}
+
+/**
+ * ice_msec_spin - Spin the thread for a time in milliseconds
+ * @time: milliseconds to delay
+ *
+ * Wrapper for ice_msec_delay with sleep sent to false.
+ */
+void
+ice_msec_spin(uint32_t time)
+{
+ ice_msec_delay(time, false);
+}
+
+/********************************************************************
+ * Manage DMA'able memory.
+ *******************************************************************/
+
+/**
+ * ice_dmamap_cb - Callback function DMA maps
+ * @arg: pointer to return the segment address
+ * @segs: the segments array
+ * @nseg: number of segments in the array
+ * @error: error code
+ *
+ * Callback used by the bus DMA code to obtain the segment address.
+ */
+static void
+ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error)
+{
+ if (error)
+ return;
+ *(bus_addr_t *) arg = segs->ds_addr;
+ return;
+}
+
+/**
+ * ice_alloc_dma_mem - Request OS to allocate DMA memory
+ * @hw: private hardware structure
+ * @mem: structure defining the DMA memory request
+ * @size: the allocation size
+ *
+ * Allocates some memory for DMA use. Use the FreeBSD bus DMA interface to
+ * track this memory using a bus DMA tag and map.
+ *
+ * Returns a pointer to the DMA memory address.
+ */
+void *
+ice_alloc_dma_mem(struct ice_hw *hw, struct ice_dma_mem *mem, u64 size)
+{
+ device_t dev = ice_hw_to_dev(hw);
+ int err;
+
+ err = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */
+ 1, 0, /* alignment, boundary */
+ BUS_SPACE_MAXADDR, /* lowaddr */
+ BUS_SPACE_MAXADDR, /* highaddr */
+ NULL, NULL, /* filtfunc, filtfuncarg */
+ size, /* maxsize */
+ 1, /* nsegments */
+ size, /* maxsegsz */
+ BUS_DMA_ALLOCNOW, /* flags */
+ NULL, /* lockfunc */
+ NULL, /* lockfuncarg */
+ &mem->tag);
+ if (err != 0) {
+ device_printf(dev,
+ "ice_alloc_dma: bus_dma_tag_create failed, "
+ "error %s\n", ice_err_str(err));
+ goto fail_0;
+ }
+ err = bus_dmamem_alloc(mem->tag, (void **)&mem->va,
+ BUS_DMA_NOWAIT | BUS_DMA_ZERO, &mem->map);
+ if (err != 0) {
+ device_printf(dev,
+ "ice_alloc_dma: bus_dmamem_alloc failed, "
+ "error %s\n", ice_err_str(err));
+ goto fail_1;
+ }
+ err = bus_dmamap_load(mem->tag, mem->map, mem->va,
+ size,
+ ice_dmamap_cb,
+ &mem->pa,
+ BUS_DMA_NOWAIT);
+ if (err != 0) {
+ device_printf(dev,
+ "ice_alloc_dma: bus_dmamap_load failed, "
+ "error %s\n", ice_err_str(err));
+ goto fail_2;
+ }
+ mem->size = size;
+ bus_dmamap_sync(mem->tag, mem->map,
+ BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+ return (mem->va);
+fail_2:
+ bus_dmamem_free(mem->tag, mem->va, mem->map);
+fail_1:
+ bus_dma_tag_destroy(mem->tag);
+fail_0:
+ mem->map = NULL;
+ mem->tag = NULL;
+ return (NULL);
+}
+
+/**
+ * ice_free_dma_mem - Free DMA memory allocated by ice_alloc_dma_mem
+ * @hw: the hardware private structure
+ * @mem: DMA memory to free
+ *
+ * Release the bus DMA tag and map, and free the DMA memory associated with
+ * it.
+ */
+void
+ice_free_dma_mem(struct ice_hw __unused *hw, struct ice_dma_mem *mem)
+{
+ bus_dmamap_sync(mem->tag, mem->map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(mem->tag, mem->map);
+ bus_dmamem_free(mem->tag, mem->va, mem->map);
+ bus_dma_tag_destroy(mem->tag);
+ mem->map = NULL;
+ mem->tag = NULL;
+}