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