1157114Sscottl/* SPDX-License-Identifier: BSD-3-Clause */
2157114Sscottl/*  Copyright (c) 2024, Intel Corporation
3157114Sscottl *  All rights reserved.
4157114Sscottl *
5157114Sscottl *  Redistribution and use in source and binary forms, with or without
6157114Sscottl *  modification, are permitted provided that the following conditions are met:
7157114Sscottl *
8157114Sscottl *   1. Redistributions of source code must retain the above copyright notice,
9157114Sscottl *      this list of conditions and the following disclaimer.
10157114Sscottl *
11157114Sscottl *   2. Redistributions in binary form must reproduce the above copyright
12157114Sscottl *      notice, this list of conditions and the following disclaimer in the
13157114Sscottl *      documentation and/or other materials provided with the distribution.
14157114Sscottl *
15157114Sscottl *   3. Neither the name of the Intel Corporation nor the names of its
16157114Sscottl *      contributors may be used to endorse or promote products derived from
17157114Sscottl *      this software without specific prior written permission.
18157114Sscottl *
19157114Sscottl *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20157114Sscottl *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21157114Sscottl *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22157114Sscottl *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23157114Sscottl *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24157114Sscottl *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25157114Sscottl *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26171980Sscottl *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27171980Sscottl *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28171980Sscottl *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29171980Sscottl *  POSSIBILITY OF SUCH DAMAGE.
30171980Sscottl */
31171980Sscottl
32171980Sscottl/**
33171980Sscottl * @file ice_osdep.c
34171980Sscottl * @brief Functions used to implement OS compatibility layer
35171980Sscottl *
36171980Sscottl * Contains functions used by ice_osdep.h to implement the OS compatibility
37171980Sscottl * layer used by some of the hardware files. Specifically, it is for the bits
38171980Sscottl * of OS compatibility which don't make sense as macros or inline functions.
39171980Sscottl */
40171980Sscottl
41171980Sscottl#include "ice_common.h"
42171980Sscottl#include "ice_iflib.h"
43171980Sscottl#include <machine/stdarg.h>
44171980Sscottl#include <sys/time.h>
45171980Sscottl
46171980Sscottl/**
47171980Sscottl * @var M_ICE_OSDEP
48171980Sscottl * @brief OS compatibility layer allocation type
49171980Sscottl *
50171980Sscottl * malloc(9) allocation type used by the OS compatibility layer for
51171980Sscottl * distinguishing allocations by this layer from those of the rest of the
52157114Sscottl * driver.
53157114Sscottl */
54157114SscottlMALLOC_DEFINE(M_ICE_OSDEP, "ice-osdep", "Intel(R) 100Gb Network Driver osdep allocations");
55157114Sscottl
56233711Sambrisko/**
57157114Sscottl * @var ice_lock_count
58157114Sscottl * @brief Global count of # of ice_lock mutexes initialized
59157114Sscottl *
60157114Sscottl * A global count of the total number of times that ice_init_lock has been
61162118Sambrisko * called. This is used to generate unique lock names for each ice_lock, to
62157114Sscottl * aid in witness lock checking.
63157114Sscottl */
64158737Sambriskou16 ice_lock_count = 0;
65158737Sambrisko
66157114Sscottlstatic void ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error);
67157114Sscottl
68157114Sscottl/**
69157114Sscottl * ice_hw_to_dev - Given a hw private struct, find the associated device_t
70157114Sscottl * @hw: the hardware private structure
71157114Sscottl *
72157114Sscottl * Given a hw structure pointer, lookup the softc and extract the device
73158737Sambrisko * pointer. Assumes that hw is embedded within the ice_softc, instead of being
74158737Sambrisko * allocated separately, so that __containerof math will work.
75163398Sscottl *
76238077Sjhb * This can't be defined in ice_osdep.h as it depends on the complete
77233711Sambrisko * definition of struct ice_softc. That can't be easily included in
78157114Sscottl * ice_osdep.h without creating circular header dependencies.
79157114Sscottl */
80157114Sscottldevice_t
81157114Sscottlice_hw_to_dev(struct ice_hw *hw) {
82157114Sscottl	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
83157114Sscottl
84157114Sscottl	return sc->dev;
85233711Sambrisko}
86233711Sambrisko
87157114Sscottl/**
88157114Sscottl * ice_debug - Log a debug message if the type is enabled
89157114Sscottl * @hw: device private hardware structure
90157114Sscottl * @mask: the debug message type
91158737Sambrisko * @fmt: printf format specifier
92159806Sps *
93180037Sjhb * Check if hw->debug_mask has enabled the given message type. If so, log the
94157114Sscottl * message to the console using vprintf. Mimic the output of device_printf by
95157114Sscottl * using device_print_prettyname().
96157114Sscottl */
97159811Spsvoid
98233711Sambriskoice_debug(struct ice_hw *hw, uint64_t mask, char *fmt, ...)
99233711Sambrisko{
100158737Sambrisko	device_t dev = ice_hw_to_dev(hw);
101158737Sambrisko	va_list args;
102159811Sps
103159811Sps	if (!(mask & hw->debug_mask))
104233711Sambrisko		return;
105233711Sambrisko
106157114Sscottl	device_print_prettyname(dev);
107157114Sscottl	va_start(args, fmt);
108233711Sambrisko	vprintf(fmt, args);
109233711Sambrisko	va_end(args);
110157114Sscottl}
111247369Ssmh
112242681Sambrisko/**
113192450Simp * ice_debug_array - Format and print an array of values to the console
114162619Sscottl * @hw: private hardware structure
115178968Sscottl * @mask: the debug message type
116178968Sscottl * @rowsize: preferred number of rows to use
117233711Sambrisko * @groupsize: preferred size in bytes to print each chunk
118233711Sambrisko * @buf: the array buffer to print
119233711Sambrisko * @len: size of the array buffer
120233711Sambrisko *
121233711Sambrisko * Format the given array as a series of uint8_t values with hexadecimal
122233711Sambrisko * notation and log the contents to the console log.
123233711Sambrisko *
124233711Sambrisko * TODO: Currently only supports a group size of 1, due to the way hexdump is
125233711Sambrisko * implemented.
126233711Sambrisko */
127233711Sambriskovoid
128233711Sambriskoice_debug_array(struct ice_hw *hw, uint64_t mask, uint32_t rowsize,
129233711Sambrisko		uint32_t __unused groupsize, uint8_t *buf, size_t len)
130233711Sambrisko{
131233711Sambrisko	device_t dev = ice_hw_to_dev(hw);
132157114Sscottl	char prettyname[20];
133227562Sjhb
134162118Sambrisko	if (!(mask & hw->debug_mask))
135247369Ssmh		return;
136247369Ssmh
137162473Sambrisko	/* Format the device header to a string */
138165852Sscottl	snprintf(prettyname, sizeof(prettyname), "%s: ", device_get_nameunit(dev));
139247369Ssmh
140247369Ssmh	/* Make sure the row-size isn't too large */
141162118Sambrisko	if (rowsize > 0xFF)
142178968Sscottl		rowsize = 0xFF;
143247369Ssmh
144247369Ssmh	hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
145178968Sscottl}
146233711Sambrisko
147247369Ssmh/**
148233711Sambrisko * ice_info_fwlog - Format and print an array of values to the console
149233711Sambrisko * @hw: private hardware structure
150247369Ssmh * @rowsize: preferred number of rows to use
151247369Ssmh * @groupsize: preferred size in bytes to print each chunk
152247369Ssmh * @buf: the array buffer to print
153247369Ssmh * @len: size of the array buffer
154247369Ssmh *
155247426Ssmh * Format the given array as a series of uint8_t values with hexadecimal
156247426Ssmh * notation and log the contents to the console log.  This variation is
157247426Ssmh * specific to firmware logging.
158247426Ssmh *
159157114Sscottl * TODO: Currently only supports a group size of 1, due to the way hexdump is
160157114Sscottl * implemented.
161157114Sscottl */
162157114Sscottlvoid
163158737Sambriskoice_info_fwlog(struct ice_hw *hw, uint32_t rowsize, uint32_t __unused groupsize,
164157114Sscottl	       uint8_t *buf, size_t len)
165157114Sscottl{
166157114Sscottl	device_t dev = ice_hw_to_dev(hw);
167157114Sscottl	char prettyname[20];
168157114Sscottl
169157114Sscottl	if (!ice_fwlog_supported(hw))
170157114Sscottl		return;
171158737Sambrisko
172157114Sscottl	/* Format the device header to a string */
173157114Sscottl	snprintf(prettyname, sizeof(prettyname), "%s: FWLOG: ",
174157114Sscottl	    device_get_nameunit(dev));
175157114Sscottl
176157114Sscottl	/* Make sure the row-size isn't too large */
177158737Sambrisko	if (rowsize > 0xFF)
178233711Sambrisko		rowsize = 0xFF;
179157114Sscottl
180171980Sscottl	hexdump(buf, len, prettyname, HD_OMIT_CHARS | rowsize);
181171980Sscottl}
182171980Sscottl
183171980Sscottl/**
184171980Sscottl * rd32 - Read a 32bit hardware register value
185171980Sscottl * @hw: the private hardware structure
186171980Sscottl * @reg: register address to read
187171980Sscottl *
188171980Sscottl * Read the specified 32bit register value from BAR0 and return its contents.
189184897Sambrisko */
190233711Sambriskouint32_t
191184897Sambriskord32(struct ice_hw *hw, uint32_t reg)
192233711Sambrisko{
193233711Sambrisko	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
194233711Sambrisko
195184897Sambrisko	return bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
196184897Sambrisko}
197233711Sambrisko
198233711Sambrisko/**
199233711Sambrisko * rd64 - Read a 64bit hardware register value
200171980Sscottl * @hw: the private hardware structure
201171980Sscottl * @reg: register address to read
202171980Sscottl *
203171980Sscottl * Read the specified 64bit register value from BAR0 and return its contents.
204171980Sscottl *
205171980Sscottl * @pre For 32-bit builds, assumes that the 64bit register read can be
206171980Sscottl * safely broken up into two 32-bit register reads.
207184897Sambrisko */
208171980Sscottluint64_t
209171980Sscottlrd64(struct ice_hw *hw, uint32_t reg)
210171980Sscottl{
211171980Sscottl	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
212171980Sscottl	uint64_t data;
213171980Sscottl
214184897Sambrisko#ifdef __amd64__
215171980Sscottl	data = bus_space_read_8(sc->bar0.tag, sc->bar0.handle, reg);
216171980Sscottl#else
217171980Sscottl	/*
218171980Sscottl	 * bus_space_read_8 isn't supported on 32bit platforms, so we fall
219171980Sscottl	 * back to using two bus_space_read_4 calls.
220171980Sscottl	 */
221171980Sscottl	data = bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
222171980Sscottl	data |= ((uint64_t)bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg + 4)) << 32;
223171980Sscottl#endif
224171980Sscottl
225182085Simp	return data;
226171980Sscottl}
227184897Sambrisko
228171980Sscottl/**
229171980Sscottl * wr32 - Write a 32bit hardware register
230171980Sscottl * @hw: the private hardware structure
231171980Sscottl * @reg: the register address to write to
232171980Sscottl * @val: the 32bit value to write
233184897Sambrisko *
234184897Sambrisko * Write the specified 32bit value to a register address in BAR0.
235184897Sambrisko */
236184897Sambriskovoid
237233711Sambriskowr32(struct ice_hw *hw, uint32_t reg, uint32_t val)
238233711Sambrisko{
239184897Sambrisko	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
240184897Sambrisko
241184897Sambrisko	bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, val);
242184897Sambrisko}
243233711Sambrisko
244233711Sambrisko/**
245233711Sambrisko * wr64 - Write a 64bit hardware register
246233711Sambrisko * @hw: the private hardware structure
247233711Sambrisko * @reg: the register address to write to
248233711Sambrisko * @val: the 64bit value to write
249233711Sambrisko *
250233711Sambrisko * Write the specified 64bit value to a register address in BAR0.
251233711Sambrisko *
252171980Sscottl * @pre For 32-bit builds, assumes that the 64bit register write can be safely
253182085Simp * broken up into two 32-bit register writes.
254171980Sscottl */
255184897Sambriskovoid
256233711Sambriskowr64(struct ice_hw *hw, uint32_t reg, uint64_t val)
257171980Sscottl{
258171980Sscottl	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
259171980Sscottl
260184897Sambrisko#ifdef __amd64__
261184897Sambrisko	bus_space_write_8(sc->bar0.tag, sc->bar0.handle, reg, val);
262233711Sambrisko#else
263171980Sscottl	uint32_t lo_val, hi_val;
264233711Sambrisko
265233711Sambrisko	/*
266233711Sambrisko	 * bus_space_write_8 isn't supported on 32bit platforms, so we fall
267233711Sambrisko	 * back to using two bus_space_write_4 calls.
268233711Sambrisko	 */
269233711Sambrisko	lo_val = (uint32_t)val;
270171980Sscottl	hi_val = (uint32_t)(val >> 32);
271171980Sscottl	bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, lo_val);
272233711Sambrisko	bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg + 4, hi_val);
273157114Sscottl#endif
274157114Sscottl}
275194851Sscottl
276157114Sscottl/**
277233711Sambrisko * ice_usec_delay - Delay for the specified number of microseconds
278233711Sambrisko * @time: microseconds to delay
279157114Sscottl * @sleep: if true, sleep where possible
280233711Sambrisko *
281233711Sambrisko * If sleep is true, and if the current thread is allowed to sleep, pause so
282157114Sscottl * that another thread can execute. Otherwise, use DELAY to spin the thread
283157114Sscottl * instead.
284157114Sscottl */
285171980Sscottlvoid
286157114Sscottlice_usec_delay(uint32_t time, bool sleep)
287157114Sscottl{
288157114Sscottl	if (sleep && THREAD_CAN_SLEEP())
289157114Sscottl		pause("ice_usec_delay", USEC_2_TICKS(time));
290157114Sscottl	else
291157114Sscottl		DELAY(time);
292233711Sambrisko}
293233711Sambrisko
294233711Sambrisko/**
295233711Sambrisko * ice_msec_delay - Delay for the specified number of milliseconds
296233711Sambrisko * @time: milliseconds to delay
297157114Sscottl * @sleep: if true, sleep where possible
298157114Sscottl *
299233711Sambrisko * If sleep is true, and if the current thread is allowed to sleep, pause so
300233711Sambrisko * that another thread can execute. Otherwise, use DELAY to spin the thread
301233711Sambrisko * instead.
302233711Sambrisko */
303233711Sambriskovoid
304157114Sscottlice_msec_delay(uint32_t time, bool sleep)
305157114Sscottl{
306157114Sscottl	if (sleep && THREAD_CAN_SLEEP())
307233711Sambrisko		pause("ice_msec_delay", MSEC_2_TICKS(time));
308157114Sscottl	else
309233711Sambrisko		DELAY(time * 1000);
310233711Sambrisko}
311233711Sambrisko
312157114Sscottl/**
313157114Sscottl * ice_msec_pause - pause (sleep) the thread for a time in milliseconds
314233711Sambrisko * @time: milliseconds to sleep
315157114Sscottl *
316233711Sambrisko * Wrapper for ice_msec_delay with sleep set to true.
317233711Sambrisko */
318233711Sambriskovoid
319233711Sambriskoice_msec_pause(uint32_t time)
320224041Sjhb{
321233711Sambrisko	ice_msec_delay(time, true);
322233711Sambrisko}
323233711Sambrisko
324233711Sambrisko/**
325233711Sambrisko * ice_msec_spin - Spin the thread for a time in milliseconds
326224041Sjhb * @time: milliseconds to delay
327157114Sscottl *
328233711Sambrisko * Wrapper for ice_msec_delay with sleep sent to false.
329157114Sscottl */
330157114Sscottlvoid
331157114Sscottlice_msec_spin(uint32_t time)
332157114Sscottl{
333233711Sambrisko	ice_msec_delay(time, false);
334233711Sambrisko}
335157114Sscottl
336157114Sscottl/********************************************************************
337157114Sscottl * Manage DMA'able memory.
338157114Sscottl *******************************************************************/
339157114Sscottl
340233711Sambrisko/**
341233711Sambrisko * ice_dmamap_cb - Callback function DMA maps
342233711Sambrisko * @arg: pointer to return the segment address
343233711Sambrisko * @segs: the segments array
344233711Sambrisko * @nseg: number of segments in the array
345233711Sambrisko * @error: error code
346157114Sscottl *
347224041Sjhb * Callback used by the bus DMA code to obtain the segment address.
348157114Sscottl */
349157114Sscottlstatic void
350157114Sscottlice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error)
351157114Sscottl{
352157114Sscottl	if (error)
353157114Sscottl		return;
354157114Sscottl	*(bus_addr_t *) arg = segs->ds_addr;
355157114Sscottl	return;
356233711Sambrisko}
357157114Sscottl
358233711Sambrisko/**
359157114Sscottl * ice_alloc_dma_mem - Request OS to allocate DMA memory
360157114Sscottl * @hw: private hardware structure
361157114Sscottl * @mem: structure defining the DMA memory request
362157114Sscottl * @size: the allocation size
363157114Sscottl *
364233711Sambrisko * Allocates some memory for DMA use. Use the FreeBSD bus DMA interface to
365157114Sscottl * track this memory using a bus DMA tag and map.
366157114Sscottl *
367157114Sscottl * Returns a pointer to the DMA memory address.
368157114Sscottl */
369157114Sscottlvoid *
370247369Ssmhice_alloc_dma_mem(struct ice_hw *hw, struct ice_dma_mem *mem, u64 size)
371233711Sambrisko{
372284180Sambrisko	device_t dev = ice_hw_to_dev(hw);
373157114Sscottl	int err;
374233711Sambrisko
375233711Sambrisko	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
376186132Sambrisko				 1, 0,			/* alignment, boundary */
377233711Sambrisko				 BUS_SPACE_MAXADDR,	/* lowaddr */
378233711Sambrisko				 BUS_SPACE_MAXADDR,	/* highaddr */
379233711Sambrisko				 NULL, NULL,		/* filtfunc, filtfuncarg */
380157114Sscottl				 size,			/* maxsize */
381171821Sjhb				 1,			/* nsegments */
382157114Sscottl				 size,			/* maxsegsz */
383233711Sambrisko				 BUS_DMA_ALLOCNOW,	/* flags */
384242681Sambrisko				 NULL,			/* lockfunc */
385242681Sambrisko				 NULL,			/* lockfuncarg */
386233711Sambrisko				 &mem->tag);
387233711Sambrisko	if (err != 0) {
388235014Sambrisko		device_printf(dev,
389158737Sambrisko		    "ice_alloc_dma: bus_dma_tag_create failed, "
390169611Sscottl		    "error %s\n", ice_err_str(err));
391157114Sscottl		goto fail_0;
392157114Sscottl	}
393157114Sscottl	err = bus_dmamem_alloc(mem->tag, (void **)&mem->va,
394157114Sscottl			     BUS_DMA_NOWAIT | BUS_DMA_ZERO, &mem->map);
395157114Sscottl	if (err != 0) {
396157114Sscottl		device_printf(dev,
397233711Sambrisko		    "ice_alloc_dma: bus_dmamem_alloc failed, "
398233711Sambrisko		    "error %s\n", ice_err_str(err));
399233711Sambrisko		goto fail_1;
400233711Sambrisko	}
401233711Sambrisko	err = bus_dmamap_load(mem->tag, mem->map, mem->va,
402233711Sambrisko			    size,
403171980Sscottl			    ice_dmamap_cb,
404171980Sscottl			    &mem->pa,
405171980Sscottl			    BUS_DMA_NOWAIT);
406171980Sscottl	if (err != 0) {
407171980Sscottl		device_printf(dev,
408233711Sambrisko		    "ice_alloc_dma: bus_dmamap_load failed, "
409233711Sambrisko		    "error %s\n", ice_err_str(err));
410233711Sambrisko		goto fail_2;
411233711Sambrisko	}
412233711Sambrisko	mem->size = size;
413233711Sambrisko	bus_dmamap_sync(mem->tag, mem->map,
414233711Sambrisko	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
415233711Sambrisko	return (mem->va);
416233711Sambriskofail_2:
417233711Sambrisko	bus_dmamem_free(mem->tag, mem->va, mem->map);
418171980Sscottlfail_1:
419233711Sambrisko	bus_dma_tag_destroy(mem->tag);
420171980Sscottlfail_0:
421171980Sscottl	mem->map = NULL;
422171980Sscottl	mem->tag = NULL;
423171980Sscottl	return (NULL);
424171980Sscottl}
425157114Sscottl
426157114Sscottl/**
427157114Sscottl * ice_free_dma_mem - Free DMA memory allocated by ice_alloc_dma_mem
428157114Sscottl * @hw: the hardware private structure
429157114Sscottl * @mem: DMA memory to free
430157114Sscottl *
431157114Sscottl * Release the bus DMA tag and map, and free the DMA memory associated with
432233711Sambrisko * it.
433233711Sambrisko */
434233711Sambriskovoid
435233711Sambriskoice_free_dma_mem(struct ice_hw __unused *hw, struct ice_dma_mem *mem)
436233711Sambrisko{
437233711Sambrisko	bus_dmamap_sync(mem->tag, mem->map,
438233711Sambrisko	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
439233711Sambrisko	bus_dmamap_unload(mem->tag, mem->map);
440233711Sambrisko	bus_dmamem_free(mem->tag, mem->va, mem->map);
441233711Sambrisko	bus_dma_tag_destroy(mem->tag);
442233711Sambrisko	mem->map = NULL;
443233711Sambrisko	mem->tag = NULL;
444233711Sambrisko}
445233711Sambrisko