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 */
55MALLOC_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 */
65u16 ice_lock_count = 0;
66
67static 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 */
81device_t
82ice_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 */
98void
99ice_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 */
128void
129ice_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 * rd32 - Read a 32bit hardware register value
150 * @hw: the private hardware structure
151 * @reg: register address to read
152 *
153 * Read the specified 32bit register value from BAR0 and return its contents.
154 */
155uint32_t
156rd32(struct ice_hw *hw, uint32_t reg)
157{
158	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
159
160	return bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
161}
162
163/**
164 * rd64 - Read a 64bit hardware register value
165 * @hw: the private hardware structure
166 * @reg: register address to read
167 *
168 * Read the specified 64bit register value from BAR0 and return its contents.
169 *
170 * @pre For 32-bit builds, assumes that the 64bit register read can be
171 * safely broken up into two 32-bit register reads.
172 */
173uint64_t
174rd64(struct ice_hw *hw, uint32_t reg)
175{
176	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
177	uint64_t data;
178
179#ifdef __amd64__
180	data = bus_space_read_8(sc->bar0.tag, sc->bar0.handle, reg);
181#else
182	/*
183	 * bus_space_read_8 isn't supported on 32bit platforms, so we fall
184	 * back to using two bus_space_read_4 calls.
185	 */
186	data = bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg);
187	data |= ((uint64_t)bus_space_read_4(sc->bar0.tag, sc->bar0.handle, reg + 4)) << 32;
188#endif
189
190	return data;
191}
192
193/**
194 * wr32 - Write a 32bit hardware register
195 * @hw: the private hardware structure
196 * @reg: the register address to write to
197 * @val: the 32bit value to write
198 *
199 * Write the specified 32bit value to a register address in BAR0.
200 */
201void
202wr32(struct ice_hw *hw, uint32_t reg, uint32_t val)
203{
204	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
205
206	bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, val);
207}
208
209/**
210 * wr64 - Write a 64bit hardware register
211 * @hw: the private hardware structure
212 * @reg: the register address to write to
213 * @val: the 64bit value to write
214 *
215 * Write the specified 64bit value to a register address in BAR0.
216 *
217 * @pre For 32-bit builds, assumes that the 64bit register write can be safely
218 * broken up into two 32-bit register writes.
219 */
220void
221wr64(struct ice_hw *hw, uint32_t reg, uint64_t val)
222{
223	struct ice_softc *sc = __containerof(hw, struct ice_softc, hw);
224
225#ifdef __amd64__
226	bus_space_write_8(sc->bar0.tag, sc->bar0.handle, reg, val);
227#else
228	uint32_t lo_val, hi_val;
229
230	/*
231	 * bus_space_write_8 isn't supported on 32bit platforms, so we fall
232	 * back to using two bus_space_write_4 calls.
233	 */
234	lo_val = (uint32_t)val;
235	hi_val = (uint32_t)(val >> 32);
236	bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg, lo_val);
237	bus_space_write_4(sc->bar0.tag, sc->bar0.handle, reg + 4, hi_val);
238#endif
239}
240
241/**
242 * ice_usec_delay - Delay for the specified number of microseconds
243 * @time: microseconds to delay
244 * @sleep: if true, sleep where possible
245 *
246 * If sleep is true, and if the current thread is allowed to sleep, pause so
247 * that another thread can execute. Otherwise, use DELAY to spin the thread
248 * instead.
249 */
250void
251ice_usec_delay(uint32_t time, bool sleep)
252{
253	if (sleep && THREAD_CAN_SLEEP())
254		pause("ice_usec_delay", USEC_2_TICKS(time));
255	else
256		DELAY(time);
257}
258
259/**
260 * ice_msec_delay - Delay for the specified number of milliseconds
261 * @time: milliseconds to delay
262 * @sleep: if true, sleep where possible
263 *
264 * If sleep is true, and if the current thread is allowed to sleep, pause so
265 * that another thread can execute. Otherwise, use DELAY to spin the thread
266 * instead.
267 */
268void
269ice_msec_delay(uint32_t time, bool sleep)
270{
271	if (sleep && THREAD_CAN_SLEEP())
272		pause("ice_msec_delay", MSEC_2_TICKS(time));
273	else
274		DELAY(time * 1000);
275}
276
277/**
278 * ice_msec_pause - pause (sleep) the thread for a time in milliseconds
279 * @time: milliseconds to sleep
280 *
281 * Wrapper for ice_msec_delay with sleep set to true.
282 */
283void
284ice_msec_pause(uint32_t time)
285{
286	ice_msec_delay(time, true);
287}
288
289/**
290 * ice_msec_spin - Spin the thread for a time in milliseconds
291 * @time: milliseconds to delay
292 *
293 * Wrapper for ice_msec_delay with sleep sent to false.
294 */
295void
296ice_msec_spin(uint32_t time)
297{
298	ice_msec_delay(time, false);
299}
300
301/********************************************************************
302 * Manage DMA'able memory.
303 *******************************************************************/
304
305/**
306 * ice_dmamap_cb - Callback function DMA maps
307 * @arg: pointer to return the segment address
308 * @segs: the segments array
309 * @nseg: number of segments in the array
310 * @error: error code
311 *
312 * Callback used by the bus DMA code to obtain the segment address.
313 */
314static void
315ice_dmamap_cb(void *arg, bus_dma_segment_t * segs, int __unused nseg, int error)
316{
317	if (error)
318		return;
319	*(bus_addr_t *) arg = segs->ds_addr;
320	return;
321}
322
323/**
324 * ice_alloc_dma_mem - Request OS to allocate DMA memory
325 * @hw: private hardware structure
326 * @mem: structure defining the DMA memory request
327 * @size: the allocation size
328 *
329 * Allocates some memory for DMA use. Use the FreeBSD bus DMA interface to
330 * track this memory using a bus DMA tag and map.
331 *
332 * Returns a pointer to the DMA memory address.
333 */
334void *
335ice_alloc_dma_mem(struct ice_hw *hw, struct ice_dma_mem *mem, u64 size)
336{
337	device_t dev = ice_hw_to_dev(hw);
338	int err;
339
340	err = bus_dma_tag_create(bus_get_dma_tag(dev),	/* parent */
341				 1, 0,			/* alignment, boundary */
342				 BUS_SPACE_MAXADDR,	/* lowaddr */
343				 BUS_SPACE_MAXADDR,	/* highaddr */
344				 NULL, NULL,		/* filtfunc, filtfuncarg */
345				 size,			/* maxsize */
346				 1,			/* nsegments */
347				 size,			/* maxsegsz */
348				 BUS_DMA_ALLOCNOW,	/* flags */
349				 NULL,			/* lockfunc */
350				 NULL,			/* lockfuncarg */
351				 &mem->tag);
352	if (err != 0) {
353		device_printf(dev,
354		    "ice_alloc_dma: bus_dma_tag_create failed, "
355		    "error %s\n", ice_err_str(err));
356		goto fail_0;
357	}
358	err = bus_dmamem_alloc(mem->tag, (void **)&mem->va,
359			     BUS_DMA_NOWAIT | BUS_DMA_ZERO, &mem->map);
360	if (err != 0) {
361		device_printf(dev,
362		    "ice_alloc_dma: bus_dmamem_alloc failed, "
363		    "error %s\n", ice_err_str(err));
364		goto fail_1;
365	}
366	err = bus_dmamap_load(mem->tag, mem->map, mem->va,
367			    size,
368			    ice_dmamap_cb,
369			    &mem->pa,
370			    BUS_DMA_NOWAIT);
371	if (err != 0) {
372		device_printf(dev,
373		    "ice_alloc_dma: bus_dmamap_load failed, "
374		    "error %s\n", ice_err_str(err));
375		goto fail_2;
376	}
377	mem->size = size;
378	bus_dmamap_sync(mem->tag, mem->map,
379	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
380	return (mem->va);
381fail_2:
382	bus_dmamem_free(mem->tag, mem->va, mem->map);
383fail_1:
384	bus_dma_tag_destroy(mem->tag);
385fail_0:
386	mem->map = NULL;
387	mem->tag = NULL;
388	return (NULL);
389}
390
391/**
392 * ice_free_dma_mem - Free DMA memory allocated by ice_alloc_dma_mem
393 * @hw: the hardware private structure
394 * @mem: DMA memory to free
395 *
396 * Release the bus DMA tag and map, and free the DMA memory associated with
397 * it.
398 */
399void
400ice_free_dma_mem(struct ice_hw __unused *hw, struct ice_dma_mem *mem)
401{
402	bus_dmamap_sync(mem->tag, mem->map,
403	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
404	bus_dmamap_unload(mem->tag, mem->map);
405	bus_dmamem_free(mem->tag, mem->va, mem->map);
406	bus_dma_tag_destroy(mem->tag);
407	mem->map = NULL;
408	mem->tag = NULL;
409}
410