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