1 /* SPDX-License-Identifier: BSD-3-Clause */ 2 /* Copyright (c) 2020, 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 * 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 */ 155 uint32_t 156 rd32(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 */ 173 uint64_t 174 rd64(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 */ 201 void 202 wr32(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 */ 220 void 221 wr64(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 */ 250 void 251 ice_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 */ 268 void 269 ice_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 */ 283 void 284 ice_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 */ 295 void 296 ice_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 */ 314 static void 315 ice_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 */ 334 void * 335 ice_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); 381 fail_2: 382 bus_dmamem_free(mem->tag, mem->va, mem->map); 383 fail_1: 384 bus_dma_tag_destroy(mem->tag); 385 fail_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 */ 399 void 400 ice_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