1331766Sken/*- 2331766Sken * Copyright (c) 2017 Broadcom. All rights reserved. 3331766Sken * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4331766Sken * 5331766Sken * Redistribution and use in source and binary forms, with or without 6331766Sken * modification, are permitted provided that the following conditions are met: 7331766Sken * 8331766Sken * 1. Redistributions of source code must retain the above copyright notice, 9331766Sken * this list of conditions and the following disclaimer. 10331766Sken * 11331766Sken * 2. Redistributions in binary form must reproduce the above copyright notice, 12331766Sken * this list of conditions and the following disclaimer in the documentation 13331766Sken * and/or other materials provided with the distribution. 14331766Sken * 15331766Sken * 3. Neither the name of the copyright holder nor the names of its contributors 16331766Sken * may be used to endorse or promote products derived from this software 17331766Sken * without specific prior written permission. 18331766Sken * 19331766Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20331766Sken * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21331766Sken * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22331766Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23331766Sken * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24331766Sken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25331766Sken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26331766Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27331766Sken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28331766Sken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29331766Sken * POSSIBILITY OF SUCH DAMAGE. 30331766Sken * 31331766Sken * $FreeBSD: stable/11/sys/dev/ocs_fc/ocs_os.c 333991 2018-05-21 18:59:34Z ken $ 32331766Sken */ 33331766Sken 34331766Sken/** 35331766Sken * @file 36331766Sken * Implementation of common BSD OS abstraction functions 37331766Sken */ 38331766Sken 39331766Sken#include "ocs.h" 40331766Sken 41331766Skenstatic MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data"); 42331766Sken 43331766Sken#include <dev/pci/pcireg.h> 44331766Sken#include <dev/pci/pcivar.h> 45331766Sken 46331766Sken#include <machine/bus.h> 47331766Sken 48331766Skentimeout_t __ocs_callout; 49331766Sken 50331766Skenuint32_t 51331766Skenocs_config_read32(ocs_os_handle_t os, uint32_t reg) 52331766Sken{ 53331766Sken return pci_read_config(os->dev, reg, 4); 54331766Sken} 55331766Sken 56331766Skenuint16_t 57331766Skenocs_config_read16(ocs_os_handle_t os, uint32_t reg) 58331766Sken{ 59331766Sken return pci_read_config(os->dev, reg, 2); 60331766Sken} 61331766Sken 62331766Skenuint8_t 63331766Skenocs_config_read8(ocs_os_handle_t os, uint32_t reg) 64331766Sken{ 65331766Sken return pci_read_config(os->dev, reg, 1); 66331766Sken} 67331766Sken 68331766Skenvoid 69331766Skenocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val) 70331766Sken{ 71331766Sken return pci_write_config(os->dev, reg, val, 1); 72331766Sken} 73331766Sken 74331766Skenvoid 75331766Skenocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val) 76331766Sken{ 77331766Sken return pci_write_config(os->dev, reg, val, 2); 78331766Sken} 79331766Sken 80331766Skenvoid 81331766Skenocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val) 82331766Sken{ 83331766Sken return pci_write_config(os->dev, reg, val, 4); 84331766Sken} 85331766Sken 86331766Sken/** 87331766Sken * @ingroup os 88331766Sken * @brief Read a 32bit PCI register 89331766Sken * 90331766Sken * The SLI documentation uses the term "register set" to describe one or more 91331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses 92331766Sken * two BARs, and thus constitute a register set. 93331766Sken * 94331766Sken * @param ocs Pointer to the driver's context 95331766Sken * @param rset Register Set to use 96331766Sken * @param off Offset from the base address of the Register Set 97331766Sken * 98331766Sken * @return register value 99331766Sken */ 100331766Skenuint32_t 101331766Skenocs_reg_read32(ocs_t *ocs, uint32_t rset, uint32_t off) 102331766Sken{ 103331766Sken ocs_pci_reg_t *reg = NULL; 104331766Sken 105331766Sken reg = &ocs->reg[rset]; 106331766Sken 107331766Sken return bus_space_read_4(reg->btag, reg->bhandle, off); 108331766Sken} 109331766Sken 110331766Sken/** 111331766Sken * @ingroup os 112331766Sken * @brief Read a 16bit PCI register 113331766Sken * 114331766Sken * The SLI documentation uses the term "register set" to describe one or more 115331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses 116331766Sken * two BARs, and thus constitute a register set. 117331766Sken * 118331766Sken * @param ocs Pointer to the driver's context 119331766Sken * @param rset Register Set to use 120331766Sken * @param off Offset from the base address of the Register Set 121331766Sken * 122331766Sken * @return register value 123331766Sken */ 124331766Skenuint16_t 125331766Skenocs_reg_read16(ocs_t *ocs, uint32_t rset, uint32_t off) 126331766Sken{ 127331766Sken ocs_pci_reg_t *reg = NULL; 128331766Sken 129331766Sken reg = &ocs->reg[rset]; 130331766Sken 131331766Sken return bus_space_read_2(reg->btag, reg->bhandle, off); 132331766Sken} 133331766Sken 134331766Sken/** 135331766Sken * @ingroup os 136331766Sken * @brief Read a 8bit PCI register 137331766Sken * 138331766Sken * The SLI documentation uses the term "register set" to describe one or more 139331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses 140331766Sken * two BARs, and thus constitute a register set. 141331766Sken * 142331766Sken * @param ocs Pointer to the driver's context 143331766Sken * @param rset Register Set to use 144331766Sken * @param off Offset from the base address of the Register Set 145331766Sken * 146331766Sken * @return register value 147331766Sken */ 148331766Skenuint8_t 149331766Skenocs_reg_read8(ocs_t *ocs, uint32_t rset, uint32_t off) 150331766Sken{ 151331766Sken ocs_pci_reg_t *reg = NULL; 152331766Sken 153331766Sken reg = &ocs->reg[rset]; 154331766Sken 155331766Sken return bus_space_read_1(reg->btag, reg->bhandle, off); 156331766Sken} 157331766Sken 158331766Sken/** 159331766Sken * @ingroup os 160331766Sken * @brief Write a 32bit PCI register 161331766Sken * 162331766Sken * The SLI documentation uses the term "register set" to describe one or more 163331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses 164331766Sken * two BARs, and thus constitute a register set. 165331766Sken * 166331766Sken * @param ocs Pointer to the driver's context 167331766Sken * @param rset Register Set to use 168331766Sken * @param off Offset from the base address of the Register Set 169331766Sken * @param val Value to write 170331766Sken * 171331766Sken * @return none 172331766Sken */ 173331766Skenvoid 174331766Skenocs_reg_write32(ocs_t *ocs, uint32_t rset, uint32_t off, uint32_t val) 175331766Sken{ 176331766Sken ocs_pci_reg_t *reg = NULL; 177331766Sken 178331766Sken reg = &ocs->reg[rset]; 179331766Sken 180331766Sken return bus_space_write_4(reg->btag, reg->bhandle, off, val); 181331766Sken} 182331766Sken 183331766Sken/** 184331766Sken * @ingroup os 185331766Sken * @brief Write a 16-bit PCI register 186331766Sken * 187331766Sken * The SLI documentation uses the term "register set" to describe one or more 188331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses 189331766Sken * two BARs, and thus constitute a register set. 190331766Sken * 191331766Sken * @param ocs Pointer to the driver's context 192331766Sken * @param rset Register Set to use 193331766Sken * @param off Offset from the base address of the Register Set 194331766Sken * @param val Value to write 195331766Sken * 196331766Sken * @return none 197331766Sken */ 198331766Skenvoid 199331766Skenocs_reg_write16(ocs_t *ocs, uint32_t rset, uint32_t off, uint16_t val) 200331766Sken{ 201331766Sken ocs_pci_reg_t *reg = NULL; 202331766Sken 203331766Sken reg = &ocs->reg[rset]; 204331766Sken 205331766Sken return bus_space_write_2(reg->btag, reg->bhandle, off, val); 206331766Sken} 207331766Sken 208331766Sken/** 209331766Sken * @ingroup os 210331766Sken * @brief Write a 8-bit PCI register 211331766Sken * 212331766Sken * The SLI documentation uses the term "register set" to describe one or more 213331766Sken * PCI BARs which form a logical address. For example, a 64-bit address uses 214331766Sken * two BARs, and thus constitute a register set. 215331766Sken * 216331766Sken * @param ocs Pointer to the driver's context 217331766Sken * @param rset Register Set to use 218331766Sken * @param off Offset from the base address of the Register Set 219331766Sken * @param val Value to write 220331766Sken * 221331766Sken * @return none 222331766Sken */ 223331766Skenvoid 224331766Skenocs_reg_write8(ocs_t *ocs, uint32_t rset, uint32_t off, uint8_t val) 225331766Sken{ 226331766Sken ocs_pci_reg_t *reg = NULL; 227331766Sken 228331766Sken reg = &ocs->reg[rset]; 229331766Sken 230331766Sken return bus_space_write_1(reg->btag, reg->bhandle, off, val); 231331766Sken} 232331766Sken 233331766Sken/** 234331766Sken * @ingroup os 235331766Sken * @brief Allocate host memory 236331766Sken * 237331766Sken * @param os OS handle 238331766Sken * @param size number of bytes to allocate 239331766Sken * @param flags additional options 240331766Sken * 241331766Sken * @return pointer to allocated memory, NULL otherwise 242331766Sken */ 243331766Skenvoid * 244331766Skenocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags) 245331766Sken{ 246331766Sken if ((flags & OCS_M_NOWAIT) == 0) { 247331766Sken flags |= M_WAITOK; 248331766Sken } 249331766Sken 250331766Sken#ifndef OCS_DEBUG_MEMORY 251331766Sken return malloc(size, M_OCS, flags); 252331766Sken#else 253331766Sken char nameb[80]; 254331766Sken long offset = 0; 255331766Sken void *addr = malloc(size, M_OCS, flags); 256331766Sken 257331766Sken linker_ddb_search_symbol_name(__builtin_return_address(1), nameb, sizeof(nameb), &offset); 258331766Sken printf("A: %p %ld @ %s+%#lx\n", addr, size, nameb, offset); 259331766Sken 260331766Sken return addr; 261331766Sken#endif 262331766Sken} 263331766Sken 264331766Sken/** 265331766Sken * @ingroup os 266331766Sken * @brief Free host memory 267331766Sken * 268331766Sken * @param os OS handle 269331766Sken * @param addr pointer to memory 270331766Sken * @param size bytes to free 271331766Sken * 272331766Sken * @note size ignored in BSD 273331766Sken */ 274331766Skenvoid 275331766Skenocs_free(ocs_os_handle_t os, void *addr, size_t size) 276331766Sken{ 277331766Sken#ifndef OCS_DEBUG_MEMORY 278331766Sken free(addr, M_OCS); 279331766Sken#else 280331766Sken printf("F: %p %ld\n", addr, size); 281331766Sken free(addr, M_OCS); 282331766Sken#endif 283331766Sken} 284331766Sken 285331766Sken/** 286331766Sken * @brief Callback function provided to bus_dmamap_load 287331766Sken * 288331766Sken * Function loads the physical / bus address into the DMA descriptor. The caller 289331766Sken * can detect a mapping failure if a descriptor's phys element is zero. 290331766Sken * 291331766Sken * @param arg Argument provided to bus_dmamap_load is a ocs_dma_t 292331766Sken * @param seg Array of DMA segment(s), each describing segment's address and length 293331766Sken * @param nseg Number of elements in array 294331766Sken * @param error Indicates success (0) or failure of mapping 295331766Sken */ 296331766Skenstatic void 297331766Skenocs_dma_load(void *arg, bus_dma_segment_t *seg, int nseg, int error) 298331766Sken{ 299331766Sken ocs_dma_t *dma = arg; 300331766Sken 301331766Sken if (error) { 302331766Sken printf("%s: error=%d\n", __func__, error); 303331766Sken dma->phys = 0; 304331766Sken } else { 305331766Sken dma->phys = seg->ds_addr; 306331766Sken } 307331766Sken} 308331766Sken 309331766Sken/** 310331766Sken * @ingroup os 311331766Sken * @brief Free a DMA capable block of memory 312331766Sken * 313331766Sken * @param os Device abstraction 314331766Sken * @param dma DMA descriptor for memory to be freed 315331766Sken * 316331766Sken * @return 0 if memory is de-allocated, -1 otherwise 317331766Sken */ 318331766Skenint32_t 319331766Skenocs_dma_free(ocs_os_handle_t os, ocs_dma_t *dma) 320331766Sken{ 321331766Sken struct ocs_softc *ocs = os; 322331766Sken 323331766Sken if (!dma) { 324331766Sken device_printf(ocs->dev, "%s: bad parameter(s) dma=%p\n", __func__, dma); 325331766Sken return -1; 326331766Sken } 327331766Sken 328331766Sken if (dma->size == 0) { 329331766Sken return 0; 330331766Sken } 331331766Sken 332331766Sken if (dma->map) { 333331766Sken bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD | 334331766Sken BUS_DMASYNC_POSTWRITE); 335331766Sken bus_dmamap_unload(dma->tag, dma->map); 336331766Sken } 337331766Sken 338331766Sken if (dma->virt) { 339331766Sken bus_dmamem_free(dma->tag, dma->virt, dma->map); 340331766Sken bus_dmamap_destroy(dma->tag, dma->map); 341331766Sken } 342331766Sken bus_dma_tag_destroy(dma->tag); 343331766Sken 344331766Sken bzero(dma, sizeof(ocs_dma_t)); 345331766Sken 346331766Sken return 0; 347331766Sken} 348331766Sken 349331766Sken/** 350331766Sken * @ingroup os 351331766Sken * @brief Allocate a DMA capable block of memory 352331766Sken * 353331766Sken * @param os Device abstraction 354331766Sken * @param dma DMA descriptor containing results of memory allocation 355331766Sken * @param size Size in bytes of desired allocation 356331766Sken * @param align Alignment in bytes 357331766Sken * 358331766Sken * @return 0 on success, ENOMEM otherwise 359331766Sken */ 360331766Skenint32_t 361331766Skenocs_dma_alloc(ocs_os_handle_t os, ocs_dma_t *dma, size_t size, size_t align) 362331766Sken{ 363331766Sken struct ocs_softc *ocs = os; 364331766Sken 365331766Sken if (!dma || !size) { 366331766Sken device_printf(ocs->dev, "%s bad parameter(s) dma=%p size=%zd\n", 367331766Sken __func__, dma, size); 368331766Sken return ENOMEM; 369331766Sken } 370331766Sken 371331766Sken bzero(dma, sizeof(ocs_dma_t)); 372331766Sken 373331766Sken /* create a "tag" that describes the desired memory allocation */ 374331766Sken if (bus_dma_tag_create(ocs->dmat, align, 0, BUS_SPACE_MAXADDR, 375331766Sken BUS_SPACE_MAXADDR, NULL, NULL, 376331766Sken size, 1, size, 0, NULL, NULL, &dma->tag)) { 377331766Sken device_printf(ocs->dev, "DMA tag allocation failed\n"); 378331766Sken return ENOMEM; 379331766Sken } 380331766Sken 381331766Sken dma->size = size; 382331766Sken 383331766Sken /* allocate the memory */ 384331766Sken if (bus_dmamem_alloc(dma->tag, &dma->virt, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 385331766Sken &dma->map)) { 386331766Sken device_printf(ocs->dev, "DMA memory allocation failed s=%zd a=%zd\n", size, align); 387331766Sken ocs_dma_free(ocs, dma); 388331766Sken return ENOMEM; 389331766Sken } 390331766Sken 391331766Sken dma->alloc = dma->virt; 392331766Sken 393331766Sken /* map virtual address to device visible address */ 394331766Sken if (bus_dmamap_load(dma->tag, dma->map, dma->virt, dma->size, ocs_dma_load, 395331766Sken dma, 0)) { 396331766Sken device_printf(ocs->dev, "DMA memory load failed\n"); 397331766Sken ocs_dma_free(ocs, dma); 398331766Sken return ENOMEM; 399331766Sken } 400331766Sken 401331766Sken /* if the DMA map load callback fails, it sets the physical address to zero */ 402331766Sken if (0 == dma->phys) { 403331766Sken device_printf(ocs->dev, "ocs_dma_load failed\n"); 404331766Sken ocs_dma_free(ocs, dma); 405331766Sken return ENOMEM; 406331766Sken } 407331766Sken 408331766Sken return 0; 409331766Sken} 410331766Sken 411331766Sken/** 412331766Sken * @ingroup os 413331766Sken * @brief Synchronize the DMA buffer memory 414331766Sken * 415331766Sken * Ensures memory coherency between the CPU and device 416331766Sken * 417331766Sken * @param dma DMA descriptor of memory to synchronize 418331766Sken * @param flags Describes direction of synchronization 419331766Sken * See BUS_DMA(9) for details 420331766Sken * - BUS_DMASYNC_PREWRITE 421331766Sken * - BUS_DMASYNC_POSTREAD 422331766Sken */ 423331766Skenvoid 424331766Skenocs_dma_sync(ocs_dma_t *dma, uint32_t flags) 425331766Sken{ 426331766Sken bus_dmamap_sync(dma->tag, dma->map, flags); 427331766Sken} 428331766Sken 429331766Skenint32_t 430331766Skenocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length) 431331766Sken{ 432331766Sken if (!dma) 433331766Sken return -1; 434331766Sken if (!buffer) 435331766Sken return -1; 436331766Sken if (buffer_length == 0) 437331766Sken return 0; 438331766Sken if (buffer_length > dma->size) 439331766Sken buffer_length = dma->size; 440331766Sken ocs_memcpy(dma->virt, buffer, buffer_length); 441331766Sken dma->len = buffer_length; 442331766Sken return buffer_length; 443331766Sken} 444331766Sken 445331766Skenint32_t 446331766Skenocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length) 447331766Sken{ 448331766Sken if (!dma) 449331766Sken return -1; 450331766Sken if (!buffer) 451331766Sken return -1; 452331766Sken if (buffer_length == 0) 453331766Sken return 0; 454331766Sken if (buffer_length > dma->len) 455331766Sken buffer_length = dma->len; 456331766Sken ocs_memcpy(buffer, dma->virt, buffer_length); 457331766Sken return buffer_length; 458331766Sken} 459331766Sken 460331766Sken/** 461331766Sken * @ingroup os 462331766Sken * @brief Initialize a lock 463331766Sken * 464331766Sken * @param lock lock to initialize 465331766Sken * @param name string identifier for the lock 466331766Sken */ 467331766Skenvoid 468331766Skenocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...) 469331766Sken{ 470331766Sken va_list ap; 471331766Sken 472331766Sken va_start(ap, name); 473331766Sken ocs_vsnprintf(lock->name, MAX_LOCK_DESC_LEN, name, ap); 474331766Sken va_end(ap); 475331766Sken 476331766Sken mtx_init(&lock->lock, lock->name, NULL, MTX_DEF); 477331766Sken} 478331766Sken 479331766Sken/** 480331766Sken * @brief Allocate a bit map 481331766Sken * 482331766Sken * For BSD, this is a simple character string 483331766Sken * 484331766Sken * @param n_bits number of bits in bit map 485331766Sken * 486331766Sken * @return pointer to the bit map, NULL on error 487331766Sken */ 488331766Skenocs_bitmap_t * 489331766Skenocs_bitmap_alloc(uint32_t n_bits) 490331766Sken{ 491331766Sken 492331766Sken return malloc(bitstr_size(n_bits), M_OCS, M_ZERO | M_NOWAIT); 493331766Sken} 494331766Sken 495331766Sken/** 496331766Sken * @brief Free a bit map 497331766Sken * 498331766Sken * @param bitmap pointer to previously allocated bit map 499331766Sken */ 500331766Skenvoid 501331766Skenocs_bitmap_free(ocs_bitmap_t *bitmap) 502331766Sken{ 503331766Sken 504331766Sken free(bitmap, M_OCS); 505331766Sken} 506331766Sken 507331766Sken/** 508331766Sken * @brief find next unset bit and set it 509331766Sken * 510331766Sken * @param bitmap bit map to search 511331766Sken * @param n_bits number of bits in map 512331766Sken * 513331766Sken * @return bit position or -1 if map is full 514331766Sken */ 515331766Skenint32_t 516331766Skenocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits) 517331766Sken{ 518331766Sken int32_t position = -1; 519331766Sken 520331766Sken bit_ffc(bitmap, n_bits, &position); 521331766Sken 522331766Sken if (-1 != position) { 523331766Sken bit_set(bitmap, position); 524331766Sken } 525331766Sken 526331766Sken return position; 527331766Sken} 528331766Sken 529331766Sken/** 530331766Sken * @brief search for next (un)set bit 531331766Sken * 532331766Sken * @param bitmap bit map to search 533331766Sken * @param set search for a set or unset bit 534331766Sken * @param n_bits number of bits in map 535331766Sken * 536331766Sken * @return bit position or -1 537331766Sken */ 538331766Skenint32_t 539331766Skenocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits) 540331766Sken{ 541331766Sken int32_t position; 542331766Sken 543331766Sken if (!bitmap) { 544331766Sken return -1; 545331766Sken } 546331766Sken 547331766Sken if (set) { 548331766Sken bit_ffs(bitmap, n_bits, &position); 549331766Sken } else { 550331766Sken bit_ffc(bitmap, n_bits, &position); 551331766Sken } 552331766Sken 553331766Sken return position; 554331766Sken} 555331766Sken 556331766Sken/** 557331766Sken * @brief clear the specified bit 558331766Sken * 559331766Sken * @param bitmap pointer to bit map 560331766Sken * @param bit bit number to clear 561331766Sken */ 562331766Skenvoid 563331766Skenocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit) 564331766Sken{ 565331766Sken bit_clear(bitmap, bit); 566331766Sken} 567331766Sken 568331766Skenvoid _ocs_log(ocs_t *ocs, const char *func_name, int line, const char *fmt, ...) 569331766Sken{ 570331766Sken va_list ap; 571331766Sken char buf[256]; 572331766Sken char *p = buf; 573331766Sken 574331766Sken va_start(ap, fmt); 575331766Sken 576331766Sken /* TODO: Add Current PID info here. */ 577331766Sken 578331766Sken p += snprintf(p, sizeof(buf) - (p - buf), "%s: ", DRV_NAME); 579331766Sken p += snprintf(p, sizeof(buf) - (p - buf), "%s:", func_name); 580331766Sken p += snprintf(p, sizeof(buf) - (p - buf), "%i:", line); 581331766Sken p += snprintf(p, sizeof(buf) - (p - buf), "%s:", (ocs != NULL) ? device_get_nameunit(ocs->dev) : ""); 582331766Sken p += vsnprintf(p, sizeof(buf) - (p - buf), fmt, ap); 583331766Sken 584331766Sken va_end(ap); 585331766Sken 586331766Sken printf("%s", buf); 587331766Sken} 588331766Sken 589331766Sken/** 590331766Sken * @brief Common thread call function 591331766Sken * 592331766Sken * This is the common function called whenever a thread instantiated by ocs_thread_create() is started. 593331766Sken * It captures the return value from the actual thread function and stashes it in the thread object, to 594331766Sken * be later retrieved by ocs_thread_get_retval(), and calls kthread_exit(), the proscribed method to terminate 595331766Sken * a thread. 596331766Sken * 597331766Sken * @param arg a pointer to the thread object 598331766Sken * 599331766Sken * @return none 600331766Sken */ 601331766Sken 602331766Skenstatic void 603331766Skenocs_thread_call_fctn(void *arg) 604331766Sken{ 605331766Sken ocs_thread_t *thread = arg; 606331766Sken thread->retval = (*thread->fctn)(thread->arg); 607331766Sken ocs_free(NULL, thread->name, ocs_strlen(thread->name+1)); 608331766Sken kthread_exit(); 609331766Sken} 610331766Sken 611331766Sken/** 612331766Sken * @brief Create a kernel thread 613331766Sken * 614331766Sken * Creates a kernel thread and optionally starts it. If the thread is not immediately 615331766Sken * started, ocs_thread_start() should be called at some later point. 616331766Sken * 617331766Sken * @param os OS handle 618331766Sken * @param thread pointer to thread object 619331766Sken * @param fctn function for thread to be begin executing 620331766Sken * @param name text name to identify thread 621331766Sken * @param arg application specific argument passed to thread function 622331766Sken * @param start start option, OCS_THREAD_RUN will start the thread immediately, 623331766Sken * OCS_THREAD_CREATE will create but not start the thread 624331766Sken * 625331766Sken * @return returns 0 for success, a negative error code value for failure. 626331766Sken */ 627331766Sken 628331766Skenint32_t 629331766Skenocs_thread_create(ocs_os_handle_t os, ocs_thread_t *thread, ocs_thread_fctn fctn, const char *name, void *arg, ocs_thread_start_e start) 630331766Sken{ 631331766Sken int32_t rc = 0; 632331766Sken 633333991Sken ocs_memset(thread, 0, sizeof(*thread)); 634331766Sken 635331766Sken thread->fctn = fctn; 636331766Sken thread->name = ocs_strdup(name); 637331766Sken if (thread->name == NULL) { 638331766Sken thread->name = "unknown"; 639331766Sken } 640331766Sken thread->arg = arg; 641331766Sken 642331766Sken ocs_atomic_set(&thread->terminate, 0); 643331766Sken 644331766Sken rc = kthread_add(ocs_thread_call_fctn, thread, NULL, &thread->tcb, (start == OCS_THREAD_CREATE) ? RFSTOPPED : 0, 645331766Sken OCS_THREAD_DEFAULT_STACK_SIZE_PAGES, "%s", name); 646331766Sken 647331766Sken return rc; 648331766Sken} 649331766Sken 650331766Sken/** 651331766Sken * @brief Start a thread 652331766Sken * 653331766Sken * Starts a thread that was created with OCS_THREAD_CREATE rather than OCS_THREAD_RUN 654331766Sken * 655331766Sken * @param thread pointer to thread object 656331766Sken * 657331766Sken * @return returns 0 for success, a negative error code value for failure. 658331766Sken */ 659331766Sken 660331766Skenint32_t ocs_thread_start(ocs_thread_t *thread) 661331766Sken{ 662331766Sken sched_add(thread->tcb, SRQ_BORING); 663331766Sken return 0; 664331766Sken} 665331766Sken 666331766Sken/** 667331766Sken * @brief return thread argument 668331766Sken * 669331766Sken * Returns a pointer to the thread's application specific argument 670331766Sken * 671331766Sken * @param mythread pointer to the thread object 672331766Sken * 673331766Sken * @return pointer to application specific argument 674331766Sken */ 675331766Sken 676331766Skenvoid *ocs_thread_get_arg(ocs_thread_t *mythread) 677331766Sken{ 678331766Sken return mythread->arg; 679331766Sken} 680331766Sken 681331766Sken/** 682331766Sken * @brief Request thread stop 683331766Sken * 684331766Sken * A stop request is made to the thread. This is a voluntary call, the thread needs 685331766Sken * to periodically query its terminate request using ocs_thread_terminate_requested() 686331766Sken * 687331766Sken * @param thread pointer to thread object 688331766Sken * 689331766Sken * @return returns 0 for success, a negative error code value for failure. 690331766Sken */ 691331766Sken 692331766Skenint32_t 693331766Skenocs_thread_terminate(ocs_thread_t *thread) 694331766Sken{ 695331766Sken ocs_atomic_set(&thread->terminate, 1); 696331766Sken return 0; 697331766Sken} 698331766Sken 699331766Sken/** 700331766Sken * @brief See if a terminate request has been made 701331766Sken * 702331766Sken * Check to see if a stop request has been made to the current thread. This 703331766Sken * function would be used by a thread to see if it should terminate. 704331766Sken * 705331766Sken * @return returns non-zero if a stop has been requested 706331766Sken */ 707331766Sken 708331766Skenint32_t ocs_thread_terminate_requested(ocs_thread_t *thread) 709331766Sken{ 710331766Sken return ocs_atomic_read(&thread->terminate); 711331766Sken} 712331766Sken 713331766Sken/** 714331766Sken * @brief Retrieve threads return value 715331766Sken * 716331766Sken * After a thread has terminated, it's return value may be retrieved with this function. 717331766Sken * 718331766Sken * @param thread pointer to thread object 719331766Sken * 720331766Sken * @return return value from thread function 721331766Sken */ 722331766Sken 723331766Skenint32_t 724331766Skenocs_thread_get_retval(ocs_thread_t *thread) 725331766Sken{ 726331766Sken return thread->retval; 727331766Sken} 728331766Sken 729331766Sken/** 730331766Sken * @brief Request that the currently running thread yield 731331766Sken * 732331766Sken * The currently running thread yields to the scheduler 733331766Sken * 734331766Sken * @param thread pointer to thread (ignored) 735331766Sken * 736331766Sken * @return none 737331766Sken */ 738331766Sken 739331766Skenvoid 740331766Skenocs_thread_yield(ocs_thread_t *thread) { 741331766Sken pause("thread yield", 1); 742331766Sken} 743331766Sken 744331766Skenocs_thread_t * 745331766Skenocs_thread_self(void) 746331766Sken{ 747331766Sken ocs_printf(">>> %s not implemented\n", __func__); 748331766Sken ocs_abort(); 749331766Sken} 750331766Sken 751331766Skenint32_t 752331766Skenocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu) 753331766Sken{ 754331766Sken ocs_printf(">>> %s not implemented\n", __func__); 755331766Sken return -1; 756331766Sken} 757331766Sken 758331766Skenint32_t 759331766Skenocs_thread_getcpu(void) 760331766Sken{ 761331766Sken return curcpu; 762331766Sken} 763331766Sken 764331766Skenint 765331766Skenocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...) 766331766Sken{ 767331766Sken va_list ap; 768331766Sken 769331766Sken va_start(ap, name); 770331766Sken ocs_vsnprintf(sem->name, sizeof(sem->name), name, ap); 771331766Sken va_end(ap); 772331766Sken 773331766Sken sema_init(&sem->sem, val, sem->name); 774331766Sken return 0; 775331766Sken} 776331766Sken 777331766Sken/** 778331766Sken * @ingroup os 779331766Sken * @brief Copy user arguments in to kernel space for an ioctl 780331766Sken * @par Description 781331766Sken * This function is called at the beginning of an ioctl function 782331766Sken * to copy the ioctl argument from user space to kernel space. 783331766Sken * 784331766Sken * BSD handles this for us - arg is already in kernel space, 785331766Sken * so we just return it. 786331766Sken * 787331766Sken * @param os OS handle 788331766Sken * @param arg The argument passed to the ioctl function 789331766Sken * @param size The size of the structure pointed to by arg 790331766Sken * 791331766Sken * @return A pointer to a kernel space copy of the argument on 792331766Sken * success; NULL on failure 793331766Sken */ 794331766Skenvoid *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size) 795331766Sken{ 796331766Sken return arg; 797331766Sken} 798331766Sken 799331766Sken/** 800331766Sken * @ingroup os 801331766Sken * @brief Copy results of an ioctl back to user space 802331766Sken * @par Description 803331766Sken * This function is called at the end of ioctl processing to 804331766Sken * copy the argument back to user space. 805331766Sken * 806331766Sken * BSD handles this for us. 807331766Sken * 808331766Sken * @param os OS handle 809331766Sken * @param arg The argument passed to the ioctl function 810331766Sken * @param kern_ptr A pointer to the kernel space copy of the 811331766Sken * argument 812331766Sken * @param size The size of the structure pointed to by arg. 813331766Sken * 814331766Sken * @return Returns 0. 815331766Sken */ 816331766Skenint32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size) 817331766Sken{ 818331766Sken return 0; 819331766Sken} 820331766Sken 821331766Sken/** 822331766Sken * @ingroup os 823331766Sken * @brief Free memory allocated by ocs_ioctl_preprocess 824331766Sken * @par Description 825331766Sken * This function is called in the event of an error in ioctl 826331766Sken * processing. For operating environments where ocs_ioctlpreprocess 827331766Sken * allocates memory, this call frees the memory without copying 828331766Sken * results back to user space. 829331766Sken * 830331766Sken * For BSD, because no memory was allocated in ocs_ioctl_preprocess, 831331766Sken * nothing needs to be done here. 832331766Sken * 833331766Sken * @param os OS handle 834331766Sken * @param kern_ptr A pointer to the kernel space copy of the 835331766Sken * argument 836331766Sken * @param size The size of the structure pointed to by arg. 837331766Sken * 838331766Sken * @return Returns nothing. 839331766Sken */ 840331766Skenvoid ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size) 841331766Sken{ 842331766Sken return; 843331766Sken} 844331766Sken 845331766Skenvoid ocs_intr_disable(ocs_os_handle_t os) 846331766Sken{ 847331766Sken} 848331766Sken 849331766Skenvoid ocs_intr_enable(ocs_os_handle_t os) 850331766Sken{ 851331766Sken} 852331766Sken 853331766Skenvoid ocs_print_stack(void) 854331766Sken{ 855332883Sram#if defined(STACK) 856331766Sken struct stack st; 857331766Sken 858331766Sken stack_zero(&st); 859331766Sken stack_save(&st); 860331766Sken stack_print(&st); 861332883Sram#endif 862331766Sken} 863331766Sken 864331766Skenvoid ocs_abort(void) 865331766Sken{ 866331766Sken panic(">>> abort/panic\n"); 867331766Sken} 868331766Sken 869331766Skenconst char * 870331766Skenocs_pci_model(uint16_t vendor, uint16_t device) 871331766Sken{ 872331766Sken switch (device) { 873331766Sken case PCI_PRODUCT_EMULEX_OCE16002: return "OCE16002"; 874331766Sken case PCI_PRODUCT_EMULEX_OCE1600_VF: return "OCE1600_VF"; 875331766Sken case PCI_PRODUCT_EMULEX_OCE50102: return "OCE50102"; 876331766Sken case PCI_PRODUCT_EMULEX_OCE50102_VF: return "OCE50102_VR"; 877331766Sken default: 878331766Sken break; 879331766Sken } 880331766Sken 881331766Sken return "unknown"; 882331766Sken} 883331766Sken 884331766Skenint32_t 885331766Skenocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func) 886331766Sken{ 887331766Sken *bus = pci_get_bus(ocs->dev); 888331766Sken *dev = pci_get_slot(ocs->dev); 889331766Sken *func= pci_get_function(ocs->dev); 890331766Sken return 0; 891331766Sken} 892331766Sken 893331766Sken/** 894331766Sken * @brief return CPU information 895331766Sken * 896331766Sken * This function populates the ocs_cpuinfo_t buffer with CPU information 897331766Sken * 898331766Sken * @param cpuinfo pointer to ocs_cpuinfo_t buffer 899331766Sken * 900331766Sken * @return returns 0 for success, a negative error code value for failure. 901331766Sken */ 902331766Skenextern int mp_ncpus; 903331766Skenint32_t 904331766Skenocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo) 905331766Sken{ 906331766Sken cpuinfo->num_cpus = mp_ncpus; 907331766Sken return 0; 908331766Sken} 909331766Sken 910331766Skenuint32_t 911331766Skenocs_get_num_cpus(void) 912331766Sken{ 913331766Sken static ocs_cpuinfo_t cpuinfo; 914331766Sken 915331766Sken if (cpuinfo.num_cpus == 0) { 916331766Sken ocs_get_cpuinfo(&cpuinfo); 917331766Sken } 918331766Sken return cpuinfo.num_cpus; 919331766Sken} 920331766Sken 921331766Sken 922331766Skenvoid 923331766Sken__ocs_callout(void *t) 924331766Sken{ 925331766Sken ocs_timer_t *timer = t; 926331766Sken 927331766Sken if (callout_pending(&timer->callout)) { 928331766Sken /* Callout was reset */ 929331766Sken return; 930331766Sken } 931331766Sken 932331766Sken if (!callout_active(&timer->callout)) { 933331766Sken /* Callout was stopped */ 934331766Sken return; 935331766Sken } 936331766Sken 937331766Sken callout_deactivate(&timer->callout); 938331766Sken 939331766Sken if (timer->func) { 940331766Sken timer->func(timer->data); 941331766Sken } 942331766Sken} 943331766Sken 944331766Skenint32_t 945331766Skenocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), void *data, uint32_t timeout_ms) 946331766Sken{ 947331766Sken struct timeval tv; 948331766Sken int hz; 949331766Sken 950331766Sken if (timer == NULL) { 951331766Sken ocs_log_err(NULL, "bad parameter\n"); 952331766Sken return -1; 953331766Sken } 954331766Sken 955331766Sken if (!mtx_initialized(&timer->lock)) { 956331766Sken mtx_init(&timer->lock, "ocs_timer", NULL, MTX_DEF); 957331766Sken } 958331766Sken 959331766Sken callout_init_mtx(&timer->callout, &timer->lock, 0); 960331766Sken 961331766Sken timer->func = func; 962331766Sken timer->data = data; 963331766Sken 964331766Sken tv.tv_sec = timeout_ms / 1000; 965331766Sken tv.tv_usec = (timeout_ms % 1000) * 1000; 966331766Sken 967331766Sken hz = tvtohz(&tv); 968331766Sken if (hz < 0) 969331766Sken hz = INT32_MAX; 970331766Sken if (hz == 0) 971331766Sken hz = 1; 972331766Sken 973331766Sken mtx_lock(&timer->lock); 974331766Sken callout_reset(&timer->callout, hz, __ocs_callout, timer); 975331766Sken mtx_unlock(&timer->lock); 976331766Sken 977331766Sken return 0; 978331766Sken} 979331766Sken 980331766Skenint32_t 981331766Skenocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms) 982331766Sken{ 983331766Sken struct timeval tv; 984331766Sken int hz; 985331766Sken 986331766Sken if (timer == NULL) { 987331766Sken ocs_log_err(NULL, "bad parameter\n"); 988331766Sken return -1; 989331766Sken } 990331766Sken 991331766Sken tv.tv_sec = timeout_ms / 1000; 992331766Sken tv.tv_usec = (timeout_ms % 1000) * 1000; 993331766Sken 994331766Sken hz = tvtohz(&tv); 995331766Sken if (hz < 0) 996331766Sken hz = INT32_MAX; 997331766Sken if (hz == 0) 998331766Sken hz = 1; 999331766Sken 1000331766Sken mtx_lock(&timer->lock); 1001331766Sken callout_reset(&timer->callout, hz, __ocs_callout, timer); 1002331766Sken mtx_unlock(&timer->lock); 1003331766Sken 1004331766Sken return 0; 1005331766Sken} 1006331766Sken 1007331766Skenint32_t 1008331766Skenocs_timer_pending(ocs_timer_t *timer) 1009331766Sken{ 1010331766Sken return callout_active(&timer->callout); 1011331766Sken} 1012331766Sken 1013331766Skenint32_t 1014331766Skenocs_del_timer(ocs_timer_t *timer) 1015331766Sken{ 1016331766Sken 1017331766Sken mtx_lock(&timer->lock); 1018331766Sken callout_stop(&timer->callout); 1019331766Sken mtx_unlock(&timer->lock); 1020331766Sken 1021331766Sken return 0; 1022331766Sken} 1023331766Sken 1024331766Skenchar * 1025331766Skenocs_strdup(const char *s) 1026331766Sken{ 1027331766Sken uint32_t l = strlen(s); 1028331766Sken char *d; 1029331766Sken 1030331766Sken d = ocs_malloc(NULL, l+1, OCS_M_NOWAIT); 1031331766Sken if (d != NULL) { 1032331766Sken ocs_strcpy(d, s); 1033331766Sken } 1034331766Sken return d; 1035331766Sken} 1036331766Sken 1037331766Skenvoid 1038331766Sken_ocs_assert(const char *cond, const char *filename, int linenum) 1039331766Sken{ 1040331766Sken const char *fn = strrchr(__FILE__, '/'); 1041331766Sken 1042331766Sken ocs_log_err(NULL, "%s(%d) assertion (%s) failed\n", (fn ? fn + 1 : filename), linenum, cond); 1043331766Sken ocs_print_stack(); 1044331766Sken ocs_save_ddump_all(OCS_DDUMP_FLAGS_WQES|OCS_DDUMP_FLAGS_CQES|OCS_DDUMP_FLAGS_MQES, -1, TRUE); 1045331766Sken} 1046