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