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