1 /*- 2 * Copyright (c) 2018 Microsemi Corporation. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* $FreeBSD$ */ 28 29 #include "smartpqi_includes.h" 30 31 MALLOC_DEFINE(M_SMARTPQI, "smartpqi", "Buffers for the smartpqi(4) driver"); 32 33 /* 34 * DMA map load callback function 35 */ 36 static void 37 os_dma_map(void *arg, bus_dma_segment_t *segs, int nseg, int error) 38 { 39 bus_addr_t *paddr = (bus_addr_t *)arg; 40 *paddr = segs[0].ds_addr; 41 } 42 43 /* 44 * DMA mem resource allocation wrapper function 45 */ 46 int os_dma_mem_alloc(pqisrc_softstate_t *softs, struct dma_mem *dma_mem) 47 { 48 int ret = 0; 49 50 /* DBG_FUNC("IN\n"); */ 51 52 /* DMA memory needed - allocate it */ 53 if ((ret = bus_dma_tag_create( 54 softs->os_specific.pqi_parent_dmat, /* parent */ 55 dma_mem->align, 0, /* algnmnt, boundary */ 56 BUS_SPACE_MAXADDR, /* lowaddr */ 57 BUS_SPACE_MAXADDR, /* highaddr */ 58 NULL, NULL, /* filter, filterarg */ 59 dma_mem->size, /* maxsize */ 60 1, /* nsegments */ 61 dma_mem->size, /* maxsegsize */ 62 0, /* flags */ 63 NULL, NULL, /* No locking needed */ 64 &dma_mem->dma_tag)) != 0 ) { 65 DBG_ERR("can't allocate DMA tag with error = 0x%x\n", ret); 66 goto err_out; 67 } 68 if ((ret = bus_dmamem_alloc(dma_mem->dma_tag, (void **)&dma_mem->virt_addr, 69 BUS_DMA_NOWAIT, &dma_mem->dma_map)) != 0) { 70 DBG_ERR("can't allocate DMA memory for required object \ 71 with error = 0x%x\n", ret); 72 goto err_mem; 73 } 74 75 if((ret = bus_dmamap_load(dma_mem->dma_tag, dma_mem->dma_map, 76 dma_mem->virt_addr, dma_mem->size, 77 os_dma_map, &dma_mem->dma_addr, 0)) != 0) { 78 DBG_ERR("can't load DMA memory for required \ 79 object with error = 0x%x\n", ret); 80 goto err_load; 81 } 82 83 memset(dma_mem->virt_addr, 0, dma_mem->size); 84 85 /* DBG_FUNC("OUT\n"); */ 86 return ret; 87 88 err_load: 89 if(dma_mem->virt_addr) 90 bus_dmamem_free(dma_mem->dma_tag, dma_mem->virt_addr, 91 dma_mem->dma_map); 92 err_mem: 93 if(dma_mem->dma_tag) 94 bus_dma_tag_destroy(dma_mem->dma_tag); 95 err_out: 96 DBG_FUNC("failed OUT\n"); 97 return ret; 98 } 99 100 /* 101 * DMA mem resource deallocation wrapper function 102 */ 103 void os_dma_mem_free(pqisrc_softstate_t *softs, struct dma_mem *dma_mem) 104 { 105 /* DBG_FUNC("IN\n"); */ 106 107 if(dma_mem->dma_addr) { 108 bus_dmamap_unload(dma_mem->dma_tag, dma_mem->dma_map); 109 dma_mem->dma_addr = 0; 110 } 111 112 if(dma_mem->virt_addr) { 113 bus_dmamem_free(dma_mem->dma_tag, dma_mem->virt_addr, 114 dma_mem->dma_map); 115 dma_mem->virt_addr = NULL; 116 } 117 118 if(dma_mem->dma_tag) { 119 bus_dma_tag_destroy(dma_mem->dma_tag); 120 dma_mem->dma_tag = NULL; 121 } 122 123 /* DBG_FUNC("OUT\n"); */ 124 } 125 126 /* 127 * Mem resource allocation wrapper function 128 */ 129 void *os_mem_alloc(pqisrc_softstate_t *softs, size_t size) 130 { 131 void *addr = NULL; 132 133 /* DBG_FUNC("IN\n"); */ 134 135 addr = malloc((unsigned long)size, M_SMARTPQI, 136 M_NOWAIT | M_ZERO); 137 138 /* DBG_FUNC("OUT\n"); */ 139 140 return addr; 141 } 142 143 /* 144 * Mem resource deallocation wrapper function 145 */ 146 void os_mem_free(pqisrc_softstate_t *softs, 147 char *addr, size_t size) 148 { 149 /* DBG_FUNC("IN\n"); */ 150 151 free((void*)addr, M_SMARTPQI); 152 153 /* DBG_FUNC("OUT\n"); */ 154 } 155 156 /* 157 * dma/bus resource deallocation wrapper function 158 */ 159 void os_resource_free(pqisrc_softstate_t *softs) 160 { 161 if(softs->os_specific.pqi_parent_dmat) 162 bus_dma_tag_destroy(softs->os_specific.pqi_parent_dmat); 163 164 if (softs->os_specific.pqi_regs_res0 != NULL) 165 bus_release_resource(softs->os_specific.pqi_dev, 166 SYS_RES_MEMORY, 167 softs->os_specific.pqi_regs_rid0, 168 softs->os_specific.pqi_regs_res0); 169 } 170