1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /* Copyright (c) 2021, Intel Corporation
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
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.
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.
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.
35 * @brief Functions used to implement OS compatibility layer
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.
42 #include "ice_common.h"
43 #include "ice_iflib.h"
44 #include <machine/stdarg.h>
49 * @brief OS compatibility layer allocation type
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
55 MALLOC_DEFINE(M_ICE_OSDEP, "ice-osdep", "Intel(R) 100Gb Network Driver osdep allocations");
59 * @brief Global count of # of ice_lock mutexes initialized
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.
65 u16 ice_lock_count = 0;
67 static void ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error);
70 * ice_hw_to_dev - Given a hw private struct, find the associated device_t
71 * @hw: the hardware private structure
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.
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.
82 ice_hw_to_dev(struct ice_hw *hw) {
83 struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
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
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().
99 ice_debug(struct ice_hw *hw, uint64_t mask, char *fmt, ...)
101 device_t dev = ice_hw_to_dev(hw);
104 if (!(mask & hw->debug_mask))
107 device_print_prettyname(dev);
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
122 * Format the given array as a series of uint8_t values with hexadecimal
123 * notation and log the contents to the console log.
125 * TODO: Currently only supports a group size of 1, due to the way hexdump is
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)
132 device_t dev = ice_hw_to_dev(hw);
135 if (!(mask & hw->debug_mask))
138 /* Format the device header to a string */
139 snprintf(prettyname, sizeof(prettyname), "%s: ", device_get_nameunit(dev));
141 /* Make sure the row-size isn't too large */
145 hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
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
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.
160 * TODO: Currently only supports a group size of 1, due to the way hexdump is
164 ice_info_fwlog(struct ice_hw *hw, uint32_t rowsize, uint32_t __unused groupsize,
165 uint8_t *buf, size_t len)
167 device_t dev = ice_hw_to_dev(hw);
170 if (!ice_fwlog_supported(hw))
173 /* Format the device header to a string */
174 snprintf(prettyname, sizeof(prettyname), "%s: FWLOG: ",
175 device_get_nameunit(dev));
177 /* Make sure the row-size isn't too large */
181 hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
185 * rd32 - Read a 32bit hardware register value
186 * @hw: the private hardware structure
187 * @reg: register address to read
189 * Read the specified 32bit register value from BAR0 and return its contents.
192 rd32(struct ice_hw *hw, uint32_t reg)
194 struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
196 return bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
200 * rd64 - Read a 64bit hardware register value
201 * @hw: the private hardware structure
202 * @reg: register address to read
204 * Read the specified 64bit register value from BAR0 and return its contents.
206 * @pre For 32-bit builds, assumes that the 64bit register read can be
207 * safely broken up into two 32-bit register reads.
210 rd64(struct ice_hw *hw, uint32_t reg)
212 struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
216 data = bus_space_read_8(sc->bar0.tag, sc->bar0.handle, reg);
219 * bus_space_read_8 isn't supported on 32bit platforms, so we fall
220 * back to using two bus_space_read_4 calls.
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;
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
235 * Write the specified 32bit value to a register address in BAR0.
238 wr32(struct ice_hw *hw, uint32_t reg, uint32_t val)
240 struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
242 bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, val);
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
251 * Write the specified 64bit value to a register address in BAR0.
253 * @pre For 32-bit builds, assumes that the 64bit register write can be safely
254 * broken up into two 32-bit register writes.
257 wr64(struct ice_hw *hw, uint32_t reg, uint64_t val)
259 struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
262 bus_space_write_8(sc->bar0.tag, sc->bar0.handle, reg, val);
264 uint32_t lo_val, hi_val;
267 * bus_space_write_8 isn't supported on 32bit platforms, so we fall
268 * back to using two bus_space_write_4 calls.
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);
278 * ice_usec_delay - Delay for the specified number of microseconds
279 * @time: microseconds to delay
280 * @sleep: if true, sleep where possible
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
287 ice_usec_delay(uint32_t time, bool sleep)
289 if (sleep && THREAD_CAN_SLEEP())
290 pause("ice_usec_delay", USEC_2_TICKS(time));
296 * ice_msec_delay - Delay for the specified number of milliseconds
297 * @time: milliseconds to delay
298 * @sleep: if true, sleep where possible
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
305 ice_msec_delay(uint32_t time, bool sleep)
307 if (sleep && THREAD_CAN_SLEEP())
308 pause("ice_msec_delay", MSEC_2_TICKS(time));
314 * ice_msec_pause - pause (sleep) the thread for a time in milliseconds
315 * @time: milliseconds to sleep
317 * Wrapper for ice_msec_delay with sleep set to true.
320 ice_msec_pause(uint32_t time)
322 ice_msec_delay(time, true);
326 * ice_msec_spin - Spin the thread for a time in milliseconds
327 * @time: milliseconds to delay
329 * Wrapper for ice_msec_delay with sleep sent to false.
332 ice_msec_spin(uint32_t time)
334 ice_msec_delay(time, false);
337 /********************************************************************
338 * Manage DMA'able memory.
339 *******************************************************************/
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
348 * Callback used by the bus DMA code to obtain the segment address.
351 ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error)
355 *(bus_addr_t *) arg = segs->ds_addr;
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
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.
368 * Returns a pointer to the DMA memory address.
371 ice_alloc_dma_mem(struct ice_hw *hw, struct ice_dma_mem *mem, u64 size)
373 device_t dev = ice_hw_to_dev(hw);
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 */
384 BUS_DMA_ALLOCNOW, /* flags */
386 NULL, /* lockfuncarg */
390 "ice_alloc_dma: bus_dma_tag_create failed, "
391 "error %s\n", ice_err_str(err));
394 err = bus_dmamem_alloc(mem->tag, (void **)&mem->va,
395 BUS_DMA_NOWAIT | BUS_DMA_ZERO, &mem->map);
398 "ice_alloc_dma: bus_dmamem_alloc failed, "
399 "error %s\n", ice_err_str(err));
402 err = bus_dmamap_load(mem->tag, mem->map, mem->va,
409 "ice_alloc_dma: bus_dmamap_load failed, "
410 "error %s\n", ice_err_str(err));
414 bus_dmamap_sync(mem->tag, mem->map,
415 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
418 bus_dmamem_free(mem->tag, mem->va, mem->map);
420 bus_dma_tag_destroy(mem->tag);
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
432 * Release the bus DMA tag and map, and free the DMA memory associated with
436 ice_free_dma_mem(struct ice_hw __unused *hw, struct ice_dma_mem *mem)
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);