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