1*ef270ab1SKenneth D. Merry /*- 2*ef270ab1SKenneth D. Merry * Copyright (c) 2017 Broadcom. All rights reserved. 3*ef270ab1SKenneth D. Merry * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4*ef270ab1SKenneth D. Merry * 5*ef270ab1SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 6*ef270ab1SKenneth D. Merry * modification, are permitted provided that the following conditions are met: 7*ef270ab1SKenneth D. Merry * 8*ef270ab1SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright notice, 9*ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer. 10*ef270ab1SKenneth D. Merry * 11*ef270ab1SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright notice, 12*ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer in the documentation 13*ef270ab1SKenneth D. Merry * and/or other materials provided with the distribution. 14*ef270ab1SKenneth D. Merry * 15*ef270ab1SKenneth D. Merry * 3. Neither the name of the copyright holder nor the names of its contributors 16*ef270ab1SKenneth D. Merry * may be used to endorse or promote products derived from this software 17*ef270ab1SKenneth D. Merry * without specific prior written permission. 18*ef270ab1SKenneth D. Merry * 19*ef270ab1SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20*ef270ab1SKenneth D. Merry * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21*ef270ab1SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22*ef270ab1SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23*ef270ab1SKenneth D. Merry * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24*ef270ab1SKenneth D. Merry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25*ef270ab1SKenneth D. Merry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26*ef270ab1SKenneth D. Merry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27*ef270ab1SKenneth D. Merry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28*ef270ab1SKenneth D. Merry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29*ef270ab1SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGE. 30*ef270ab1SKenneth D. Merry * 31*ef270ab1SKenneth D. Merry * $FreeBSD$ 32*ef270ab1SKenneth D. Merry */ 33*ef270ab1SKenneth D. Merry 34*ef270ab1SKenneth D. Merry /** 35*ef270ab1SKenneth D. Merry * @file 36*ef270ab1SKenneth D. Merry * Implementation of common BSD OS abstraction functions 37*ef270ab1SKenneth D. Merry */ 38*ef270ab1SKenneth D. Merry 39*ef270ab1SKenneth D. Merry #include "ocs.h" 40*ef270ab1SKenneth D. Merry #include <sys/sysctl.h> 41*ef270ab1SKenneth D. Merry #include <sys/malloc.h> 42*ef270ab1SKenneth D. Merry #include <sys/linker.h> /* for debug of memory allocations */ 43*ef270ab1SKenneth D. Merry 44*ef270ab1SKenneth D. Merry static MALLOC_DEFINE(M_OCS, "OCS", "OneCore Storage data"); 45*ef270ab1SKenneth D. Merry 46*ef270ab1SKenneth D. Merry #include <dev/pci/pcireg.h> 47*ef270ab1SKenneth D. Merry #include <dev/pci/pcivar.h> 48*ef270ab1SKenneth D. Merry 49*ef270ab1SKenneth D. Merry #include <machine/bus.h> 50*ef270ab1SKenneth D. Merry 51*ef270ab1SKenneth D. Merry timeout_t __ocs_callout; 52*ef270ab1SKenneth D. Merry 53*ef270ab1SKenneth D. Merry uint32_t 54*ef270ab1SKenneth D. Merry ocs_config_read32(ocs_os_handle_t os, uint32_t reg) 55*ef270ab1SKenneth D. Merry { 56*ef270ab1SKenneth D. Merry return pci_read_config(os->dev, reg, 4); 57*ef270ab1SKenneth D. Merry } 58*ef270ab1SKenneth D. Merry 59*ef270ab1SKenneth D. Merry uint16_t 60*ef270ab1SKenneth D. Merry ocs_config_read16(ocs_os_handle_t os, uint32_t reg) 61*ef270ab1SKenneth D. Merry { 62*ef270ab1SKenneth D. Merry return pci_read_config(os->dev, reg, 2); 63*ef270ab1SKenneth D. Merry } 64*ef270ab1SKenneth D. Merry 65*ef270ab1SKenneth D. Merry uint8_t 66*ef270ab1SKenneth D. Merry ocs_config_read8(ocs_os_handle_t os, uint32_t reg) 67*ef270ab1SKenneth D. Merry { 68*ef270ab1SKenneth D. Merry return pci_read_config(os->dev, reg, 1); 69*ef270ab1SKenneth D. Merry } 70*ef270ab1SKenneth D. Merry 71*ef270ab1SKenneth D. Merry void 72*ef270ab1SKenneth D. Merry ocs_config_write8(ocs_os_handle_t os, uint32_t reg, uint8_t val) 73*ef270ab1SKenneth D. Merry { 74*ef270ab1SKenneth D. Merry return pci_write_config(os->dev, reg, val, 1); 75*ef270ab1SKenneth D. Merry } 76*ef270ab1SKenneth D. Merry 77*ef270ab1SKenneth D. Merry void 78*ef270ab1SKenneth D. Merry ocs_config_write16(ocs_os_handle_t os, uint32_t reg, uint16_t val) 79*ef270ab1SKenneth D. Merry { 80*ef270ab1SKenneth D. Merry return pci_write_config(os->dev, reg, val, 2); 81*ef270ab1SKenneth D. Merry } 82*ef270ab1SKenneth D. Merry 83*ef270ab1SKenneth D. Merry void 84*ef270ab1SKenneth D. Merry ocs_config_write32(ocs_os_handle_t os, uint32_t reg, uint32_t val) 85*ef270ab1SKenneth D. Merry { 86*ef270ab1SKenneth D. Merry return pci_write_config(os->dev, reg, val, 4); 87*ef270ab1SKenneth D. Merry } 88*ef270ab1SKenneth D. Merry 89*ef270ab1SKenneth D. Merry /** 90*ef270ab1SKenneth D. Merry * @ingroup os 91*ef270ab1SKenneth D. Merry * @brief Read a 32bit PCI register 92*ef270ab1SKenneth D. Merry * 93*ef270ab1SKenneth D. Merry * The SLI documentation uses the term "register set" to describe one or more 94*ef270ab1SKenneth D. Merry * PCI BARs which form a logical address. For example, a 64-bit address uses 95*ef270ab1SKenneth D. Merry * two BARs, and thus constitute a register set. 96*ef270ab1SKenneth D. Merry * 97*ef270ab1SKenneth D. Merry * @param ocs Pointer to the driver's context 98*ef270ab1SKenneth D. Merry * @param rset Register Set to use 99*ef270ab1SKenneth D. Merry * @param off Offset from the base address of the Register Set 100*ef270ab1SKenneth D. Merry * 101*ef270ab1SKenneth D. Merry * @return register value 102*ef270ab1SKenneth D. Merry */ 103*ef270ab1SKenneth D. Merry uint32_t 104*ef270ab1SKenneth D. Merry ocs_reg_read32(ocs_t *ocs, uint32_t rset, uint32_t off) 105*ef270ab1SKenneth D. Merry { 106*ef270ab1SKenneth D. Merry ocs_pci_reg_t *reg = NULL; 107*ef270ab1SKenneth D. Merry 108*ef270ab1SKenneth D. Merry reg = &ocs->reg[rset]; 109*ef270ab1SKenneth D. Merry 110*ef270ab1SKenneth D. Merry return bus_space_read_4(reg->btag, reg->bhandle, off); 111*ef270ab1SKenneth D. Merry } 112*ef270ab1SKenneth D. Merry 113*ef270ab1SKenneth D. Merry /** 114*ef270ab1SKenneth D. Merry * @ingroup os 115*ef270ab1SKenneth D. Merry * @brief Read a 16bit PCI register 116*ef270ab1SKenneth D. Merry * 117*ef270ab1SKenneth D. Merry * The SLI documentation uses the term "register set" to describe one or more 118*ef270ab1SKenneth D. Merry * PCI BARs which form a logical address. For example, a 64-bit address uses 119*ef270ab1SKenneth D. Merry * two BARs, and thus constitute a register set. 120*ef270ab1SKenneth D. Merry * 121*ef270ab1SKenneth D. Merry * @param ocs Pointer to the driver's context 122*ef270ab1SKenneth D. Merry * @param rset Register Set to use 123*ef270ab1SKenneth D. Merry * @param off Offset from the base address of the Register Set 124*ef270ab1SKenneth D. Merry * 125*ef270ab1SKenneth D. Merry * @return register value 126*ef270ab1SKenneth D. Merry */ 127*ef270ab1SKenneth D. Merry uint16_t 128*ef270ab1SKenneth D. Merry ocs_reg_read16(ocs_t *ocs, uint32_t rset, uint32_t off) 129*ef270ab1SKenneth D. Merry { 130*ef270ab1SKenneth D. Merry ocs_pci_reg_t *reg = NULL; 131*ef270ab1SKenneth D. Merry 132*ef270ab1SKenneth D. Merry reg = &ocs->reg[rset]; 133*ef270ab1SKenneth D. Merry 134*ef270ab1SKenneth D. Merry return bus_space_read_2(reg->btag, reg->bhandle, off); 135*ef270ab1SKenneth D. Merry } 136*ef270ab1SKenneth D. Merry 137*ef270ab1SKenneth D. Merry /** 138*ef270ab1SKenneth D. Merry * @ingroup os 139*ef270ab1SKenneth D. Merry * @brief Read a 8bit PCI register 140*ef270ab1SKenneth D. Merry * 141*ef270ab1SKenneth D. Merry * The SLI documentation uses the term "register set" to describe one or more 142*ef270ab1SKenneth D. Merry * PCI BARs which form a logical address. For example, a 64-bit address uses 143*ef270ab1SKenneth D. Merry * two BARs, and thus constitute a register set. 144*ef270ab1SKenneth D. Merry * 145*ef270ab1SKenneth D. Merry * @param ocs Pointer to the driver's context 146*ef270ab1SKenneth D. Merry * @param rset Register Set to use 147*ef270ab1SKenneth D. Merry * @param off Offset from the base address of the Register Set 148*ef270ab1SKenneth D. Merry * 149*ef270ab1SKenneth D. Merry * @return register value 150*ef270ab1SKenneth D. Merry */ 151*ef270ab1SKenneth D. Merry uint8_t 152*ef270ab1SKenneth D. Merry ocs_reg_read8(ocs_t *ocs, uint32_t rset, uint32_t off) 153*ef270ab1SKenneth D. Merry { 154*ef270ab1SKenneth D. Merry ocs_pci_reg_t *reg = NULL; 155*ef270ab1SKenneth D. Merry 156*ef270ab1SKenneth D. Merry reg = &ocs->reg[rset]; 157*ef270ab1SKenneth D. Merry 158*ef270ab1SKenneth D. Merry return bus_space_read_1(reg->btag, reg->bhandle, off); 159*ef270ab1SKenneth D. Merry } 160*ef270ab1SKenneth D. Merry 161*ef270ab1SKenneth D. Merry /** 162*ef270ab1SKenneth D. Merry * @ingroup os 163*ef270ab1SKenneth D. Merry * @brief Write a 32bit PCI register 164*ef270ab1SKenneth D. Merry * 165*ef270ab1SKenneth D. Merry * The SLI documentation uses the term "register set" to describe one or more 166*ef270ab1SKenneth D. Merry * PCI BARs which form a logical address. For example, a 64-bit address uses 167*ef270ab1SKenneth D. Merry * two BARs, and thus constitute a register set. 168*ef270ab1SKenneth D. Merry * 169*ef270ab1SKenneth D. Merry * @param ocs Pointer to the driver's context 170*ef270ab1SKenneth D. Merry * @param rset Register Set to use 171*ef270ab1SKenneth D. Merry * @param off Offset from the base address of the Register Set 172*ef270ab1SKenneth D. Merry * @param val Value to write 173*ef270ab1SKenneth D. Merry * 174*ef270ab1SKenneth D. Merry * @return none 175*ef270ab1SKenneth D. Merry */ 176*ef270ab1SKenneth D. Merry void 177*ef270ab1SKenneth D. Merry ocs_reg_write32(ocs_t *ocs, uint32_t rset, uint32_t off, uint32_t val) 178*ef270ab1SKenneth D. Merry { 179*ef270ab1SKenneth D. Merry ocs_pci_reg_t *reg = NULL; 180*ef270ab1SKenneth D. Merry 181*ef270ab1SKenneth D. Merry reg = &ocs->reg[rset]; 182*ef270ab1SKenneth D. Merry 183*ef270ab1SKenneth D. Merry return bus_space_write_4(reg->btag, reg->bhandle, off, val); 184*ef270ab1SKenneth D. Merry } 185*ef270ab1SKenneth D. Merry 186*ef270ab1SKenneth D. Merry /** 187*ef270ab1SKenneth D. Merry * @ingroup os 188*ef270ab1SKenneth D. Merry * @brief Write a 16-bit PCI register 189*ef270ab1SKenneth D. Merry * 190*ef270ab1SKenneth D. Merry * The SLI documentation uses the term "register set" to describe one or more 191*ef270ab1SKenneth D. Merry * PCI BARs which form a logical address. For example, a 64-bit address uses 192*ef270ab1SKenneth D. Merry * two BARs, and thus constitute a register set. 193*ef270ab1SKenneth D. Merry * 194*ef270ab1SKenneth D. Merry * @param ocs Pointer to the driver's context 195*ef270ab1SKenneth D. Merry * @param rset Register Set to use 196*ef270ab1SKenneth D. Merry * @param off Offset from the base address of the Register Set 197*ef270ab1SKenneth D. Merry * @param val Value to write 198*ef270ab1SKenneth D. Merry * 199*ef270ab1SKenneth D. Merry * @return none 200*ef270ab1SKenneth D. Merry */ 201*ef270ab1SKenneth D. Merry void 202*ef270ab1SKenneth D. Merry ocs_reg_write16(ocs_t *ocs, uint32_t rset, uint32_t off, uint16_t val) 203*ef270ab1SKenneth D. Merry { 204*ef270ab1SKenneth D. Merry ocs_pci_reg_t *reg = NULL; 205*ef270ab1SKenneth D. Merry 206*ef270ab1SKenneth D. Merry reg = &ocs->reg[rset]; 207*ef270ab1SKenneth D. Merry 208*ef270ab1SKenneth D. Merry return bus_space_write_2(reg->btag, reg->bhandle, off, val); 209*ef270ab1SKenneth D. Merry } 210*ef270ab1SKenneth D. Merry 211*ef270ab1SKenneth D. Merry /** 212*ef270ab1SKenneth D. Merry * @ingroup os 213*ef270ab1SKenneth D. Merry * @brief Write a 8-bit PCI register 214*ef270ab1SKenneth D. Merry * 215*ef270ab1SKenneth D. Merry * The SLI documentation uses the term "register set" to describe one or more 216*ef270ab1SKenneth D. Merry * PCI BARs which form a logical address. For example, a 64-bit address uses 217*ef270ab1SKenneth D. Merry * two BARs, and thus constitute a register set. 218*ef270ab1SKenneth D. Merry * 219*ef270ab1SKenneth D. Merry * @param ocs Pointer to the driver's context 220*ef270ab1SKenneth D. Merry * @param rset Register Set to use 221*ef270ab1SKenneth D. Merry * @param off Offset from the base address of the Register Set 222*ef270ab1SKenneth D. Merry * @param val Value to write 223*ef270ab1SKenneth D. Merry * 224*ef270ab1SKenneth D. Merry * @return none 225*ef270ab1SKenneth D. Merry */ 226*ef270ab1SKenneth D. Merry void 227*ef270ab1SKenneth D. Merry ocs_reg_write8(ocs_t *ocs, uint32_t rset, uint32_t off, uint8_t val) 228*ef270ab1SKenneth D. Merry { 229*ef270ab1SKenneth D. Merry ocs_pci_reg_t *reg = NULL; 230*ef270ab1SKenneth D. Merry 231*ef270ab1SKenneth D. Merry reg = &ocs->reg[rset]; 232*ef270ab1SKenneth D. Merry 233*ef270ab1SKenneth D. Merry return bus_space_write_1(reg->btag, reg->bhandle, off, val); 234*ef270ab1SKenneth D. Merry } 235*ef270ab1SKenneth D. Merry 236*ef270ab1SKenneth D. Merry /** 237*ef270ab1SKenneth D. Merry * @ingroup os 238*ef270ab1SKenneth D. Merry * @brief Allocate host memory 239*ef270ab1SKenneth D. Merry * 240*ef270ab1SKenneth D. Merry * @param os OS handle 241*ef270ab1SKenneth D. Merry * @param size number of bytes to allocate 242*ef270ab1SKenneth D. Merry * @param flags additional options 243*ef270ab1SKenneth D. Merry * 244*ef270ab1SKenneth D. Merry * @return pointer to allocated memory, NULL otherwise 245*ef270ab1SKenneth D. Merry */ 246*ef270ab1SKenneth D. Merry void * 247*ef270ab1SKenneth D. Merry ocs_malloc(ocs_os_handle_t os, size_t size, int32_t flags) 248*ef270ab1SKenneth D. Merry { 249*ef270ab1SKenneth D. Merry if ((flags & OCS_M_NOWAIT) == 0) { 250*ef270ab1SKenneth D. Merry flags |= M_WAITOK; 251*ef270ab1SKenneth D. Merry } 252*ef270ab1SKenneth D. Merry 253*ef270ab1SKenneth D. Merry #ifndef OCS_DEBUG_MEMORY 254*ef270ab1SKenneth D. Merry return malloc(size, M_OCS, flags); 255*ef270ab1SKenneth D. Merry #else 256*ef270ab1SKenneth D. Merry char nameb[80]; 257*ef270ab1SKenneth D. Merry long offset = 0; 258*ef270ab1SKenneth D. Merry void *addr = malloc(size, M_OCS, flags); 259*ef270ab1SKenneth D. Merry 260*ef270ab1SKenneth D. Merry linker_ddb_search_symbol_name(__builtin_return_address(1), nameb, sizeof(nameb), &offset); 261*ef270ab1SKenneth D. Merry printf("A: %p %ld @ %s+%#lx\n", addr, size, nameb, offset); 262*ef270ab1SKenneth D. Merry 263*ef270ab1SKenneth D. Merry return addr; 264*ef270ab1SKenneth D. Merry #endif 265*ef270ab1SKenneth D. Merry } 266*ef270ab1SKenneth D. Merry 267*ef270ab1SKenneth D. Merry /** 268*ef270ab1SKenneth D. Merry * @ingroup os 269*ef270ab1SKenneth D. Merry * @brief Free host memory 270*ef270ab1SKenneth D. Merry * 271*ef270ab1SKenneth D. Merry * @param os OS handle 272*ef270ab1SKenneth D. Merry * @param addr pointer to memory 273*ef270ab1SKenneth D. Merry * @param size bytes to free 274*ef270ab1SKenneth D. Merry * 275*ef270ab1SKenneth D. Merry * @note size ignored in BSD 276*ef270ab1SKenneth D. Merry */ 277*ef270ab1SKenneth D. Merry void 278*ef270ab1SKenneth D. Merry ocs_free(ocs_os_handle_t os, void *addr, size_t size) 279*ef270ab1SKenneth D. Merry { 280*ef270ab1SKenneth D. Merry #ifndef OCS_DEBUG_MEMORY 281*ef270ab1SKenneth D. Merry free(addr, M_OCS); 282*ef270ab1SKenneth D. Merry #else 283*ef270ab1SKenneth D. Merry printf("F: %p %ld\n", addr, size); 284*ef270ab1SKenneth D. Merry free(addr, M_OCS); 285*ef270ab1SKenneth D. Merry #endif 286*ef270ab1SKenneth D. Merry } 287*ef270ab1SKenneth D. Merry 288*ef270ab1SKenneth D. Merry /** 289*ef270ab1SKenneth D. Merry * @brief Callback function provided to bus_dmamap_load 290*ef270ab1SKenneth D. Merry * 291*ef270ab1SKenneth D. Merry * Function loads the physical / bus address into the DMA descriptor. The caller 292*ef270ab1SKenneth D. Merry * can detect a mapping failure if a descriptor's phys element is zero. 293*ef270ab1SKenneth D. Merry * 294*ef270ab1SKenneth D. Merry * @param arg Argument provided to bus_dmamap_load is a ocs_dma_t 295*ef270ab1SKenneth D. Merry * @param seg Array of DMA segment(s), each describing segment's address and length 296*ef270ab1SKenneth D. Merry * @param nseg Number of elements in array 297*ef270ab1SKenneth D. Merry * @param error Indicates success (0) or failure of mapping 298*ef270ab1SKenneth D. Merry */ 299*ef270ab1SKenneth D. Merry static void 300*ef270ab1SKenneth D. Merry ocs_dma_load(void *arg, bus_dma_segment_t *seg, int nseg, int error) 301*ef270ab1SKenneth D. Merry { 302*ef270ab1SKenneth D. Merry ocs_dma_t *dma = arg; 303*ef270ab1SKenneth D. Merry 304*ef270ab1SKenneth D. Merry if (error) { 305*ef270ab1SKenneth D. Merry printf("%s: error=%d\n", __func__, error); 306*ef270ab1SKenneth D. Merry dma->phys = 0; 307*ef270ab1SKenneth D. Merry } else { 308*ef270ab1SKenneth D. Merry dma->phys = seg->ds_addr; 309*ef270ab1SKenneth D. Merry } 310*ef270ab1SKenneth D. Merry } 311*ef270ab1SKenneth D. Merry 312*ef270ab1SKenneth D. Merry /** 313*ef270ab1SKenneth D. Merry * @ingroup os 314*ef270ab1SKenneth D. Merry * @brief Free a DMA capable block of memory 315*ef270ab1SKenneth D. Merry * 316*ef270ab1SKenneth D. Merry * @param os Device abstraction 317*ef270ab1SKenneth D. Merry * @param dma DMA descriptor for memory to be freed 318*ef270ab1SKenneth D. Merry * 319*ef270ab1SKenneth D. Merry * @return 0 if memory is de-allocated, -1 otherwise 320*ef270ab1SKenneth D. Merry */ 321*ef270ab1SKenneth D. Merry int32_t 322*ef270ab1SKenneth D. Merry ocs_dma_free(ocs_os_handle_t os, ocs_dma_t *dma) 323*ef270ab1SKenneth D. Merry { 324*ef270ab1SKenneth D. Merry struct ocs_softc *ocs = os; 325*ef270ab1SKenneth D. Merry 326*ef270ab1SKenneth D. Merry if (!dma) { 327*ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s: bad parameter(s) dma=%p\n", __func__, dma); 328*ef270ab1SKenneth D. Merry return -1; 329*ef270ab1SKenneth D. Merry } 330*ef270ab1SKenneth D. Merry 331*ef270ab1SKenneth D. Merry if (dma->size == 0) { 332*ef270ab1SKenneth D. Merry return 0; 333*ef270ab1SKenneth D. Merry } 334*ef270ab1SKenneth D. Merry 335*ef270ab1SKenneth D. Merry if (dma->map) { 336*ef270ab1SKenneth D. Merry bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD | 337*ef270ab1SKenneth D. Merry BUS_DMASYNC_POSTWRITE); 338*ef270ab1SKenneth D. Merry bus_dmamap_unload(dma->tag, dma->map); 339*ef270ab1SKenneth D. Merry } 340*ef270ab1SKenneth D. Merry 341*ef270ab1SKenneth D. Merry if (dma->virt) { 342*ef270ab1SKenneth D. Merry bus_dmamem_free(dma->tag, dma->virt, dma->map); 343*ef270ab1SKenneth D. Merry bus_dmamap_destroy(dma->tag, dma->map); 344*ef270ab1SKenneth D. Merry } 345*ef270ab1SKenneth D. Merry bus_dma_tag_destroy(dma->tag); 346*ef270ab1SKenneth D. Merry 347*ef270ab1SKenneth D. Merry bzero(dma, sizeof(ocs_dma_t)); 348*ef270ab1SKenneth D. Merry 349*ef270ab1SKenneth D. Merry return 0; 350*ef270ab1SKenneth D. Merry } 351*ef270ab1SKenneth D. Merry 352*ef270ab1SKenneth D. Merry /** 353*ef270ab1SKenneth D. Merry * @ingroup os 354*ef270ab1SKenneth D. Merry * @brief Allocate a DMA capable block of memory 355*ef270ab1SKenneth D. Merry * 356*ef270ab1SKenneth D. Merry * @param os Device abstraction 357*ef270ab1SKenneth D. Merry * @param dma DMA descriptor containing results of memory allocation 358*ef270ab1SKenneth D. Merry * @param size Size in bytes of desired allocation 359*ef270ab1SKenneth D. Merry * @param align Alignment in bytes 360*ef270ab1SKenneth D. Merry * 361*ef270ab1SKenneth D. Merry * @return 0 on success, ENOMEM otherwise 362*ef270ab1SKenneth D. Merry */ 363*ef270ab1SKenneth D. Merry int32_t 364*ef270ab1SKenneth D. Merry ocs_dma_alloc(ocs_os_handle_t os, ocs_dma_t *dma, size_t size, size_t align) 365*ef270ab1SKenneth D. Merry { 366*ef270ab1SKenneth D. Merry struct ocs_softc *ocs = os; 367*ef270ab1SKenneth D. Merry 368*ef270ab1SKenneth D. Merry if (!dma || !size) { 369*ef270ab1SKenneth D. Merry device_printf(ocs->dev, "%s bad parameter(s) dma=%p size=%zd\n", 370*ef270ab1SKenneth D. Merry __func__, dma, size); 371*ef270ab1SKenneth D. Merry return ENOMEM; 372*ef270ab1SKenneth D. Merry } 373*ef270ab1SKenneth D. Merry 374*ef270ab1SKenneth D. Merry bzero(dma, sizeof(ocs_dma_t)); 375*ef270ab1SKenneth D. Merry 376*ef270ab1SKenneth D. Merry /* create a "tag" that describes the desired memory allocation */ 377*ef270ab1SKenneth D. Merry if (bus_dma_tag_create(ocs->dmat, align, 0, BUS_SPACE_MAXADDR, 378*ef270ab1SKenneth D. Merry BUS_SPACE_MAXADDR, NULL, NULL, 379*ef270ab1SKenneth D. Merry size, 1, size, 0, NULL, NULL, &dma->tag)) { 380*ef270ab1SKenneth D. Merry device_printf(ocs->dev, "DMA tag allocation failed\n"); 381*ef270ab1SKenneth D. Merry return ENOMEM; 382*ef270ab1SKenneth D. Merry } 383*ef270ab1SKenneth D. Merry 384*ef270ab1SKenneth D. Merry dma->size = size; 385*ef270ab1SKenneth D. Merry 386*ef270ab1SKenneth D. Merry /* allocate the memory */ 387*ef270ab1SKenneth D. Merry if (bus_dmamem_alloc(dma->tag, &dma->virt, BUS_DMA_NOWAIT | BUS_DMA_COHERENT, 388*ef270ab1SKenneth D. Merry &dma->map)) { 389*ef270ab1SKenneth D. Merry device_printf(ocs->dev, "DMA memory allocation failed s=%zd a=%zd\n", size, align); 390*ef270ab1SKenneth D. Merry ocs_dma_free(ocs, dma); 391*ef270ab1SKenneth D. Merry return ENOMEM; 392*ef270ab1SKenneth D. Merry } 393*ef270ab1SKenneth D. Merry 394*ef270ab1SKenneth D. Merry dma->alloc = dma->virt; 395*ef270ab1SKenneth D. Merry 396*ef270ab1SKenneth D. Merry /* map virtual address to device visible address */ 397*ef270ab1SKenneth D. Merry if (bus_dmamap_load(dma->tag, dma->map, dma->virt, dma->size, ocs_dma_load, 398*ef270ab1SKenneth D. Merry dma, 0)) { 399*ef270ab1SKenneth D. Merry device_printf(ocs->dev, "DMA memory load failed\n"); 400*ef270ab1SKenneth D. Merry ocs_dma_free(ocs, dma); 401*ef270ab1SKenneth D. Merry return ENOMEM; 402*ef270ab1SKenneth D. Merry } 403*ef270ab1SKenneth D. Merry 404*ef270ab1SKenneth D. Merry /* if the DMA map load callback fails, it sets the physical address to zero */ 405*ef270ab1SKenneth D. Merry if (0 == dma->phys) { 406*ef270ab1SKenneth D. Merry device_printf(ocs->dev, "ocs_dma_load failed\n"); 407*ef270ab1SKenneth D. Merry ocs_dma_free(ocs, dma); 408*ef270ab1SKenneth D. Merry return ENOMEM; 409*ef270ab1SKenneth D. Merry } 410*ef270ab1SKenneth D. Merry 411*ef270ab1SKenneth D. Merry return 0; 412*ef270ab1SKenneth D. Merry } 413*ef270ab1SKenneth D. Merry 414*ef270ab1SKenneth D. Merry /** 415*ef270ab1SKenneth D. Merry * @ingroup os 416*ef270ab1SKenneth D. Merry * @brief Synchronize the DMA buffer memory 417*ef270ab1SKenneth D. Merry * 418*ef270ab1SKenneth D. Merry * Ensures memory coherency between the CPU and device 419*ef270ab1SKenneth D. Merry * 420*ef270ab1SKenneth D. Merry * @param dma DMA descriptor of memory to synchronize 421*ef270ab1SKenneth D. Merry * @param flags Describes direction of synchronization 422*ef270ab1SKenneth D. Merry * See BUS_DMA(9) for details 423*ef270ab1SKenneth D. Merry * - BUS_DMASYNC_PREWRITE 424*ef270ab1SKenneth D. Merry * - BUS_DMASYNC_POSTREAD 425*ef270ab1SKenneth D. Merry */ 426*ef270ab1SKenneth D. Merry void 427*ef270ab1SKenneth D. Merry ocs_dma_sync(ocs_dma_t *dma, uint32_t flags) 428*ef270ab1SKenneth D. Merry { 429*ef270ab1SKenneth D. Merry bus_dmamap_sync(dma->tag, dma->map, flags); 430*ef270ab1SKenneth D. Merry } 431*ef270ab1SKenneth D. Merry 432*ef270ab1SKenneth D. Merry int32_t 433*ef270ab1SKenneth D. Merry ocs_dma_copy_in(ocs_dma_t *dma, void *buffer, uint32_t buffer_length) 434*ef270ab1SKenneth D. Merry { 435*ef270ab1SKenneth D. Merry if (!dma) 436*ef270ab1SKenneth D. Merry return -1; 437*ef270ab1SKenneth D. Merry if (!buffer) 438*ef270ab1SKenneth D. Merry return -1; 439*ef270ab1SKenneth D. Merry if (buffer_length == 0) 440*ef270ab1SKenneth D. Merry return 0; 441*ef270ab1SKenneth D. Merry if (buffer_length > dma->size) 442*ef270ab1SKenneth D. Merry buffer_length = dma->size; 443*ef270ab1SKenneth D. Merry ocs_memcpy(dma->virt, buffer, buffer_length); 444*ef270ab1SKenneth D. Merry dma->len = buffer_length; 445*ef270ab1SKenneth D. Merry return buffer_length; 446*ef270ab1SKenneth D. Merry } 447*ef270ab1SKenneth D. Merry 448*ef270ab1SKenneth D. Merry int32_t 449*ef270ab1SKenneth D. Merry ocs_dma_copy_out(ocs_dma_t *dma, void *buffer, uint32_t buffer_length) 450*ef270ab1SKenneth D. Merry { 451*ef270ab1SKenneth D. Merry if (!dma) 452*ef270ab1SKenneth D. Merry return -1; 453*ef270ab1SKenneth D. Merry if (!buffer) 454*ef270ab1SKenneth D. Merry return -1; 455*ef270ab1SKenneth D. Merry if (buffer_length == 0) 456*ef270ab1SKenneth D. Merry return 0; 457*ef270ab1SKenneth D. Merry if (buffer_length > dma->len) 458*ef270ab1SKenneth D. Merry buffer_length = dma->len; 459*ef270ab1SKenneth D. Merry ocs_memcpy(buffer, dma->virt, buffer_length); 460*ef270ab1SKenneth D. Merry return buffer_length; 461*ef270ab1SKenneth D. Merry } 462*ef270ab1SKenneth D. Merry 463*ef270ab1SKenneth D. Merry /** 464*ef270ab1SKenneth D. Merry * @ingroup os 465*ef270ab1SKenneth D. Merry * @brief Initialize a lock 466*ef270ab1SKenneth D. Merry * 467*ef270ab1SKenneth D. Merry * @param lock lock to initialize 468*ef270ab1SKenneth D. Merry * @param name string identifier for the lock 469*ef270ab1SKenneth D. Merry */ 470*ef270ab1SKenneth D. Merry void 471*ef270ab1SKenneth D. Merry ocs_lock_init(void *os, ocs_lock_t *lock, const char *name, ...) 472*ef270ab1SKenneth D. Merry { 473*ef270ab1SKenneth D. Merry va_list ap; 474*ef270ab1SKenneth D. Merry 475*ef270ab1SKenneth D. Merry va_start(ap, name); 476*ef270ab1SKenneth D. Merry ocs_vsnprintf(lock->name, MAX_LOCK_DESC_LEN, name, ap); 477*ef270ab1SKenneth D. Merry va_end(ap); 478*ef270ab1SKenneth D. Merry 479*ef270ab1SKenneth D. Merry mtx_init(&lock->lock, lock->name, NULL, MTX_DEF); 480*ef270ab1SKenneth D. Merry } 481*ef270ab1SKenneth D. Merry 482*ef270ab1SKenneth D. Merry /** 483*ef270ab1SKenneth D. Merry * @brief Allocate a bit map 484*ef270ab1SKenneth D. Merry * 485*ef270ab1SKenneth D. Merry * For BSD, this is a simple character string 486*ef270ab1SKenneth D. Merry * 487*ef270ab1SKenneth D. Merry * @param n_bits number of bits in bit map 488*ef270ab1SKenneth D. Merry * 489*ef270ab1SKenneth D. Merry * @return pointer to the bit map, NULL on error 490*ef270ab1SKenneth D. Merry */ 491*ef270ab1SKenneth D. Merry ocs_bitmap_t * 492*ef270ab1SKenneth D. Merry ocs_bitmap_alloc(uint32_t n_bits) 493*ef270ab1SKenneth D. Merry { 494*ef270ab1SKenneth D. Merry 495*ef270ab1SKenneth D. Merry return malloc(bitstr_size(n_bits), M_OCS, M_ZERO | M_NOWAIT); 496*ef270ab1SKenneth D. Merry } 497*ef270ab1SKenneth D. Merry 498*ef270ab1SKenneth D. Merry /** 499*ef270ab1SKenneth D. Merry * @brief Free a bit map 500*ef270ab1SKenneth D. Merry * 501*ef270ab1SKenneth D. Merry * @param bitmap pointer to previously allocated bit map 502*ef270ab1SKenneth D. Merry */ 503*ef270ab1SKenneth D. Merry void 504*ef270ab1SKenneth D. Merry ocs_bitmap_free(ocs_bitmap_t *bitmap) 505*ef270ab1SKenneth D. Merry { 506*ef270ab1SKenneth D. Merry 507*ef270ab1SKenneth D. Merry free(bitmap, M_OCS); 508*ef270ab1SKenneth D. Merry } 509*ef270ab1SKenneth D. Merry 510*ef270ab1SKenneth D. Merry /** 511*ef270ab1SKenneth D. Merry * @brief find next unset bit and set it 512*ef270ab1SKenneth D. Merry * 513*ef270ab1SKenneth D. Merry * @param bitmap bit map to search 514*ef270ab1SKenneth D. Merry * @param n_bits number of bits in map 515*ef270ab1SKenneth D. Merry * 516*ef270ab1SKenneth D. Merry * @return bit position or -1 if map is full 517*ef270ab1SKenneth D. Merry */ 518*ef270ab1SKenneth D. Merry int32_t 519*ef270ab1SKenneth D. Merry ocs_bitmap_find(ocs_bitmap_t *bitmap, uint32_t n_bits) 520*ef270ab1SKenneth D. Merry { 521*ef270ab1SKenneth D. Merry int32_t position = -1; 522*ef270ab1SKenneth D. Merry 523*ef270ab1SKenneth D. Merry bit_ffc(bitmap, n_bits, &position); 524*ef270ab1SKenneth D. Merry 525*ef270ab1SKenneth D. Merry if (-1 != position) { 526*ef270ab1SKenneth D. Merry bit_set(bitmap, position); 527*ef270ab1SKenneth D. Merry } 528*ef270ab1SKenneth D. Merry 529*ef270ab1SKenneth D. Merry return position; 530*ef270ab1SKenneth D. Merry } 531*ef270ab1SKenneth D. Merry 532*ef270ab1SKenneth D. Merry /** 533*ef270ab1SKenneth D. Merry * @brief search for next (un)set bit 534*ef270ab1SKenneth D. Merry * 535*ef270ab1SKenneth D. Merry * @param bitmap bit map to search 536*ef270ab1SKenneth D. Merry * @param set search for a set or unset bit 537*ef270ab1SKenneth D. Merry * @param n_bits number of bits in map 538*ef270ab1SKenneth D. Merry * 539*ef270ab1SKenneth D. Merry * @return bit position or -1 540*ef270ab1SKenneth D. Merry */ 541*ef270ab1SKenneth D. Merry int32_t 542*ef270ab1SKenneth D. Merry ocs_bitmap_search(ocs_bitmap_t *bitmap, uint8_t set, uint32_t n_bits) 543*ef270ab1SKenneth D. Merry { 544*ef270ab1SKenneth D. Merry int32_t position; 545*ef270ab1SKenneth D. Merry 546*ef270ab1SKenneth D. Merry if (!bitmap) { 547*ef270ab1SKenneth D. Merry return -1; 548*ef270ab1SKenneth D. Merry } 549*ef270ab1SKenneth D. Merry 550*ef270ab1SKenneth D. Merry if (set) { 551*ef270ab1SKenneth D. Merry bit_ffs(bitmap, n_bits, &position); 552*ef270ab1SKenneth D. Merry } else { 553*ef270ab1SKenneth D. Merry bit_ffc(bitmap, n_bits, &position); 554*ef270ab1SKenneth D. Merry } 555*ef270ab1SKenneth D. Merry 556*ef270ab1SKenneth D. Merry return position; 557*ef270ab1SKenneth D. Merry } 558*ef270ab1SKenneth D. Merry 559*ef270ab1SKenneth D. Merry /** 560*ef270ab1SKenneth D. Merry * @brief clear the specified bit 561*ef270ab1SKenneth D. Merry * 562*ef270ab1SKenneth D. Merry * @param bitmap pointer to bit map 563*ef270ab1SKenneth D. Merry * @param bit bit number to clear 564*ef270ab1SKenneth D. Merry */ 565*ef270ab1SKenneth D. Merry void 566*ef270ab1SKenneth D. Merry ocs_bitmap_clear(ocs_bitmap_t *bitmap, uint32_t bit) 567*ef270ab1SKenneth D. Merry { 568*ef270ab1SKenneth D. Merry bit_clear(bitmap, bit); 569*ef270ab1SKenneth D. Merry } 570*ef270ab1SKenneth D. Merry 571*ef270ab1SKenneth D. Merry void _ocs_log(ocs_t *ocs, const char *func_name, int line, const char *fmt, ...) 572*ef270ab1SKenneth D. Merry { 573*ef270ab1SKenneth D. Merry va_list ap; 574*ef270ab1SKenneth D. Merry char buf[256]; 575*ef270ab1SKenneth D. Merry char *p = buf; 576*ef270ab1SKenneth D. Merry 577*ef270ab1SKenneth D. Merry va_start(ap, fmt); 578*ef270ab1SKenneth D. Merry 579*ef270ab1SKenneth D. Merry /* TODO: Add Current PID info here. */ 580*ef270ab1SKenneth D. Merry 581*ef270ab1SKenneth D. Merry p += snprintf(p, sizeof(buf) - (p - buf), "%s: ", DRV_NAME); 582*ef270ab1SKenneth D. Merry p += snprintf(p, sizeof(buf) - (p - buf), "%s:", func_name); 583*ef270ab1SKenneth D. Merry p += snprintf(p, sizeof(buf) - (p - buf), "%i:", line); 584*ef270ab1SKenneth D. Merry p += snprintf(p, sizeof(buf) - (p - buf), "%s:", (ocs != NULL) ? device_get_nameunit(ocs->dev) : ""); 585*ef270ab1SKenneth D. Merry p += vsnprintf(p, sizeof(buf) - (p - buf), fmt, ap); 586*ef270ab1SKenneth D. Merry 587*ef270ab1SKenneth D. Merry va_end(ap); 588*ef270ab1SKenneth D. Merry 589*ef270ab1SKenneth D. Merry printf("%s", buf); 590*ef270ab1SKenneth D. Merry } 591*ef270ab1SKenneth D. Merry 592*ef270ab1SKenneth D. Merry /** 593*ef270ab1SKenneth D. Merry * @brief Common thread call function 594*ef270ab1SKenneth D. Merry * 595*ef270ab1SKenneth D. Merry * This is the common function called whenever a thread instantiated by ocs_thread_create() is started. 596*ef270ab1SKenneth D. Merry * It captures the return value from the actual thread function and stashes it in the thread object, to 597*ef270ab1SKenneth D. Merry * be later retrieved by ocs_thread_get_retval(), and calls kthread_exit(), the proscribed method to terminate 598*ef270ab1SKenneth D. Merry * a thread. 599*ef270ab1SKenneth D. Merry * 600*ef270ab1SKenneth D. Merry * @param arg a pointer to the thread object 601*ef270ab1SKenneth D. Merry * 602*ef270ab1SKenneth D. Merry * @return none 603*ef270ab1SKenneth D. Merry */ 604*ef270ab1SKenneth D. Merry 605*ef270ab1SKenneth D. Merry static void 606*ef270ab1SKenneth D. Merry ocs_thread_call_fctn(void *arg) 607*ef270ab1SKenneth D. Merry { 608*ef270ab1SKenneth D. Merry ocs_thread_t *thread = arg; 609*ef270ab1SKenneth D. Merry thread->retval = (*thread->fctn)(thread->arg); 610*ef270ab1SKenneth D. Merry ocs_free(NULL, thread->name, ocs_strlen(thread->name+1)); 611*ef270ab1SKenneth D. Merry kthread_exit(); 612*ef270ab1SKenneth D. Merry } 613*ef270ab1SKenneth D. Merry 614*ef270ab1SKenneth D. Merry /** 615*ef270ab1SKenneth D. Merry * @brief Create a kernel thread 616*ef270ab1SKenneth D. Merry * 617*ef270ab1SKenneth D. Merry * Creates a kernel thread and optionally starts it. If the thread is not immediately 618*ef270ab1SKenneth D. Merry * started, ocs_thread_start() should be called at some later point. 619*ef270ab1SKenneth D. Merry * 620*ef270ab1SKenneth D. Merry * @param os OS handle 621*ef270ab1SKenneth D. Merry * @param thread pointer to thread object 622*ef270ab1SKenneth D. Merry * @param fctn function for thread to be begin executing 623*ef270ab1SKenneth D. Merry * @param name text name to identify thread 624*ef270ab1SKenneth D. Merry * @param arg application specific argument passed to thread function 625*ef270ab1SKenneth D. Merry * @param start start option, OCS_THREAD_RUN will start the thread immediately, 626*ef270ab1SKenneth D. Merry * OCS_THREAD_CREATE will create but not start the thread 627*ef270ab1SKenneth D. Merry * 628*ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 629*ef270ab1SKenneth D. Merry */ 630*ef270ab1SKenneth D. Merry 631*ef270ab1SKenneth D. Merry int32_t 632*ef270ab1SKenneth D. Merry ocs_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) 633*ef270ab1SKenneth D. Merry { 634*ef270ab1SKenneth D. Merry int32_t rc = 0; 635*ef270ab1SKenneth D. Merry 636*ef270ab1SKenneth D. Merry ocs_memset(thread, 0, sizeof(thread)); 637*ef270ab1SKenneth D. Merry 638*ef270ab1SKenneth D. Merry thread->fctn = fctn; 639*ef270ab1SKenneth D. Merry thread->name = ocs_strdup(name); 640*ef270ab1SKenneth D. Merry if (thread->name == NULL) { 641*ef270ab1SKenneth D. Merry thread->name = "unknown"; 642*ef270ab1SKenneth D. Merry } 643*ef270ab1SKenneth D. Merry thread->arg = arg; 644*ef270ab1SKenneth D. Merry 645*ef270ab1SKenneth D. Merry ocs_atomic_set(&thread->terminate, 0); 646*ef270ab1SKenneth D. Merry 647*ef270ab1SKenneth D. Merry rc = kthread_add(ocs_thread_call_fctn, thread, NULL, &thread->tcb, (start == OCS_THREAD_CREATE) ? RFSTOPPED : 0, 648*ef270ab1SKenneth D. Merry OCS_THREAD_DEFAULT_STACK_SIZE_PAGES, "%s", name); 649*ef270ab1SKenneth D. Merry 650*ef270ab1SKenneth D. Merry return rc; 651*ef270ab1SKenneth D. Merry } 652*ef270ab1SKenneth D. Merry 653*ef270ab1SKenneth D. Merry /** 654*ef270ab1SKenneth D. Merry * @brief Start a thread 655*ef270ab1SKenneth D. Merry * 656*ef270ab1SKenneth D. Merry * Starts a thread that was created with OCS_THREAD_CREATE rather than OCS_THREAD_RUN 657*ef270ab1SKenneth D. Merry * 658*ef270ab1SKenneth D. Merry * @param thread pointer to thread object 659*ef270ab1SKenneth D. Merry * 660*ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 661*ef270ab1SKenneth D. Merry */ 662*ef270ab1SKenneth D. Merry 663*ef270ab1SKenneth D. Merry int32_t ocs_thread_start(ocs_thread_t *thread) 664*ef270ab1SKenneth D. Merry { 665*ef270ab1SKenneth D. Merry sched_add(thread->tcb, SRQ_BORING); 666*ef270ab1SKenneth D. Merry return 0; 667*ef270ab1SKenneth D. Merry } 668*ef270ab1SKenneth D. Merry 669*ef270ab1SKenneth D. Merry /** 670*ef270ab1SKenneth D. Merry * @brief return thread argument 671*ef270ab1SKenneth D. Merry * 672*ef270ab1SKenneth D. Merry * Returns a pointer to the thread's application specific argument 673*ef270ab1SKenneth D. Merry * 674*ef270ab1SKenneth D. Merry * @param mythread pointer to the thread object 675*ef270ab1SKenneth D. Merry * 676*ef270ab1SKenneth D. Merry * @return pointer to application specific argument 677*ef270ab1SKenneth D. Merry */ 678*ef270ab1SKenneth D. Merry 679*ef270ab1SKenneth D. Merry void *ocs_thread_get_arg(ocs_thread_t *mythread) 680*ef270ab1SKenneth D. Merry { 681*ef270ab1SKenneth D. Merry return mythread->arg; 682*ef270ab1SKenneth D. Merry } 683*ef270ab1SKenneth D. Merry 684*ef270ab1SKenneth D. Merry /** 685*ef270ab1SKenneth D. Merry * @brief Request thread stop 686*ef270ab1SKenneth D. Merry * 687*ef270ab1SKenneth D. Merry * A stop request is made to the thread. This is a voluntary call, the thread needs 688*ef270ab1SKenneth D. Merry * to periodically query its terminate request using ocs_thread_terminate_requested() 689*ef270ab1SKenneth D. Merry * 690*ef270ab1SKenneth D. Merry * @param thread pointer to thread object 691*ef270ab1SKenneth D. Merry * 692*ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 693*ef270ab1SKenneth D. Merry */ 694*ef270ab1SKenneth D. Merry 695*ef270ab1SKenneth D. Merry int32_t 696*ef270ab1SKenneth D. Merry ocs_thread_terminate(ocs_thread_t *thread) 697*ef270ab1SKenneth D. Merry { 698*ef270ab1SKenneth D. Merry ocs_atomic_set(&thread->terminate, 1); 699*ef270ab1SKenneth D. Merry return 0; 700*ef270ab1SKenneth D. Merry } 701*ef270ab1SKenneth D. Merry 702*ef270ab1SKenneth D. Merry /** 703*ef270ab1SKenneth D. Merry * @brief See if a terminate request has been made 704*ef270ab1SKenneth D. Merry * 705*ef270ab1SKenneth D. Merry * Check to see if a stop request has been made to the current thread. This 706*ef270ab1SKenneth D. Merry * function would be used by a thread to see if it should terminate. 707*ef270ab1SKenneth D. Merry * 708*ef270ab1SKenneth D. Merry * @return returns non-zero if a stop has been requested 709*ef270ab1SKenneth D. Merry */ 710*ef270ab1SKenneth D. Merry 711*ef270ab1SKenneth D. Merry int32_t ocs_thread_terminate_requested(ocs_thread_t *thread) 712*ef270ab1SKenneth D. Merry { 713*ef270ab1SKenneth D. Merry return ocs_atomic_read(&thread->terminate); 714*ef270ab1SKenneth D. Merry } 715*ef270ab1SKenneth D. Merry 716*ef270ab1SKenneth D. Merry /** 717*ef270ab1SKenneth D. Merry * @brief Retrieve threads return value 718*ef270ab1SKenneth D. Merry * 719*ef270ab1SKenneth D. Merry * After a thread has terminated, it's return value may be retrieved with this function. 720*ef270ab1SKenneth D. Merry * 721*ef270ab1SKenneth D. Merry * @param thread pointer to thread object 722*ef270ab1SKenneth D. Merry * 723*ef270ab1SKenneth D. Merry * @return return value from thread function 724*ef270ab1SKenneth D. Merry */ 725*ef270ab1SKenneth D. Merry 726*ef270ab1SKenneth D. Merry int32_t 727*ef270ab1SKenneth D. Merry ocs_thread_get_retval(ocs_thread_t *thread) 728*ef270ab1SKenneth D. Merry { 729*ef270ab1SKenneth D. Merry return thread->retval; 730*ef270ab1SKenneth D. Merry } 731*ef270ab1SKenneth D. Merry 732*ef270ab1SKenneth D. Merry /** 733*ef270ab1SKenneth D. Merry * @brief Request that the currently running thread yield 734*ef270ab1SKenneth D. Merry * 735*ef270ab1SKenneth D. Merry * The currently running thread yields to the scheduler 736*ef270ab1SKenneth D. Merry * 737*ef270ab1SKenneth D. Merry * @param thread pointer to thread (ignored) 738*ef270ab1SKenneth D. Merry * 739*ef270ab1SKenneth D. Merry * @return none 740*ef270ab1SKenneth D. Merry */ 741*ef270ab1SKenneth D. Merry 742*ef270ab1SKenneth D. Merry void 743*ef270ab1SKenneth D. Merry ocs_thread_yield(ocs_thread_t *thread) { 744*ef270ab1SKenneth D. Merry pause("thread yield", 1); 745*ef270ab1SKenneth D. Merry } 746*ef270ab1SKenneth D. Merry 747*ef270ab1SKenneth D. Merry ocs_thread_t * 748*ef270ab1SKenneth D. Merry ocs_thread_self(void) 749*ef270ab1SKenneth D. Merry { 750*ef270ab1SKenneth D. Merry ocs_printf(">>> %s not implemented\n", __func__); 751*ef270ab1SKenneth D. Merry ocs_abort(); 752*ef270ab1SKenneth D. Merry } 753*ef270ab1SKenneth D. Merry 754*ef270ab1SKenneth D. Merry int32_t 755*ef270ab1SKenneth D. Merry ocs_thread_setcpu(ocs_thread_t *thread, uint32_t cpu) 756*ef270ab1SKenneth D. Merry { 757*ef270ab1SKenneth D. Merry ocs_printf(">>> %s not implemented\n", __func__); 758*ef270ab1SKenneth D. Merry return -1; 759*ef270ab1SKenneth D. Merry } 760*ef270ab1SKenneth D. Merry 761*ef270ab1SKenneth D. Merry int32_t 762*ef270ab1SKenneth D. Merry ocs_thread_getcpu(void) 763*ef270ab1SKenneth D. Merry { 764*ef270ab1SKenneth D. Merry return curcpu; 765*ef270ab1SKenneth D. Merry } 766*ef270ab1SKenneth D. Merry 767*ef270ab1SKenneth D. Merry int 768*ef270ab1SKenneth D. Merry ocs_sem_init(ocs_sem_t *sem, int val, const char *name, ...) 769*ef270ab1SKenneth D. Merry { 770*ef270ab1SKenneth D. Merry va_list ap; 771*ef270ab1SKenneth D. Merry 772*ef270ab1SKenneth D. Merry va_start(ap, name); 773*ef270ab1SKenneth D. Merry ocs_vsnprintf(sem->name, sizeof(sem->name), name, ap); 774*ef270ab1SKenneth D. Merry va_end(ap); 775*ef270ab1SKenneth D. Merry 776*ef270ab1SKenneth D. Merry sema_init(&sem->sem, val, sem->name); 777*ef270ab1SKenneth D. Merry return 0; 778*ef270ab1SKenneth D. Merry } 779*ef270ab1SKenneth D. Merry 780*ef270ab1SKenneth D. Merry /** 781*ef270ab1SKenneth D. Merry * @ingroup os 782*ef270ab1SKenneth D. Merry * @brief Copy user arguments in to kernel space for an ioctl 783*ef270ab1SKenneth D. Merry * @par Description 784*ef270ab1SKenneth D. Merry * This function is called at the beginning of an ioctl function 785*ef270ab1SKenneth D. Merry * to copy the ioctl argument from user space to kernel space. 786*ef270ab1SKenneth D. Merry * 787*ef270ab1SKenneth D. Merry * BSD handles this for us - arg is already in kernel space, 788*ef270ab1SKenneth D. Merry * so we just return it. 789*ef270ab1SKenneth D. Merry * 790*ef270ab1SKenneth D. Merry * @param os OS handle 791*ef270ab1SKenneth D. Merry * @param arg The argument passed to the ioctl function 792*ef270ab1SKenneth D. Merry * @param size The size of the structure pointed to by arg 793*ef270ab1SKenneth D. Merry * 794*ef270ab1SKenneth D. Merry * @return A pointer to a kernel space copy of the argument on 795*ef270ab1SKenneth D. Merry * success; NULL on failure 796*ef270ab1SKenneth D. Merry */ 797*ef270ab1SKenneth D. Merry void *ocs_ioctl_preprocess(ocs_os_handle_t os, void *arg, size_t size) 798*ef270ab1SKenneth D. Merry { 799*ef270ab1SKenneth D. Merry return arg; 800*ef270ab1SKenneth D. Merry } 801*ef270ab1SKenneth D. Merry 802*ef270ab1SKenneth D. Merry /** 803*ef270ab1SKenneth D. Merry * @ingroup os 804*ef270ab1SKenneth D. Merry * @brief Copy results of an ioctl back to user space 805*ef270ab1SKenneth D. Merry * @par Description 806*ef270ab1SKenneth D. Merry * This function is called at the end of ioctl processing to 807*ef270ab1SKenneth D. Merry * copy the argument back to user space. 808*ef270ab1SKenneth D. Merry * 809*ef270ab1SKenneth D. Merry * BSD handles this for us. 810*ef270ab1SKenneth D. Merry * 811*ef270ab1SKenneth D. Merry * @param os OS handle 812*ef270ab1SKenneth D. Merry * @param arg The argument passed to the ioctl function 813*ef270ab1SKenneth D. Merry * @param kern_ptr A pointer to the kernel space copy of the 814*ef270ab1SKenneth D. Merry * argument 815*ef270ab1SKenneth D. Merry * @param size The size of the structure pointed to by arg. 816*ef270ab1SKenneth D. Merry * 817*ef270ab1SKenneth D. Merry * @return Returns 0. 818*ef270ab1SKenneth D. Merry */ 819*ef270ab1SKenneth D. Merry int32_t ocs_ioctl_postprocess(ocs_os_handle_t os, void *arg, void *kern_ptr, size_t size) 820*ef270ab1SKenneth D. Merry { 821*ef270ab1SKenneth D. Merry return 0; 822*ef270ab1SKenneth D. Merry } 823*ef270ab1SKenneth D. Merry 824*ef270ab1SKenneth D. Merry /** 825*ef270ab1SKenneth D. Merry * @ingroup os 826*ef270ab1SKenneth D. Merry * @brief Free memory allocated by ocs_ioctl_preprocess 827*ef270ab1SKenneth D. Merry * @par Description 828*ef270ab1SKenneth D. Merry * This function is called in the event of an error in ioctl 829*ef270ab1SKenneth D. Merry * processing. For operating environments where ocs_ioctlpreprocess 830*ef270ab1SKenneth D. Merry * allocates memory, this call frees the memory without copying 831*ef270ab1SKenneth D. Merry * results back to user space. 832*ef270ab1SKenneth D. Merry * 833*ef270ab1SKenneth D. Merry * For BSD, because no memory was allocated in ocs_ioctl_preprocess, 834*ef270ab1SKenneth D. Merry * nothing needs to be done here. 835*ef270ab1SKenneth D. Merry * 836*ef270ab1SKenneth D. Merry * @param os OS handle 837*ef270ab1SKenneth D. Merry * @param kern_ptr A pointer to the kernel space copy of the 838*ef270ab1SKenneth D. Merry * argument 839*ef270ab1SKenneth D. Merry * @param size The size of the structure pointed to by arg. 840*ef270ab1SKenneth D. Merry * 841*ef270ab1SKenneth D. Merry * @return Returns nothing. 842*ef270ab1SKenneth D. Merry */ 843*ef270ab1SKenneth D. Merry void ocs_ioctl_free(ocs_os_handle_t os, void *kern_ptr, size_t size) 844*ef270ab1SKenneth D. Merry { 845*ef270ab1SKenneth D. Merry return; 846*ef270ab1SKenneth D. Merry } 847*ef270ab1SKenneth D. Merry 848*ef270ab1SKenneth D. Merry void ocs_intr_disable(ocs_os_handle_t os) 849*ef270ab1SKenneth D. Merry { 850*ef270ab1SKenneth D. Merry } 851*ef270ab1SKenneth D. Merry 852*ef270ab1SKenneth D. Merry void ocs_intr_enable(ocs_os_handle_t os) 853*ef270ab1SKenneth D. Merry { 854*ef270ab1SKenneth D. Merry } 855*ef270ab1SKenneth D. Merry 856*ef270ab1SKenneth D. Merry void ocs_print_stack(void) 857*ef270ab1SKenneth D. Merry { 858*ef270ab1SKenneth D. Merry struct stack st; 859*ef270ab1SKenneth D. Merry 860*ef270ab1SKenneth D. Merry stack_zero(&st); 861*ef270ab1SKenneth D. Merry stack_save(&st); 862*ef270ab1SKenneth D. Merry stack_print(&st); 863*ef270ab1SKenneth D. Merry } 864*ef270ab1SKenneth D. Merry 865*ef270ab1SKenneth D. Merry void ocs_abort(void) 866*ef270ab1SKenneth D. Merry { 867*ef270ab1SKenneth D. Merry panic(">>> abort/panic\n"); 868*ef270ab1SKenneth D. Merry } 869*ef270ab1SKenneth D. Merry 870*ef270ab1SKenneth D. Merry const char * 871*ef270ab1SKenneth D. Merry ocs_pci_model(uint16_t vendor, uint16_t device) 872*ef270ab1SKenneth D. Merry { 873*ef270ab1SKenneth D. Merry switch (device) { 874*ef270ab1SKenneth D. Merry case PCI_PRODUCT_EMULEX_OCE16002: return "OCE16002"; 875*ef270ab1SKenneth D. Merry case PCI_PRODUCT_EMULEX_OCE1600_VF: return "OCE1600_VF"; 876*ef270ab1SKenneth D. Merry case PCI_PRODUCT_EMULEX_OCE50102: return "OCE50102"; 877*ef270ab1SKenneth D. Merry case PCI_PRODUCT_EMULEX_OCE50102_VF: return "OCE50102_VR"; 878*ef270ab1SKenneth D. Merry default: 879*ef270ab1SKenneth D. Merry break; 880*ef270ab1SKenneth D. Merry } 881*ef270ab1SKenneth D. Merry 882*ef270ab1SKenneth D. Merry return "unknown"; 883*ef270ab1SKenneth D. Merry } 884*ef270ab1SKenneth D. Merry 885*ef270ab1SKenneth D. Merry int32_t 886*ef270ab1SKenneth D. Merry ocs_get_bus_dev_func(ocs_t *ocs, uint8_t* bus, uint8_t* dev, uint8_t* func) 887*ef270ab1SKenneth D. Merry { 888*ef270ab1SKenneth D. Merry *bus = pci_get_bus(ocs->dev); 889*ef270ab1SKenneth D. Merry *dev = pci_get_slot(ocs->dev); 890*ef270ab1SKenneth D. Merry *func= pci_get_function(ocs->dev); 891*ef270ab1SKenneth D. Merry return 0; 892*ef270ab1SKenneth D. Merry } 893*ef270ab1SKenneth D. Merry 894*ef270ab1SKenneth D. Merry /** 895*ef270ab1SKenneth D. Merry * @brief return CPU information 896*ef270ab1SKenneth D. Merry * 897*ef270ab1SKenneth D. Merry * This function populates the ocs_cpuinfo_t buffer with CPU information 898*ef270ab1SKenneth D. Merry * 899*ef270ab1SKenneth D. Merry * @param cpuinfo pointer to ocs_cpuinfo_t buffer 900*ef270ab1SKenneth D. Merry * 901*ef270ab1SKenneth D. Merry * @return returns 0 for success, a negative error code value for failure. 902*ef270ab1SKenneth D. Merry */ 903*ef270ab1SKenneth D. Merry extern int mp_ncpus; 904*ef270ab1SKenneth D. Merry int32_t 905*ef270ab1SKenneth D. Merry ocs_get_cpuinfo(ocs_cpuinfo_t *cpuinfo) 906*ef270ab1SKenneth D. Merry { 907*ef270ab1SKenneth D. Merry cpuinfo->num_cpus = mp_ncpus; 908*ef270ab1SKenneth D. Merry return 0; 909*ef270ab1SKenneth D. Merry } 910*ef270ab1SKenneth D. Merry 911*ef270ab1SKenneth D. Merry uint32_t 912*ef270ab1SKenneth D. Merry ocs_get_num_cpus(void) 913*ef270ab1SKenneth D. Merry { 914*ef270ab1SKenneth D. Merry static ocs_cpuinfo_t cpuinfo; 915*ef270ab1SKenneth D. Merry 916*ef270ab1SKenneth D. Merry if (cpuinfo.num_cpus == 0) { 917*ef270ab1SKenneth D. Merry ocs_get_cpuinfo(&cpuinfo); 918*ef270ab1SKenneth D. Merry } 919*ef270ab1SKenneth D. Merry return cpuinfo.num_cpus; 920*ef270ab1SKenneth D. Merry } 921*ef270ab1SKenneth D. Merry 922*ef270ab1SKenneth D. Merry 923*ef270ab1SKenneth D. Merry void 924*ef270ab1SKenneth D. Merry __ocs_callout(void *t) 925*ef270ab1SKenneth D. Merry { 926*ef270ab1SKenneth D. Merry ocs_timer_t *timer = t; 927*ef270ab1SKenneth D. Merry 928*ef270ab1SKenneth D. Merry if (callout_pending(&timer->callout)) { 929*ef270ab1SKenneth D. Merry /* Callout was reset */ 930*ef270ab1SKenneth D. Merry return; 931*ef270ab1SKenneth D. Merry } 932*ef270ab1SKenneth D. Merry 933*ef270ab1SKenneth D. Merry if (!callout_active(&timer->callout)) { 934*ef270ab1SKenneth D. Merry /* Callout was stopped */ 935*ef270ab1SKenneth D. Merry return; 936*ef270ab1SKenneth D. Merry } 937*ef270ab1SKenneth D. Merry 938*ef270ab1SKenneth D. Merry callout_deactivate(&timer->callout); 939*ef270ab1SKenneth D. Merry 940*ef270ab1SKenneth D. Merry if (timer->func) { 941*ef270ab1SKenneth D. Merry timer->func(timer->data); 942*ef270ab1SKenneth D. Merry } 943*ef270ab1SKenneth D. Merry } 944*ef270ab1SKenneth D. Merry 945*ef270ab1SKenneth D. Merry int32_t 946*ef270ab1SKenneth D. Merry ocs_setup_timer(ocs_os_handle_t os, ocs_timer_t *timer, void(*func)(void *arg), void *data, uint32_t timeout_ms) 947*ef270ab1SKenneth D. Merry { 948*ef270ab1SKenneth D. Merry struct timeval tv; 949*ef270ab1SKenneth D. Merry int hz; 950*ef270ab1SKenneth D. Merry 951*ef270ab1SKenneth D. Merry if (timer == NULL) { 952*ef270ab1SKenneth D. Merry ocs_log_err(NULL, "bad parameter\n"); 953*ef270ab1SKenneth D. Merry return -1; 954*ef270ab1SKenneth D. Merry } 955*ef270ab1SKenneth D. Merry 956*ef270ab1SKenneth D. Merry if (!mtx_initialized(&timer->lock)) { 957*ef270ab1SKenneth D. Merry mtx_init(&timer->lock, "ocs_timer", NULL, MTX_DEF); 958*ef270ab1SKenneth D. Merry } 959*ef270ab1SKenneth D. Merry 960*ef270ab1SKenneth D. Merry callout_init_mtx(&timer->callout, &timer->lock, 0); 961*ef270ab1SKenneth D. Merry 962*ef270ab1SKenneth D. Merry timer->func = func; 963*ef270ab1SKenneth D. Merry timer->data = data; 964*ef270ab1SKenneth D. Merry 965*ef270ab1SKenneth D. Merry tv.tv_sec = timeout_ms / 1000; 966*ef270ab1SKenneth D. Merry tv.tv_usec = (timeout_ms % 1000) * 1000; 967*ef270ab1SKenneth D. Merry 968*ef270ab1SKenneth D. Merry hz = tvtohz(&tv); 969*ef270ab1SKenneth D. Merry if (hz < 0) 970*ef270ab1SKenneth D. Merry hz = INT32_MAX; 971*ef270ab1SKenneth D. Merry if (hz == 0) 972*ef270ab1SKenneth D. Merry hz = 1; 973*ef270ab1SKenneth D. Merry 974*ef270ab1SKenneth D. Merry mtx_lock(&timer->lock); 975*ef270ab1SKenneth D. Merry callout_reset(&timer->callout, hz, __ocs_callout, timer); 976*ef270ab1SKenneth D. Merry mtx_unlock(&timer->lock); 977*ef270ab1SKenneth D. Merry 978*ef270ab1SKenneth D. Merry return 0; 979*ef270ab1SKenneth D. Merry } 980*ef270ab1SKenneth D. Merry 981*ef270ab1SKenneth D. Merry int32_t 982*ef270ab1SKenneth D. Merry ocs_mod_timer(ocs_timer_t *timer, uint32_t timeout_ms) 983*ef270ab1SKenneth D. Merry { 984*ef270ab1SKenneth D. Merry struct timeval tv; 985*ef270ab1SKenneth D. Merry int hz; 986*ef270ab1SKenneth D. Merry 987*ef270ab1SKenneth D. Merry if (timer == NULL) { 988*ef270ab1SKenneth D. Merry ocs_log_err(NULL, "bad parameter\n"); 989*ef270ab1SKenneth D. Merry return -1; 990*ef270ab1SKenneth D. Merry } 991*ef270ab1SKenneth D. Merry 992*ef270ab1SKenneth D. Merry tv.tv_sec = timeout_ms / 1000; 993*ef270ab1SKenneth D. Merry tv.tv_usec = (timeout_ms % 1000) * 1000; 994*ef270ab1SKenneth D. Merry 995*ef270ab1SKenneth D. Merry hz = tvtohz(&tv); 996*ef270ab1SKenneth D. Merry if (hz < 0) 997*ef270ab1SKenneth D. Merry hz = INT32_MAX; 998*ef270ab1SKenneth D. Merry if (hz == 0) 999*ef270ab1SKenneth D. Merry hz = 1; 1000*ef270ab1SKenneth D. Merry 1001*ef270ab1SKenneth D. Merry mtx_lock(&timer->lock); 1002*ef270ab1SKenneth D. Merry callout_reset(&timer->callout, hz, __ocs_callout, timer); 1003*ef270ab1SKenneth D. Merry mtx_unlock(&timer->lock); 1004*ef270ab1SKenneth D. Merry 1005*ef270ab1SKenneth D. Merry return 0; 1006*ef270ab1SKenneth D. Merry } 1007*ef270ab1SKenneth D. Merry 1008*ef270ab1SKenneth D. Merry int32_t 1009*ef270ab1SKenneth D. Merry ocs_timer_pending(ocs_timer_t *timer) 1010*ef270ab1SKenneth D. Merry { 1011*ef270ab1SKenneth D. Merry return callout_active(&timer->callout); 1012*ef270ab1SKenneth D. Merry } 1013*ef270ab1SKenneth D. Merry 1014*ef270ab1SKenneth D. Merry int32_t 1015*ef270ab1SKenneth D. Merry ocs_del_timer(ocs_timer_t *timer) 1016*ef270ab1SKenneth D. Merry { 1017*ef270ab1SKenneth D. Merry 1018*ef270ab1SKenneth D. Merry mtx_lock(&timer->lock); 1019*ef270ab1SKenneth D. Merry callout_stop(&timer->callout); 1020*ef270ab1SKenneth D. Merry mtx_unlock(&timer->lock); 1021*ef270ab1SKenneth D. Merry 1022*ef270ab1SKenneth D. Merry return 0; 1023*ef270ab1SKenneth D. Merry } 1024*ef270ab1SKenneth D. Merry 1025*ef270ab1SKenneth D. Merry char * 1026*ef270ab1SKenneth D. Merry ocs_strdup(const char *s) 1027*ef270ab1SKenneth D. Merry { 1028*ef270ab1SKenneth D. Merry uint32_t l = strlen(s); 1029*ef270ab1SKenneth D. Merry char *d; 1030*ef270ab1SKenneth D. Merry 1031*ef270ab1SKenneth D. Merry d = ocs_malloc(NULL, l+1, OCS_M_NOWAIT); 1032*ef270ab1SKenneth D. Merry if (d != NULL) { 1033*ef270ab1SKenneth D. Merry ocs_strcpy(d, s); 1034*ef270ab1SKenneth D. Merry } 1035*ef270ab1SKenneth D. Merry return d; 1036*ef270ab1SKenneth D. Merry } 1037*ef270ab1SKenneth D. Merry 1038*ef270ab1SKenneth D. Merry void 1039*ef270ab1SKenneth D. Merry _ocs_assert(const char *cond, const char *filename, int linenum) 1040*ef270ab1SKenneth D. Merry { 1041*ef270ab1SKenneth D. Merry const char *fn = strrchr(__FILE__, '/'); 1042*ef270ab1SKenneth D. Merry 1043*ef270ab1SKenneth D. Merry ocs_log_err(NULL, "%s(%d) assertion (%s) failed\n", (fn ? fn + 1 : filename), linenum, cond); 1044*ef270ab1SKenneth D. Merry ocs_print_stack(); 1045*ef270ab1SKenneth D. Merry ocs_save_ddump_all(OCS_DDUMP_FLAGS_WQES|OCS_DDUMP_FLAGS_CQES|OCS_DDUMP_FLAGS_MQES, -1, TRUE); 1046*ef270ab1SKenneth D. Merry } 1047