1 /*- 2 * Copyright (c) 2011-2012 Semihalf. 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 #include <sys/cdefs.h> 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/kernel.h> 31 #include <sys/bus.h> 32 #include <sys/lock.h> 33 #include <sys/module.h> 34 #include <sys/mutex.h> 35 #include <sys/proc.h> 36 #include <sys/pcpu.h> 37 #include <sys/rman.h> 38 #include <sys/sched.h> 39 40 #include <machine/tlb.h> 41 42 #include "bman.h" 43 44 static struct bman_softc *bman_sc; 45 46 extern t_Handle bman_portal_setup(struct bman_softc *bsc); 47 48 static void 49 bman_exception(t_Handle h_App, e_BmExceptions exception) 50 { 51 struct bman_softc *sc; 52 const char *message; 53 54 sc = h_App; 55 56 switch (exception) { 57 case e_BM_EX_INVALID_COMMAND: 58 message = "Invalid Command Verb"; 59 break; 60 case e_BM_EX_FBPR_THRESHOLD: 61 message = "FBPR pool exhaused. Consider increasing " 62 "BMAN_MAX_BUFFERS"; 63 break; 64 case e_BM_EX_SINGLE_ECC: 65 message = "Single bit ECC error"; 66 break; 67 case e_BM_EX_MULTI_ECC: 68 message = "Multi bit ECC error"; 69 break; 70 default: 71 message = "Unknown error"; 72 } 73 74 device_printf(sc->sc_dev, "BMAN Exception: %s.\n", message); 75 } 76 77 int 78 bman_attach(device_t dev) 79 { 80 struct bman_softc *sc; 81 t_BmRevisionInfo rev; 82 t_Error error; 83 t_BmParam bp; 84 85 sc = device_get_softc(dev); 86 sc->sc_dev = dev; 87 bman_sc = sc; 88 89 /* Check if MallocSmart allocator is ready */ 90 if (XX_MallocSmartInit() != E_OK) 91 return (ENXIO); 92 93 /* Allocate resources */ 94 sc->sc_rrid = 0; 95 sc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, 96 &sc->sc_rrid, BMAN_CCSR_SIZE, RF_ACTIVE); 97 if (sc->sc_rres == NULL) 98 return (ENXIO); 99 100 sc->sc_irid = 0; 101 sc->sc_ires = bus_alloc_resource_any(sc->sc_dev, SYS_RES_IRQ, 102 &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE); 103 if (sc->sc_ires == NULL) 104 goto err; 105 106 /* Initialize BMAN */ 107 memset(&bp, 0, sizeof(bp)); 108 bp.guestId = NCSW_MASTER_ID; 109 bp.baseAddress = rman_get_bushandle(sc->sc_rres); 110 bp.totalNumOfBuffers = BMAN_MAX_BUFFERS; 111 bp.f_Exception = bman_exception; 112 bp.h_App = sc; 113 bp.errIrq = (uintptr_t)sc->sc_ires; 114 bp.partBpidBase = 0; 115 bp.partNumOfPools = BM_MAX_NUM_OF_POOLS; 116 117 sc->sc_bh = BM_Config(&bp); 118 if (sc->sc_bh == NULL) 119 goto err; 120 121 /* Warn if there is less than 5% free FPBR's in pool */ 122 error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20); 123 if (error != E_OK) 124 goto err; 125 126 error = BM_Init(sc->sc_bh); 127 if (error != E_OK) 128 goto err; 129 130 error = BM_GetRevision(sc->sc_bh, &rev); 131 if (error != E_OK) 132 goto err; 133 134 device_printf(dev, "Hardware version: %d.%d.\n", 135 rev.majorRev, rev.minorRev); 136 137 return (0); 138 139 err: 140 bman_detach(dev); 141 return (ENXIO); 142 } 143 144 int 145 bman_detach(device_t dev) 146 { 147 struct bman_softc *sc; 148 149 sc = device_get_softc(dev); 150 151 if (sc->sc_bh != NULL) 152 BM_Free(sc->sc_bh); 153 154 if (sc->sc_ires != NULL) 155 bus_release_resource(dev, SYS_RES_IRQ, 156 sc->sc_irid, sc->sc_ires); 157 158 if (sc->sc_rres != NULL) 159 bus_release_resource(dev, SYS_RES_MEMORY, 160 sc->sc_rrid, sc->sc_rres); 161 162 return (0); 163 } 164 165 int 166 bman_suspend(device_t dev) 167 { 168 169 return (0); 170 } 171 172 int 173 bman_resume(device_t dev) 174 { 175 176 return (0); 177 } 178 179 int 180 bman_shutdown(device_t dev) 181 { 182 183 return (0); 184 } 185 186 /* 187 * BMAN API 188 */ 189 190 t_Handle 191 bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers, 192 uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf, 193 t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit, 194 uint32_t dep_hw_entry, uint32_t dep_hw_exit, 195 t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool, 196 t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys) 197 { 198 uint32_t thresholds[MAX_DEPLETION_THRESHOLDS]; 199 struct bman_softc *sc; 200 t_Handle pool, portal; 201 t_BmPoolParam bpp; 202 int error; 203 204 sc = bman_sc; 205 pool = NULL; 206 207 sched_pin(); 208 209 portal = bman_portal_setup(sc); 210 if (portal == NULL) 211 goto err; 212 213 memset(&bpp, 0, sizeof(bpp)); 214 bpp.h_Bm = sc->sc_bh; 215 bpp.h_BmPortal = portal; 216 bpp.h_App = h_BufferPool; 217 bpp.numOfBuffers = allocBuffers; 218 219 bpp.bufferPoolInfo.h_BufferPool = h_BufferPool; 220 bpp.bufferPoolInfo.f_GetBuf = f_GetBuf; 221 bpp.bufferPoolInfo.f_PutBuf = f_PutBuf; 222 bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt; 223 bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys; 224 bpp.bufferPoolInfo.bufferSize = bufferSize; 225 226 pool = BM_POOL_Config(&bpp); 227 if (pool == NULL) 228 goto err; 229 230 /* 231 * Buffer context must be disabled on FreeBSD 232 * as it could cause memory corruption. 233 */ 234 BM_POOL_ConfigBuffContextMode(pool, 0); 235 236 if (minBuffers != 0 || maxBuffers != 0) { 237 error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers); 238 if (error != E_OK) 239 goto err; 240 } 241 242 if (f_Depletion != NULL) { 243 thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry; 244 thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit; 245 thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry; 246 thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit; 247 error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds); 248 if (error != E_OK) 249 goto err; 250 } 251 252 error = BM_POOL_Init(pool); 253 if (error != E_OK) 254 goto err; 255 256 *bpid = BM_POOL_GetId(pool); 257 sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid); 258 259 sched_unpin(); 260 261 return (pool); 262 263 err: 264 if (pool != NULL) 265 BM_POOL_Free(pool); 266 267 sched_unpin(); 268 269 return (NULL); 270 } 271 272 int 273 bman_pool_destroy(t_Handle pool) 274 { 275 struct bman_softc *sc; 276 277 sc = bman_sc; 278 thread_lock(curthread); 279 sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]); 280 thread_unlock(curthread); 281 282 BM_POOL_Free(pool); 283 284 thread_lock(curthread); 285 sched_unbind(curthread); 286 thread_unlock(curthread); 287 288 return (0); 289 } 290 291 int 292 bman_pool_fill(t_Handle pool, uint16_t nbufs) 293 { 294 struct bman_softc *sc; 295 t_Handle portal; 296 int error; 297 298 sc = bman_sc; 299 sched_pin(); 300 301 portal = bman_portal_setup(sc); 302 if (portal == NULL) { 303 sched_unpin(); 304 return (EIO); 305 } 306 307 error = BM_POOL_FillBufs(pool, portal, nbufs); 308 309 sched_unpin(); 310 311 return ((error == E_OK) ? 0 : EIO); 312 } 313 314 void * 315 bman_get_buffer(t_Handle pool) 316 { 317 struct bman_softc *sc; 318 t_Handle portal; 319 void *buffer; 320 321 sc = bman_sc; 322 sched_pin(); 323 324 portal = bman_portal_setup(sc); 325 if (portal == NULL) { 326 sched_unpin(); 327 return (NULL); 328 } 329 330 buffer = BM_POOL_GetBuf(pool, portal); 331 332 sched_unpin(); 333 334 return (buffer); 335 } 336 337 int 338 bman_put_buffer(t_Handle pool, void *buffer) 339 { 340 struct bman_softc *sc; 341 t_Handle portal; 342 int error; 343 344 sc = bman_sc; 345 sched_pin(); 346 347 portal = bman_portal_setup(sc); 348 if (portal == NULL) { 349 sched_unpin(); 350 return (EIO); 351 } 352 353 error = BM_POOL_PutBuf(pool, portal, buffer); 354 355 sched_unpin(); 356 357 return ((error == E_OK) ? 0 : EIO); 358 } 359 360 uint32_t 361 bman_count(t_Handle pool) 362 { 363 364 return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT)); 365 } 366