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