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(dev, SYS_RES_MEMORY, 100 &sc->sc_rrid, 0, ~0, 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 = (int)sc->sc_ires; 118 bp.partBpidBase = 0; 119 bp.partNumOfPools = BM_MAX_NUM_OF_POOLS; 120 printf("base address: %llx\n", (uint64_t)bp.baseAddress); 121 122 sc->sc_bh = BM_Config(&bp); 123 if (sc->sc_bh == NULL) 124 goto err; 125 126 /* Warn if there is less than 5% free FPBR's in pool */ 127 error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20); 128 if (error != E_OK) 129 goto err; 130 131 error = BM_Init(sc->sc_bh); 132 if (error != E_OK) 133 goto err; 134 135 error = BM_GetRevision(sc->sc_bh, &rev); 136 if (error != E_OK) 137 goto err; 138 139 device_printf(dev, "Hardware version: %d.%d.\n", 140 rev.majorRev, rev.minorRev); 141 142 return (0); 143 144 err: 145 bman_detach(dev); 146 return (ENXIO); 147 } 148 149 int 150 bman_detach(device_t dev) 151 { 152 struct bman_softc *sc; 153 154 sc = device_get_softc(dev); 155 156 if (sc->sc_bh != NULL) 157 BM_Free(sc->sc_bh); 158 159 if (sc->sc_ires != NULL) 160 bus_release_resource(dev, SYS_RES_IRQ, 161 sc->sc_irid, sc->sc_ires); 162 163 if (sc->sc_rres != NULL) 164 bus_release_resource(dev, SYS_RES_MEMORY, 165 sc->sc_rrid, sc->sc_rres); 166 167 return (0); 168 } 169 170 int 171 bman_suspend(device_t dev) 172 { 173 174 return (0); 175 } 176 177 int 178 bman_resume(device_t dev) 179 { 180 181 return (0); 182 } 183 184 int 185 bman_shutdown(device_t dev) 186 { 187 188 return (0); 189 } 190 191 /* 192 * BMAN API 193 */ 194 195 t_Handle 196 bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers, 197 uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf, 198 t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit, 199 uint32_t dep_hw_entry, uint32_t dep_hw_exit, 200 t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool, 201 t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys) 202 { 203 uint32_t thresholds[MAX_DEPLETION_THRESHOLDS]; 204 struct bman_softc *sc; 205 t_Handle pool, portal; 206 t_BmPoolParam bpp; 207 int error; 208 209 sc = bman_sc; 210 pool = NULL; 211 212 sched_pin(); 213 214 portal = bman_portal_setup(sc); 215 if (portal == NULL) 216 goto err; 217 218 memset(&bpp, 0, sizeof(bpp)); 219 bpp.h_Bm = sc->sc_bh; 220 bpp.h_BmPortal = portal; 221 bpp.h_App = h_BufferPool; 222 bpp.numOfBuffers = allocBuffers; 223 224 bpp.bufferPoolInfo.h_BufferPool = h_BufferPool; 225 bpp.bufferPoolInfo.f_GetBuf = f_GetBuf; 226 bpp.bufferPoolInfo.f_PutBuf = f_PutBuf; 227 bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt; 228 bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys; 229 bpp.bufferPoolInfo.bufferSize = bufferSize; 230 231 pool = BM_POOL_Config(&bpp); 232 if (pool == NULL) 233 goto err; 234 235 /* 236 * Buffer context must be disabled on FreeBSD 237 * as it could cause memory corruption. 238 */ 239 BM_POOL_ConfigBuffContextMode(pool, 0); 240 241 if (minBuffers != 0 || maxBuffers != 0) { 242 error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers); 243 if (error != E_OK) 244 goto err; 245 } 246 247 if (f_Depletion != NULL) { 248 thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry; 249 thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit; 250 thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry; 251 thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit; 252 error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds); 253 if (error != E_OK) 254 goto err; 255 } 256 257 error = BM_POOL_Init(pool); 258 if (error != E_OK) 259 goto err; 260 261 *bpid = BM_POOL_GetId(pool); 262 sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid); 263 264 sched_unpin(); 265 266 return (pool); 267 268 err: 269 if (pool != NULL) 270 BM_POOL_Free(pool); 271 272 sched_unpin(); 273 274 return (NULL); 275 } 276 277 int 278 bman_pool_destroy(t_Handle pool) 279 { 280 struct bman_softc *sc; 281 282 sc = bman_sc; 283 thread_lock(curthread); 284 sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]); 285 thread_unlock(curthread); 286 287 BM_POOL_Free(pool); 288 289 thread_lock(curthread); 290 sched_unbind(curthread); 291 thread_unlock(curthread); 292 293 return (0); 294 } 295 296 int 297 bman_pool_fill(t_Handle pool, uint16_t nbufs) 298 { 299 struct bman_softc *sc; 300 t_Handle portal; 301 int error; 302 303 sc = bman_sc; 304 sched_pin(); 305 306 portal = bman_portal_setup(sc); 307 if (portal == NULL) { 308 sched_unpin(); 309 return (EIO); 310 } 311 312 error = BM_POOL_FillBufs(pool, portal, nbufs); 313 314 sched_unpin(); 315 316 return ((error == E_OK) ? 0 : EIO); 317 } 318 319 void * 320 bman_get_buffer(t_Handle pool) 321 { 322 struct bman_softc *sc; 323 t_Handle portal; 324 void *buffer; 325 326 sc = bman_sc; 327 sched_pin(); 328 329 portal = bman_portal_setup(sc); 330 if (portal == NULL) { 331 sched_unpin(); 332 return (NULL); 333 } 334 335 buffer = BM_POOL_GetBuf(pool, portal); 336 337 sched_unpin(); 338 339 return (buffer); 340 } 341 342 int 343 bman_put_buffer(t_Handle pool, void *buffer) 344 { 345 struct bman_softc *sc; 346 t_Handle portal; 347 int error; 348 349 sc = bman_sc; 350 sched_pin(); 351 352 portal = bman_portal_setup(sc); 353 if (portal == NULL) { 354 sched_unpin(); 355 return (EIO); 356 } 357 358 error = BM_POOL_PutBuf(pool, portal, buffer); 359 360 sched_unpin(); 361 362 return ((error == E_OK) ? 0 : EIO); 363 } 364 365 uint32_t 366 bman_count(t_Handle pool) 367 { 368 369 return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT)); 370 } 371