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 #include <sys/smp.h> 42 43 #include <machine/bus.h> 44 #include <machine/resource.h> 45 #include <machine/tlb.h> 46 47 #include "qman.h" 48 #include "portals.h" 49 50 extern struct dpaa_portals_softc *qp_sc; 51 static struct qman_softc *qman_sc; 52 53 extern t_Handle qman_portal_setup(struct qman_softc *qsc); 54 55 static void 56 qman_exception(t_Handle app, e_QmExceptions exception) 57 { 58 struct qman_softc *sc; 59 const char *message; 60 61 sc = app; 62 63 switch (exception) { 64 case e_QM_EX_CORENET_INITIATOR_DATA: 65 message = "Initiator Data Error"; 66 break; 67 case e_QM_EX_CORENET_TARGET_DATA: 68 message = "CoreNet Target Data Error"; 69 break; 70 case e_QM_EX_CORENET_INVALID_TARGET_TRANSACTION: 71 message = "Invalid Target Transaction"; 72 break; 73 case e_QM_EX_PFDR_THRESHOLD: 74 message = "PFDR Low Watermark Interrupt"; 75 break; 76 case e_QM_EX_PFDR_ENQUEUE_BLOCKED: 77 message = "PFDR Enqueues Blocked Interrupt"; 78 break; 79 case e_QM_EX_SINGLE_ECC: 80 message = "Single Bit ECC Error Interrupt"; 81 break; 82 case e_QM_EX_MULTI_ECC: 83 message = "Multi Bit ECC Error Interrupt"; 84 break; 85 case e_QM_EX_INVALID_COMMAND: 86 message = "Invalid Command Verb Interrupt"; 87 break; 88 case e_QM_EX_DEQUEUE_DCP: 89 message = "Invalid Dequeue Direct Connect Portal Interrupt"; 90 break; 91 case e_QM_EX_DEQUEUE_FQ: 92 message = "Invalid Dequeue FQ Interrupt"; 93 break; 94 case e_QM_EX_DEQUEUE_SOURCE: 95 message = "Invalid Dequeue Source Interrupt"; 96 break; 97 case e_QM_EX_DEQUEUE_QUEUE: 98 message = "Invalid Dequeue Queue Interrupt"; 99 break; 100 case e_QM_EX_ENQUEUE_OVERFLOW: 101 message = "Invalid Enqueue Overflow Interrupt"; 102 break; 103 case e_QM_EX_ENQUEUE_STATE: 104 message = "Invalid Enqueue State Interrupt"; 105 break; 106 case e_QM_EX_ENQUEUE_CHANNEL: 107 message = "Invalid Enqueue Channel Interrupt"; 108 break; 109 case e_QM_EX_ENQUEUE_QUEUE: 110 message = "Invalid Enqueue Queue Interrupt"; 111 break; 112 case e_QM_EX_CG_STATE_CHANGE: 113 message = "CG change state notification"; 114 break; 115 default: 116 message = "Unknown error"; 117 } 118 119 device_printf(sc->sc_dev, "QMan Exception: %s.\n", message); 120 } 121 122 /** 123 * General received frame callback. 124 * This is called, when user did not register his own callback for a given 125 * frame queue range (fqr). 126 */ 127 e_RxStoreResponse 128 qman_received_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal, 129 uint32_t fqid_offset, t_DpaaFD *frame) 130 { 131 struct qman_softc *sc; 132 133 sc = app; 134 135 device_printf(sc->sc_dev, "dummy callback for received frame.\n"); 136 return (e_RX_STORE_RESPONSE_CONTINUE); 137 } 138 139 /** 140 * General rejected frame callback. 141 * This is called, when user did not register his own callback for a given 142 * frame queue range (fqr). 143 */ 144 e_RxStoreResponse 145 qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal, 146 uint32_t fqid_offset, t_DpaaFD *frame, 147 t_QmRejectedFrameInfo *qm_rejected_frame_info) 148 { 149 struct qman_softc *sc; 150 151 sc = app; 152 153 device_printf(sc->sc_dev, "dummy callback for rejected frame.\n"); 154 return (e_RX_STORE_RESPONSE_CONTINUE); 155 } 156 157 int 158 qman_attach(device_t dev) 159 { 160 struct qman_softc *sc; 161 t_QmParam qp; 162 t_Error error; 163 t_QmRevisionInfo rev; 164 165 sc = device_get_softc(dev); 166 sc->sc_dev = dev; 167 qman_sc = sc; 168 169 if (XX_MallocSmartInit() != E_OK) { 170 device_printf(dev, "could not initialize smart allocator.\n"); 171 return (ENXIO); 172 } 173 174 sched_pin(); 175 176 /* Allocate resources */ 177 sc->sc_rrid = 0; 178 sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, 179 &sc->sc_rrid, 0, ~0, QMAN_CCSR_SIZE, RF_ACTIVE); 180 if (sc->sc_rres == NULL) { 181 device_printf(dev, "could not allocate memory.\n"); 182 goto err; 183 } 184 185 sc->sc_irid = 0; 186 sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 187 &sc->sc_irid, RF_ACTIVE | RF_SHAREABLE); 188 if (sc->sc_ires == NULL) { 189 device_printf(dev, "could not allocate error interrupt.\n"); 190 goto err; 191 } 192 193 if (qp_sc == NULL) 194 goto err; 195 196 dpaa_portal_map_registers(qp_sc); 197 198 /* Initialize QMan */ 199 qp.guestId = NCSW_MASTER_ID; 200 qp.baseAddress = rman_get_bushandle(sc->sc_rres); 201 qp.swPortalsBaseAddress = rman_get_bushandle(qp_sc->sc_rres[0]); 202 qp.liodn = 0; 203 qp.totalNumOfFqids = QMAN_MAX_FQIDS; 204 qp.fqdMemPartitionId = NCSW_MASTER_ID; 205 qp.pfdrMemPartitionId = NCSW_MASTER_ID; 206 qp.f_Exception = qman_exception; 207 qp.h_App = sc; 208 qp.errIrq = (int)sc->sc_ires; 209 qp.partFqidBase = QMAN_FQID_BASE; 210 qp.partNumOfFqids = QMAN_MAX_FQIDS; 211 qp.partCgsBase = 0; 212 qp.partNumOfCgs = 0; 213 214 sc->sc_qh = QM_Config(&qp); 215 if (sc->sc_qh == NULL) { 216 device_printf(dev, "could not be configured\n"); 217 goto err; 218 } 219 220 error = QM_Init(sc->sc_qh); 221 if (error != E_OK) { 222 device_printf(dev, "could not be initialized\n"); 223 goto err; 224 } 225 226 error = QM_GetRevision(sc->sc_qh, &rev); 227 if (error != E_OK) { 228 device_printf(dev, "could not get QMan revision\n"); 229 goto err; 230 } 231 232 device_printf(dev, "Hardware version: %d.%d.\n", 233 rev.majorRev, rev.minorRev); 234 235 sched_unpin(); 236 237 qman_portal_setup(sc); 238 239 return (0); 240 241 err: 242 sched_unpin(); 243 qman_detach(dev); 244 return (ENXIO); 245 } 246 247 int 248 qman_detach(device_t dev) 249 { 250 struct qman_softc *sc; 251 252 sc = device_get_softc(dev); 253 254 if (sc->sc_qh) 255 QM_Free(sc->sc_qh); 256 257 if (sc->sc_ires != NULL) 258 XX_DeallocIntr((int)sc->sc_ires); 259 260 if (sc->sc_ires != NULL) 261 bus_release_resource(dev, SYS_RES_IRQ, 262 sc->sc_irid, sc->sc_ires); 263 264 if (sc->sc_rres != NULL) 265 bus_release_resource(dev, SYS_RES_MEMORY, 266 sc->sc_rrid, sc->sc_rres); 267 268 return (0); 269 } 270 271 int 272 qman_suspend(device_t dev) 273 { 274 275 return (0); 276 } 277 278 int 279 qman_resume(device_t dev) 280 { 281 282 return (0); 283 } 284 285 int 286 qman_shutdown(device_t dev) 287 { 288 289 return (0); 290 } 291 292 293 /** 294 * @group QMan API functions implementation. 295 * @{ 296 */ 297 298 t_Handle 299 qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq, 300 bool force_fqid, uint32_t fqid_or_align, bool init_parked, 301 bool hold_active, bool prefer_in_cache, bool congst_avoid_ena, 302 t_Handle congst_group, int8_t overhead_accounting_len, 303 uint32_t tail_drop_threshold) 304 { 305 struct qman_softc *sc; 306 t_QmFqrParams fqr; 307 unsigned int cpu; 308 t_Handle fqrh, portal; 309 310 sc = qman_sc; 311 312 sched_pin(); 313 cpu = PCPU_GET(cpuid); 314 315 /* Ensure we have got QMan port initialized */ 316 portal = qman_portal_setup(sc); 317 if (portal == NULL) { 318 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 319 goto err; 320 } 321 322 fqr.h_Qm = sc->sc_qh; 323 fqr.h_QmPortal = portal; 324 fqr.initParked = init_parked; 325 fqr.holdActive = hold_active; 326 fqr.preferInCache = prefer_in_cache; 327 328 /* We do not support stashing */ 329 fqr.useContextAForStash = FALSE; 330 fqr.p_ContextA = 0; 331 fqr.p_ContextB = 0; 332 333 fqr.channel = channel; 334 fqr.wq = wq; 335 fqr.shadowMode = FALSE; 336 fqr.numOfFqids = fqids_num; 337 338 /* FQID */ 339 fqr.useForce = force_fqid; 340 if (force_fqid) { 341 fqr.qs.frcQ.fqid = fqid_or_align; 342 } else { 343 fqr.qs.nonFrcQs.align = fqid_or_align; 344 } 345 346 /* Congestion Avoidance */ 347 fqr.congestionAvoidanceEnable = congst_avoid_ena; 348 if (congst_avoid_ena) { 349 fqr.congestionAvoidanceParams.h_QmCg = congst_group; 350 fqr.congestionAvoidanceParams.overheadAccountingLength = 351 overhead_accounting_len; 352 fqr.congestionAvoidanceParams.fqTailDropThreshold = 353 tail_drop_threshold; 354 } else { 355 fqr.congestionAvoidanceParams.h_QmCg = 0; 356 fqr.congestionAvoidanceParams.overheadAccountingLength = 0; 357 fqr.congestionAvoidanceParams.fqTailDropThreshold = 0; 358 } 359 360 fqrh = QM_FQR_Create(&fqr); 361 if (fqrh == NULL) { 362 device_printf(sc->sc_dev, "could not create Frame Queue Range" 363 "\n"); 364 goto err; 365 } 366 367 sc->sc_fqr_cpu[QM_FQR_GetFqid(fqrh)] = PCPU_GET(cpuid); 368 369 sched_unpin(); 370 371 return (fqrh); 372 373 err: 374 sched_unpin(); 375 376 return (NULL); 377 } 378 379 t_Error 380 qman_fqr_free(t_Handle fqr) 381 { 382 struct qman_softc *sc; 383 t_Error error; 384 385 sc = qman_sc; 386 thread_lock(curthread); 387 sched_bind(curthread, sc->sc_fqr_cpu[QM_FQR_GetFqid(fqr)]); 388 thread_unlock(curthread); 389 390 error = QM_FQR_Free(fqr); 391 392 thread_lock(curthread); 393 sched_unbind(curthread); 394 thread_unlock(curthread); 395 396 return (error); 397 } 398 399 t_Error 400 qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback, 401 t_Handle app) 402 { 403 struct qman_softc *sc; 404 t_Error error; 405 t_Handle portal; 406 407 sc = qman_sc; 408 sched_pin(); 409 410 /* Ensure we have got QMan port initialized */ 411 portal = qman_portal_setup(sc); 412 if (portal == NULL) { 413 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 414 sched_unpin(); 415 return (E_NOT_SUPPORTED); 416 } 417 418 error = QM_FQR_RegisterCB(fqr, callback, app); 419 420 sched_unpin(); 421 422 return (error); 423 } 424 425 t_Error 426 qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame) 427 { 428 struct qman_softc *sc; 429 t_Error error; 430 t_Handle portal; 431 432 sc = qman_sc; 433 sched_pin(); 434 435 /* Ensure we have got QMan port initialized */ 436 portal = qman_portal_setup(sc); 437 if (portal == NULL) { 438 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 439 sched_unpin(); 440 return (E_NOT_SUPPORTED); 441 } 442 443 error = QM_FQR_Enqueue(fqr, portal, fqid_off, frame); 444 445 sched_unpin(); 446 447 return (error); 448 } 449 450 uint32_t 451 qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off, 452 e_QmFqrCounters counter) 453 { 454 struct qman_softc *sc; 455 uint32_t val; 456 t_Handle portal; 457 458 sc = qman_sc; 459 sched_pin(); 460 461 /* Ensure we have got QMan port initialized */ 462 portal = qman_portal_setup(sc); 463 if (portal == NULL) { 464 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 465 sched_unpin(); 466 return (0); 467 } 468 469 val = QM_FQR_GetCounter(fqr, portal, fqid_off, counter); 470 471 sched_unpin(); 472 473 return (val); 474 } 475 476 t_Error 477 qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame) 478 { 479 struct qman_softc *sc; 480 t_Error error; 481 t_Handle portal; 482 483 sc = qman_sc; 484 sched_pin(); 485 486 /* Ensure we have got QMan port initialized */ 487 portal = qman_portal_setup(sc); 488 if (portal == NULL) { 489 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 490 sched_unpin(); 491 return (E_NOT_SUPPORTED); 492 } 493 494 error = QM_FQR_PullFrame(fqr, portal, fqid_off, frame); 495 496 sched_unpin(); 497 498 return (error); 499 } 500 501 uint32_t 502 qman_fqr_get_base_fqid(t_Handle fqr) 503 { 504 struct qman_softc *sc; 505 uint32_t val; 506 t_Handle portal; 507 508 sc = qman_sc; 509 sched_pin(); 510 511 /* Ensure we have got QMan port initialized */ 512 portal = qman_portal_setup(sc); 513 if (portal == NULL) { 514 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 515 sched_unpin(); 516 return (0); 517 } 518 519 val = QM_FQR_GetFqid(fqr); 520 521 sched_unpin(); 522 523 return (val); 524 } 525 526 t_Error 527 qman_poll(e_QmPortalPollSource source) 528 { 529 struct qman_softc *sc; 530 t_Error error; 531 t_Handle portal; 532 533 sc = qman_sc; 534 sched_pin(); 535 536 /* Ensure we have got QMan port initialized */ 537 portal = qman_portal_setup(sc); 538 if (portal == NULL) { 539 device_printf(sc->sc_dev, "could not setup QMan portal\n"); 540 sched_unpin(); 541 return (E_NOT_SUPPORTED); 542 } 543 544 error = QM_Poll(sc->sc_qh, source); 545 546 sched_unpin(); 547 548 return (error); 549 } 550 551 /* 552 * TODO: add polling and/or congestion support. 553 */ 554 555 /** @} */ 556