layerscape: make uImage with zImage for 32-bit kernel
[openwrt/openwrt.git] / target / linux / layerscape / patches-4.4 / 7017-fsl_qbman-add-qbman-driver.patch
1 From f6f8ed4784936724154832ff9e4c5afe8caa63e4 Mon Sep 17 00:00:00 2001
2 From: Zhao Qiang <qiang.zhao@nxp.com>
3 Date: Mon, 11 Jul 2016 14:39:18 +0800
4 Subject: [PATCH 17/70] fsl_qbman: add qbman driver
5
6 The QMan and BMan are infrastructure components of dpaa, which are used
7 by both software and hardware for queuing and memory allocation/deallocation.
8
9 Signed-off-by: Roy Pledge <Roy.Pledge@freescale.com> Signed-off-by:
10 Camelia Groza <camelia.groza@freescale.com> Signed-off-by: Geoff Thorpe
11 <Geoff.Thorpe@freescale.com> Signed-off-by: Ahmed Mansour
12 <Ahmed.Mansour@freescale.com> Signed-off-by: Alex Porosanu
13 <alexandru.porosanu@nxp.com> Signed-off-by: Pan Jiafei
14 <Jiafei.Pan@nxp.com> Signed-off-by: Haiying Wang
15 <Haiying.wang@freescale.com>
16 Signed-off-by: Xie Jianhua-B29408 <Jianhua.Xie@freescale.com>
17 Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com>
18 ---
19 arch/arm/Kconfig | 5 +
20 arch/powerpc/Kconfig | 9 +-
21 drivers/misc/Kconfig | 17 +
22 drivers/staging/Kconfig | 2 +
23 drivers/staging/Makefile | 1 +
24 drivers/staging/fsl_qbman/Kconfig | 211 +
25 drivers/staging/fsl_qbman/Makefile | 28 +
26 drivers/staging/fsl_qbman/bman_config.c | 705 +++
27 drivers/staging/fsl_qbman/bman_debugfs.c | 119 +
28 drivers/staging/fsl_qbman/bman_driver.c | 574 +++
29 drivers/staging/fsl_qbman/bman_high.c | 1141 +++++
30 drivers/staging/fsl_qbman/bman_low.h | 559 +++
31 drivers/staging/fsl_qbman/bman_private.h | 166 +
32 drivers/staging/fsl_qbman/bman_test.c | 56 +
33 drivers/staging/fsl_qbman/bman_test.h | 44 +
34 drivers/staging/fsl_qbman/bman_test_high.c | 183 +
35 drivers/staging/fsl_qbman/bman_test_thresh.c | 196 +
36 drivers/staging/fsl_qbman/dpa_alloc.c | 706 +++
37 drivers/staging/fsl_qbman/dpa_sys.h | 259 ++
38 drivers/staging/fsl_qbman/dpa_sys_arm.h | 95 +
39 drivers/staging/fsl_qbman/dpa_sys_arm64.h | 102 +
40 drivers/staging/fsl_qbman/dpa_sys_ppc32.h | 70 +
41 drivers/staging/fsl_qbman/dpa_sys_ppc64.h | 79 +
42 drivers/staging/fsl_qbman/fsl_usdpaa.c | 1982 ++++++++
43 drivers/staging/fsl_qbman/fsl_usdpaa_irq.c | 289 ++
44 drivers/staging/fsl_qbman/qbman_driver.c | 88 +
45 drivers/staging/fsl_qbman/qman_config.c | 1199 +++++
46 drivers/staging/fsl_qbman/qman_debugfs.c | 1594 +++++++
47 drivers/staging/fsl_qbman/qman_driver.c | 980 ++++
48 drivers/staging/fsl_qbman/qman_high.c | 5568 +++++++++++++++++++++++
49 drivers/staging/fsl_qbman/qman_low.h | 1407 ++++++
50 drivers/staging/fsl_qbman/qman_private.h | 398 ++
51 drivers/staging/fsl_qbman/qman_test.c | 57 +
52 drivers/staging/fsl_qbman/qman_test.h | 45 +
53 drivers/staging/fsl_qbman/qman_test_high.c | 216 +
54 drivers/staging/fsl_qbman/qman_test_hotpotato.c | 499 ++
55 drivers/staging/fsl_qbman/qman_utility.c | 129 +
56 include/linux/fsl_bman.h | 532 +++
57 include/linux/fsl_qman.h | 3889 ++++++++++++++++
58 include/linux/fsl_usdpaa.h | 372 ++
59 40 files changed, 24569 insertions(+), 2 deletions(-)
60 create mode 100644 drivers/staging/fsl_qbman/Kconfig
61 create mode 100644 drivers/staging/fsl_qbman/Makefile
62 create mode 100644 drivers/staging/fsl_qbman/bman_config.c
63 create mode 100644 drivers/staging/fsl_qbman/bman_debugfs.c
64 create mode 100644 drivers/staging/fsl_qbman/bman_driver.c
65 create mode 100644 drivers/staging/fsl_qbman/bman_high.c
66 create mode 100644 drivers/staging/fsl_qbman/bman_low.h
67 create mode 100644 drivers/staging/fsl_qbman/bman_private.h
68 create mode 100644 drivers/staging/fsl_qbman/bman_test.c
69 create mode 100644 drivers/staging/fsl_qbman/bman_test.h
70 create mode 100644 drivers/staging/fsl_qbman/bman_test_high.c
71 create mode 100644 drivers/staging/fsl_qbman/bman_test_thresh.c
72 create mode 100644 drivers/staging/fsl_qbman/dpa_alloc.c
73 create mode 100644 drivers/staging/fsl_qbman/dpa_sys.h
74 create mode 100644 drivers/staging/fsl_qbman/dpa_sys_arm.h
75 create mode 100644 drivers/staging/fsl_qbman/dpa_sys_arm64.h
76 create mode 100644 drivers/staging/fsl_qbman/dpa_sys_ppc32.h
77 create mode 100644 drivers/staging/fsl_qbman/dpa_sys_ppc64.h
78 create mode 100644 drivers/staging/fsl_qbman/fsl_usdpaa.c
79 create mode 100644 drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
80 create mode 100644 drivers/staging/fsl_qbman/qbman_driver.c
81 create mode 100644 drivers/staging/fsl_qbman/qman_config.c
82 create mode 100644 drivers/staging/fsl_qbman/qman_debugfs.c
83 create mode 100644 drivers/staging/fsl_qbman/qman_driver.c
84 create mode 100644 drivers/staging/fsl_qbman/qman_high.c
85 create mode 100644 drivers/staging/fsl_qbman/qman_low.h
86 create mode 100644 drivers/staging/fsl_qbman/qman_private.h
87 create mode 100644 drivers/staging/fsl_qbman/qman_test.c
88 create mode 100644 drivers/staging/fsl_qbman/qman_test.h
89 create mode 100644 drivers/staging/fsl_qbman/qman_test_high.c
90 create mode 100644 drivers/staging/fsl_qbman/qman_test_hotpotato.c
91 create mode 100644 drivers/staging/fsl_qbman/qman_utility.c
92 create mode 100644 include/linux/fsl_bman.h
93 create mode 100644 include/linux/fsl_qman.h
94 create mode 100644 include/linux/fsl_usdpaa.h
95
96 --- a/arch/arm/Kconfig
97 +++ b/arch/arm/Kconfig
98 @@ -1250,6 +1250,11 @@ source "arch/arm/common/Kconfig"
99
100 menu "Bus support"
101
102 +config HAS_FSL_QBMAN
103 + bool "Datapath Acceleration Queue and Buffer management"
104 + help
105 + Datapath Acceleration Queue and Buffer management
106 +
107 config ISA
108 bool
109 help
110 --- a/arch/powerpc/Kconfig
111 +++ b/arch/powerpc/Kconfig
112 @@ -786,6 +786,11 @@ config FSL_GTM
113 help
114 Freescale General-purpose Timers support
115
116 +config HAS_FSL_QBMAN
117 + bool "Datapath Acceleration Queue and Buffer management"
118 + help
119 + Datapath Acceleration Queue and Buffer management
120 +
121 # Yes MCA RS/6000s exist but Linux-PPC does not currently support any
122 config MCA
123 bool
124 @@ -918,14 +923,14 @@ config DYNAMIC_MEMSTART
125 select NONSTATIC_KERNEL
126 help
127 This option enables the kernel to be loaded at any page aligned
128 - physical address. The kernel creates a mapping from KERNELBASE to
129 + physical address. The kernel creates a mapping from KERNELBASE to
130 the address where the kernel is loaded. The page size here implies
131 the TLB page size of the mapping for kernel on the particular platform.
132 Please refer to the init code for finding the TLB page size.
133
134 DYNAMIC_MEMSTART is an easy way of implementing pseudo-RELOCATABLE
135 kernel image, where the only restriction is the page aligned kernel
136 - load address. When this option is enabled, the compile time physical
137 + load address. When this option is enabled, the compile time physical
138 address CONFIG_PHYSICAL_START is ignored.
139
140 This option is overridden by CONFIG_RELOCATABLE
141 --- a/drivers/misc/Kconfig
142 +++ b/drivers/misc/Kconfig
143 @@ -236,6 +236,23 @@ config SGI_XP
144 this feature will allow for direct communication between SSIs
145 based on a network adapter and DMA messaging.
146
147 +config FSL_USDPAA
148 + bool "Freescale USDPAA process driver"
149 + depends on FSL_DPA
150 + default y
151 + help
152 + This driver provides user-space access to kernel-managed
153 + resource interfaces for USDPAA applications, on the assumption
154 + that each process will open this device once. Specifically, this
155 + device exposes functionality that would be awkward if exposed
156 + via the portal devices - ie. this device exposes functionality
157 + that is inherently process-wide rather than portal-specific.
158 + This device is necessary for obtaining access to DMA memory and
159 + for allocation of Qman and Bman resources. In short, if you wish
160 + to use USDPAA applications, you need this.
161 +
162 + If unsure, say Y.
163 +
164 config CS5535_MFGPT
165 tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support"
166 depends on MFD_CS5535
167 --- a/drivers/staging/Kconfig
168 +++ b/drivers/staging/Kconfig
169 @@ -106,6 +106,8 @@ source "drivers/staging/fbtft/Kconfig"
170
171 source "drivers/staging/fsl-mc/Kconfig"
172
173 +source "drivers/staging/fsl_qbman/Kconfig"
174 +
175 source "drivers/staging/wilc1000/Kconfig"
176
177 source "drivers/staging/most/Kconfig"
178 --- a/drivers/staging/Makefile
179 +++ b/drivers/staging/Makefile
180 @@ -45,5 +45,6 @@ obj-$(CONFIG_UNISYSSPAR) += unisys/
181 obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
182 obj-$(CONFIG_FB_TFT) += fbtft/
183 obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/
184 +obj-$(CONFIG_FSL_DPA) += fsl_qbman/
185 obj-$(CONFIG_WILC1000) += wilc1000/
186 obj-$(CONFIG_MOST) += most/
187 --- /dev/null
188 +++ b/drivers/staging/fsl_qbman/Kconfig
189 @@ -0,0 +1,211 @@
190 +config FSL_DPA
191 + bool "Freescale Datapath Queue and Buffer management"
192 + depends on HAS_FSL_QBMAN
193 + default y
194 + select FSL_QMAN_FQ_LOOKUP if PPC64
195 + select FSL_QMAN_FQ_LOOKUP if ARM64
196 +
197 +
198 +menu "Freescale Datapath QMan/BMan options"
199 + depends on FSL_DPA
200 +
201 +config FSL_DPA_CHECKING
202 + bool "additional driver checking"
203 + default n
204 + ---help---
205 + Compiles in additional checks to sanity-check the drivers and any
206 + use of it by other code. Not recommended for performance.
207 +
208 +config FSL_DPA_CAN_WAIT
209 + bool
210 + default y
211 +
212 +config FSL_DPA_CAN_WAIT_SYNC
213 + bool
214 + default y
215 +
216 +config FSL_DPA_PIRQ_FAST
217 + bool
218 + default y
219 +
220 +config FSL_DPA_PIRQ_SLOW
221 + bool
222 + default y
223 +
224 +config FSL_DPA_PORTAL_SHARE
225 + bool
226 + default y
227 +
228 +config FSL_BMAN
229 + bool "Freescale Buffer Manager (BMan) support"
230 + default y
231 +
232 +if FSL_BMAN
233 +
234 +config FSL_BMAN_CONFIG
235 + bool "BMan device management"
236 + default y
237 + ---help---
238 + If this linux image is running natively, you need this option. If this
239 + linux image is running as a guest OS under the hypervisor, only one
240 + guest OS ("the control plane") needs this option.
241 +
242 +config FSL_BMAN_TEST
243 + tristate "BMan self-tests"
244 + default n
245 + ---help---
246 + This option compiles self-test code for BMan.
247 +
248 +config FSL_BMAN_TEST_HIGH
249 + bool "BMan high-level self-test"
250 + depends on FSL_BMAN_TEST
251 + default y
252 + ---help---
253 + This requires the presence of cpu-affine portals, and performs
254 + high-level API testing with them (whichever portal(s) are affine to
255 + the cpu(s) the test executes on).
256 +
257 +config FSL_BMAN_TEST_THRESH
258 + bool "BMan threshold test"
259 + depends on FSL_BMAN_TEST
260 + default y
261 + ---help---
262 + Multi-threaded (SMP) test of BMan pool depletion. A pool is seeded
263 + before multiple threads (one per cpu) create pool objects to track
264 + depletion state changes. The pool is then drained to empty by a
265 + "drainer" thread, and the other threads that they observe exactly
266 + the depletion state changes that are expected.
267 +
268 +config FSL_BMAN_DEBUGFS
269 + tristate "BMan debugfs interface"
270 + depends on DEBUG_FS
271 + default y
272 + ---help---
273 + This option compiles debugfs code for BMan.
274 +
275 +endif # FSL_BMAN
276 +
277 +config FSL_QMAN
278 + bool "Freescale Queue Manager (QMan) support"
279 + default y
280 +
281 +if FSL_QMAN
282 +
283 +config FSL_QMAN_POLL_LIMIT
284 + int
285 + default 32
286 +
287 +config FSL_QMAN_CONFIG
288 + bool "QMan device management"
289 + default y
290 + ---help---
291 + If this linux image is running natively, you need this option. If this
292 + linux image is running as a guest OS under the hypervisor, only one
293 + guest OS ("the control plane") needs this option.
294 +
295 +config FSL_QMAN_TEST
296 + tristate "QMan self-tests"
297 + default n
298 + ---help---
299 + This option compiles self-test code for QMan.
300 +
301 +config FSL_QMAN_TEST_STASH_POTATO
302 + bool "QMan 'hot potato' data-stashing self-test"
303 + depends on FSL_QMAN_TEST
304 + default y
305 + ---help---
306 + This performs a "hot potato" style test enqueuing/dequeuing a frame
307 + across a series of FQs scheduled to different portals (and cpus), with
308 + DQRR, data and context stashing always on.
309 +
310 +config FSL_QMAN_TEST_HIGH
311 + bool "QMan high-level self-test"
312 + depends on FSL_QMAN_TEST
313 + default y
314 + ---help---
315 + This requires the presence of cpu-affine portals, and performs
316 + high-level API testing with them (whichever portal(s) are affine to
317 + the cpu(s) the test executes on).
318 +
319 +config FSL_QMAN_DEBUGFS
320 + tristate "QMan debugfs interface"
321 + depends on DEBUG_FS
322 + default y
323 + ---help---
324 + This option compiles debugfs code for QMan.
325 +
326 +# H/w settings that can be hard-coded for now.
327 +config FSL_QMAN_FQD_SZ
328 + int "size of Frame Queue Descriptor region"
329 + default 10
330 + ---help---
331 + This is the size of the FQD region defined as: PAGE_SIZE * (2^value)
332 + ex: 10 => PAGE_SIZE * (2^10)
333 + Note: Default device-trees now require minimum Kconfig setting of 10.
334 +
335 +config FSL_QMAN_PFDR_SZ
336 + int "size of the PFDR pool"
337 + default 13
338 + ---help---
339 + This is the size of the PFDR pool defined as: PAGE_SIZE * (2^value)
340 + ex: 13 => PAGE_SIZE * (2^13)
341 +
342 +# Corenet initiator settings. Stash request queues are 4-deep to match cores'
343 +# ability to snart. Stash priority is 3, other priorities are 2.
344 +config FSL_QMAN_CI_SCHED_CFG_SRCCIV
345 + int
346 + depends on FSL_QMAN_CONFIG
347 + default 4
348 +config FSL_QMAN_CI_SCHED_CFG_SRQ_W
349 + int
350 + depends on FSL_QMAN_CONFIG
351 + default 3
352 +config FSL_QMAN_CI_SCHED_CFG_RW_W
353 + int
354 + depends on FSL_QMAN_CONFIG
355 + default 2
356 +config FSL_QMAN_CI_SCHED_CFG_BMAN_W
357 + int
358 + depends on FSL_QMAN_CONFIG
359 + default 2
360 +
361 +# portal interrupt settings
362 +config FSL_QMAN_PIRQ_DQRR_ITHRESH
363 + int
364 + default 12
365 +config FSL_QMAN_PIRQ_MR_ITHRESH
366 + int
367 + default 4
368 +config FSL_QMAN_PIRQ_IPERIOD
369 + int
370 + default 100
371 +
372 +# 64 bit kernel support
373 +config FSL_QMAN_FQ_LOOKUP
374 + bool
375 + default n
376 +
377 +config QMAN_CEETM_UPDATE_PERIOD
378 + int "Token update period for shaping, in nanoseconds"
379 + default 1000
380 + ---help---
381 + Traffic shaping works by performing token calculations (using
382 + credits) on shaper instances periodically. This update period
383 + sets the granularity for how often those token rate credit
384 + updates are performed, and thus determines the accuracy and
385 + range of traffic rates that can be configured by users. The
386 + reference manual recommends a 1 microsecond period as providing
387 + a good balance between granularity and range.
388 +
389 + Unless you know what you are doing, leave this value at its default.
390 +
391 +config FSL_QMAN_INIT_TIMEOUT
392 + int "timeout for qman init stage, in seconds"
393 + default 10
394 + ---help---
395 + The timeout setting to quit the initialization loop for non-control
396 + partition in case the control partition fails to boot-up.
397 +
398 +endif # FSL_QMAN
399 +
400 +endmenu
401 --- /dev/null
402 +++ b/drivers/staging/fsl_qbman/Makefile
403 @@ -0,0 +1,28 @@
404 +subdir-ccflags-y := -Werror
405 +
406 +# Common
407 +obj-$(CONFIG_FSL_DPA) += dpa_alloc.o
408 +obj-$(CONFIG_HAS_FSL_QBMAN) += qbman_driver.o
409 +
410 +# Bman
411 +obj-$(CONFIG_FSL_BMAN) += bman_high.o
412 +obj-$(CONFIG_FSL_BMAN_CONFIG) += bman_config.o bman_driver.o
413 +obj-$(CONFIG_FSL_BMAN_TEST) += bman_tester.o
414 +obj-$(CONFIG_FSL_BMAN_DEBUGFS) += bman_debugfs_interface.o
415 +bman_tester-y = bman_test.o
416 +bman_tester-$(CONFIG_FSL_BMAN_TEST_HIGH) += bman_test_high.o
417 +bman_tester-$(CONFIG_FSL_BMAN_TEST_THRESH) += bman_test_thresh.o
418 +bman_debugfs_interface-y = bman_debugfs.o
419 +
420 +# Qman
421 +obj-$(CONFIG_FSL_QMAN) += qman_high.o qman_utility.o
422 +obj-$(CONFIG_FSL_QMAN_CONFIG) += qman_config.o qman_driver.o
423 +obj-$(CONFIG_FSL_QMAN_TEST) += qman_tester.o
424 +qman_tester-y = qman_test.o
425 +qman_tester-$(CONFIG_FSL_QMAN_TEST_STASH_POTATO) += qman_test_hotpotato.o
426 +qman_tester-$(CONFIG_FSL_QMAN_TEST_HIGH) += qman_test_high.o
427 +obj-$(CONFIG_FSL_QMAN_DEBUGFS) += qman_debugfs_interface.o
428 +qman_debugfs_interface-y = qman_debugfs.o
429 +
430 +# USDPAA
431 +obj-$(CONFIG_FSL_USDPAA) += fsl_usdpaa.o fsl_usdpaa_irq.o
432 --- /dev/null
433 +++ b/drivers/staging/fsl_qbman/bman_config.c
434 @@ -0,0 +1,705 @@
435 +/* Copyright (c) 2009-2012 Freescale Semiconductor, Inc.
436 + *
437 + * Redistribution and use in source and binary forms, with or without
438 + * modification, are permitted provided that the following conditions are met:
439 + * * Redistributions of source code must retain the above copyright
440 + * notice, this list of conditions and the following disclaimer.
441 + * * Redistributions in binary form must reproduce the above copyright
442 + * notice, this list of conditions and the following disclaimer in the
443 + * documentation and/or other materials provided with the distribution.
444 + * * Neither the name of Freescale Semiconductor nor the
445 + * names of its contributors may be used to endorse or promote products
446 + * derived from this software without specific prior written permission.
447 + *
448 + *
449 + * ALTERNATIVELY, this software may be distributed under the terms of the
450 + * GNU General Public License ("GPL") as published by the Free Software
451 + * Foundation, either version 2 of that License or (at your option) any
452 + * later version.
453 + *
454 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
455 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
456 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
457 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
458 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
459 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
460 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
461 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
462 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
463 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
464 + */
465 +
466 +#include <asm/cacheflush.h>
467 +#include "bman_private.h"
468 +#include <linux/of_reserved_mem.h>
469 +
470 +/* Last updated for v00.79 of the BG */
471 +
472 +struct bman;
473 +
474 +/* Register offsets */
475 +#define REG_POOL_SWDET(n) (0x0000 + ((n) * 0x04))
476 +#define REG_POOL_HWDET(n) (0x0100 + ((n) * 0x04))
477 +#define REG_POOL_SWDXT(n) (0x0200 + ((n) * 0x04))
478 +#define REG_POOL_HWDXT(n) (0x0300 + ((n) * 0x04))
479 +#define REG_POOL_CONTENT(n) (0x0600 + ((n) * 0x04))
480 +#define REG_FBPR_FPC 0x0800
481 +#define REG_STATE_IDLE 0x960
482 +#define REG_STATE_STOP 0x964
483 +#define REG_ECSR 0x0a00
484 +#define REG_ECIR 0x0a04
485 +#define REG_EADR 0x0a08
486 +#define REG_EDATA(n) (0x0a10 + ((n) * 0x04))
487 +#define REG_SBEC(n) (0x0a80 + ((n) * 0x04))
488 +#define REG_IP_REV_1 0x0bf8
489 +#define REG_IP_REV_2 0x0bfc
490 +#define REG_FBPR_BARE 0x0c00
491 +#define REG_FBPR_BAR 0x0c04
492 +#define REG_FBPR_AR 0x0c10
493 +#define REG_SRCIDR 0x0d04
494 +#define REG_LIODNR 0x0d08
495 +#define REG_ERR_ISR 0x0e00 /* + "enum bm_isr_reg" */
496 +
497 +/* Used by all error interrupt registers except 'inhibit' */
498 +#define BM_EIRQ_IVCI 0x00000010 /* Invalid Command Verb */
499 +#define BM_EIRQ_FLWI 0x00000008 /* FBPR Low Watermark */
500 +#define BM_EIRQ_MBEI 0x00000004 /* Multi-bit ECC Error */
501 +#define BM_EIRQ_SBEI 0x00000002 /* Single-bit ECC Error */
502 +#define BM_EIRQ_BSCN 0x00000001 /* pool State Change Notification */
503 +
504 +/* BMAN_ECIR valid error bit */
505 +#define PORTAL_ECSR_ERR (BM_EIRQ_IVCI)
506 +
507 +union bman_ecir {
508 + u32 ecir_raw;
509 + struct {
510 + u32 __reserved1:4;
511 + u32 portal_num:4;
512 + u32 __reserved2:12;
513 + u32 numb:4;
514 + u32 __reserved3:2;
515 + u32 pid:6;
516 + } __packed info;
517 +};
518 +
519 +union bman_eadr {
520 + u32 eadr_raw;
521 + struct {
522 + u32 __reserved1:5;
523 + u32 memid:3;
524 + u32 __reserved2:14;
525 + u32 eadr:10;
526 + } __packed info;
527 +};
528 +
529 +struct bman_hwerr_txt {
530 + u32 mask;
531 + const char *txt;
532 +};
533 +
534 +#define BMAN_HWE_TXT(a, b) { .mask = BM_EIRQ_##a, .txt = b }
535 +
536 +static const struct bman_hwerr_txt bman_hwerr_txts[] = {
537 + BMAN_HWE_TXT(IVCI, "Invalid Command Verb"),
538 + BMAN_HWE_TXT(FLWI, "FBPR Low Watermark"),
539 + BMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"),
540 + BMAN_HWE_TXT(SBEI, "Single-bit ECC Error"),
541 + BMAN_HWE_TXT(BSCN, "Pool State Change Notification"),
542 +};
543 +#define BMAN_HWE_COUNT (sizeof(bman_hwerr_txts)/sizeof(struct bman_hwerr_txt))
544 +
545 +struct bman_error_info_mdata {
546 + u16 addr_mask;
547 + u16 bits;
548 + const char *txt;
549 +};
550 +
551 +#define BMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c}
552 +static const struct bman_error_info_mdata error_mdata[] = {
553 + BMAN_ERR_MDATA(0x03FF, 192, "Stockpile memory"),
554 + BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 1"),
555 + BMAN_ERR_MDATA(0x00FF, 256, "SW portal ring memory port 2"),
556 +};
557 +#define BMAN_ERR_MDATA_COUNT \
558 + (sizeof(error_mdata)/sizeof(struct bman_error_info_mdata))
559 +
560 +/* Add this in Kconfig */
561 +#define BMAN_ERRS_TO_UNENABLE (BM_EIRQ_FLWI)
562 +
563 +/**
564 + * bm_err_isr_<reg>_<verb> - Manipulate global interrupt registers
565 + * @v: for accessors that write values, this is the 32-bit value
566 + *
567 + * Manipulates BMAN_ERR_ISR, BMAN_ERR_IER, BMAN_ERR_ISDR, BMAN_ERR_IIR. All
568 + * manipulations except bm_err_isr_[un]inhibit() use 32-bit masks composed of
569 + * the BM_EIRQ_*** definitions. Note that "bm_err_isr_enable_write" means
570 + * "write the enable register" rather than "enable the write register"!
571 + */
572 +#define bm_err_isr_status_read(bm) \
573 + __bm_err_isr_read(bm, bm_isr_status)
574 +#define bm_err_isr_status_clear(bm, m) \
575 + __bm_err_isr_write(bm, bm_isr_status, m)
576 +#define bm_err_isr_enable_read(bm) \
577 + __bm_err_isr_read(bm, bm_isr_enable)
578 +#define bm_err_isr_enable_write(bm, v) \
579 + __bm_err_isr_write(bm, bm_isr_enable, v)
580 +#define bm_err_isr_disable_read(bm) \
581 + __bm_err_isr_read(bm, bm_isr_disable)
582 +#define bm_err_isr_disable_write(bm, v) \
583 + __bm_err_isr_write(bm, bm_isr_disable, v)
584 +#define bm_err_isr_inhibit(bm) \
585 + __bm_err_isr_write(bm, bm_isr_inhibit, 1)
586 +#define bm_err_isr_uninhibit(bm) \
587 + __bm_err_isr_write(bm, bm_isr_inhibit, 0)
588 +
589 +/*
590 + * TODO: unimplemented registers
591 + *
592 + * BMAN_POOLk_SDCNT, BMAN_POOLk_HDCNT, BMAN_FULT,
593 + * BMAN_VLDPL, BMAN_EECC, BMAN_SBET, BMAN_EINJ
594 + */
595 +
596 +/* Encapsulate "struct bman *" as a cast of the register space address. */
597 +
598 +static struct bman *bm_create(void *regs)
599 +{
600 + return (struct bman *)regs;
601 +}
602 +
603 +static inline u32 __bm_in(struct bman *bm, u32 offset)
604 +{
605 + return in_be32((void *)bm + offset);
606 +}
607 +static inline void __bm_out(struct bman *bm, u32 offset, u32 val)
608 +{
609 + out_be32((void *)bm + offset, val);
610 +}
611 +#define bm_in(reg) __bm_in(bm, REG_##reg)
612 +#define bm_out(reg, val) __bm_out(bm, REG_##reg, val)
613 +
614 +static u32 __bm_err_isr_read(struct bman *bm, enum bm_isr_reg n)
615 +{
616 + return __bm_in(bm, REG_ERR_ISR + (n << 2));
617 +}
618 +
619 +static void __bm_err_isr_write(struct bman *bm, enum bm_isr_reg n, u32 val)
620 +{
621 + __bm_out(bm, REG_ERR_ISR + (n << 2), val);
622 +}
623 +
624 +static void bm_get_version(struct bman *bm, u16 *id, u8 *major, u8 *minor)
625 +{
626 + u32 v = bm_in(IP_REV_1);
627 + *id = (v >> 16);
628 + *major = (v >> 8) & 0xff;
629 + *minor = v & 0xff;
630 +}
631 +
632 +static u32 __generate_thresh(u32 val, int roundup)
633 +{
634 + u32 e = 0; /* co-efficient, exponent */
635 + int oddbit = 0;
636 + while (val > 0xff) {
637 + oddbit = val & 1;
638 + val >>= 1;
639 + e++;
640 + if (roundup && oddbit)
641 + val++;
642 + }
643 + DPA_ASSERT(e < 0x10);
644 + return val | (e << 8);
645 +}
646 +
647 +static void bm_set_pool(struct bman *bm, u8 pool, u32 swdet, u32 swdxt,
648 + u32 hwdet, u32 hwdxt)
649 +{
650 + DPA_ASSERT(pool < bman_pool_max);
651 + bm_out(POOL_SWDET(pool), __generate_thresh(swdet, 0));
652 + bm_out(POOL_SWDXT(pool), __generate_thresh(swdxt, 1));
653 + bm_out(POOL_HWDET(pool), __generate_thresh(hwdet, 0));
654 + bm_out(POOL_HWDXT(pool), __generate_thresh(hwdxt, 1));
655 +}
656 +
657 +static void bm_set_memory(struct bman *bm, u64 ba, int prio, u32 size)
658 +{
659 + u32 exp = ilog2(size);
660 + /* choke if size isn't within range */
661 + DPA_ASSERT((size >= 4096) && (size <= 1073741824) &&
662 + is_power_of_2(size));
663 + /* choke if '[e]ba' has lower-alignment than 'size' */
664 + DPA_ASSERT(!(ba & (size - 1)));
665 + bm_out(FBPR_BARE, upper_32_bits(ba));
666 + bm_out(FBPR_BAR, lower_32_bits(ba));
667 + bm_out(FBPR_AR, (prio ? 0x40000000 : 0) | (exp - 1));
668 +}
669 +
670 +/*****************/
671 +/* Config driver */
672 +/*****************/
673 +
674 +/* TODO: Kconfig these? */
675 +#define DEFAULT_FBPR_SZ (PAGE_SIZE << 12)
676 +
677 +/* We support only one of these. */
678 +static struct bman *bm;
679 +static struct device_node *bm_node;
680 +
681 +/* And this state belongs to 'bm'. It is set during fsl_bman_init(), but used
682 + * during bman_init_ccsr(). */
683 +static dma_addr_t fbpr_a;
684 +static size_t fbpr_sz = DEFAULT_FBPR_SZ;
685 +
686 +static int bman_fbpr(struct reserved_mem *rmem)
687 +{
688 + fbpr_a = rmem->base;
689 + fbpr_sz = rmem->size;
690 +
691 + WARN_ON(!(fbpr_a && fbpr_sz));
692 +
693 + return 0;
694 +}
695 +RESERVEDMEM_OF_DECLARE(bman_fbpr, "fsl,bman-fbpr", bman_fbpr);
696 +
697 +static int __init fsl_bman_init(struct device_node *node)
698 +{
699 + struct resource res;
700 + u32 __iomem *regs;
701 + const char *s;
702 + int ret, standby = 0;
703 + u16 id;
704 + u8 major, minor;
705 +
706 + ret = of_address_to_resource(node, 0, &res);
707 + if (ret) {
708 + pr_err("Can't get %s property 'reg'\n",
709 + node->full_name);
710 + return ret;
711 + }
712 + s = of_get_property(node, "fsl,hv-claimable", &ret);
713 + if (s && !strcmp(s, "standby"))
714 + standby = 1;
715 + /* Global configuration */
716 + regs = ioremap(res.start, res.end - res.start + 1);
717 + bm = bm_create(regs);
718 + BUG_ON(!bm);
719 + bm_node = node;
720 + bm_get_version(bm, &id, &major, &minor);
721 + pr_info("Bman ver:%04x,%02x,%02x\n", id, major, minor);
722 + if ((major == 1) && (minor == 0)) {
723 + bman_ip_rev = BMAN_REV10;
724 + bman_pool_max = 64;
725 + } else if ((major == 2) && (minor == 0)) {
726 + bman_ip_rev = BMAN_REV20;
727 + bman_pool_max = 8;
728 + } else if ((major == 2) && (minor == 1)) {
729 + bman_ip_rev = BMAN_REV21;
730 + bman_pool_max = 64;
731 + } else {
732 + pr_warn("unknown Bman version, default to rev1.0\n");
733 + }
734 +
735 + if (standby) {
736 + pr_info(" -> in standby mode\n");
737 + return 0;
738 + }
739 + return 0;
740 +}
741 +
742 +int bman_have_ccsr(void)
743 +{
744 + return bm ? 1 : 0;
745 +}
746 +
747 +int bm_pool_set(u32 bpid, const u32 *thresholds)
748 +{
749 + if (!bm)
750 + return -ENODEV;
751 + bm_set_pool(bm, bpid, thresholds[0],
752 + thresholds[1], thresholds[2],
753 + thresholds[3]);
754 + return 0;
755 +}
756 +EXPORT_SYMBOL(bm_pool_set);
757 +
758 +__init int bman_init_early(void)
759 +{
760 + struct device_node *dn;
761 + int ret;
762 +
763 + for_each_compatible_node(dn, NULL, "fsl,bman") {
764 + if (bm)
765 + pr_err("%s: only one 'fsl,bman' allowed\n",
766 + dn->full_name);
767 + else {
768 + if (!of_device_is_available(dn))
769 + continue;
770 +
771 + ret = fsl_bman_init(dn);
772 + BUG_ON(ret);
773 + }
774 + }
775 + return 0;
776 +}
777 +postcore_initcall_sync(bman_init_early);
778 +
779 +
780 +static void log_edata_bits(u32 bit_count)
781 +{
782 + u32 i, j, mask = 0xffffffff;
783 +
784 + pr_warn("Bman ErrInt, EDATA:\n");
785 + i = bit_count/32;
786 + if (bit_count%32) {
787 + i++;
788 + mask = ~(mask << bit_count%32);
789 + }
790 + j = 16-i;
791 + pr_warn(" 0x%08x\n", bm_in(EDATA(j)) & mask);
792 + j++;
793 + for (; j < 16; j++)
794 + pr_warn(" 0x%08x\n", bm_in(EDATA(j)));
795 +}
796 +
797 +static void log_additional_error_info(u32 isr_val, u32 ecsr_val)
798 +{
799 + union bman_ecir ecir_val;
800 + union bman_eadr eadr_val;
801 +
802 + ecir_val.ecir_raw = bm_in(ECIR);
803 + /* Is portal info valid */
804 + if (ecsr_val & PORTAL_ECSR_ERR) {
805 + pr_warn("Bman ErrInt: SWP id %d, numb %d, pid %d\n",
806 + ecir_val.info.portal_num, ecir_val.info.numb,
807 + ecir_val.info.pid);
808 + }
809 + if (ecsr_val & (BM_EIRQ_SBEI|BM_EIRQ_MBEI)) {
810 + eadr_val.eadr_raw = bm_in(EADR);
811 + pr_warn("Bman ErrInt: EADR Memory: %s, 0x%x\n",
812 + error_mdata[eadr_val.info.memid].txt,
813 + error_mdata[eadr_val.info.memid].addr_mask
814 + & eadr_val.info.eadr);
815 + log_edata_bits(error_mdata[eadr_val.info.memid].bits);
816 + }
817 +}
818 +
819 +/* Bman interrupt handler */
820 +static irqreturn_t bman_isr(int irq, void *ptr)
821 +{
822 + u32 isr_val, ier_val, ecsr_val, isr_mask, i;
823 +
824 + ier_val = bm_err_isr_enable_read(bm);
825 + isr_val = bm_err_isr_status_read(bm);
826 + ecsr_val = bm_in(ECSR);
827 + isr_mask = isr_val & ier_val;
828 +
829 + if (!isr_mask)
830 + return IRQ_NONE;
831 + for (i = 0; i < BMAN_HWE_COUNT; i++) {
832 + if (bman_hwerr_txts[i].mask & isr_mask) {
833 + pr_warn("Bman ErrInt: %s\n", bman_hwerr_txts[i].txt);
834 + if (bman_hwerr_txts[i].mask & ecsr_val) {
835 + log_additional_error_info(isr_mask, ecsr_val);
836 + /* Re-arm error capture registers */
837 + bm_out(ECSR, ecsr_val);
838 + }
839 + if (bman_hwerr_txts[i].mask & BMAN_ERRS_TO_UNENABLE) {
840 + pr_devel("Bman un-enabling error 0x%x\n",
841 + bman_hwerr_txts[i].mask);
842 + ier_val &= ~bman_hwerr_txts[i].mask;
843 + bm_err_isr_enable_write(bm, ier_val);
844 + }
845 + }
846 + }
847 + bm_err_isr_status_clear(bm, isr_val);
848 + return IRQ_HANDLED;
849 +}
850 +
851 +static int __bind_irq(void)
852 +{
853 + int ret, err_irq;
854 +
855 + err_irq = of_irq_to_resource(bm_node, 0, NULL);
856 + if (err_irq == 0) {
857 + pr_info("Can't get %s property '%s'\n", bm_node->full_name,
858 + "interrupts");
859 + return -ENODEV;
860 + }
861 + ret = request_irq(err_irq, bman_isr, IRQF_SHARED, "bman-err", bm_node);
862 + if (ret) {
863 + pr_err("request_irq() failed %d for '%s'\n", ret,
864 + bm_node->full_name);
865 + return -ENODEV;
866 + }
867 + /* Disable Buffer Pool State Change */
868 + bm_err_isr_disable_write(bm, BM_EIRQ_BSCN);
869 + /* Write-to-clear any stale bits, (eg. starvation being asserted prior
870 + * to resource allocation during driver init). */
871 + bm_err_isr_status_clear(bm, 0xffffffff);
872 + /* Enable Error Interrupts */
873 + bm_err_isr_enable_write(bm, 0xffffffff);
874 + return 0;
875 +}
876 +
877 +int bman_init_ccsr(struct device_node *node)
878 +{
879 + int ret;
880 + if (!bman_have_ccsr())
881 + return 0;
882 + if (node != bm_node)
883 + return -EINVAL;
884 + /* FBPR memory */
885 + bm_set_memory(bm, fbpr_a, 0, fbpr_sz);
886 + pr_info("bman-fbpr addr 0x%llx size 0x%zx\n",
887 + (unsigned long long)fbpr_a, fbpr_sz);
888 +
889 + ret = __bind_irq();
890 + if (ret)
891 + return ret;
892 + return 0;
893 +}
894 +
895 +u32 bm_pool_free_buffers(u32 bpid)
896 +{
897 + return bm_in(POOL_CONTENT(bpid));
898 +}
899 +
900 +#ifdef CONFIG_SYSFS
901 +
902 +#define DRV_NAME "fsl-bman"
903 +#define SBEC_MAX_ID 1
904 +#define SBEC_MIN_ID 0
905 +
906 +static ssize_t show_fbpr_fpc(struct device *dev,
907 + struct device_attribute *dev_attr, char *buf)
908 +{
909 + return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(FBPR_FPC));
910 +};
911 +
912 +static ssize_t show_pool_count(struct device *dev,
913 + struct device_attribute *dev_attr, char *buf)
914 +{
915 + u32 data;
916 + int i;
917 +
918 + if (!sscanf(dev_attr->attr.name, "%d", &i) || (i >= bman_pool_max))
919 + return -EINVAL;
920 + data = bm_in(POOL_CONTENT(i));
921 + return snprintf(buf, PAGE_SIZE, "%d\n", data);
922 +};
923 +
924 +static ssize_t show_err_isr(struct device *dev,
925 + struct device_attribute *dev_attr, char *buf)
926 +{
927 + return snprintf(buf, PAGE_SIZE, "0x%08x\n", bm_in(ERR_ISR));
928 +};
929 +
930 +static ssize_t show_sbec(struct device *dev,
931 + struct device_attribute *dev_attr, char *buf)
932 +{
933 + int i;
934 +
935 + if (!sscanf(dev_attr->attr.name, "sbec_%d", &i))
936 + return -EINVAL;
937 + if (i < SBEC_MIN_ID || i > SBEC_MAX_ID)
938 + return -EINVAL;
939 + return snprintf(buf, PAGE_SIZE, "%u\n", bm_in(SBEC(i)));
940 +};
941 +
942 +static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL);
943 +static DEVICE_ATTR(fbpr_fpc, S_IRUSR, show_fbpr_fpc, NULL);
944 +
945 +/* Didn't use DEVICE_ATTR as 64 of this would be required.
946 + * Initialize them when needed. */
947 +static char *name_attrs_pool_count; /* "xx" + null-terminator */
948 +static struct device_attribute *dev_attr_buffer_pool_count;
949 +
950 +static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL);
951 +static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL);
952 +
953 +static struct attribute *bman_dev_attributes[] = {
954 + &dev_attr_fbpr_fpc.attr,
955 + &dev_attr_err_isr.attr,
956 + NULL
957 +};
958 +
959 +static struct attribute *bman_dev_ecr_attributes[] = {
960 + &dev_attr_sbec_0.attr,
961 + &dev_attr_sbec_1.attr,
962 + NULL
963 +};
964 +
965 +static struct attribute **bman_dev_pool_count_attributes;
966 +
967 +
968 +/* root level */
969 +static const struct attribute_group bman_dev_attr_grp = {
970 + .name = NULL,
971 + .attrs = bman_dev_attributes
972 +};
973 +static const struct attribute_group bman_dev_ecr_grp = {
974 + .name = "error_capture",
975 + .attrs = bman_dev_ecr_attributes
976 +};
977 +static struct attribute_group bman_dev_pool_countent_grp = {
978 + .name = "pool_count",
979 +};
980 +
981 +static int of_fsl_bman_remove(struct platform_device *ofdev)
982 +{
983 + sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp);
984 + return 0;
985 +};
986 +
987 +static int of_fsl_bman_probe(struct platform_device *ofdev)
988 +{
989 + int ret, i;
990 +
991 + ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_attr_grp);
992 + if (ret)
993 + goto done;
994 + ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_ecr_grp);
995 + if (ret)
996 + goto del_group_0;
997 +
998 + name_attrs_pool_count = kmalloc(sizeof(char) * bman_pool_max * 3,
999 + GFP_KERNEL);
1000 + if (!name_attrs_pool_count) {
1001 + pr_err("Can't alloc name_attrs_pool_count\n");
1002 + goto del_group_1;
1003 + }
1004 +
1005 + dev_attr_buffer_pool_count = kmalloc(sizeof(struct device_attribute) *
1006 + bman_pool_max, GFP_KERNEL);
1007 + if (!dev_attr_buffer_pool_count) {
1008 + pr_err("Can't alloc dev_attr-buffer_pool_count\n");
1009 + goto del_group_2;
1010 + }
1011 +
1012 + bman_dev_pool_count_attributes = kmalloc(sizeof(struct attribute *) *
1013 + (bman_pool_max + 1), GFP_KERNEL);
1014 + if (!bman_dev_pool_count_attributes) {
1015 + pr_err("can't alloc bman_dev_pool_count_attributes\n");
1016 + goto del_group_3;
1017 + }
1018 +
1019 + for (i = 0; i < bman_pool_max; i++) {
1020 + ret = scnprintf((name_attrs_pool_count + i * 3), 3, "%d", i);
1021 + if (!ret)
1022 + goto del_group_4;
1023 + dev_attr_buffer_pool_count[i].attr.name =
1024 + (name_attrs_pool_count + i * 3);
1025 + dev_attr_buffer_pool_count[i].attr.mode = S_IRUSR;
1026 + dev_attr_buffer_pool_count[i].show = show_pool_count;
1027 + bman_dev_pool_count_attributes[i] =
1028 + &dev_attr_buffer_pool_count[i].attr;
1029 + sysfs_attr_init(bman_dev_pool_count_attributes[i]);
1030 + }
1031 + bman_dev_pool_count_attributes[bman_pool_max] = NULL;
1032 +
1033 + bman_dev_pool_countent_grp.attrs = bman_dev_pool_count_attributes;
1034 +
1035 + ret = sysfs_create_group(&ofdev->dev.kobj, &bman_dev_pool_countent_grp);
1036 + if (ret)
1037 + goto del_group_4;
1038 +
1039 + goto done;
1040 +
1041 +del_group_4:
1042 + kfree(bman_dev_pool_count_attributes);
1043 +del_group_3:
1044 + kfree(dev_attr_buffer_pool_count);
1045 +del_group_2:
1046 + kfree(name_attrs_pool_count);
1047 +del_group_1:
1048 + sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_ecr_grp);
1049 +del_group_0:
1050 + sysfs_remove_group(&ofdev->dev.kobj, &bman_dev_attr_grp);
1051 +done:
1052 + if (ret)
1053 + dev_err(&ofdev->dev,
1054 + "Cannot create dev attributes ret=%d\n", ret);
1055 + return ret;
1056 +};
1057 +
1058 +static struct of_device_id of_fsl_bman_ids[] = {
1059 + {
1060 + .compatible = "fsl,bman",
1061 + },
1062 + {}
1063 +};
1064 +MODULE_DEVICE_TABLE(of, of_fsl_bman_ids);
1065 +
1066 +#ifdef CONFIG_SUSPEND
1067 +static u32 saved_isdr;
1068 +
1069 +static int bman_pm_suspend_noirq(struct device *dev)
1070 +{
1071 + uint32_t idle_state;
1072 +
1073 + suspend_unused_bportal();
1074 + /* save isdr, disable all, clear isr */
1075 + saved_isdr = bm_err_isr_disable_read(bm);
1076 + bm_err_isr_disable_write(bm, 0xffffffff);
1077 + bm_err_isr_status_clear(bm, 0xffffffff);
1078 +
1079 + if (bman_ip_rev < BMAN_REV21) {
1080 +#ifdef CONFIG_PM_DEBUG
1081 + pr_info("Bman version doesn't have STATE_IDLE\n");
1082 +#endif
1083 + return 0;
1084 + }
1085 + idle_state = bm_in(STATE_IDLE);
1086 + if (!(idle_state & 0x1)) {
1087 + pr_err("Bman not idle 0x%x aborting\n", idle_state);
1088 + bm_err_isr_disable_write(bm, saved_isdr);
1089 + resume_unused_bportal();
1090 + return -EBUSY;
1091 + }
1092 +#ifdef CONFIG_PM_DEBUG
1093 + pr_info("Bman suspend code, IDLE_STAT = 0x%x\n", idle_state);
1094 +#endif
1095 + return 0;
1096 +}
1097 +
1098 +static int bman_pm_resume_noirq(struct device *dev)
1099 +{
1100 + /* restore isdr */
1101 + bm_err_isr_disable_write(bm, saved_isdr);
1102 + resume_unused_bportal();
1103 + return 0;
1104 +}
1105 +#else
1106 +#define bman_pm_suspend_noirq NULL
1107 +#define bman_pm_resume_noirq NULL
1108 +#endif
1109 +
1110 +static const struct dev_pm_ops bman_pm_ops = {
1111 + .suspend_noirq = bman_pm_suspend_noirq,
1112 + .resume_noirq = bman_pm_resume_noirq,
1113 +};
1114 +
1115 +static struct platform_driver of_fsl_bman_driver = {
1116 + .driver = {
1117 + .owner = THIS_MODULE,
1118 + .name = DRV_NAME,
1119 + .of_match_table = of_fsl_bman_ids,
1120 + .pm = &bman_pm_ops,
1121 + },
1122 + .probe = of_fsl_bman_probe,
1123 + .remove = of_fsl_bman_remove,
1124 +};
1125 +
1126 +static int bman_ctrl_init(void)
1127 +{
1128 + return platform_driver_register(&of_fsl_bman_driver);
1129 +}
1130 +
1131 +static void bman_ctrl_exit(void)
1132 +{
1133 + platform_driver_unregister(&of_fsl_bman_driver);
1134 +}
1135 +
1136 +module_init(bman_ctrl_init);
1137 +module_exit(bman_ctrl_exit);
1138 +
1139 +#endif /* CONFIG_SYSFS */
1140 --- /dev/null
1141 +++ b/drivers/staging/fsl_qbman/bman_debugfs.c
1142 @@ -0,0 +1,119 @@
1143 +/* Copyright 2010-2011 Freescale Semiconductor, Inc.
1144 + *
1145 + * Redistribution and use in source and binary forms, with or without
1146 + * modification, are permitted provided that the following conditions are met:
1147 + * * Redistributions of source code must retain the above copyright
1148 + * notice, this list of conditions and the following disclaimer.
1149 + * * Redistributions in binary form must reproduce the above copyright
1150 + * notice, this list of conditions and the following disclaimer in the
1151 + * documentation and/or other materials provided with the distribution.
1152 + * * Neither the name of Freescale Semiconductor nor the
1153 + * names of its contributors may be used to endorse or promote products
1154 + * derived from this software without specific prior written permission.
1155 + *
1156 + *
1157 + * ALTERNATIVELY, this software may be distributed under the terms of the
1158 + * GNU General Public License ("GPL") as published by the Free Software
1159 + * Foundation, either version 2 of that License or (at your option) any
1160 + * later version.
1161 + *
1162 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
1163 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1164 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1165 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
1166 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1167 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1168 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1169 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1170 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1171 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1172 + */
1173 +#include <linux/module.h>
1174 +#include <linux/fsl_bman.h>
1175 +#include <linux/debugfs.h>
1176 +#include <linux/seq_file.h>
1177 +#include <linux/uaccess.h>
1178 +
1179 +static struct dentry *dfs_root; /* debugfs root directory */
1180 +
1181 +/*******************************************************************************
1182 + * Query Buffer Pool State
1183 + ******************************************************************************/
1184 +static int query_bp_state_show(struct seq_file *file, void *offset)
1185 +{
1186 + int ret;
1187 + struct bm_pool_state state;
1188 + int i, j;
1189 + u32 mask;
1190 +
1191 + memset(&state, 0, sizeof(struct bm_pool_state));
1192 + ret = bman_query_pools(&state);
1193 + if (ret) {
1194 + seq_printf(file, "Error %d\n", ret);
1195 + return 0;
1196 + }
1197 + seq_puts(file, "bp_id free_buffers_avail bp_depleted\n");
1198 + for (i = 0; i < 2; i++) {
1199 + mask = 0x80000000;
1200 + for (j = 0; j < 32; j++) {
1201 + seq_printf(file,
1202 + " %-2u %-3s %-3s\n",
1203 + (i*32)+j,
1204 + (state.as.state.__state[i] & mask) ? "no" : "yes",
1205 + (state.ds.state.__state[i] & mask) ? "yes" : "no");
1206 + mask >>= 1;
1207 + }
1208 + }
1209 + return 0;
1210 +}
1211 +
1212 +static int query_bp_state_open(struct inode *inode, struct file *file)
1213 +{
1214 + return single_open(file, query_bp_state_show, NULL);
1215 +}
1216 +
1217 +static const struct file_operations query_bp_state_fops = {
1218 + .owner = THIS_MODULE,
1219 + .open = query_bp_state_open,
1220 + .read = seq_read,
1221 + .release = single_release,
1222 +};
1223 +
1224 +static int __init bman_debugfs_module_init(void)
1225 +{
1226 + int ret = 0;
1227 + struct dentry *d;
1228 +
1229 + dfs_root = debugfs_create_dir("bman", NULL);
1230 +
1231 + if (dfs_root == NULL) {
1232 + ret = -ENOMEM;
1233 + pr_err("Cannot create bman debugfs dir\n");
1234 + goto _return;
1235 + }
1236 + d = debugfs_create_file("query_bp_state",
1237 + S_IRUGO,
1238 + dfs_root,
1239 + NULL,
1240 + &query_bp_state_fops);
1241 + if (d == NULL) {
1242 + ret = -ENOMEM;
1243 + pr_err("Cannot create query_bp_state\n");
1244 + goto _return;
1245 + }
1246 + return 0;
1247 +
1248 +_return:
1249 + debugfs_remove_recursive(dfs_root);
1250 + return ret;
1251 +}
1252 +
1253 +static void __exit bman_debugfs_module_exit(void)
1254 +{
1255 + debugfs_remove_recursive(dfs_root);
1256 +}
1257 +
1258 +
1259 +module_init(bman_debugfs_module_init);
1260 +module_exit(bman_debugfs_module_exit);
1261 +MODULE_LICENSE("Dual BSD/GPL");
1262 --- /dev/null
1263 +++ b/drivers/staging/fsl_qbman/bman_driver.c
1264 @@ -0,0 +1,574 @@
1265 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
1266 + *
1267 + * Redistribution and use in source and binary forms, with or without
1268 + * modification, are permitted provided that the following conditions are met:
1269 + * * Redistributions of source code must retain the above copyright
1270 + * notice, this list of conditions and the following disclaimer.
1271 + * * Redistributions in binary form must reproduce the above copyright
1272 + * notice, this list of conditions and the following disclaimer in the
1273 + * documentation and/or other materials provided with the distribution.
1274 + * * Neither the name of Freescale Semiconductor nor the
1275 + * names of its contributors may be used to endorse or promote products
1276 + * derived from this software without specific prior written permission.
1277 + *
1278 + *
1279 + * ALTERNATIVELY, this software may be distributed under the terms of the
1280 + * GNU General Public License ("GPL") as published by the Free Software
1281 + * Foundation, either version 2 of that License or (at your option) any
1282 + * later version.
1283 + *
1284 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
1285 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1286 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1287 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
1288 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1289 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1290 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1291 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1292 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1293 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1294 + */
1295 +#include "bman_low.h"
1296 +#ifdef CONFIG_HOTPLUG_CPU
1297 +#include <linux/cpu.h>
1298 +#endif
1299 +/*
1300 + * Global variables of the max portal/pool number this bman version supported
1301 + */
1302 +u16 bman_ip_rev;
1303 +EXPORT_SYMBOL(bman_ip_rev);
1304 +u16 bman_pool_max;
1305 +EXPORT_SYMBOL(bman_pool_max);
1306 +static u16 bman_portal_max;
1307 +
1308 +/* After initialising cpus that own shared portal configs, we cache the
1309 + * resulting portals (ie. not just the configs) in this array. Then we
1310 + * initialise slave cpus that don't have their own portals, redirecting them to
1311 + * portals from this cache in a round-robin assignment. */
1312 +static struct bman_portal *shared_portals[NR_CPUS];
1313 +static int num_shared_portals;
1314 +static int shared_portals_idx;
1315 +static LIST_HEAD(unused_pcfgs);
1316 +static DEFINE_SPINLOCK(unused_pcfgs_lock);
1317 +static void *affine_bportals[NR_CPUS];
1318 +
1319 +static int __init fsl_bpool_init(struct device_node *node)
1320 +{
1321 + int ret;
1322 + u32 *thresh, *bpid = (u32 *)of_get_property(node, "fsl,bpid", &ret);
1323 + if (!bpid || (ret != 4)) {
1324 + pr_err("Can't get %s property 'fsl,bpid'\n", node->full_name);
1325 + return -ENODEV;
1326 + }
1327 + thresh = (u32 *)of_get_property(node, "fsl,bpool-thresholds", &ret);
1328 + if (thresh) {
1329 + if (ret != 16) {
1330 + pr_err("Invalid %s property '%s'\n",
1331 + node->full_name, "fsl,bpool-thresholds");
1332 + return -ENODEV;
1333 + }
1334 + }
1335 + if (thresh) {
1336 +#ifdef CONFIG_FSL_BMAN_CONFIG
1337 + ret = bm_pool_set(be32_to_cpu(*bpid), thresh);
1338 + if (ret)
1339 + pr_err("No CCSR node for %s property '%s'\n",
1340 + node->full_name, "fsl,bpool-thresholds");
1341 + return ret;
1342 +#else
1343 + pr_err("Ignoring %s property '%s', no CCSR support\n",
1344 + node->full_name, "fsl,bpool-thresholds");
1345 +#endif
1346 + }
1347 + return 0;
1348 +}
1349 +
1350 +static int __init fsl_bpid_range_init(struct device_node *node)
1351 +{
1352 + int ret;
1353 + u32 *range = (u32 *)of_get_property(node, "fsl,bpid-range", &ret);
1354 + if (!range) {
1355 + pr_err("No 'fsl,bpid-range' property in node %s\n",
1356 + node->full_name);
1357 + return -EINVAL;
1358 + }
1359 + if (ret != 8) {
1360 + pr_err("'fsl,bpid-range' is not a 2-cell range in node %s\n",
1361 + node->full_name);
1362 + return -EINVAL;
1363 + }
1364 + bman_seed_bpid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
1365 + pr_info("Bman: BPID allocator includes range %d:%d\n",
1366 + be32_to_cpu(range[0]), be32_to_cpu(range[1]));
1367 + return 0;
1368 +}
1369 +
1370 +static struct bm_portal_config * __init parse_pcfg(struct device_node *node)
1371 +{
1372 + struct bm_portal_config *pcfg;
1373 + const u32 *index;
1374 + int irq, ret;
1375 + resource_size_t len;
1376 +
1377 + pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL);
1378 + if (!pcfg) {
1379 + pr_err("can't allocate portal config");
1380 + return NULL;
1381 + }
1382 +
1383 + if (of_device_is_compatible(node, "fsl,bman-portal-1.0") ||
1384 + of_device_is_compatible(node, "fsl,bman-portal-1.0.0")) {
1385 + bman_ip_rev = BMAN_REV10;
1386 + bman_pool_max = 64;
1387 + bman_portal_max = 10;
1388 + } else if (of_device_is_compatible(node, "fsl,bman-portal-2.0") ||
1389 + of_device_is_compatible(node, "fsl,bman-portal-2.0.8")) {
1390 + bman_ip_rev = BMAN_REV20;
1391 + bman_pool_max = 8;
1392 + bman_portal_max = 3;
1393 + } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.0")) {
1394 + bman_ip_rev = BMAN_REV21;
1395 + bman_pool_max = 64;
1396 + bman_portal_max = 50;
1397 + } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.1")) {
1398 + bman_ip_rev = BMAN_REV21;
1399 + bman_pool_max = 64;
1400 + bman_portal_max = 25;
1401 + } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.2")) {
1402 + bman_ip_rev = BMAN_REV21;
1403 + bman_pool_max = 64;
1404 + bman_portal_max = 18;
1405 + } else if (of_device_is_compatible(node, "fsl,bman-portal-2.1.3")) {
1406 + bman_ip_rev = BMAN_REV21;
1407 + bman_pool_max = 64;
1408 + bman_portal_max = 10;
1409 + } else {
1410 + pr_warn("unknown BMan version in portal node,"
1411 + "default to rev1.0\n");
1412 + bman_ip_rev = BMAN_REV10;
1413 + bman_pool_max = 64;
1414 + bman_portal_max = 10;
1415 + }
1416 +
1417 + ret = of_address_to_resource(node, DPA_PORTAL_CE,
1418 + &pcfg->addr_phys[DPA_PORTAL_CE]);
1419 + if (ret) {
1420 + pr_err("Can't get %s property 'reg::CE'\n", node->full_name);
1421 + goto err;
1422 + }
1423 + ret = of_address_to_resource(node, DPA_PORTAL_CI,
1424 + &pcfg->addr_phys[DPA_PORTAL_CI]);
1425 + if (ret) {
1426 + pr_err("Can't get %s property 'reg::CI'\n", node->full_name);
1427 + goto err;
1428 + }
1429 +
1430 + index = of_get_property(node, "cell-index", &ret);
1431 + if (!index || (ret != 4)) {
1432 + pr_err("Can't get %s property '%s'\n", node->full_name,
1433 + "cell-index");
1434 + goto err;
1435 + }
1436 + if (be32_to_cpu(*index) >= bman_portal_max) {
1437 + pr_err("BMan portal cell index %d out of range, max %d\n",
1438 + be32_to_cpu(*index), bman_portal_max);
1439 + goto err;
1440 + }
1441 +
1442 + pcfg->public_cfg.cpu = -1;
1443 +
1444 + irq = irq_of_parse_and_map(node, 0);
1445 + if (irq == 0) {
1446 + pr_err("Can't get %s property 'interrupts'\n", node->full_name);
1447 + goto err;
1448 + }
1449 + pcfg->public_cfg.irq = irq;
1450 + pcfg->public_cfg.index = be32_to_cpu(*index);
1451 + bman_depletion_fill(&pcfg->public_cfg.mask);
1452 +
1453 + len = resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]);
1454 + if (len != (unsigned long)len)
1455 + goto err;
1456 +
1457 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
1458 + pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_cache_ns(
1459 + pcfg->addr_phys[DPA_PORTAL_CE].start,
1460 + resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]));
1461 + pcfg->addr_virt[DPA_PORTAL_CI] = ioremap(
1462 + pcfg->addr_phys[DPA_PORTAL_CI].start,
1463 + resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
1464 +
1465 +#else
1466 + pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot(
1467 + pcfg->addr_phys[DPA_PORTAL_CE].start,
1468 + (unsigned long)len,
1469 + 0);
1470 + pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot(
1471 + pcfg->addr_phys[DPA_PORTAL_CI].start,
1472 + resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]),
1473 + _PAGE_GUARDED | _PAGE_NO_CACHE);
1474 +#endif
1475 + /* disable bp depletion */
1476 + __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(0));
1477 + __raw_writel(0x0, pcfg->addr_virt[DPA_PORTAL_CI] + BM_REG_SCN(1));
1478 + return pcfg;
1479 +err:
1480 + kfree(pcfg);
1481 + return NULL;
1482 +}
1483 +
1484 +static struct bm_portal_config *get_pcfg(struct list_head *list)
1485 +{
1486 + struct bm_portal_config *pcfg;
1487 + if (list_empty(list))
1488 + return NULL;
1489 + pcfg = list_entry(list->prev, struct bm_portal_config, list);
1490 + list_del(&pcfg->list);
1491 + return pcfg;
1492 +}
1493 +
1494 +static struct bm_portal_config *get_pcfg_idx(struct list_head *list,
1495 + uint32_t idx)
1496 +{
1497 + struct bm_portal_config *pcfg;
1498 + if (list_empty(list))
1499 + return NULL;
1500 + list_for_each_entry(pcfg, list, list) {
1501 + if (pcfg->public_cfg.index == idx) {
1502 + list_del(&pcfg->list);
1503 + return pcfg;
1504 + }
1505 + }
1506 + return NULL;
1507 +}
1508 +
1509 +struct bm_portal_config *bm_get_unused_portal(void)
1510 +{
1511 + return bm_get_unused_portal_idx(QBMAN_ANY_PORTAL_IDX);
1512 +}
1513 +
1514 +struct bm_portal_config *bm_get_unused_portal_idx(uint32_t idx)
1515 +{
1516 + struct bm_portal_config *ret;
1517 + spin_lock(&unused_pcfgs_lock);
1518 + if (idx == QBMAN_ANY_PORTAL_IDX)
1519 + ret = get_pcfg(&unused_pcfgs);
1520 + else
1521 + ret = get_pcfg_idx(&unused_pcfgs, idx);
1522 + spin_unlock(&unused_pcfgs_lock);
1523 + return ret;
1524 +}
1525 +
1526 +void bm_put_unused_portal(struct bm_portal_config *pcfg)
1527 +{
1528 + spin_lock(&unused_pcfgs_lock);
1529 + list_add(&pcfg->list, &unused_pcfgs);
1530 + spin_unlock(&unused_pcfgs_lock);
1531 +}
1532 +
1533 +static struct bman_portal *init_pcfg(struct bm_portal_config *pcfg)
1534 +{
1535 + struct bman_portal *p;
1536 + p = bman_create_affine_portal(pcfg);
1537 + if (p) {
1538 +#ifdef CONFIG_FSL_DPA_PIRQ_SLOW
1539 + bman_p_irqsource_add(p, BM_PIRQ_RCRI | BM_PIRQ_BSCN);
1540 +#endif
1541 + pr_info("Bman portal %sinitialised, cpu %d\n",
1542 + pcfg->public_cfg.is_shared ? "(shared) " : "",
1543 + pcfg->public_cfg.cpu);
1544 + affine_bportals[pcfg->public_cfg.cpu] = p;
1545 + } else
1546 + pr_crit("Bman portal failure on cpu %d\n",
1547 + pcfg->public_cfg.cpu);
1548 + return p;
1549 +}
1550 +
1551 +static void init_slave(int cpu)
1552 +{
1553 + struct bman_portal *p;
1554 + p = bman_create_affine_slave(shared_portals[shared_portals_idx++], cpu);
1555 + if (!p)
1556 + pr_err("Bman slave portal failure on cpu %d\n", cpu);
1557 + else
1558 + pr_info("Bman portal %sinitialised, cpu %d\n", "(slave) ", cpu);
1559 + if (shared_portals_idx >= num_shared_portals)
1560 + shared_portals_idx = 0;
1561 + affine_bportals[cpu] = p;
1562 +}
1563 +
1564 +/* Bootarg "bportals=[...]" has the same syntax as "qportals=", and so the
1565 + * parsing is in dpa_sys.h. The syntax is a comma-separated list of indexes
1566 + * and/or ranges of indexes, with each being optionally prefixed by "s" to
1567 + * explicitly mark it or them for sharing.
1568 + * Eg;
1569 + * bportals=s0,1-3,s4
1570 + * means that cpus 1,2,3 get "unshared" portals, cpus 0 and 4 get "shared"
1571 + * portals, and any remaining cpus share the portals that are assigned to cpus 0
1572 + * or 4, selected in a round-robin fashion. (In this example, cpu 5 would share
1573 + * cpu 0's portal, cpu 6 would share cpu4's portal, and cpu 7 would share cpu
1574 + * 0's portal.) */
1575 +static struct cpumask want_unshared __initdata; /* cpus requested without "s" */
1576 +static struct cpumask want_shared __initdata; /* cpus requested with "s" */
1577 +
1578 +static int __init parse_bportals(char *str)
1579 +{
1580 + return parse_portals_bootarg(str, &want_shared, &want_unshared,
1581 + "bportals");
1582 +}
1583 +__setup("bportals=", parse_bportals);
1584 +
1585 +static void bman_offline_cpu(unsigned int cpu)
1586 +{
1587 + struct bman_portal *p;
1588 + const struct bm_portal_config *pcfg;
1589 + p = (struct bman_portal *)affine_bportals[cpu];
1590 + if (p) {
1591 + pcfg = bman_get_bm_portal_config(p);
1592 + if (pcfg)
1593 + irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0));
1594 + }
1595 +}
1596 +
1597 +#ifdef CONFIG_HOTPLUG_CPU
1598 +static void bman_online_cpu(unsigned int cpu)
1599 +{
1600 + struct bman_portal *p;
1601 + const struct bm_portal_config *pcfg;
1602 + p = (struct bman_portal *)affine_bportals[cpu];
1603 + if (p) {
1604 + pcfg = bman_get_bm_portal_config(p);
1605 + if (pcfg)
1606 + irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu));
1607 + }
1608 +}
1609 +
1610 +static int bman_hotplug_cpu_callback(struct notifier_block *nfb,
1611 + unsigned long action, void *hcpu)
1612 +{
1613 + unsigned int cpu = (unsigned long)hcpu;
1614 +
1615 + switch (action) {
1616 + case CPU_ONLINE:
1617 + case CPU_ONLINE_FROZEN:
1618 + bman_online_cpu(cpu);
1619 + break;
1620 + case CPU_DOWN_PREPARE:
1621 + case CPU_DOWN_PREPARE_FROZEN:
1622 + bman_offline_cpu(cpu);
1623 + default:
1624 + break;
1625 + }
1626 + return NOTIFY_OK;
1627 +}
1628 +
1629 +static struct notifier_block bman_hotplug_cpu_notifier = {
1630 + .notifier_call = bman_hotplug_cpu_callback,
1631 +};
1632 +#endif /* CONFIG_HOTPLUG_CPU */
1633 +
1634 +/* Initialise the Bman driver. The meat of this function deals with portals. The
1635 + * following describes the flow of portal-handling, the code "steps" refer to
1636 + * this description;
1637 + * 1. Portal configs are parsed from the device-tree into 'unused_pcfgs', with
1638 + * ::cpu==-1. Regions and interrupts are mapped (but interrupts are not
1639 + * bound).
1640 + * 2. The "want_shared" and "want_unshared" lists (as filled by the
1641 + * "bportals=[...]" bootarg) are processed, allocating portals and assigning
1642 + * them to cpus, placing them in the relevant list and setting ::cpu as
1643 + * appropriate. If no "bportals" bootarg was present, the defaut is to try to
1644 + * assign portals to all online cpus at the time of driver initialisation.
1645 + * Any failure to allocate portals (when parsing the "want" lists or when
1646 + * using default behaviour) will be silently tolerated (the "fixup" logic in
1647 + * step 3 will determine what happens in this case).
1648 + * 3. Do fixups relative to cpu_online_mask(). If no portals are marked for
1649 + * sharing and sharing is required (because not all cpus have been assigned
1650 + * portals), then one portal will marked for sharing. Conversely if no
1651 + * sharing is required, any portals marked for sharing will not be shared. It
1652 + * may be that sharing occurs when it wasn't expected, if portal allocation
1653 + * failed to honour all the requested assignments (including the default
1654 + * assignments if no bootarg is present).
1655 + * 4. Unshared portals are initialised on their respective cpus.
1656 + * 5. Shared portals are initialised on their respective cpus.
1657 + * 6. Each remaining cpu is initialised to slave to one of the shared portals,
1658 + * which are selected in a round-robin fashion.
1659 + * Any portal configs left unused are available for USDPAA allocation.
1660 + */
1661 +__init int bman_init(void)
1662 +{
1663 + struct cpumask slave_cpus;
1664 + struct cpumask unshared_cpus = *cpu_none_mask;
1665 + struct cpumask shared_cpus = *cpu_none_mask;
1666 + LIST_HEAD(unshared_pcfgs);
1667 + LIST_HEAD(shared_pcfgs);
1668 + struct device_node *dn;
1669 + struct bm_portal_config *pcfg;
1670 + struct bman_portal *p;
1671 + int cpu, ret;
1672 + struct cpumask offline_cpus;
1673 +
1674 + /* Initialise the Bman (CCSR) device */
1675 + for_each_compatible_node(dn, NULL, "fsl,bman") {
1676 + if (!bman_init_ccsr(dn))
1677 + pr_info("Bman err interrupt handler present\n");
1678 + else
1679 + pr_err("Bman CCSR setup failed\n");
1680 + }
1681 + /* Initialise any declared buffer pools */
1682 + for_each_compatible_node(dn, NULL, "fsl,bpool") {
1683 + ret = fsl_bpool_init(dn);
1684 + if (ret)
1685 + return ret;
1686 + }
1687 + /* Step 1. See comments at the beginning of the file. */
1688 + for_each_compatible_node(dn, NULL, "fsl,bman-portal") {
1689 + if (!of_device_is_available(dn))
1690 + continue;
1691 + pcfg = parse_pcfg(dn);
1692 + if (pcfg)
1693 + list_add_tail(&pcfg->list, &unused_pcfgs);
1694 + }
1695 + /* Step 2. */
1696 + for_each_possible_cpu(cpu) {
1697 + if (cpumask_test_cpu(cpu, &want_shared)) {
1698 + pcfg = get_pcfg(&unused_pcfgs);
1699 + if (!pcfg)
1700 + break;
1701 + pcfg->public_cfg.cpu = cpu;
1702 + list_add_tail(&pcfg->list, &shared_pcfgs);
1703 + cpumask_set_cpu(cpu, &shared_cpus);
1704 + }
1705 + if (cpumask_test_cpu(cpu, &want_unshared)) {
1706 + if (cpumask_test_cpu(cpu, &shared_cpus))
1707 + continue;
1708 + pcfg = get_pcfg(&unused_pcfgs);
1709 + if (!pcfg)
1710 + break;
1711 + pcfg->public_cfg.cpu = cpu;
1712 + list_add_tail(&pcfg->list, &unshared_pcfgs);
1713 + cpumask_set_cpu(cpu, &unshared_cpus);
1714 + }
1715 + }
1716 + if (list_empty(&shared_pcfgs) && list_empty(&unshared_pcfgs)) {
1717 + /* Default, give an unshared portal to each online cpu */
1718 + for_each_online_cpu(cpu) {
1719 + pcfg = get_pcfg(&unused_pcfgs);
1720 + if (!pcfg)
1721 + break;
1722 + pcfg->public_cfg.cpu = cpu;
1723 + list_add_tail(&pcfg->list, &unshared_pcfgs);
1724 + cpumask_set_cpu(cpu, &unshared_cpus);
1725 + }
1726 + }
1727 + /* Step 3. */
1728 + cpumask_andnot(&slave_cpus, cpu_possible_mask, &shared_cpus);
1729 + cpumask_andnot(&slave_cpus, &slave_cpus, &unshared_cpus);
1730 + if (cpumask_empty(&slave_cpus)) {
1731 + /* No sharing required */
1732 + if (!list_empty(&shared_pcfgs)) {
1733 + /* Migrate "shared" to "unshared" */
1734 + cpumask_or(&unshared_cpus, &unshared_cpus,
1735 + &shared_cpus);
1736 + cpumask_clear(&shared_cpus);
1737 + list_splice_tail(&shared_pcfgs, &unshared_pcfgs);
1738 + INIT_LIST_HEAD(&shared_pcfgs);
1739 + }
1740 + } else {
1741 + /* Sharing required */
1742 + if (list_empty(&shared_pcfgs)) {
1743 + /* Migrate one "unshared" to "shared" */
1744 + pcfg = get_pcfg(&unshared_pcfgs);
1745 + if (!pcfg) {
1746 + pr_crit("No BMan portals available!\n");
1747 + return 0;
1748 + }
1749 + cpumask_clear_cpu(pcfg->public_cfg.cpu, &unshared_cpus);
1750 + cpumask_set_cpu(pcfg->public_cfg.cpu, &shared_cpus);
1751 + list_add_tail(&pcfg->list, &shared_pcfgs);
1752 + }
1753 + }
1754 + /* Step 4. */
1755 + list_for_each_entry(pcfg, &unshared_pcfgs, list) {
1756 + pcfg->public_cfg.is_shared = 0;
1757 + p = init_pcfg(pcfg);
1758 + if (!p) {
1759 + pr_crit("Unable to initialize bman portal\n");
1760 + return 0;
1761 + }
1762 + }
1763 + /* Step 5. */
1764 + list_for_each_entry(pcfg, &shared_pcfgs, list) {
1765 + pcfg->public_cfg.is_shared = 1;
1766 + p = init_pcfg(pcfg);
1767 + if (p)
1768 + shared_portals[num_shared_portals++] = p;
1769 + }
1770 + /* Step 6. */
1771 + if (!cpumask_empty(&slave_cpus))
1772 + for_each_cpu(cpu, &slave_cpus)
1773 + init_slave(cpu);
1774 + pr_info("Bman portals initialised\n");
1775 + cpumask_andnot(&offline_cpus, cpu_possible_mask, cpu_online_mask);
1776 + for_each_cpu(cpu, &offline_cpus)
1777 + bman_offline_cpu(cpu);
1778 +#ifdef CONFIG_HOTPLUG_CPU
1779 + register_hotcpu_notifier(&bman_hotplug_cpu_notifier);
1780 +#endif
1781 + return 0;
1782 +}
1783 +
1784 +__init int bman_resource_init(void)
1785 +{
1786 + struct device_node *dn;
1787 + int ret;
1788 +
1789 + /* Initialise BPID allocation ranges */
1790 + for_each_compatible_node(dn, NULL, "fsl,bpid-range") {
1791 + ret = fsl_bpid_range_init(dn);
1792 + if (ret)
1793 + return ret;
1794 + }
1795 + return 0;
1796 +}
1797 +
1798 +#ifdef CONFIG_SUSPEND
1799 +void suspend_unused_bportal(void)
1800 +{
1801 + struct bm_portal_config *pcfg;
1802 +
1803 + if (list_empty(&unused_pcfgs))
1804 + return;
1805 +
1806 + list_for_each_entry(pcfg, &unused_pcfgs, list) {
1807 +#ifdef CONFIG_PM_DEBUG
1808 + pr_info("Need to save bportal %d\n", pcfg->public_cfg.index);
1809 +#endif
1810 + /* save isdr, disable all via isdr, clear isr */
1811 + pcfg->saved_isdr =
1812 + __raw_readl(pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
1813 + __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
1814 + 0xe08);
1815 + __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
1816 + 0xe00);
1817 + }
1818 + return;
1819 +}
1820 +
1821 +void resume_unused_bportal(void)
1822 +{
1823 + struct bm_portal_config *pcfg;
1824 +
1825 + if (list_empty(&unused_pcfgs))
1826 + return;
1827 +
1828 + list_for_each_entry(pcfg, &unused_pcfgs, list) {
1829 +#ifdef CONFIG_PM_DEBUG
1830 + pr_info("Need to resume bportal %d\n", pcfg->public_cfg.index);
1831 +#endif
1832 + /* restore isdr */
1833 + __raw_writel(pcfg->saved_isdr,
1834 + pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
1835 + }
1836 + return;
1837 +}
1838 +#endif
1839 --- /dev/null
1840 +++ b/drivers/staging/fsl_qbman/bman_high.c
1841 @@ -0,0 +1,1141 @@
1842 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
1843 + *
1844 + * Redistribution and use in source and binary forms, with or without
1845 + * modification, are permitted provided that the following conditions are met:
1846 + * * Redistributions of source code must retain the above copyright
1847 + * notice, this list of conditions and the following disclaimer.
1848 + * * Redistributions in binary form must reproduce the above copyright
1849 + * notice, this list of conditions and the following disclaimer in the
1850 + * documentation and/or other materials provided with the distribution.
1851 + * * Neither the name of Freescale Semiconductor nor the
1852 + * names of its contributors may be used to endorse or promote products
1853 + * derived from this software without specific prior written permission.
1854 + *
1855 + *
1856 + * ALTERNATIVELY, this software may be distributed under the terms of the
1857 + * GNU General Public License ("GPL") as published by the Free Software
1858 + * Foundation, either version 2 of that License or (at your option) any
1859 + * later version.
1860 + *
1861 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
1862 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1863 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1864 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
1865 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
1866 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
1867 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1868 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
1869 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1870 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1871 + */
1872 +
1873 +#include "bman_low.h"
1874 +
1875 +/* Compilation constants */
1876 +#define RCR_THRESH 2 /* reread h/w CI when running out of space */
1877 +#define IRQNAME "BMan portal %d"
1878 +#define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */
1879 +
1880 +struct bman_portal {
1881 + struct bm_portal p;
1882 + /* 2-element array. pools[0] is mask, pools[1] is snapshot. */
1883 + struct bman_depletion *pools;
1884 + int thresh_set;
1885 + unsigned long irq_sources;
1886 + u32 slowpoll; /* only used when interrupts are off */
1887 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
1888 + struct bman_pool *rcri_owned; /* only 1 release WAIT_SYNC at a time */
1889 +#endif
1890 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
1891 + raw_spinlock_t sharing_lock; /* only used if is_shared */
1892 + int is_shared;
1893 + struct bman_portal *sharing_redirect;
1894 +#endif
1895 + /* When the cpu-affine portal is activated, this is non-NULL */
1896 + const struct bm_portal_config *config;
1897 + /* This is needed for power management */
1898 + struct platform_device *pdev;
1899 + /* 64-entry hash-table of pool objects that are tracking depletion
1900 + * entry/exit (ie. BMAN_POOL_FLAG_DEPLETION). This isn't fast-path, so
1901 + * we're not fussy about cache-misses and so forth - whereas the above
1902 + * members should all fit in one cacheline.
1903 + * BTW, with 64 entries in the hash table and 64 buffer pools to track,
1904 + * you'll never guess the hash-function ... */
1905 + struct bman_pool *cb[64];
1906 + char irqname[MAX_IRQNAME];
1907 + /* Track if the portal was alloced by the driver */
1908 + u8 alloced;
1909 + /* power management data */
1910 + u32 save_isdr;
1911 +};
1912 +
1913 +/* For an explanation of the locking, redirection, or affine-portal logic,
1914 + * please consult the Qman driver for details. This is the same, only simpler
1915 + * (no fiddly Qman-specific bits.) */
1916 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
1917 +#define PORTAL_IRQ_LOCK(p, irqflags) \
1918 + do { \
1919 + if ((p)->is_shared) \
1920 + raw_spin_lock_irqsave(&(p)->sharing_lock, irqflags); \
1921 + else \
1922 + local_irq_save(irqflags); \
1923 + } while (0)
1924 +#define PORTAL_IRQ_UNLOCK(p, irqflags) \
1925 + do { \
1926 + if ((p)->is_shared) \
1927 + raw_spin_unlock_irqrestore(&(p)->sharing_lock, \
1928 + irqflags); \
1929 + else \
1930 + local_irq_restore(irqflags); \
1931 + } while (0)
1932 +#else
1933 +#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags)
1934 +#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags)
1935 +#endif
1936 +
1937 +static cpumask_t affine_mask;
1938 +static DEFINE_SPINLOCK(affine_mask_lock);
1939 +static DEFINE_PER_CPU(struct bman_portal, bman_affine_portal);
1940 +static inline struct bman_portal *get_raw_affine_portal(void)
1941 +{
1942 + return &get_cpu_var(bman_affine_portal);
1943 +}
1944 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
1945 +static inline struct bman_portal *get_affine_portal(void)
1946 +{
1947 + struct bman_portal *p = get_raw_affine_portal();
1948 + if (p->sharing_redirect)
1949 + return p->sharing_redirect;
1950 + return p;
1951 +}
1952 +#else
1953 +#define get_affine_portal() get_raw_affine_portal()
1954 +#endif
1955 +static inline void put_affine_portal(void)
1956 +{
1957 + put_cpu_var(bman_affine_portal);
1958 +}
1959 +static inline struct bman_portal *get_poll_portal(void)
1960 +{
1961 + return &get_cpu_var(bman_affine_portal);
1962 +}
1963 +#define put_poll_portal()
1964 +
1965 +/* GOTCHA: this object type refers to a pool, it isn't *the* pool. There may be
1966 + * more than one such object per Bman buffer pool, eg. if different users of the
1967 + * pool are operating via different portals. */
1968 +struct bman_pool {
1969 + struct bman_pool_params params;
1970 + /* Used for hash-table admin when using depletion notifications. */
1971 + struct bman_portal *portal;
1972 + struct bman_pool *next;
1973 + /* stockpile state - NULL unless BMAN_POOL_FLAG_STOCKPILE is set */
1974 + struct bm_buffer *sp;
1975 + unsigned int sp_fill;
1976 +#ifdef CONFIG_FSL_DPA_CHECKING
1977 + atomic_t in_use;
1978 +#endif
1979 +};
1980 +
1981 +/* (De)Registration of depletion notification callbacks */
1982 +static void depletion_link(struct bman_portal *portal, struct bman_pool *pool)
1983 +{
1984 + __maybe_unused unsigned long irqflags;
1985 + pool->portal = portal;
1986 + PORTAL_IRQ_LOCK(portal, irqflags);
1987 + pool->next = portal->cb[pool->params.bpid];
1988 + portal->cb[pool->params.bpid] = pool;
1989 + if (!pool->next)
1990 + /* First object for that bpid on this portal, enable the BSCN
1991 + * mask bit. */
1992 + bm_isr_bscn_mask(&portal->p, pool->params.bpid, 1);
1993 + PORTAL_IRQ_UNLOCK(portal, irqflags);
1994 +}
1995 +static void depletion_unlink(struct bman_pool *pool)
1996 +{
1997 + struct bman_pool *it, *last = NULL;
1998 + struct bman_pool **base = &pool->portal->cb[pool->params.bpid];
1999 + __maybe_unused unsigned long irqflags;
2000 + PORTAL_IRQ_LOCK(pool->portal, irqflags);
2001 + it = *base; /* <-- gotcha, don't do this prior to the irq_save */
2002 + while (it != pool) {
2003 + last = it;
2004 + it = it->next;
2005 + }
2006 + if (!last)
2007 + *base = pool->next;
2008 + else
2009 + last->next = pool->next;
2010 + if (!last && !pool->next) {
2011 + /* Last object for that bpid on this portal, disable the BSCN
2012 + * mask bit. */
2013 + bm_isr_bscn_mask(&pool->portal->p, pool->params.bpid, 0);
2014 + /* And "forget" that we last saw this pool as depleted */
2015 + bman_depletion_unset(&pool->portal->pools[1],
2016 + pool->params.bpid);
2017 + }
2018 + PORTAL_IRQ_UNLOCK(pool->portal, irqflags);
2019 +}
2020 +
2021 +/* In the case that the application's core loop calls qman_poll() and
2022 + * bman_poll(), we ought to balance how often we incur the overheads of the
2023 + * slow-path poll. We'll use two decrementer sources. The idle decrementer
2024 + * constant is used when the last slow-poll detected no work to do, and the busy
2025 + * decrementer constant when the last slow-poll had work to do. */
2026 +#define SLOW_POLL_IDLE 1000
2027 +#define SLOW_POLL_BUSY 10
2028 +static u32 __poll_portal_slow(struct bman_portal *p, u32 is);
2029 +
2030 +/* Portal interrupt handler */
2031 +static irqreturn_t portal_isr(__always_unused int irq, void *ptr)
2032 +{
2033 + struct bman_portal *p = ptr;
2034 + u32 clear = p->irq_sources;
2035 + u32 is = bm_isr_status_read(&p->p) & p->irq_sources;
2036 + clear |= __poll_portal_slow(p, is);
2037 + bm_isr_status_clear(&p->p, clear);
2038 + return IRQ_HANDLED;
2039 +}
2040 +
2041 +#ifdef CONFIG_SUSPEND
2042 +static int _bman_portal_suspend_noirq(struct device *dev)
2043 +{
2044 + struct bman_portal *p = (struct bman_portal *)dev->platform_data;
2045 +#ifdef CONFIG_PM_DEBUG
2046 + struct platform_device *pdev = to_platform_device(dev);
2047 +#endif
2048 + p->save_isdr = bm_isr_disable_read(&p->p);
2049 + bm_isr_disable_write(&p->p, 0xffffffff);
2050 + bm_isr_status_clear(&p->p, 0xffffffff);
2051 +#ifdef CONFIG_PM_DEBUG
2052 + pr_info("Suspend for %s\n", pdev->name);
2053 +#endif
2054 + return 0;
2055 +}
2056 +
2057 +static int _bman_portal_resume_noirq(struct device *dev)
2058 +{
2059 + struct bman_portal *p = (struct bman_portal *)dev->platform_data;
2060 +
2061 + /* restore isdr */
2062 + bm_isr_disable_write(&p->p, p->save_isdr);
2063 + return 0;
2064 +}
2065 +#else
2066 +#define _bman_portal_suspend_noirq NULL
2067 +#define _bman_portal_resume_noirq NULL
2068 +#endif
2069 +
2070 +struct dev_pm_domain bman_portal_device_pm_domain = {
2071 + .ops = {
2072 + USE_PLATFORM_PM_SLEEP_OPS
2073 + .suspend_noirq = _bman_portal_suspend_noirq,
2074 + .resume_noirq = _bman_portal_resume_noirq,
2075 + }
2076 +};
2077 +
2078 +struct bman_portal *bman_create_portal(
2079 + struct bman_portal *portal,
2080 + const struct bm_portal_config *config)
2081 +{
2082 + struct bm_portal *__p;
2083 + const struct bman_depletion *pools = &config->public_cfg.mask;
2084 + int ret;
2085 + u8 bpid = 0;
2086 + char buf[16];
2087 +
2088 + if (!portal) {
2089 + portal = kmalloc(sizeof(*portal), GFP_KERNEL);
2090 + if (!portal)
2091 + return portal;
2092 + portal->alloced = 1;
2093 + } else
2094 + portal->alloced = 0;
2095 +
2096 + __p = &portal->p;
2097 +
2098 + /* prep the low-level portal struct with the mapped addresses from the
2099 + * config, everything that follows depends on it and "config" is more
2100 + * for (de)reference... */
2101 + __p->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
2102 + __p->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
2103 + if (bm_rcr_init(__p, bm_rcr_pvb, bm_rcr_cce)) {
2104 + pr_err("Bman RCR initialisation failed\n");
2105 + goto fail_rcr;
2106 + }
2107 + if (bm_mc_init(__p)) {
2108 + pr_err("Bman MC initialisation failed\n");
2109 + goto fail_mc;
2110 + }
2111 + if (bm_isr_init(__p)) {
2112 + pr_err("Bman ISR initialisation failed\n");
2113 + goto fail_isr;
2114 + }
2115 + portal->pools = kmalloc(2 * sizeof(*pools), GFP_KERNEL);
2116 + if (!portal->pools)
2117 + goto fail_pools;
2118 + portal->pools[0] = *pools;
2119 + bman_depletion_init(portal->pools + 1);
2120 + while (bpid < bman_pool_max) {
2121 + /* Default to all BPIDs disabled, we enable as required at
2122 + * run-time. */
2123 + bm_isr_bscn_mask(__p, bpid, 0);
2124 + bpid++;
2125 + }
2126 + portal->slowpoll = 0;
2127 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2128 + portal->rcri_owned = NULL;
2129 +#endif
2130 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2131 + raw_spin_lock_init(&portal->sharing_lock);
2132 + portal->is_shared = config->public_cfg.is_shared;
2133 + portal->sharing_redirect = NULL;
2134 +#endif
2135 + sprintf(buf, "bportal-%u", config->public_cfg.index);
2136 + portal->pdev = platform_device_alloc(buf, -1);
2137 + if (!portal->pdev)
2138 + goto fail_devalloc;
2139 + portal->pdev->dev.pm_domain = &bman_portal_device_pm_domain;
2140 + portal->pdev->dev.platform_data = portal;
2141 + ret = platform_device_add(portal->pdev);
2142 + if (ret)
2143 + goto fail_devadd;
2144 + memset(&portal->cb, 0, sizeof(portal->cb));
2145 + /* Write-to-clear any stale interrupt status bits */
2146 + bm_isr_disable_write(__p, 0xffffffff);
2147 + portal->irq_sources = 0;
2148 + bm_isr_enable_write(__p, portal->irq_sources);
2149 + bm_isr_status_clear(__p, 0xffffffff);
2150 + snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu);
2151 + if (request_irq(config->public_cfg.irq, portal_isr, 0, portal->irqname,
2152 + portal)) {
2153 + pr_err("request_irq() failed\n");
2154 + goto fail_irq;
2155 + }
2156 + if ((config->public_cfg.cpu != -1) &&
2157 + irq_can_set_affinity(config->public_cfg.irq) &&
2158 + irq_set_affinity(config->public_cfg.irq,
2159 + cpumask_of(config->public_cfg.cpu))) {
2160 + pr_err("irq_set_affinity() failed %s\n", portal->irqname);
2161 + goto fail_affinity;
2162 + }
2163 +
2164 + /* Need RCR to be empty before continuing */
2165 + ret = bm_rcr_get_fill(__p);
2166 + if (ret) {
2167 + pr_err("Bman RCR unclean\n");
2168 + goto fail_rcr_empty;
2169 + }
2170 + /* Success */
2171 + portal->config = config;
2172 +
2173 + bm_isr_disable_write(__p, 0);
2174 + bm_isr_uninhibit(__p);
2175 + return portal;
2176 +fail_rcr_empty:
2177 +fail_affinity:
2178 + free_irq(config->public_cfg.irq, portal);
2179 +fail_irq:
2180 + platform_device_del(portal->pdev);
2181 +fail_devadd:
2182 + platform_device_put(portal->pdev);
2183 +fail_devalloc:
2184 + kfree(portal->pools);
2185 +fail_pools:
2186 + bm_isr_finish(__p);
2187 +fail_isr:
2188 + bm_mc_finish(__p);
2189 +fail_mc:
2190 + bm_rcr_finish(__p);
2191 +fail_rcr:
2192 + if (portal->alloced)
2193 + kfree(portal);
2194 + return NULL;
2195 +}
2196 +
2197 +struct bman_portal *bman_create_affine_portal(
2198 + const struct bm_portal_config *config)
2199 +{
2200 + struct bman_portal *portal;
2201 +
2202 + portal = &per_cpu(bman_affine_portal, config->public_cfg.cpu);
2203 + portal = bman_create_portal(portal, config);
2204 + if (portal) {
2205 + spin_lock(&affine_mask_lock);
2206 + cpumask_set_cpu(config->public_cfg.cpu, &affine_mask);
2207 + spin_unlock(&affine_mask_lock);
2208 + }
2209 + return portal;
2210 +}
2211 +
2212 +
2213 +struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect,
2214 + int cpu)
2215 +{
2216 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2217 + struct bman_portal *p;
2218 + p = &per_cpu(bman_affine_portal, cpu);
2219 + BUG_ON(p->config);
2220 + BUG_ON(p->is_shared);
2221 + BUG_ON(!redirect->config->public_cfg.is_shared);
2222 + p->irq_sources = 0;
2223 + p->sharing_redirect = redirect;
2224 + return p;
2225 +#else
2226 + BUG();
2227 + return NULL;
2228 +#endif
2229 +}
2230 +
2231 +void bman_destroy_portal(struct bman_portal *bm)
2232 +{
2233 + const struct bm_portal_config *pcfg;
2234 + pcfg = bm->config;
2235 + bm_rcr_cce_update(&bm->p);
2236 + bm_rcr_cce_update(&bm->p);
2237 +
2238 + free_irq(pcfg->public_cfg.irq, bm);
2239 +
2240 + kfree(bm->pools);
2241 + bm_isr_finish(&bm->p);
2242 + bm_mc_finish(&bm->p);
2243 + bm_rcr_finish(&bm->p);
2244 + bm->config = NULL;
2245 + if (bm->alloced)
2246 + kfree(bm);
2247 +}
2248 +
2249 +const struct bm_portal_config *bman_destroy_affine_portal(void)
2250 +{
2251 + struct bman_portal *bm = get_raw_affine_portal();
2252 + const struct bm_portal_config *pcfg;
2253 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2254 + if (bm->sharing_redirect) {
2255 + bm->sharing_redirect = NULL;
2256 + put_affine_portal();
2257 + return NULL;
2258 + }
2259 + bm->is_shared = 0;
2260 +#endif
2261 + pcfg = bm->config;
2262 + bman_destroy_portal(bm);
2263 + spin_lock(&affine_mask_lock);
2264 + cpumask_clear_cpu(pcfg->public_cfg.cpu, &affine_mask);
2265 + spin_unlock(&affine_mask_lock);
2266 + put_affine_portal();
2267 + return pcfg;
2268 +}
2269 +
2270 +/* When release logic waits on available RCR space, we need a global waitqueue
2271 + * in the case of "affine" use (as the waits wake on different cpus which means
2272 + * different portals - so we can't wait on any per-portal waitqueue). */
2273 +static DECLARE_WAIT_QUEUE_HEAD(affine_queue);
2274 +
2275 +static u32 __poll_portal_slow(struct bman_portal *p, u32 is)
2276 +{
2277 + struct bman_depletion tmp;
2278 + u32 ret = is;
2279 +
2280 + /* There is a gotcha to be aware of. If we do the query before clearing
2281 + * the status register, we may miss state changes that occur between the
2282 + * two. If we write to clear the status register before the query, the
2283 + * cache-enabled query command may overtake the status register write
2284 + * unless we use a heavyweight sync (which we don't want). Instead, we
2285 + * write-to-clear the status register then *read it back* before doing
2286 + * the query, hence the odd while loop with the 'is' accumulation. */
2287 + if (is & BM_PIRQ_BSCN) {
2288 + struct bm_mc_result *mcr;
2289 + __maybe_unused unsigned long irqflags;
2290 + unsigned int i, j;
2291 + u32 __is;
2292 + bm_isr_status_clear(&p->p, BM_PIRQ_BSCN);
2293 + while ((__is = bm_isr_status_read(&p->p)) & BM_PIRQ_BSCN) {
2294 + is |= __is;
2295 + bm_isr_status_clear(&p->p, BM_PIRQ_BSCN);
2296 + }
2297 + is &= ~BM_PIRQ_BSCN;
2298 + PORTAL_IRQ_LOCK(p, irqflags);
2299 + bm_mc_start(&p->p);
2300 + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY);
2301 + while (!(mcr = bm_mc_result(&p->p)))
2302 + cpu_relax();
2303 + tmp = mcr->query.ds.state;
2304 + tmp.__state[0] = be32_to_cpu(tmp.__state[0]);
2305 + tmp.__state[1] = be32_to_cpu(tmp.__state[1]);
2306 + PORTAL_IRQ_UNLOCK(p, irqflags);
2307 + for (i = 0; i < 2; i++) {
2308 + int idx = i * 32;
2309 + /* tmp is a mask of currently-depleted pools.
2310 + * pools[0] is mask of those we care about.
2311 + * pools[1] is our previous view (we only want to
2312 + * be told about changes). */
2313 + tmp.__state[i] &= p->pools[0].__state[i];
2314 + if (tmp.__state[i] == p->pools[1].__state[i])
2315 + /* fast-path, nothing to see, move along */
2316 + continue;
2317 + for (j = 0; j <= 31; j++, idx++) {
2318 + struct bman_pool *pool = p->cb[idx];
2319 + int b4 = bman_depletion_get(&p->pools[1], idx);
2320 + int af = bman_depletion_get(&tmp, idx);
2321 + if (b4 == af)
2322 + continue;
2323 + while (pool) {
2324 + pool->params.cb(p, pool,
2325 + pool->params.cb_ctx, af);
2326 + pool = pool->next;
2327 + }
2328 + }
2329 + }
2330 + p->pools[1] = tmp;
2331 + }
2332 +
2333 + if (is & BM_PIRQ_RCRI) {
2334 + __maybe_unused unsigned long irqflags;
2335 + PORTAL_IRQ_LOCK(p, irqflags);
2336 + bm_rcr_cce_update(&p->p);
2337 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2338 + /* If waiting for sync, we only cancel the interrupt threshold
2339 + * when the ring utilisation hits zero. */
2340 + if (p->rcri_owned) {
2341 + if (!bm_rcr_get_fill(&p->p)) {
2342 + p->rcri_owned = NULL;
2343 + bm_rcr_set_ithresh(&p->p, 0);
2344 + }
2345 + } else
2346 +#endif
2347 + bm_rcr_set_ithresh(&p->p, 0);
2348 + PORTAL_IRQ_UNLOCK(p, irqflags);
2349 + wake_up(&affine_queue);
2350 + bm_isr_status_clear(&p->p, BM_PIRQ_RCRI);
2351 + is &= ~BM_PIRQ_RCRI;
2352 + }
2353 +
2354 + /* There should be no status register bits left undefined */
2355 + DPA_ASSERT(!is);
2356 + return ret;
2357 +}
2358 +
2359 +const struct bman_portal_config *bman_get_portal_config(void)
2360 +{
2361 + struct bman_portal *p = get_affine_portal();
2362 + const struct bman_portal_config *ret = &p->config->public_cfg;
2363 + put_affine_portal();
2364 + return ret;
2365 +}
2366 +EXPORT_SYMBOL(bman_get_portal_config);
2367 +
2368 +u32 bman_irqsource_get(void)
2369 +{
2370 + struct bman_portal *p = get_raw_affine_portal();
2371 + u32 ret = p->irq_sources & BM_PIRQ_VISIBLE;
2372 + put_affine_portal();
2373 + return ret;
2374 +}
2375 +EXPORT_SYMBOL(bman_irqsource_get);
2376 +
2377 +int bman_p_irqsource_add(struct bman_portal *p, __maybe_unused u32 bits)
2378 +{
2379 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2380 + if (p->sharing_redirect)
2381 + return -EINVAL;
2382 + else
2383 +#endif
2384 + {
2385 + __maybe_unused unsigned long irqflags;
2386 + PORTAL_IRQ_LOCK(p, irqflags);
2387 + set_bits(bits & BM_PIRQ_VISIBLE, &p->irq_sources);
2388 + bm_isr_enable_write(&p->p, p->irq_sources);
2389 + PORTAL_IRQ_UNLOCK(p, irqflags);
2390 + }
2391 + return 0;
2392 +}
2393 +EXPORT_SYMBOL(bman_p_irqsource_add);
2394 +
2395 +int bman_irqsource_add(__maybe_unused u32 bits)
2396 +{
2397 + struct bman_portal *p = get_raw_affine_portal();
2398 + int ret = 0;
2399 + ret = bman_p_irqsource_add(p, bits);
2400 + put_affine_portal();
2401 + return ret;
2402 +}
2403 +EXPORT_SYMBOL(bman_irqsource_add);
2404 +
2405 +int bman_irqsource_remove(u32 bits)
2406 +{
2407 + struct bman_portal *p = get_raw_affine_portal();
2408 + __maybe_unused unsigned long irqflags;
2409 + u32 ier;
2410 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2411 + if (p->sharing_redirect) {
2412 + put_affine_portal();
2413 + return -EINVAL;
2414 + }
2415 +#endif
2416 + /* Our interrupt handler only processes+clears status register bits that
2417 + * are in p->irq_sources. As we're trimming that mask, if one of them
2418 + * were to assert in the status register just before we remove it from
2419 + * the enable register, there would be an interrupt-storm when we
2420 + * release the IRQ lock. So we wait for the enable register update to
2421 + * take effect in h/w (by reading it back) and then clear all other bits
2422 + * in the status register. Ie. we clear them from ISR once it's certain
2423 + * IER won't allow them to reassert. */
2424 + PORTAL_IRQ_LOCK(p, irqflags);
2425 + bits &= BM_PIRQ_VISIBLE;
2426 + clear_bits(bits, &p->irq_sources);
2427 + bm_isr_enable_write(&p->p, p->irq_sources);
2428 + ier = bm_isr_enable_read(&p->p);
2429 + /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a
2430 + * data-dependency, ie. to protect against re-ordering. */
2431 + bm_isr_status_clear(&p->p, ~ier);
2432 + PORTAL_IRQ_UNLOCK(p, irqflags);
2433 + put_affine_portal();
2434 + return 0;
2435 +}
2436 +EXPORT_SYMBOL(bman_irqsource_remove);
2437 +
2438 +const cpumask_t *bman_affine_cpus(void)
2439 +{
2440 + return &affine_mask;
2441 +}
2442 +EXPORT_SYMBOL(bman_affine_cpus);
2443 +
2444 +u32 bman_poll_slow(void)
2445 +{
2446 + struct bman_portal *p = get_poll_portal();
2447 + u32 ret;
2448 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2449 + if (unlikely(p->sharing_redirect))
2450 + ret = (u32)-1;
2451 + else
2452 +#endif
2453 + {
2454 + u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources;
2455 + ret = __poll_portal_slow(p, is);
2456 + bm_isr_status_clear(&p->p, ret);
2457 + }
2458 + put_poll_portal();
2459 + return ret;
2460 +}
2461 +EXPORT_SYMBOL(bman_poll_slow);
2462 +
2463 +/* Legacy wrapper */
2464 +void bman_poll(void)
2465 +{
2466 + struct bman_portal *p = get_poll_portal();
2467 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2468 + if (unlikely(p->sharing_redirect))
2469 + goto done;
2470 +#endif
2471 + if (!(p->slowpoll--)) {
2472 + u32 is = bm_isr_status_read(&p->p) & ~p->irq_sources;
2473 + u32 active = __poll_portal_slow(p, is);
2474 + if (active)
2475 + p->slowpoll = SLOW_POLL_BUSY;
2476 + else
2477 + p->slowpoll = SLOW_POLL_IDLE;
2478 + }
2479 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
2480 +done:
2481 +#endif
2482 + put_poll_portal();
2483 +}
2484 +EXPORT_SYMBOL(bman_poll);
2485 +
2486 +static const u32 zero_thresholds[4] = {0, 0, 0, 0};
2487 +
2488 +struct bman_pool *bman_new_pool(const struct bman_pool_params *params)
2489 +{
2490 + struct bman_pool *pool = NULL;
2491 + u32 bpid;
2492 +
2493 + if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) {
2494 + int ret = bman_alloc_bpid(&bpid);
2495 + if (ret)
2496 + return NULL;
2497 + } else {
2498 + if (params->bpid >= bman_pool_max)
2499 + return NULL;
2500 + bpid = params->bpid;
2501 + }
2502 +#ifdef CONFIG_FSL_BMAN_CONFIG
2503 + if (params->flags & BMAN_POOL_FLAG_THRESH) {
2504 + int ret = bm_pool_set(bpid, params->thresholds);
2505 + if (ret)
2506 + goto err;
2507 + }
2508 +#else
2509 + if (params->flags & BMAN_POOL_FLAG_THRESH)
2510 + goto err;
2511 +#endif
2512 + pool = kmalloc(sizeof(*pool), GFP_KERNEL);
2513 + if (!pool)
2514 + goto err;
2515 + pool->sp = NULL;
2516 + pool->sp_fill = 0;
2517 + pool->params = *params;
2518 +#ifdef CONFIG_FSL_DPA_CHECKING
2519 + atomic_set(&pool->in_use, 1);
2520 +#endif
2521 + if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
2522 + pool->params.bpid = bpid;
2523 + if (params->flags & BMAN_POOL_FLAG_STOCKPILE) {
2524 + pool->sp = kmalloc(sizeof(struct bm_buffer) * BMAN_STOCKPILE_SZ,
2525 + GFP_KERNEL);
2526 + if (!pool->sp)
2527 + goto err;
2528 + }
2529 + if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION) {
2530 + struct bman_portal *p = get_affine_portal();
2531 + if (!p->pools || !bman_depletion_get(&p->pools[0], bpid)) {
2532 + pr_err("Depletion events disabled for bpid %d\n", bpid);
2533 + goto err;
2534 + }
2535 + depletion_link(p, pool);
2536 + put_affine_portal();
2537 + }
2538 + return pool;
2539 +err:
2540 +#ifdef CONFIG_FSL_BMAN_CONFIG
2541 + if (params->flags & BMAN_POOL_FLAG_THRESH)
2542 + bm_pool_set(bpid, zero_thresholds);
2543 +#endif
2544 + if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
2545 + bman_release_bpid(bpid);
2546 + if (pool) {
2547 + kfree(pool->sp);
2548 + kfree(pool);
2549 + }
2550 + return NULL;
2551 +}
2552 +EXPORT_SYMBOL(bman_new_pool);
2553 +
2554 +void bman_free_pool(struct bman_pool *pool)
2555 +{
2556 +#ifdef CONFIG_FSL_BMAN_CONFIG
2557 + if (pool->params.flags & BMAN_POOL_FLAG_THRESH)
2558 + bm_pool_set(pool->params.bpid, zero_thresholds);
2559 +#endif
2560 + if (pool->params.flags & BMAN_POOL_FLAG_DEPLETION)
2561 + depletion_unlink(pool);
2562 + if (pool->params.flags & BMAN_POOL_FLAG_STOCKPILE) {
2563 + if (pool->sp_fill)
2564 + pr_err("Stockpile not flushed, has %u in bpid %u.\n",
2565 + pool->sp_fill, pool->params.bpid);
2566 + kfree(pool->sp);
2567 + pool->sp = NULL;
2568 + pool->params.flags ^= BMAN_POOL_FLAG_STOCKPILE;
2569 + }
2570 + if (pool->params.flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
2571 + bman_release_bpid(pool->params.bpid);
2572 + kfree(pool);
2573 +}
2574 +EXPORT_SYMBOL(bman_free_pool);
2575 +
2576 +const struct bman_pool_params *bman_get_params(const struct bman_pool *pool)
2577 +{
2578 + return &pool->params;
2579 +}
2580 +EXPORT_SYMBOL(bman_get_params);
2581 +
2582 +static noinline void update_rcr_ci(struct bman_portal *p, u8 avail)
2583 +{
2584 + if (avail)
2585 + bm_rcr_cce_prefetch(&p->p);
2586 + else
2587 + bm_rcr_cce_update(&p->p);
2588 +}
2589 +
2590 +int bman_rcr_is_empty(void)
2591 +{
2592 + __maybe_unused unsigned long irqflags;
2593 + struct bman_portal *p = get_affine_portal();
2594 + u8 avail;
2595 +
2596 + PORTAL_IRQ_LOCK(p, irqflags);
2597 + update_rcr_ci(p, 0);
2598 + avail = bm_rcr_get_fill(&p->p);
2599 + PORTAL_IRQ_UNLOCK(p, irqflags);
2600 + put_affine_portal();
2601 + return avail == 0;
2602 +}
2603 +EXPORT_SYMBOL(bman_rcr_is_empty);
2604 +
2605 +static inline struct bm_rcr_entry *try_rel_start(struct bman_portal **p,
2606 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
2607 + __maybe_unused struct bman_pool *pool,
2608 +#endif
2609 + __maybe_unused unsigned long *irqflags,
2610 + __maybe_unused u32 flags)
2611 +{
2612 + struct bm_rcr_entry *r;
2613 + u8 avail;
2614 +
2615 + *p = get_affine_portal();
2616 + PORTAL_IRQ_LOCK(*p, (*irqflags));
2617 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2618 + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
2619 + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) {
2620 + if ((*p)->rcri_owned) {
2621 + PORTAL_IRQ_UNLOCK(*p, (*irqflags));
2622 + put_affine_portal();
2623 + return NULL;
2624 + }
2625 + (*p)->rcri_owned = pool;
2626 + }
2627 +#endif
2628 + avail = bm_rcr_get_avail(&(*p)->p);
2629 + if (avail < 2)
2630 + update_rcr_ci(*p, avail);
2631 + r = bm_rcr_start(&(*p)->p);
2632 + if (unlikely(!r)) {
2633 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2634 + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
2635 + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC)))
2636 + (*p)->rcri_owned = NULL;
2637 +#endif
2638 + PORTAL_IRQ_UNLOCK(*p, (*irqflags));
2639 + put_affine_portal();
2640 + }
2641 + return r;
2642 +}
2643 +
2644 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
2645 +static noinline struct bm_rcr_entry *__wait_rel_start(struct bman_portal **p,
2646 + struct bman_pool *pool,
2647 + __maybe_unused unsigned long *irqflags,
2648 + u32 flags)
2649 +{
2650 + struct bm_rcr_entry *rcr = try_rel_start(p, pool, irqflags, flags);
2651 + if (!rcr)
2652 + bm_rcr_set_ithresh(&(*p)->p, 1);
2653 + return rcr;
2654 +}
2655 +
2656 +static noinline struct bm_rcr_entry *wait_rel_start(struct bman_portal **p,
2657 + struct bman_pool *pool,
2658 + __maybe_unused unsigned long *irqflags,
2659 + u32 flags)
2660 +{
2661 + struct bm_rcr_entry *rcr;
2662 +#ifndef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2663 + pool = NULL;
2664 +#endif
2665 + if (flags & BMAN_RELEASE_FLAG_WAIT_INT)
2666 + /* NB: return NULL if signal occurs before completion. Signal
2667 + * can occur during return. Caller must check for signal */
2668 + wait_event_interruptible(affine_queue,
2669 + (rcr = __wait_rel_start(p, pool, irqflags, flags)));
2670 + else
2671 + wait_event(affine_queue,
2672 + (rcr = __wait_rel_start(p, pool, irqflags, flags)));
2673 + return rcr;
2674 +}
2675 +#endif
2676 +
2677 +static inline int __bman_release(struct bman_pool *pool,
2678 + const struct bm_buffer *bufs, u8 num, u32 flags)
2679 +{
2680 + struct bman_portal *p;
2681 + struct bm_rcr_entry *r;
2682 + __maybe_unused unsigned long irqflags;
2683 + u32 i = num - 1;
2684 +
2685 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
2686 + if (flags & BMAN_RELEASE_FLAG_WAIT)
2687 + r = wait_rel_start(&p, pool, &irqflags, flags);
2688 + else
2689 + r = try_rel_start(&p, pool, &irqflags, flags);
2690 +#else
2691 + r = try_rel_start(&p, &irqflags, flags);
2692 +#endif
2693 + if (!r)
2694 + return -EBUSY;
2695 + /* We can copy all but the first entry, as this can trigger badness
2696 + * with the valid-bit. Use the overlay to mask the verb byte. */
2697 + r->bufs[0].opaque =
2698 + ((cpu_to_be64((bufs[0].opaque |
2699 + ((u64)pool->params.bpid<<48))
2700 + & 0x00ffffffffffffff)));
2701 + if (i) {
2702 + for (i = 1; i < num; i++)
2703 + r->bufs[i].opaque =
2704 + cpu_to_be64(bufs[i].opaque);
2705 + }
2706 +
2707 + bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
2708 + (num & BM_RCR_VERB_BUFCOUNT_MASK));
2709 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2710 + /* if we wish to sync we need to set the threshold after h/w sees the
2711 + * new ring entry. As we're mixing cache-enabled and cache-inhibited
2712 + * accesses, this requires a heavy-weight sync. */
2713 + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
2714 + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) {
2715 + hwsync();
2716 + bm_rcr_set_ithresh(&p->p, 1);
2717 + }
2718 +#endif
2719 + PORTAL_IRQ_UNLOCK(p, irqflags);
2720 + put_affine_portal();
2721 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
2722 + if (unlikely((flags & BMAN_RELEASE_FLAG_WAIT) &&
2723 + (flags & BMAN_RELEASE_FLAG_WAIT_SYNC))) {
2724 + if (flags & BMAN_RELEASE_FLAG_WAIT_INT)
2725 + /* NB: return success even if signal occurs before
2726 + * condition is true. pvb_commit guarantees success */
2727 + wait_event_interruptible(affine_queue,
2728 + (p->rcri_owned != pool));
2729 + else
2730 + wait_event(affine_queue, (p->rcri_owned != pool));
2731 + }
2732 +#endif
2733 + return 0;
2734 +}
2735 +
2736 +int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num,
2737 + u32 flags)
2738 +{
2739 + int ret;
2740 +#ifdef CONFIG_FSL_DPA_CHECKING
2741 + if (!num || (num > 8))
2742 + return -EINVAL;
2743 + if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE)
2744 + return -EINVAL;
2745 +#endif
2746 + /* Without stockpile, this API is a pass-through to the h/w operation */
2747 + if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE))
2748 + return __bman_release(pool, bufs, num, flags);
2749 +#ifdef CONFIG_FSL_DPA_CHECKING
2750 + if (!atomic_dec_and_test(&pool->in_use)) {
2751 + pr_crit("Parallel attempts to enter bman_released() detected.");
2752 + panic("only one instance of bman_released/acquired allowed");
2753 + }
2754 +#endif
2755 + /* Two movements of buffers are possible, and can occur in either order.
2756 + * A: moving buffers from the caller to the stockpile.
2757 + * B: moving buffers from the stockpile to hardware.
2758 + * Order 1: if there is already enough space in the stockpile for A
2759 + * then we want to do A first, and only do B if we trigger the
2760 + * stockpile-high threshold.
2761 + * Order 2: if there is not enough space in the stockpile for A, then
2762 + * we want to do B first, then do A if B had succeeded. However in this
2763 + * case B is dependent on how many buffers the user needs to release,
2764 + * not the stockpile-high threshold.
2765 + * Due to the different handling of B between the two cases, putting A
2766 + * and B in a while() loop would require quite obscure logic, so handle
2767 + * the different sequences explicitly. */
2768 + if ((pool->sp_fill + num) <= BMAN_STOCKPILE_SZ) {
2769 + /* Order 1: do A */
2770 + copy_words(pool->sp + pool->sp_fill, bufs,
2771 + sizeof(struct bm_buffer) * num);
2772 + pool->sp_fill += num;
2773 + /* do B relative to STOCKPILE_HIGH */
2774 + while (pool->sp_fill >= BMAN_STOCKPILE_HIGH) {
2775 + ret = __bman_release(pool,
2776 + pool->sp + (pool->sp_fill - 8), 8,
2777 + flags);
2778 + if (ret >= 0)
2779 + pool->sp_fill -= 8;
2780 + }
2781 + } else {
2782 + /* Order 2: do B relative to 'num' */
2783 + do {
2784 + ret = __bman_release(pool,
2785 + pool->sp + (pool->sp_fill - 8), 8,
2786 + flags);
2787 + if (ret < 0)
2788 + /* failure */
2789 + goto release_done;
2790 + pool->sp_fill -= 8;
2791 + } while ((pool->sp_fill + num) > BMAN_STOCKPILE_SZ);
2792 + /* do A */
2793 + copy_words(pool->sp + pool->sp_fill, bufs,
2794 + sizeof(struct bm_buffer) * num);
2795 + pool->sp_fill += num;
2796 + }
2797 + /* success */
2798 + ret = 0;
2799 +release_done:
2800 +#ifdef CONFIG_FSL_DPA_CHECKING
2801 + atomic_inc(&pool->in_use);
2802 +#endif
2803 + return ret;
2804 +}
2805 +EXPORT_SYMBOL(bman_release);
2806 +
2807 +static inline int __bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs,
2808 + u8 num)
2809 +{
2810 + struct bman_portal *p = get_affine_portal();
2811 + struct bm_mc_command *mcc;
2812 + struct bm_mc_result *mcr;
2813 + __maybe_unused unsigned long irqflags;
2814 + int ret, i;
2815 +
2816 + PORTAL_IRQ_LOCK(p, irqflags);
2817 + mcc = bm_mc_start(&p->p);
2818 + mcc->acquire.bpid = pool->params.bpid;
2819 + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
2820 + (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
2821 + while (!(mcr = bm_mc_result(&p->p)))
2822 + cpu_relax();
2823 + ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
2824 + if (bufs) {
2825 + for (i = 0; i < num; i++)
2826 + bufs[i].opaque =
2827 + be64_to_cpu(mcr->acquire.bufs[i].opaque);
2828 + }
2829 + PORTAL_IRQ_UNLOCK(p, irqflags);
2830 + put_affine_portal();
2831 + if (ret != num)
2832 + ret = -ENOMEM;
2833 + return ret;
2834 +}
2835 +
2836 +int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num,
2837 + u32 flags)
2838 +{
2839 + int ret;
2840 +#ifdef CONFIG_FSL_DPA_CHECKING
2841 + if (!num || (num > 8))
2842 + return -EINVAL;
2843 + if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE)
2844 + return -EINVAL;
2845 +#endif
2846 + /* Without stockpile, this API is a pass-through to the h/w operation */
2847 + if (!(pool->params.flags & BMAN_POOL_FLAG_STOCKPILE))
2848 + return __bman_acquire(pool, bufs, num);
2849 +#ifdef CONFIG_FSL_DPA_CHECKING
2850 + if (!atomic_dec_and_test(&pool->in_use)) {
2851 + pr_crit("Parallel attempts to enter bman_acquire() detected.");
2852 + panic("only one instance of bman_released/acquired allowed");
2853 + }
2854 +#endif
2855 + /* Two movements of buffers are possible, and can occur in either order.
2856 + * A: moving buffers from stockpile to the caller.
2857 + * B: moving buffers from hardware to the stockpile.
2858 + * Order 1: if there are already enough buffers in the stockpile for A
2859 + * then we want to do A first, and only do B if we trigger the
2860 + * stockpile-low threshold.
2861 + * Order 2: if there are not enough buffers in the stockpile for A,
2862 + * then we want to do B first, then do A if B had succeeded. However in
2863 + * this case B is dependent on how many buffers the user needs, not the
2864 + * stockpile-low threshold.
2865 + * Due to the different handling of B between the two cases, putting A
2866 + * and B in a while() loop would require quite obscure logic, so handle
2867 + * the different sequences explicitly. */
2868 + if (num <= pool->sp_fill) {
2869 + /* Order 1: do A */
2870 + copy_words(bufs, pool->sp + (pool->sp_fill - num),
2871 + sizeof(struct bm_buffer) * num);
2872 + pool->sp_fill -= num;
2873 + /* do B relative to STOCKPILE_LOW */
2874 + while (pool->sp_fill <= BMAN_STOCKPILE_LOW) {
2875 + ret = __bman_acquire(pool, pool->sp + pool->sp_fill, 8);
2876 + if (ret < 0)
2877 + ret = __bman_acquire(pool,
2878 + pool->sp + pool->sp_fill, 1);
2879 + if (ret < 0)
2880 + break;
2881 + pool->sp_fill += ret;
2882 + }
2883 + } else {
2884 + /* Order 2: do B relative to 'num' */
2885 + do {
2886 + ret = __bman_acquire(pool, pool->sp + pool->sp_fill, 8);
2887 + if (ret < 0)
2888 + ret = __bman_acquire(pool,
2889 + pool->sp + pool->sp_fill, 1);
2890 + if (ret < 0)
2891 + /* failure */
2892 + goto acquire_done;
2893 + pool->sp_fill += ret;
2894 + } while (pool->sp_fill < num);
2895 + /* do A */
2896 + copy_words(bufs, pool->sp + (pool->sp_fill - num),
2897 + sizeof(struct bm_buffer) * num);
2898 + pool->sp_fill -= num;
2899 + }
2900 + /* success */
2901 + ret = num;
2902 +acquire_done:
2903 +#ifdef CONFIG_FSL_DPA_CHECKING
2904 + atomic_inc(&pool->in_use);
2905 +#endif
2906 + return ret;
2907 +}
2908 +EXPORT_SYMBOL(bman_acquire);
2909 +
2910 +int bman_flush_stockpile(struct bman_pool *pool, u32 flags)
2911 +{
2912 + u8 num;
2913 + int ret;
2914 +
2915 + while (pool->sp_fill) {
2916 + num = ((pool->sp_fill > 8) ? 8 : pool->sp_fill);
2917 + ret = __bman_release(pool, pool->sp + (pool->sp_fill - num),
2918 + num, flags);
2919 + if (ret)
2920 + return ret;
2921 + pool->sp_fill -= num;
2922 + }
2923 + return 0;
2924 +}
2925 +EXPORT_SYMBOL(bman_flush_stockpile);
2926 +
2927 +int bman_query_pools(struct bm_pool_state *state)
2928 +{
2929 + struct bman_portal *p = get_affine_portal();
2930 + struct bm_mc_result *mcr;
2931 + __maybe_unused unsigned long irqflags;
2932 +
2933 + PORTAL_IRQ_LOCK(p, irqflags);
2934 + bm_mc_start(&p->p);
2935 + bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY);
2936 + while (!(mcr = bm_mc_result(&p->p)))
2937 + cpu_relax();
2938 + DPA_ASSERT((mcr->verb & BM_MCR_VERB_CMD_MASK) == BM_MCR_VERB_CMD_QUERY);
2939 + *state = mcr->query;
2940 + PORTAL_IRQ_UNLOCK(p, irqflags);
2941 + put_affine_portal();
2942 + return 0;
2943 +}
2944 +EXPORT_SYMBOL(bman_query_pools);
2945 +
2946 +#ifdef CONFIG_FSL_BMAN_CONFIG
2947 +u32 bman_query_free_buffers(struct bman_pool *pool)
2948 +{
2949 + return bm_pool_free_buffers(pool->params.bpid);
2950 +}
2951 +EXPORT_SYMBOL(bman_query_free_buffers);
2952 +
2953 +int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds)
2954 +{
2955 + u32 bpid;
2956 +
2957 + bpid = bman_get_params(pool)->bpid;
2958 +
2959 + return bm_pool_set(bpid, thresholds);
2960 +}
2961 +EXPORT_SYMBOL(bman_update_pool_thresholds);
2962 +#endif
2963 +
2964 +int bman_shutdown_pool(u32 bpid)
2965 +{
2966 + struct bman_portal *p = get_affine_portal();
2967 + __maybe_unused unsigned long irqflags;
2968 + int ret;
2969 +
2970 + PORTAL_IRQ_LOCK(p, irqflags);
2971 + ret = bm_shutdown_pool(&p->p, bpid);
2972 + PORTAL_IRQ_UNLOCK(p, irqflags);
2973 + put_affine_portal();
2974 + return ret;
2975 +}
2976 +EXPORT_SYMBOL(bman_shutdown_pool);
2977 +
2978 +const struct bm_portal_config *bman_get_bm_portal_config(
2979 + struct bman_portal *portal)
2980 +{
2981 + return portal->sharing_redirect ? NULL : portal->config;
2982 +}
2983 --- /dev/null
2984 +++ b/drivers/staging/fsl_qbman/bman_low.h
2985 @@ -0,0 +1,559 @@
2986 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
2987 + *
2988 + * Redistribution and use in source and binary forms, with or without
2989 + * modification, are permitted provided that the following conditions are met:
2990 + * * Redistributions of source code must retain the above copyright
2991 + * notice, this list of conditions and the following disclaimer.
2992 + * * Redistributions in binary form must reproduce the above copyright
2993 + * notice, this list of conditions and the following disclaimer in the
2994 + * documentation and/or other materials provided with the distribution.
2995 + * * Neither the name of Freescale Semiconductor nor the
2996 + * names of its contributors may be used to endorse or promote products
2997 + * derived from this software without specific prior written permission.
2998 + *
2999 + *
3000 + * ALTERNATIVELY, this software may be distributed under the terms of the
3001 + * GNU General Public License ("GPL") as published by the Free Software
3002 + * Foundation, either version 2 of that License or (at your option) any
3003 + * later version.
3004 + *
3005 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
3006 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3007 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3008 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
3009 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3010 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3011 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3012 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3013 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3014 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3015 + */
3016 +
3017 +#include "bman_private.h"
3018 +
3019 +/***************************/
3020 +/* Portal register assists */
3021 +/***************************/
3022 +
3023 +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
3024 +
3025 +/* Cache-inhibited register offsets */
3026 +#define BM_REG_RCR_PI_CINH 0x0000
3027 +#define BM_REG_RCR_CI_CINH 0x0004
3028 +#define BM_REG_RCR_ITR 0x0008
3029 +#define BM_REG_CFG 0x0100
3030 +#define BM_REG_SCN(n) (0x0200 + ((n) << 2))
3031 +#define BM_REG_ISR 0x0e00
3032 +#define BM_REG_IIR 0x0e0c
3033 +
3034 +/* Cache-enabled register offsets */
3035 +#define BM_CL_CR 0x0000
3036 +#define BM_CL_RR0 0x0100
3037 +#define BM_CL_RR1 0x0140
3038 +#define BM_CL_RCR 0x1000
3039 +#define BM_CL_RCR_PI_CENA 0x3000
3040 +#define BM_CL_RCR_CI_CENA 0x3100
3041 +
3042 +#endif
3043 +
3044 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
3045 +
3046 +/* Cache-inhibited register offsets */
3047 +#define BM_REG_RCR_PI_CINH 0x3000
3048 +#define BM_REG_RCR_CI_CINH 0x3100
3049 +#define BM_REG_RCR_ITR 0x3200
3050 +#define BM_REG_CFG 0x3300
3051 +#define BM_REG_SCN(n) (0x3400 + ((n) << 6))
3052 +#define BM_REG_ISR 0x3e00
3053 +#define BM_REG_IIR 0x3ec0
3054 +
3055 +/* Cache-enabled register offsets */
3056 +#define BM_CL_CR 0x0000
3057 +#define BM_CL_RR0 0x0100
3058 +#define BM_CL_RR1 0x0140
3059 +#define BM_CL_RCR 0x1000
3060 +#define BM_CL_RCR_PI_CENA 0x3000
3061 +#define BM_CL_RCR_CI_CENA 0x3100
3062 +
3063 +#endif
3064 +
3065 +/* BTW, the drivers (and h/w programming model) already obtain the required
3066 + * synchronisation for portal accesses via lwsync(), hwsync(), and
3067 + * data-dependencies. Use of barrier()s or other order-preserving primitives
3068 + * simply degrade performance. Hence the use of the __raw_*() interfaces, which
3069 + * simply ensure that the compiler treats the portal registers as volatile (ie.
3070 + * non-coherent). */
3071 +
3072 +/* Cache-inhibited register access. */
3073 +#define __bm_in(bm, o) be32_to_cpu(__raw_readl((bm)->addr_ci + (o)))
3074 +#define __bm_out(bm, o, val) __raw_writel(cpu_to_be32(val), \
3075 + (bm)->addr_ci + (o));
3076 +#define bm_in(reg) __bm_in(&portal->addr, BM_REG_##reg)
3077 +#define bm_out(reg, val) __bm_out(&portal->addr, BM_REG_##reg, val)
3078 +
3079 +/* Cache-enabled (index) register access */
3080 +#define __bm_cl_touch_ro(bm, o) dcbt_ro((bm)->addr_ce + (o))
3081 +#define __bm_cl_touch_rw(bm, o) dcbt_rw((bm)->addr_ce + (o))
3082 +#define __bm_cl_in(bm, o) be32_to_cpu(__raw_readl((bm)->addr_ce + (o)))
3083 +#define __bm_cl_out(bm, o, val) \
3084 + do { \
3085 + u32 *__tmpclout = (bm)->addr_ce + (o); \
3086 + __raw_writel(cpu_to_be32(val), __tmpclout); \
3087 + dcbf(__tmpclout); \
3088 + } while (0)
3089 +#define __bm_cl_invalidate(bm, o) dcbi((bm)->addr_ce + (o))
3090 +#define bm_cl_touch_ro(reg) __bm_cl_touch_ro(&portal->addr, BM_CL_##reg##_CENA)
3091 +#define bm_cl_touch_rw(reg) __bm_cl_touch_rw(&portal->addr, BM_CL_##reg##_CENA)
3092 +#define bm_cl_in(reg) __bm_cl_in(&portal->addr, BM_CL_##reg##_CENA)
3093 +#define bm_cl_out(reg, val) __bm_cl_out(&portal->addr, BM_CL_##reg##_CENA, val)
3094 +#define bm_cl_invalidate(reg)\
3095 + __bm_cl_invalidate(&portal->addr, BM_CL_##reg##_CENA)
3096 +
3097 +/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf
3098 + * analysis, look at using the "extra" bit in the ring index registers to avoid
3099 + * cyclic issues. */
3100 +static inline u8 bm_cyc_diff(u8 ringsize, u8 first, u8 last)
3101 +{
3102 + /* 'first' is included, 'last' is excluded */
3103 + if (first <= last)
3104 + return last - first;
3105 + return ringsize + last - first;
3106 +}
3107 +
3108 +/* Portal modes.
3109 + * Enum types;
3110 + * pmode == production mode
3111 + * cmode == consumption mode,
3112 + * Enum values use 3 letter codes. First letter matches the portal mode,
3113 + * remaining two letters indicate;
3114 + * ci == cache-inhibited portal register
3115 + * ce == cache-enabled portal register
3116 + * vb == in-band valid-bit (cache-enabled)
3117 + */
3118 +enum bm_rcr_pmode { /* matches BCSP_CFG::RPM */
3119 + bm_rcr_pci = 0, /* PI index, cache-inhibited */
3120 + bm_rcr_pce = 1, /* PI index, cache-enabled */
3121 + bm_rcr_pvb = 2 /* valid-bit */
3122 +};
3123 +enum bm_rcr_cmode { /* s/w-only */
3124 + bm_rcr_cci, /* CI index, cache-inhibited */
3125 + bm_rcr_cce /* CI index, cache-enabled */
3126 +};
3127 +
3128 +
3129 +/* ------------------------- */
3130 +/* --- Portal structures --- */
3131 +
3132 +#define BM_RCR_SIZE 8
3133 +
3134 +struct bm_rcr {
3135 + struct bm_rcr_entry *ring, *cursor;
3136 + u8 ci, available, ithresh, vbit;
3137 +#ifdef CONFIG_FSL_DPA_CHECKING
3138 + u32 busy;
3139 + enum bm_rcr_pmode pmode;
3140 + enum bm_rcr_cmode cmode;
3141 +#endif
3142 +};
3143 +
3144 +struct bm_mc {
3145 + struct bm_mc_command *cr;
3146 + struct bm_mc_result *rr;
3147 + u8 rridx, vbit;
3148 +#ifdef CONFIG_FSL_DPA_CHECKING
3149 + enum {
3150 + /* Can only be _mc_start()ed */
3151 + mc_idle,
3152 + /* Can only be _mc_commit()ed or _mc_abort()ed */
3153 + mc_user,
3154 + /* Can only be _mc_retry()ed */
3155 + mc_hw
3156 + } state;
3157 +#endif
3158 +};
3159 +
3160 +struct bm_addr {
3161 + void __iomem *addr_ce; /* cache-enabled */
3162 + void __iomem *addr_ci; /* cache-inhibited */
3163 +};
3164 +
3165 +struct bm_portal {
3166 + struct bm_addr addr;
3167 + struct bm_rcr rcr;
3168 + struct bm_mc mc;
3169 + struct bm_portal_config config;
3170 +} ____cacheline_aligned;
3171 +
3172 +
3173 +/* --------------- */
3174 +/* --- RCR API --- */
3175 +
3176 +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */
3177 +#define RCR_CARRYCLEAR(p) \
3178 + (void *)((unsigned long)(p) & (~(unsigned long)(BM_RCR_SIZE << 6)))
3179 +
3180 +/* Bit-wise logic to convert a ring pointer to a ring index */
3181 +static inline u8 RCR_PTR2IDX(struct bm_rcr_entry *e)
3182 +{
3183 + return ((uintptr_t)e >> 6) & (BM_RCR_SIZE - 1);
3184 +}
3185 +
3186 +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */
3187 +static inline void RCR_INC(struct bm_rcr *rcr)
3188 +{
3189 + /* NB: this is odd-looking, but experiments show that it generates
3190 + * fast code with essentially no branching overheads. We increment to
3191 + * the next RCR pointer and handle overflow and 'vbit'. */
3192 + struct bm_rcr_entry *partial = rcr->cursor + 1;
3193 + rcr->cursor = RCR_CARRYCLEAR(partial);
3194 + if (partial != rcr->cursor)
3195 + rcr->vbit ^= BM_RCR_VERB_VBIT;
3196 +}
3197 +
3198 +static inline int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode,
3199 + __maybe_unused enum bm_rcr_cmode cmode)
3200 +{
3201 + /* This use of 'register', as well as all other occurrences, is because
3202 + * it has been observed to generate much faster code with gcc than is
3203 + * otherwise the case. */
3204 + register struct bm_rcr *rcr = &portal->rcr;
3205 + u32 cfg;
3206 + u8 pi;
3207 +
3208 + rcr->ring = portal->addr.addr_ce + BM_CL_RCR;
3209 + rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1);
3210 +
3211 + pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1);
3212 + rcr->cursor = rcr->ring + pi;
3213 + rcr->vbit = (bm_in(RCR_PI_CINH) & BM_RCR_SIZE) ? BM_RCR_VERB_VBIT : 0;
3214 + rcr->available = BM_RCR_SIZE - 1
3215 + - bm_cyc_diff(BM_RCR_SIZE, rcr->ci, pi);
3216 + rcr->ithresh = bm_in(RCR_ITR);
3217 +#ifdef CONFIG_FSL_DPA_CHECKING
3218 + rcr->busy = 0;
3219 + rcr->pmode = pmode;
3220 + rcr->cmode = cmode;
3221 +#endif
3222 + cfg = (bm_in(CFG) & 0xffffffe0) | (pmode & 0x3); /* BCSP_CFG::RPM */
3223 + bm_out(CFG, cfg);
3224 + return 0;
3225 +}
3226 +
3227 +static inline void bm_rcr_finish(struct bm_portal *portal)
3228 +{
3229 + register struct bm_rcr *rcr = &portal->rcr;
3230 + u8 pi = bm_in(RCR_PI_CINH) & (BM_RCR_SIZE - 1);
3231 + u8 ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1);
3232 + DPA_ASSERT(!rcr->busy);
3233 + if (pi != RCR_PTR2IDX(rcr->cursor))
3234 + pr_crit("losing uncommited RCR entries\n");
3235 + if (ci != rcr->ci)
3236 + pr_crit("missing existing RCR completions\n");
3237 + if (rcr->ci != RCR_PTR2IDX(rcr->cursor))
3238 + pr_crit("RCR destroyed unquiesced\n");
3239 +}
3240 +
3241 +static inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal)
3242 +{
3243 + register struct bm_rcr *rcr = &portal->rcr;
3244 + DPA_ASSERT(!rcr->busy);
3245 + if (!rcr->available)
3246 + return NULL;
3247 +#ifdef CONFIG_FSL_DPA_CHECKING
3248 + rcr->busy = 1;
3249 +#endif
3250 + dcbz_64(rcr->cursor);
3251 + return rcr->cursor;
3252 +}
3253 +
3254 +static inline void bm_rcr_abort(struct bm_portal *portal)
3255 +{
3256 + __maybe_unused register struct bm_rcr *rcr = &portal->rcr;
3257 + DPA_ASSERT(rcr->busy);
3258 +#ifdef CONFIG_FSL_DPA_CHECKING
3259 + rcr->busy = 0;
3260 +#endif
3261 +}
3262 +
3263 +static inline struct bm_rcr_entry *bm_rcr_pend_and_next(
3264 + struct bm_portal *portal, u8 myverb)
3265 +{
3266 + register struct bm_rcr *rcr = &portal->rcr;
3267 + DPA_ASSERT(rcr->busy);
3268 + DPA_ASSERT(rcr->pmode != bm_rcr_pvb);
3269 + if (rcr->available == 1)
3270 + return NULL;
3271 + rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit;
3272 + dcbf_64(rcr->cursor);
3273 + RCR_INC(rcr);
3274 + rcr->available--;
3275 + dcbz_64(rcr->cursor);
3276 + return rcr->cursor;
3277 +}
3278 +
3279 +static inline void bm_rcr_pci_commit(struct bm_portal *portal, u8 myverb)
3280 +{
3281 + register struct bm_rcr *rcr = &portal->rcr;
3282 + DPA_ASSERT(rcr->busy);
3283 + DPA_ASSERT(rcr->pmode == bm_rcr_pci);
3284 + rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit;
3285 + RCR_INC(rcr);
3286 + rcr->available--;
3287 + hwsync();
3288 + bm_out(RCR_PI_CINH, RCR_PTR2IDX(rcr->cursor));
3289 +#ifdef CONFIG_FSL_DPA_CHECKING
3290 + rcr->busy = 0;
3291 +#endif
3292 +}
3293 +
3294 +static inline void bm_rcr_pce_prefetch(struct bm_portal *portal)
3295 +{
3296 + __maybe_unused register struct bm_rcr *rcr = &portal->rcr;
3297 + DPA_ASSERT(rcr->pmode == bm_rcr_pce);
3298 + bm_cl_invalidate(RCR_PI);
3299 + bm_cl_touch_rw(RCR_PI);
3300 +}
3301 +
3302 +static inline void bm_rcr_pce_commit(struct bm_portal *portal, u8 myverb)
3303 +{
3304 + register struct bm_rcr *rcr = &portal->rcr;
3305 + DPA_ASSERT(rcr->busy);
3306 + DPA_ASSERT(rcr->pmode == bm_rcr_pce);
3307 + rcr->cursor->__dont_write_directly__verb = myverb | rcr->vbit;
3308 + RCR_INC(rcr);
3309 + rcr->available--;
3310 + lwsync();
3311 + bm_cl_out(RCR_PI, RCR_PTR2IDX(rcr->cursor));
3312 +#ifdef CONFIG_FSL_DPA_CHECKING
3313 + rcr->busy = 0;
3314 +#endif
3315 +}
3316 +
3317 +static inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb)
3318 +{
3319 + register struct bm_rcr *rcr = &portal->rcr;
3320 + struct bm_rcr_entry *rcursor;
3321 + DPA_ASSERT(rcr->busy);
3322 + DPA_ASSERT(rcr->pmode == bm_rcr_pvb);
3323 + lwsync();
3324 + rcursor = rcr->cursor;
3325 + rcursor->__dont_write_directly__verb = myverb | rcr->vbit;
3326 + dcbf_64(rcursor);
3327 + RCR_INC(rcr);
3328 + rcr->available--;
3329 +#ifdef CONFIG_FSL_DPA_CHECKING
3330 + rcr->busy = 0;
3331 +#endif
3332 +}
3333 +
3334 +static inline u8 bm_rcr_cci_update(struct bm_portal *portal)
3335 +{
3336 + register struct bm_rcr *rcr = &portal->rcr;
3337 + u8 diff, old_ci = rcr->ci;
3338 + DPA_ASSERT(rcr->cmode == bm_rcr_cci);
3339 + rcr->ci = bm_in(RCR_CI_CINH) & (BM_RCR_SIZE - 1);
3340 + diff = bm_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci);
3341 + rcr->available += diff;
3342 + return diff;
3343 +}
3344 +
3345 +static inline void bm_rcr_cce_prefetch(struct bm_portal *portal)
3346 +{
3347 + __maybe_unused register struct bm_rcr *rcr = &portal->rcr;
3348 + DPA_ASSERT(rcr->cmode == bm_rcr_cce);
3349 + bm_cl_touch_ro(RCR_CI);
3350 +}
3351 +
3352 +static inline u8 bm_rcr_cce_update(struct bm_portal *portal)
3353 +{
3354 + register struct bm_rcr *rcr = &portal->rcr;
3355 + u8 diff, old_ci = rcr->ci;
3356 + DPA_ASSERT(rcr->cmode == bm_rcr_cce);
3357 + rcr->ci = bm_cl_in(RCR_CI) & (BM_RCR_SIZE - 1);
3358 + bm_cl_invalidate(RCR_CI);
3359 + diff = bm_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci);
3360 + rcr->available += diff;
3361 + return diff;
3362 +}
3363 +
3364 +static inline u8 bm_rcr_get_ithresh(struct bm_portal *portal)
3365 +{
3366 + register struct bm_rcr *rcr = &portal->rcr;
3367 + return rcr->ithresh;
3368 +}
3369 +
3370 +static inline void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh)
3371 +{
3372 + register struct bm_rcr *rcr = &portal->rcr;
3373 + rcr->ithresh = ithresh;
3374 + bm_out(RCR_ITR, ithresh);
3375 +}
3376 +
3377 +static inline u8 bm_rcr_get_avail(struct bm_portal *portal)
3378 +{
3379 + register struct bm_rcr *rcr = &portal->rcr;
3380 + return rcr->available;
3381 +}
3382 +
3383 +static inline u8 bm_rcr_get_fill(struct bm_portal *portal)
3384 +{
3385 + register struct bm_rcr *rcr = &portal->rcr;
3386 + return BM_RCR_SIZE - 1 - rcr->available;
3387 +}
3388 +
3389 +
3390 +/* ------------------------------ */
3391 +/* --- Management command API --- */
3392 +
3393 +static inline int bm_mc_init(struct bm_portal *portal)
3394 +{
3395 + register struct bm_mc *mc = &portal->mc;
3396 + mc->cr = portal->addr.addr_ce + BM_CL_CR;
3397 + mc->rr = portal->addr.addr_ce + BM_CL_RR0;
3398 + mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) &
3399 + BM_MCC_VERB_VBIT) ? 0 : 1;
3400 + mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0;
3401 +#ifdef CONFIG_FSL_DPA_CHECKING
3402 + mc->state = mc_idle;
3403 +#endif
3404 + return 0;
3405 +}
3406 +
3407 +static inline void bm_mc_finish(struct bm_portal *portal)
3408 +{
3409 + __maybe_unused register struct bm_mc *mc = &portal->mc;
3410 + DPA_ASSERT(mc->state == mc_idle);
3411 +#ifdef CONFIG_FSL_DPA_CHECKING
3412 + if (mc->state != mc_idle)
3413 + pr_crit("Losing incomplete MC command\n");
3414 +#endif
3415 +}
3416 +
3417 +static inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal)
3418 +{
3419 + register struct bm_mc *mc = &portal->mc;
3420 + DPA_ASSERT(mc->state == mc_idle);
3421 +#ifdef CONFIG_FSL_DPA_CHECKING
3422 + mc->state = mc_user;
3423 +#endif
3424 + dcbz_64(mc->cr);
3425 + return mc->cr;
3426 +}
3427 +
3428 +static inline void bm_mc_abort(struct bm_portal *portal)
3429 +{
3430 + __maybe_unused register struct bm_mc *mc = &portal->mc;
3431 + DPA_ASSERT(mc->state == mc_user);
3432 +#ifdef CONFIG_FSL_DPA_CHECKING
3433 + mc->state = mc_idle;
3434 +#endif
3435 +}
3436 +
3437 +static inline void bm_mc_commit(struct bm_portal *portal, u8 myverb)
3438 +{
3439 + register struct bm_mc *mc = &portal->mc;
3440 + struct bm_mc_result *rr = mc->rr + mc->rridx;
3441 + DPA_ASSERT(mc->state == mc_user);
3442 + lwsync();
3443 + mc->cr->__dont_write_directly__verb = myverb | mc->vbit;
3444 + dcbf(mc->cr);
3445 + dcbit_ro(rr);
3446 +#ifdef CONFIG_FSL_DPA_CHECKING
3447 + mc->state = mc_hw;
3448 +#endif
3449 +}
3450 +
3451 +static inline struct bm_mc_result *bm_mc_result(struct bm_portal *portal)
3452 +{
3453 + register struct bm_mc *mc = &portal->mc;
3454 + struct bm_mc_result *rr = mc->rr + mc->rridx;
3455 + DPA_ASSERT(mc->state == mc_hw);
3456 + /* The inactive response register's verb byte always returns zero until
3457 + * its command is submitted and completed. This includes the valid-bit,
3458 + * in case you were wondering... */
3459 + if (!__raw_readb(&rr->verb)) {
3460 + dcbit_ro(rr);
3461 + return NULL;
3462 + }
3463 + mc->rridx ^= 1;
3464 + mc->vbit ^= BM_MCC_VERB_VBIT;
3465 +#ifdef CONFIG_FSL_DPA_CHECKING
3466 + mc->state = mc_idle;
3467 +#endif
3468 + return rr;
3469 +}
3470 +
3471 +
3472 +/* ------------------------------------- */
3473 +/* --- Portal interrupt register API --- */
3474 +
3475 +static inline int bm_isr_init(__always_unused struct bm_portal *portal)
3476 +{
3477 + return 0;
3478 +}
3479 +
3480 +static inline void bm_isr_finish(__always_unused struct bm_portal *portal)
3481 +{
3482 +}
3483 +
3484 +#define SCN_REG(bpid) BM_REG_SCN((bpid) / 32)
3485 +#define SCN_BIT(bpid) (0x80000000 >> (bpid & 31))
3486 +static inline void bm_isr_bscn_mask(struct bm_portal *portal, u8 bpid,
3487 + int enable)
3488 +{
3489 + u32 val;
3490 + DPA_ASSERT(bpid < bman_pool_max);
3491 + /* REG_SCN for bpid=0..31, REG_SCN+4 for bpid=32..63 */
3492 + val = __bm_in(&portal->addr, SCN_REG(bpid));
3493 + if (enable)
3494 + val |= SCN_BIT(bpid);
3495 + else
3496 + val &= ~SCN_BIT(bpid);
3497 + __bm_out(&portal->addr, SCN_REG(bpid), val);
3498 +}
3499 +
3500 +static inline u32 __bm_isr_read(struct bm_portal *portal, enum bm_isr_reg n)
3501 +{
3502 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
3503 + return __bm_in(&portal->addr, BM_REG_ISR + (n << 6));
3504 +#else
3505 + return __bm_in(&portal->addr, BM_REG_ISR + (n << 2));
3506 +#endif
3507 +}
3508 +
3509 +static inline void __bm_isr_write(struct bm_portal *portal, enum bm_isr_reg n,
3510 + u32 val)
3511 +{
3512 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
3513 + __bm_out(&portal->addr, BM_REG_ISR + (n << 6), val);
3514 +#else
3515 + __bm_out(&portal->addr, BM_REG_ISR + (n << 2), val);
3516 +#endif
3517 +}
3518 +
3519 +/* Buffer Pool Cleanup */
3520 +static inline int bm_shutdown_pool(struct bm_portal *p, u32 bpid)
3521 +{
3522 + struct bm_mc_command *bm_cmd;
3523 + struct bm_mc_result *bm_res;
3524 +
3525 + int aq_count = 0;
3526 + bool stop = false;
3527 + while (!stop) {
3528 + /* Acquire buffers until empty */
3529 + bm_cmd = bm_mc_start(p);
3530 + bm_cmd->acquire.bpid = bpid;
3531 + bm_mc_commit(p, BM_MCC_VERB_CMD_ACQUIRE | 1);
3532 + while (!(bm_res = bm_mc_result(p)))
3533 + cpu_relax();
3534 + if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) {
3535 + /* Pool is empty */
3536 + /* TBD : Should we do a few extra iterations in
3537 + case some other some blocks keep buffers 'on deck',
3538 + which may also be problematic */
3539 + stop = true;
3540 + } else
3541 + ++aq_count;
3542 + }
3543 + return 0;
3544 +}
3545 --- /dev/null
3546 +++ b/drivers/staging/fsl_qbman/bman_private.h
3547 @@ -0,0 +1,166 @@
3548 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
3549 + *
3550 + * Redistribution and use in source and binary forms, with or without
3551 + * modification, are permitted provided that the following conditions are met:
3552 + * * Redistributions of source code must retain the above copyright
3553 + * notice, this list of conditions and the following disclaimer.
3554 + * * Redistributions in binary form must reproduce the above copyright
3555 + * notice, this list of conditions and the following disclaimer in the
3556 + * documentation and/or other materials provided with the distribution.
3557 + * * Neither the name of Freescale Semiconductor nor the
3558 + * names of its contributors may be used to endorse or promote products
3559 + * derived from this software without specific prior written permission.
3560 + *
3561 + *
3562 + * ALTERNATIVELY, this software may be distributed under the terms of the
3563 + * GNU General Public License ("GPL") as published by the Free Software
3564 + * Foundation, either version 2 of that License or (at your option) any
3565 + * later version.
3566 + *
3567 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
3568 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3569 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3570 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
3571 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3572 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3573 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3574 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3575 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3576 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3577 + */
3578 +
3579 +#include "dpa_sys.h"
3580 +#include <linux/fsl_bman.h>
3581 +
3582 +/* Revision info (for errata and feature handling) */
3583 +#define BMAN_REV10 0x0100
3584 +#define BMAN_REV20 0x0200
3585 +#define BMAN_REV21 0x0201
3586 +#define QBMAN_ANY_PORTAL_IDX 0xffffffff
3587 +extern u16 bman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */
3588 +
3589 +/*
3590 + * Global variables of the max portal/pool number this bman version supported
3591 + */
3592 +extern u16 bman_pool_max;
3593 +
3594 +/* used by CCSR and portal interrupt code */
3595 +enum bm_isr_reg {
3596 + bm_isr_status = 0,
3597 + bm_isr_enable = 1,
3598 + bm_isr_disable = 2,
3599 + bm_isr_inhibit = 3
3600 +};
3601 +
3602 +struct bm_portal_config {
3603 + /* Corenet portal addresses;
3604 + * [0]==cache-enabled, [1]==cache-inhibited. */
3605 + __iomem void *addr_virt[2];
3606 + struct resource addr_phys[2];
3607 + /* Allow these to be joined in lists */
3608 + struct list_head list;
3609 + /* User-visible portal configuration settings */
3610 + struct bman_portal_config public_cfg;
3611 + /* power management saved data */
3612 + u32 saved_isdr;
3613 +};
3614 +
3615 +#ifdef CONFIG_FSL_BMAN_CONFIG
3616 +/* Hooks from bman_driver.c to bman_config.c */
3617 +int bman_init_ccsr(struct device_node *node);
3618 +#endif
3619 +
3620 +/* Hooks from bman_driver.c in to bman_high.c */
3621 +struct bman_portal *bman_create_portal(
3622 + struct bman_portal *portal,
3623 + const struct bm_portal_config *config);
3624 +struct bman_portal *bman_create_affine_portal(
3625 + const struct bm_portal_config *config);
3626 +struct bman_portal *bman_create_affine_slave(struct bman_portal *redirect,
3627 + int cpu);
3628 +void bman_destroy_portal(struct bman_portal *bm);
3629 +
3630 +const struct bm_portal_config *bman_destroy_affine_portal(void);
3631 +
3632 +/* Hooks from fsl_usdpaa.c to bman_driver.c */
3633 +struct bm_portal_config *bm_get_unused_portal(void);
3634 +struct bm_portal_config *bm_get_unused_portal_idx(uint32_t idx);
3635 +void bm_put_unused_portal(struct bm_portal_config *pcfg);
3636 +void bm_set_liodns(struct bm_portal_config *pcfg);
3637 +
3638 +/* Pool logic in the portal driver, during initialisation, needs to know if
3639 + * there's access to CCSR or not (if not, it'll cripple the pool allocator). */
3640 +#ifdef CONFIG_FSL_BMAN_CONFIG
3641 +int bman_have_ccsr(void);
3642 +#else
3643 +#define bman_have_ccsr() 0
3644 +#endif
3645 +
3646 +/* Stockpile build constants. The _LOW value: when bman_acquire() is called and
3647 + * the stockpile fill-level is <= _LOW, an acquire is attempted from h/w but it
3648 + * might fail (if the buffer pool is depleted). So this value provides some
3649 + * "stagger" in that the bman_acquire() function will only fail if lots of bufs
3650 + * are requested at once or if h/w has been tested a couple of times without
3651 + * luck. The _HIGH value: when bman_release() is called and the stockpile
3652 + * fill-level is >= _HIGH, a release is attempted to h/w but it might fail (if
3653 + * the release ring is full). So this value provides some "stagger" so that
3654 + * ring-access is retried a couple of times prior to the API returning a
3655 + * failure. The following *must* be true;
3656 + * BMAN_STOCKPILE_HIGH-BMAN_STOCKPILE_LOW > 8
3657 + * (to avoid thrashing)
3658 + * BMAN_STOCKPILE_SZ >= 16
3659 + * (as the release logic expects to either send 8 buffers to hw prior to
3660 + * adding the given buffers to the stockpile or add the buffers to the
3661 + * stockpile before sending 8 to hw, as the API must be an all-or-nothing
3662 + * success/fail.)
3663 + */
3664 +#define BMAN_STOCKPILE_SZ 16u /* number of bufs in per-pool cache */
3665 +#define BMAN_STOCKPILE_LOW 2u /* when fill is <= this, acquire from hw */
3666 +#define BMAN_STOCKPILE_HIGH 14u /* when fill is >= this, release to hw */
3667 +
3668 +/*************************************************/
3669 +/* BMan s/w corenet portal, low-level i/face */
3670 +/*************************************************/
3671 +
3672 +/* Used by all portal interrupt registers except 'inhibit'
3673 + * This mask contains all the "irqsource" bits visible to API users
3674 + */
3675 +#define BM_PIRQ_VISIBLE (BM_PIRQ_RCRI | BM_PIRQ_BSCN)
3676 +
3677 +/* These are bm_<reg>_<verb>(). So for example, bm_disable_write() means "write
3678 + * the disable register" rather than "disable the ability to write". */
3679 +#define bm_isr_status_read(bm) __bm_isr_read(bm, bm_isr_status)
3680 +#define bm_isr_status_clear(bm, m) __bm_isr_write(bm, bm_isr_status, m)
3681 +#define bm_isr_enable_read(bm) __bm_isr_read(bm, bm_isr_enable)
3682 +#define bm_isr_enable_write(bm, v) __bm_isr_write(bm, bm_isr_enable, v)
3683 +#define bm_isr_disable_read(bm) __bm_isr_read(bm, bm_isr_disable)
3684 +#define bm_isr_disable_write(bm, v) __bm_isr_write(bm, bm_isr_disable, v)
3685 +#define bm_isr_inhibit(bm) __bm_isr_write(bm, bm_isr_inhibit, 1)
3686 +#define bm_isr_uninhibit(bm) __bm_isr_write(bm, bm_isr_inhibit, 0)
3687 +
3688 +#ifdef CONFIG_FSL_BMAN_CONFIG
3689 +/* Set depletion thresholds associated with a buffer pool. Requires that the
3690 + * operating system have access to Bman CCSR (ie. compiled in support and
3691 + * run-time access courtesy of the device-tree). */
3692 +int bm_pool_set(u32 bpid, const u32 *thresholds);
3693 +#define BM_POOL_THRESH_SW_ENTER 0
3694 +#define BM_POOL_THRESH_SW_EXIT 1
3695 +#define BM_POOL_THRESH_HW_ENTER 2
3696 +#define BM_POOL_THRESH_HW_EXIT 3
3697 +
3698 +/* Read the free buffer count for a given buffer */
3699 +u32 bm_pool_free_buffers(u32 bpid);
3700 +
3701 +__init int bman_init(void);
3702 +__init int bman_resource_init(void);
3703 +
3704 +const struct bm_portal_config *bman_get_bm_portal_config(
3705 + struct bman_portal *portal);
3706 +
3707 +/* power management */
3708 +#ifdef CONFIG_SUSPEND
3709 +void suspend_unused_bportal(void);
3710 +void resume_unused_bportal(void);
3711 +#endif
3712 +
3713 +#endif /* CONFIG_FSL_BMAN_CONFIG */
3714 --- /dev/null
3715 +++ b/drivers/staging/fsl_qbman/bman_test.c
3716 @@ -0,0 +1,56 @@
3717 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
3718 + *
3719 + * Redistribution and use in source and binary forms, with or without
3720 + * modification, are permitted provided that the following conditions are met:
3721 + * * Redistributions of source code must retain the above copyright
3722 + * notice, this list of conditions and the following disclaimer.
3723 + * * Redistributions in binary form must reproduce the above copyright
3724 + * notice, this list of conditions and the following disclaimer in the
3725 + * documentation and/or other materials provided with the distribution.
3726 + * * Neither the name of Freescale Semiconductor nor the
3727 + * names of its contributors may be used to endorse or promote products
3728 + * derived from this software without specific prior written permission.
3729 + *
3730 + *
3731 + * ALTERNATIVELY, this software may be distributed under the terms of the
3732 + * GNU General Public License ("GPL") as published by the Free Software
3733 + * Foundation, either version 2 of that License or (at your option) any
3734 + * later version.
3735 + *
3736 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
3737 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3738 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3739 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
3740 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3741 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3742 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3743 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3744 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3745 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3746 + */
3747 +
3748 +#include "bman_test.h"
3749 +
3750 +MODULE_AUTHOR("Geoff Thorpe");
3751 +MODULE_LICENSE("Dual BSD/GPL");
3752 +MODULE_DESCRIPTION("Bman testing");
3753 +
3754 +static int test_init(void)
3755 +{
3756 +#ifdef CONFIG_FSL_BMAN_TEST_HIGH
3757 + int loop = 1;
3758 + while (loop--)
3759 + bman_test_high();
3760 +#endif
3761 +#ifdef CONFIG_FSL_BMAN_TEST_THRESH
3762 + bman_test_thresh();
3763 +#endif
3764 + return 0;
3765 +}
3766 +
3767 +static void test_exit(void)
3768 +{
3769 +}
3770 +
3771 +module_init(test_init);
3772 +module_exit(test_exit);
3773 --- /dev/null
3774 +++ b/drivers/staging/fsl_qbman/bman_test.h
3775 @@ -0,0 +1,44 @@
3776 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
3777 + *
3778 + * Redistribution and use in source and binary forms, with or without
3779 + * modification, are permitted provided that the following conditions are met:
3780 + * * Redistributions of source code must retain the above copyright
3781 + * notice, this list of conditions and the following disclaimer.
3782 + * * Redistributions in binary form must reproduce the above copyright
3783 + * notice, this list of conditions and the following disclaimer in the
3784 + * documentation and/or other materials provided with the distribution.
3785 + * * Neither the name of Freescale Semiconductor nor the
3786 + * names of its contributors may be used to endorse or promote products
3787 + * derived from this software without specific prior written permission.
3788 + *
3789 + *
3790 + * ALTERNATIVELY, this software may be distributed under the terms of the
3791 + * GNU General Public License ("GPL") as published by the Free Software
3792 + * Foundation, either version 2 of that License or (at your option) any
3793 + * later version.
3794 + *
3795 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
3796 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3797 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3798 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
3799 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3800 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3801 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3802 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3803 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3804 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3805 + */
3806 +
3807 +#include <linux/kernel.h>
3808 +#include <linux/errno.h>
3809 +#include <linux/io.h>
3810 +#include <linux/slab.h>
3811 +#include <linux/module.h>
3812 +#include <linux/interrupt.h>
3813 +#include <linux/delay.h>
3814 +#include <linux/kthread.h>
3815 +
3816 +#include <linux/fsl_bman.h>
3817 +
3818 +void bman_test_high(void);
3819 +void bman_test_thresh(void);
3820 --- /dev/null
3821 +++ b/drivers/staging/fsl_qbman/bman_test_high.c
3822 @@ -0,0 +1,183 @@
3823 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
3824 + *
3825 + * Redistribution and use in source and binary forms, with or without
3826 + * modification, are permitted provided that the following conditions are met:
3827 + * * Redistributions of source code must retain the above copyright
3828 + * notice, this list of conditions and the following disclaimer.
3829 + * * Redistributions in binary form must reproduce the above copyright
3830 + * notice, this list of conditions and the following disclaimer in the
3831 + * documentation and/or other materials provided with the distribution.
3832 + * * Neither the name of Freescale Semiconductor nor the
3833 + * names of its contributors may be used to endorse or promote products
3834 + * derived from this software without specific prior written permission.
3835 + *
3836 + *
3837 + * ALTERNATIVELY, this software may be distributed under the terms of the
3838 + * GNU General Public License ("GPL") as published by the Free Software
3839 + * Foundation, either version 2 of that License or (at your option) any
3840 + * later version.
3841 + *
3842 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
3843 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
3844 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
3845 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
3846 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
3847 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
3848 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
3849 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3850 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3851 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3852 + */
3853 +
3854 +#include "bman_test.h"
3855 +#include "bman_private.h"
3856 +
3857 +/*************/
3858 +/* constants */
3859 +/*************/
3860 +
3861 +#define PORTAL_OPAQUE ((void *)0xf00dbeef)
3862 +#define POOL_OPAQUE ((void *)0xdeadabba)
3863 +#define NUM_BUFS 93
3864 +#define LOOPS 3
3865 +#define BMAN_TOKEN_MASK 0x00FFFFFFFFFFLLU
3866 +
3867 +/***************/
3868 +/* global vars */
3869 +/***************/
3870 +
3871 +static struct bman_pool *pool;
3872 +static int depleted;
3873 +static struct bm_buffer bufs_in[NUM_BUFS] ____cacheline_aligned;
3874 +static struct bm_buffer bufs_out[NUM_BUFS] ____cacheline_aligned;
3875 +static int bufs_received;
3876 +
3877 +/* Predeclare the callback so we can instantiate pool parameters */
3878 +static void depletion_cb(struct bman_portal *, struct bman_pool *, void *, int);
3879 +
3880 +/**********************/
3881 +/* internal functions */
3882 +/**********************/
3883 +
3884 +static void bufs_init(void)
3885 +{
3886 + int i;
3887 + for (i = 0; i < NUM_BUFS; i++)
3888 + bm_buffer_set64(&bufs_in[i], 0xfedc01234567LLU * i);
3889 + bufs_received = 0;
3890 +}
3891 +
3892 +static inline int bufs_cmp(const struct bm_buffer *a, const struct bm_buffer *b)
3893 +{
3894 + if ((bman_ip_rev == BMAN_REV20) || (bman_ip_rev == BMAN_REV21)) {
3895 +
3896 + /* On SoCs with Bman revison 2.0, Bman only respects the 40
3897 + * LS-bits of buffer addresses, masking off the upper 8-bits on
3898 + * release commands. The API provides for 48-bit addresses
3899 + * because some SoCs support all 48-bits. When generating
3900 + * garbage addresses for testing, we either need to zero the
3901 + * upper 8-bits when releasing to Bman (otherwise we'll be
3902 + * disappointed when the buffers we acquire back from Bman
3903 + * don't match), or we need to mask the upper 8-bits off when
3904 + * comparing. We do the latter.
3905 + */
3906 + if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK)
3907 + < (bm_buffer_get64(b) & BMAN_TOKEN_MASK))
3908 + return -1;
3909 + if ((bm_buffer_get64(a) & BMAN_TOKEN_MASK)
3910 + > (bm_buffer_get64(b) & BMAN_TOKEN_MASK))
3911 + return 1;
3912 + } else {
3913 + if (bm_buffer_get64(a) < bm_buffer_get64(b))
3914 + return -1;
3915 + if (bm_buffer_get64(a) > bm_buffer_get64(b))
3916 + return 1;
3917 + }
3918 +
3919 + return 0;
3920 +}
3921 +
3922 +static void bufs_confirm(void)
3923 +{
3924 + int i, j;
3925 + for (i = 0; i < NUM_BUFS; i++) {
3926 + int matches = 0;
3927 + for (j = 0; j < NUM_BUFS; j++)
3928 + if (!bufs_cmp(&bufs_in[i], &bufs_out[j]))
3929 + matches++;
3930 + BUG_ON(matches != 1);
3931 + }
3932 +}
3933 +
3934 +/********/
3935 +/* test */
3936 +/********/
3937 +
3938 +static void depletion_cb(struct bman_portal *__portal, struct bman_pool *__pool,
3939 + void *pool_ctx, int __depleted)
3940 +{
3941 + BUG_ON(__pool != pool);
3942 + BUG_ON(pool_ctx != POOL_OPAQUE);
3943 + depleted = __depleted;
3944 +}
3945 +
3946 +void bman_test_high(void)
3947 +{
3948 + struct bman_pool_params pparams = {
3949 + .flags = BMAN_POOL_FLAG_DEPLETION | BMAN_POOL_FLAG_DYNAMIC_BPID,
3950 + .cb = depletion_cb,
3951 + .cb_ctx = POOL_OPAQUE,
3952 + };
3953 + int i, loops = LOOPS;
3954 + struct bm_buffer tmp_buf;
3955 +
3956 + bufs_init();
3957 +
3958 + pr_info("BMAN: --- starting high-level test ---\n");
3959 +
3960 + pool = bman_new_pool(&pparams);
3961 + BUG_ON(!pool);
3962 +
3963 + /*******************/
3964 + /* Release buffers */
3965 + /*******************/
3966 +do_loop:
3967 + i = 0;
3968 + while (i < NUM_BUFS) {
3969 + u32 flags = BMAN_RELEASE_FLAG_WAIT;
3970 + int num = 8;
3971 + if ((i + num) > NUM_BUFS)
3972 + num = NUM_BUFS - i;
3973 + if ((i + num) == NUM_BUFS)
3974 + flags |= BMAN_RELEASE_FLAG_WAIT_SYNC;
3975 + if (bman_release(pool, bufs_in + i, num, flags))
3976 + panic("bman_release() failed\n");
3977 + i += num;
3978 + }
3979 +
3980 + /*******************/
3981 + /* Acquire buffers */
3982 + /*******************/
3983 + while (i > 0) {
3984 + int tmp, num = 8;
3985 + if (num > i)
3986 + num = i;
3987 + tmp = bman_acquire(pool, bufs_out + i - num, num, 0);
3988 + BUG_ON(tmp != num);
3989 + i -= num;
3990 + }
3991 +
3992 + i = bman_acquire(pool, &tmp_buf, 1, 0);
3993 + BUG_ON(i > 0);
3994 +
3995 + bufs_confirm();
3996 +
3997 + if (--loops)
3998 + goto do_loop;
3999 +
4000 + /************/
4001 + /* Clean up */
4002 + /************/
4003 + bman_free_pool(pool);
4004 + pr_info("BMAN: --- finished high-level test ---\n");
4005 +}
4006 --- /dev/null
4007 +++ b/drivers/staging/fsl_qbman/bman_test_thresh.c
4008 @@ -0,0 +1,196 @@
4009 +/* Copyright 2010-2011 Freescale Semiconductor, Inc.
4010 + *
4011 + * Redistribution and use in source and binary forms, with or without
4012 + * modification, are permitted provided that the following conditions are met:
4013 + * * Redistributions of source code must retain the above copyright
4014 + * notice, this list of conditions and the following disclaimer.
4015 + * * Redistributions in binary form must reproduce the above copyright
4016 + * notice, this list of conditions and the following disclaimer in the
4017 + * documentation and/or other materials provided with the distribution.
4018 + * * Neither the name of Freescale Semiconductor nor the
4019 + * names of its contributors may be used to endorse or promote products
4020 + * derived from this software without specific prior written permission.
4021 + *
4022 + *
4023 + * ALTERNATIVELY, this software may be distributed under the terms of the
4024 + * GNU General Public License ("GPL") as published by the Free Software
4025 + * Foundation, either version 2 of that License or (at your option) any
4026 + * later version.
4027 + *
4028 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
4029 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4030 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4031 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
4032 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4033 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4034 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4035 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4036 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
4037 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4038 + */
4039 +
4040 +#include "bman_test.h"
4041 +
4042 +/* Test constants */
4043 +#define TEST_NUMBUFS 129728
4044 +#define TEST_EXIT 129536
4045 +#define TEST_ENTRY 129024
4046 +
4047 +struct affine_test_data {
4048 + struct task_struct *t;
4049 + int cpu;
4050 + int expect_affinity;
4051 + int drain;
4052 + int num_enter;
4053 + int num_exit;
4054 + struct list_head node;
4055 + struct completion wakethread;
4056 + struct completion wakeparent;
4057 +};
4058 +
4059 +static void cb_depletion(struct bman_portal *portal,
4060 + struct bman_pool *pool,
4061 + void *opaque,
4062 + int depleted)
4063 +{
4064 + struct affine_test_data *data = opaque;
4065 + int c = smp_processor_id();
4066 + pr_info("cb_depletion: bpid=%d, depleted=%d, cpu=%d, original=%d\n",
4067 + bman_get_params(pool)->bpid, !!depleted, c, data->cpu);
4068 + /* We should be executing on the CPU of the thread that owns the pool if
4069 + * and that CPU has an affine portal (ie. it isn't slaved). */
4070 + BUG_ON((c != data->cpu) && data->expect_affinity);
4071 + BUG_ON((c == data->cpu) && !data->expect_affinity);
4072 + if (depleted)
4073 + data->num_enter++;
4074 + else
4075 + data->num_exit++;
4076 +}
4077 +
4078 +/* Params used to set up a pool, this also dynamically allocates a BPID */
4079 +static const struct bman_pool_params params_nocb = {
4080 + .flags = BMAN_POOL_FLAG_DYNAMIC_BPID | BMAN_POOL_FLAG_THRESH,
4081 + .thresholds = { TEST_ENTRY, TEST_EXIT, 0, 0 }
4082 +};
4083 +
4084 +/* Params used to set up each cpu's pool with callbacks enabled */
4085 +static struct bman_pool_params params_cb = {
4086 + .bpid = 0, /* will be replaced to match pool_nocb */
4087 + .flags = BMAN_POOL_FLAG_DEPLETION,
4088 + .cb = cb_depletion
4089 +};
4090 +
4091 +static struct bman_pool *pool_nocb;
4092 +static LIST_HEAD(threads);
4093 +
4094 +static int affine_test(void *__data)
4095 +{
4096 + struct bman_pool *pool;
4097 + struct affine_test_data *data = __data;
4098 + struct bman_pool_params my_params = params_cb;
4099 +
4100 + pr_info("thread %d: starting\n", data->cpu);
4101 + /* create the pool */
4102 + my_params.cb_ctx = data;
4103 + pool = bman_new_pool(&my_params);
4104 + BUG_ON(!pool);
4105 + complete(&data->wakeparent);
4106 + wait_for_completion(&data->wakethread);
4107 + init_completion(&data->wakethread);
4108 +
4109 + /* if we're the drainer, we get signalled for that */
4110 + if (data->drain) {
4111 + struct bm_buffer buf;
4112 + int ret;
4113 + pr_info("thread %d: draining...\n", data->cpu);
4114 + do {
4115 + ret = bman_acquire(pool, &buf, 1, 0);
4116 + } while (ret > 0);
4117 + pr_info("thread %d: draining done.\n", data->cpu);
4118 + complete(&data->wakeparent);
4119 + wait_for_completion(&data->wakethread);
4120 + init_completion(&data->wakethread);
4121 + }
4122 +
4123 + /* cleanup */
4124 + bman_free_pool(pool);
4125 + while (!kthread_should_stop())
4126 + cpu_relax();
4127 + pr_info("thread %d: exiting\n", data->cpu);
4128 + return 0;
4129 +}
4130 +
4131 +static struct affine_test_data *start_affine_test(int cpu, int drain)
4132 +{
4133 + struct affine_test_data *data = kmalloc(sizeof(*data), GFP_KERNEL);
4134 +
4135 + if (!data)
4136 + return NULL;
4137 + data->cpu = cpu;
4138 + data->expect_affinity = cpumask_test_cpu(cpu, bman_affine_cpus());
4139 + data->drain = drain;
4140 + data->num_enter = 0;
4141 + data->num_exit = 0;
4142 + init_completion(&data->wakethread);
4143 + init_completion(&data->wakeparent);
4144 + list_add_tail(&data->node, &threads);
4145 + data->t = kthread_create(affine_test, data, "threshtest%d", cpu);
4146 + BUG_ON(IS_ERR(data->t));
4147 + kthread_bind(data->t, cpu);
4148 + wake_up_process(data->t);
4149 + return data;
4150 +}
4151 +
4152 +void bman_test_thresh(void)
4153 +{
4154 + int loop = TEST_NUMBUFS;
4155 + int ret, num_cpus = 0;
4156 + struct affine_test_data *data, *drainer = NULL;
4157 +
4158 + pr_info("bman_test_thresh: start\n");
4159 +
4160 + /* allocate a BPID and seed it */
4161 + pool_nocb = bman_new_pool(&params_nocb);
4162 + BUG_ON(!pool_nocb);
4163 + while (loop--) {
4164 + struct bm_buffer buf;
4165 + bm_buffer_set64(&buf, 0x0badbeef + loop);
4166 + ret = bman_release(pool_nocb, &buf, 1,
4167 + BMAN_RELEASE_FLAG_WAIT);
4168 + BUG_ON(ret);
4169 + }
4170 + while (!bman_rcr_is_empty())
4171 + cpu_relax();
4172 + pr_info("bman_test_thresh: buffers are in\n");
4173 +
4174 + /* create threads and wait for them to create pools */
4175 + params_cb.bpid = bman_get_params(pool_nocb)->bpid;
4176 + for_each_cpu(loop, cpu_online_mask) {
4177 + data = start_affine_test(loop, drainer ? 0 : 1);
4178 + BUG_ON(!data);
4179 + if (!drainer)
4180 + drainer = data;
4181 + num_cpus++;
4182 + wait_for_completion(&data->wakeparent);
4183 + }
4184 +
4185 + /* signal the drainer to start draining */
4186 + complete(&drainer->wakethread);
4187 + wait_for_completion(&drainer->wakeparent);
4188 + init_completion(&drainer->wakeparent);
4189 +
4190 + /* tear down */
4191 + list_for_each_entry_safe(data, drainer, &threads, node) {
4192 + complete(&data->wakethread);
4193 + ret = kthread_stop(data->t);
4194 + BUG_ON(ret);
4195 + list_del(&data->node);
4196 + /* check that we get the expected callbacks (and no others) */
4197 + BUG_ON(data->num_enter != 1);
4198 + BUG_ON(data->num_exit != 0);
4199 + kfree(data);
4200 + }
4201 + bman_free_pool(pool_nocb);
4202 +
4203 + pr_info("bman_test_thresh: done\n");
4204 +}
4205 --- /dev/null
4206 +++ b/drivers/staging/fsl_qbman/dpa_alloc.c
4207 @@ -0,0 +1,706 @@
4208 +/* Copyright 2009-2012 Freescale Semiconductor, Inc.
4209 + *
4210 + * Redistribution and use in source and binary forms, with or without
4211 + * modification, are permitted provided that the following conditions are met:
4212 + * * Redistributions of source code must retain the above copyright
4213 + * notice, this list of conditions and the following disclaimer.
4214 + * * Redistributions in binary form must reproduce the above copyright
4215 + * notice, this list of conditions and the following disclaimer in the
4216 + * documentation and/or other materials provided with the distribution.
4217 + * * Neither the name of Freescale Semiconductor nor the
4218 + * names of its contributors may be used to endorse or promote products
4219 + * derived from this software without specific prior written permission.
4220 + *
4221 + *
4222 + * ALTERNATIVELY, this software may be distributed under the terms of the
4223 + * GNU General Public License ("GPL") as published by the Free Software
4224 + * Foundation, either version 2 of that License or (at your option) any
4225 + * later version.
4226 + *
4227 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
4228 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4229 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4230 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
4231 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4232 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4233 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4234 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4235 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
4236 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4237 + */
4238 +
4239 +#include "dpa_sys.h"
4240 +#include <linux/fsl_qman.h>
4241 +#include <linux/fsl_bman.h>
4242 +
4243 +/* Qman and Bman APIs are front-ends to the common code; */
4244 +
4245 +static DECLARE_DPA_ALLOC(bpalloc); /* BPID allocator */
4246 +static DECLARE_DPA_ALLOC(fqalloc); /* FQID allocator */
4247 +static DECLARE_DPA_ALLOC(qpalloc); /* pool-channel allocator */
4248 +static DECLARE_DPA_ALLOC(cgralloc); /* CGR ID allocator */
4249 +static DECLARE_DPA_ALLOC(ceetm0_challoc); /* CEETM Channel ID allocator */
4250 +static DECLARE_DPA_ALLOC(ceetm0_lfqidalloc); /* CEETM LFQID allocator */
4251 +static DECLARE_DPA_ALLOC(ceetm1_challoc); /* CEETM Channel ID allocator */
4252 +static DECLARE_DPA_ALLOC(ceetm1_lfqidalloc); /* CEETM LFQID allocator */
4253 +
4254 +/* This is a sort-of-conditional dpa_alloc_free() routine. Eg. when releasing
4255 + * FQIDs (probably from user-space), it can filter out those that aren't in the
4256 + * OOS state (better to leak a h/w resource than to crash). This function
4257 + * returns the number of invalid IDs that were not released. */
4258 +static u32 release_id_range(struct dpa_alloc *alloc, u32 id, u32 count,
4259 + int (*is_valid)(u32 id))
4260 +{
4261 + int valid_mode = 0;
4262 + u32 loop = id, total_invalid = 0;
4263 + while (loop < (id + count)) {
4264 + int isvalid = is_valid ? is_valid(loop) : 1;
4265 + if (!valid_mode) {
4266 + /* We're looking for a valid ID to terminate an invalid
4267 + * range */
4268 + if (isvalid) {
4269 + /* We finished a range of invalid IDs, a valid
4270 + * range is now underway */
4271 + valid_mode = 1;
4272 + count -= (loop - id);
4273 + id = loop;
4274 + } else
4275 + total_invalid++;
4276 + } else {
4277 + /* We're looking for an invalid ID to terminate a
4278 + * valid range */
4279 + if (!isvalid) {
4280 + /* Release the range of valid IDs, an unvalid
4281 + * range is now underway */
4282 + if (loop > id)
4283 + dpa_alloc_free(alloc, id, loop - id);
4284 + valid_mode = 0;
4285 + }
4286 + }
4287 + loop++;
4288 + }
4289 + /* Release any unterminated range of valid IDs */
4290 + if (valid_mode && count)
4291 + dpa_alloc_free(alloc, id, count);
4292 + return total_invalid;
4293 +}
4294 +
4295 +/* BPID allocator front-end */
4296 +
4297 +int bman_alloc_bpid_range(u32 *result, u32 count, u32 align, int partial)
4298 +{
4299 + return dpa_alloc_new(&bpalloc, result, count, align, partial);
4300 +}
4301 +EXPORT_SYMBOL(bman_alloc_bpid_range);
4302 +
4303 +static int bp_cleanup(u32 bpid)
4304 +{
4305 + return bman_shutdown_pool(bpid) == 0;
4306 +}
4307 +void bman_release_bpid_range(u32 bpid, u32 count)
4308 +{
4309 + u32 total_invalid = release_id_range(&bpalloc, bpid, count, bp_cleanup);
4310 + if (total_invalid)
4311 + pr_err("BPID range [%d..%d] (%d) had %d leaks\n",
4312 + bpid, bpid + count - 1, count, total_invalid);
4313 +}
4314 +EXPORT_SYMBOL(bman_release_bpid_range);
4315 +
4316 +void bman_seed_bpid_range(u32 bpid, u32 count)
4317 +{
4318 + dpa_alloc_seed(&bpalloc, bpid, count);
4319 +}
4320 +EXPORT_SYMBOL(bman_seed_bpid_range);
4321 +
4322 +int bman_reserve_bpid_range(u32 bpid, u32 count)
4323 +{
4324 + return dpa_alloc_reserve(&bpalloc, bpid, count);
4325 +}
4326 +EXPORT_SYMBOL(bman_reserve_bpid_range);
4327 +
4328 +
4329 +/* FQID allocator front-end */
4330 +
4331 +int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial)
4332 +{
4333 + return dpa_alloc_new(&fqalloc, result, count, align, partial);
4334 +}
4335 +EXPORT_SYMBOL(qman_alloc_fqid_range);
4336 +
4337 +static int fq_cleanup(u32 fqid)
4338 +{
4339 + return qman_shutdown_fq(fqid) == 0;
4340 +}
4341 +void qman_release_fqid_range(u32 fqid, u32 count)
4342 +{
4343 + u32 total_invalid = release_id_range(&fqalloc, fqid, count, fq_cleanup);
4344 + if (total_invalid)
4345 + pr_err("FQID range [%d..%d] (%d) had %d leaks\n",
4346 + fqid, fqid + count - 1, count, total_invalid);
4347 +}
4348 +EXPORT_SYMBOL(qman_release_fqid_range);
4349 +
4350 +int qman_reserve_fqid_range(u32 fqid, u32 count)
4351 +{
4352 + return dpa_alloc_reserve(&fqalloc, fqid, count);
4353 +}
4354 +EXPORT_SYMBOL(qman_reserve_fqid_range);
4355 +
4356 +void qman_seed_fqid_range(u32 fqid, u32 count)
4357 +{
4358 + dpa_alloc_seed(&fqalloc, fqid, count);
4359 +}
4360 +EXPORT_SYMBOL(qman_seed_fqid_range);
4361 +
4362 +/* Pool-channel allocator front-end */
4363 +
4364 +int qman_alloc_pool_range(u32 *result, u32 count, u32 align, int partial)
4365 +{
4366 + return dpa_alloc_new(&qpalloc, result, count, align, partial);
4367 +}
4368 +EXPORT_SYMBOL(qman_alloc_pool_range);
4369 +
4370 +static int qpool_cleanup(u32 qp)
4371 +{
4372 + /* We query all FQDs starting from
4373 + * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs
4374 + * whose destination channel is the pool-channel being released.
4375 + * When a non-OOS FQD is found we attempt to clean it up */
4376 + struct qman_fq fq = {
4377 + .fqid = 1
4378 + };
4379 + int err;
4380 + do {
4381 + struct qm_mcr_queryfq_np np;
4382 + err = qman_query_fq_np(&fq, &np);
4383 + if (err)
4384 + /* FQID range exceeded, found no problems */
4385 + return 1;
4386 + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) {
4387 + struct qm_fqd fqd;
4388 + err = qman_query_fq(&fq, &fqd);
4389 + BUG_ON(err);
4390 + if (fqd.dest.channel == qp) {
4391 + /* The channel is the FQ's target, clean it */
4392 + if (qman_shutdown_fq(fq.fqid) != 0)
4393 + /* Couldn't shut down the FQ
4394 + so the pool must be leaked */
4395 + return 0;
4396 + }
4397 + }
4398 + /* Move to the next FQID */
4399 + fq.fqid++;
4400 + } while (1);
4401 +}
4402 +void qman_release_pool_range(u32 qp, u32 count)
4403 +{
4404 + u32 total_invalid = release_id_range(&qpalloc, qp,
4405 + count, qpool_cleanup);
4406 + if (total_invalid) {
4407 + /* Pool channels are almost always used individually */
4408 + if (count == 1)
4409 + pr_err("Pool channel 0x%x had %d leaks\n",
4410 + qp, total_invalid);
4411 + else
4412 + pr_err("Pool channels [%d..%d] (%d) had %d leaks\n",
4413 + qp, qp + count - 1, count, total_invalid);
4414 + }
4415 +}
4416 +EXPORT_SYMBOL(qman_release_pool_range);
4417 +
4418 +
4419 +void qman_seed_pool_range(u32 poolid, u32 count)
4420 +{
4421 + dpa_alloc_seed(&qpalloc, poolid, count);
4422 +
4423 +}
4424 +EXPORT_SYMBOL(qman_seed_pool_range);
4425 +
4426 +int qman_reserve_pool_range(u32 poolid, u32 count)
4427 +{
4428 + return dpa_alloc_reserve(&qpalloc, poolid, count);
4429 +}
4430 +EXPORT_SYMBOL(qman_reserve_pool_range);
4431 +
4432 +
4433 +/* CGR ID allocator front-end */
4434 +
4435 +int qman_alloc_cgrid_range(u32 *result, u32 count, u32 align, int partial)
4436 +{
4437 + return dpa_alloc_new(&cgralloc, result, count, align, partial);
4438 +}
4439 +EXPORT_SYMBOL(qman_alloc_cgrid_range);
4440 +
4441 +static int cqr_cleanup(u32 cgrid)
4442 +{
4443 + /* We query all FQDs starting from
4444 + * FQID 1 until we get an "invalid FQID" error, looking for non-OOS FQDs
4445 + * whose CGR is the CGR being released.
4446 + */
4447 + struct qman_fq fq = {
4448 + .fqid = 1
4449 + };
4450 + int err;
4451 + do {
4452 + struct qm_mcr_queryfq_np np;
4453 + err = qman_query_fq_np(&fq, &np);
4454 + if (err)
4455 + /* FQID range exceeded, found no problems */
4456 + return 1;
4457 + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) {
4458 + struct qm_fqd fqd;
4459 + err = qman_query_fq(&fq, &fqd);
4460 + BUG_ON(err);
4461 + if ((fqd.fq_ctrl & QM_FQCTRL_CGE) &&
4462 + (fqd.cgid == cgrid)) {
4463 + pr_err("CRGID 0x%x is being used by FQID 0x%x,"
4464 + " CGR will be leaked\n",
4465 + cgrid, fq.fqid);
4466 + return 1;
4467 + }
4468 + }
4469 + /* Move to the next FQID */
4470 + fq.fqid++;
4471 + } while (1);
4472 +}
4473 +
4474 +void qman_release_cgrid_range(u32 cgrid, u32 count)
4475 +{
4476 + u32 total_invalid = release_id_range(&cgralloc, cgrid,
4477 + count, cqr_cleanup);
4478 + if (total_invalid)
4479 + pr_err("CGRID range [%d..%d] (%d) had %d leaks\n",
4480 + cgrid, cgrid + count - 1, count, total_invalid);
4481 +}
4482 +EXPORT_SYMBOL(qman_release_cgrid_range);
4483 +
4484 +void qman_seed_cgrid_range(u32 cgrid, u32 count)
4485 +{
4486 + dpa_alloc_seed(&cgralloc, cgrid, count);
4487 +
4488 +}
4489 +EXPORT_SYMBOL(qman_seed_cgrid_range);
4490 +
4491 +/* CEETM CHANNEL ID allocator front-end */
4492 +int qman_alloc_ceetm0_channel_range(u32 *result, u32 count, u32 align,
4493 + int partial)
4494 +{
4495 + return dpa_alloc_new(&ceetm0_challoc, result, count, align, partial);
4496 +}
4497 +EXPORT_SYMBOL(qman_alloc_ceetm0_channel_range);
4498 +
4499 +int qman_alloc_ceetm1_channel_range(u32 *result, u32 count, u32 align,
4500 + int partial)
4501 +{
4502 + return dpa_alloc_new(&ceetm1_challoc, result, count, align, partial);
4503 +}
4504 +EXPORT_SYMBOL(qman_alloc_ceetm1_channel_range);
4505 +
4506 +void qman_release_ceetm0_channel_range(u32 channelid, u32 count)
4507 +{
4508 + u32 total_invalid;
4509 +
4510 + total_invalid = release_id_range(&ceetm0_challoc, channelid, count,
4511 + NULL);
4512 + if (total_invalid)
4513 + pr_err("CEETM channel range [%d..%d] (%d) had %d leaks\n",
4514 + channelid, channelid + count - 1, count, total_invalid);
4515 +}
4516 +EXPORT_SYMBOL(qman_release_ceetm0_channel_range);
4517 +
4518 +void qman_seed_ceetm0_channel_range(u32 channelid, u32 count)
4519 +{
4520 + dpa_alloc_seed(&ceetm0_challoc, channelid, count);
4521 +
4522 +}
4523 +EXPORT_SYMBOL(qman_seed_ceetm0_channel_range);
4524 +
4525 +void qman_release_ceetm1_channel_range(u32 channelid, u32 count)
4526 +{
4527 + u32 total_invalid;
4528 + total_invalid = release_id_range(&ceetm1_challoc, channelid, count,
4529 + NULL);
4530 + if (total_invalid)
4531 + pr_err("CEETM channel range [%d..%d] (%d) had %d leaks\n",
4532 + channelid, channelid + count - 1, count, total_invalid);
4533 +}
4534 +EXPORT_SYMBOL(qman_release_ceetm1_channel_range);
4535 +
4536 +void qman_seed_ceetm1_channel_range(u32 channelid, u32 count)
4537 +{
4538 + dpa_alloc_seed(&ceetm1_challoc, channelid, count);
4539 +
4540 +}
4541 +EXPORT_SYMBOL(qman_seed_ceetm1_channel_range);
4542 +
4543 +/* CEETM LFQID allocator front-end */
4544 +int qman_alloc_ceetm0_lfqid_range(u32 *result, u32 count, u32 align,
4545 + int partial)
4546 +{
4547 + return dpa_alloc_new(&ceetm0_lfqidalloc, result, count, align, partial);
4548 +}
4549 +EXPORT_SYMBOL(qman_alloc_ceetm0_lfqid_range);
4550 +
4551 +int qman_alloc_ceetm1_lfqid_range(u32 *result, u32 count, u32 align,
4552 + int partial)
4553 +{
4554 + return dpa_alloc_new(&ceetm1_lfqidalloc, result, count, align, partial);
4555 +}
4556 +EXPORT_SYMBOL(qman_alloc_ceetm1_lfqid_range);
4557 +
4558 +void qman_release_ceetm0_lfqid_range(u32 lfqid, u32 count)
4559 +{
4560 + u32 total_invalid;
4561 +
4562 + total_invalid = release_id_range(&ceetm0_lfqidalloc, lfqid, count,
4563 + NULL);
4564 + if (total_invalid)
4565 + pr_err("CEETM LFQID range [0x%x..0x%x] (%d) had %d leaks\n",
4566 + lfqid, lfqid + count - 1, count, total_invalid);
4567 +}
4568 +EXPORT_SYMBOL(qman_release_ceetm0_lfqid_range);
4569 +
4570 +void qman_seed_ceetm0_lfqid_range(u32 lfqid, u32 count)
4571 +{
4572 + dpa_alloc_seed(&ceetm0_lfqidalloc, lfqid, count);
4573 +
4574 +}
4575 +EXPORT_SYMBOL(qman_seed_ceetm0_lfqid_range);
4576 +
4577 +void qman_release_ceetm1_lfqid_range(u32 lfqid, u32 count)
4578 +{
4579 + u32 total_invalid;
4580 +
4581 + total_invalid = release_id_range(&ceetm1_lfqidalloc, lfqid, count,
4582 + NULL);
4583 + if (total_invalid)
4584 + pr_err("CEETM LFQID range [0x%x..0x%x] (%d) had %d leaks\n",
4585 + lfqid, lfqid + count - 1, count, total_invalid);
4586 +}
4587 +EXPORT_SYMBOL(qman_release_ceetm1_lfqid_range);
4588 +
4589 +void qman_seed_ceetm1_lfqid_range(u32 lfqid, u32 count)
4590 +{
4591 + dpa_alloc_seed(&ceetm1_lfqidalloc, lfqid, count);
4592 +
4593 +}
4594 +EXPORT_SYMBOL(qman_seed_ceetm1_lfqid_range);
4595 +
4596 +
4597 +/* Everything else is the common backend to all the allocators */
4598 +
4599 +/* The allocator is a (possibly-empty) list of these; */
4600 +struct alloc_node {
4601 + struct list_head list;
4602 + u32 base;
4603 + u32 num;
4604 + /* refcount and is_alloced are only set
4605 + when the node is in the used list */
4606 + unsigned int refcount;
4607 + int is_alloced;
4608 +};
4609 +
4610 +/* #define DPA_ALLOC_DEBUG */
4611 +
4612 +#ifdef DPA_ALLOC_DEBUG
4613 +#define DPRINT pr_info
4614 +static void DUMP(struct dpa_alloc *alloc)
4615 +{
4616 + int off = 0;
4617 + char buf[256];
4618 + struct alloc_node *p;
4619 + pr_info("Free Nodes\n");
4620 + list_for_each_entry(p, &alloc->free, list) {
4621 + if (off < 255)
4622 + off += snprintf(buf + off, 255-off, "{%d,%d}",
4623 + p->base, p->base + p->num - 1);
4624 + }
4625 + pr_info("%s\n", buf);
4626 +
4627 + off = 0;
4628 + pr_info("Used Nodes\n");
4629 + list_for_each_entry(p, &alloc->used, list) {
4630 + if (off < 255)
4631 + off += snprintf(buf + off, 255-off, "{%d,%d}",
4632 + p->base, p->base + p->num - 1);
4633 + }
4634 + pr_info("%s\n", buf);
4635 +
4636 +
4637 +
4638 +}
4639 +#else
4640 +#define DPRINT(x...)
4641 +#define DUMP(a)
4642 +#endif
4643 +
4644 +int dpa_alloc_new(struct dpa_alloc *alloc, u32 *result, u32 count, u32 align,
4645 + int partial)
4646 +{
4647 + struct alloc_node *i = NULL, *next_best = NULL, *used_node = NULL;
4648 + u32 base, next_best_base = 0, num = 0, next_best_num = 0;
4649 + struct alloc_node *margin_left, *margin_right;
4650 +
4651 + *result = (u32)-1;
4652 + DPRINT("alloc_range(%d,%d,%d)\n", count, align, partial);
4653 + DUMP(alloc);
4654 + /* If 'align' is 0, it should behave as though it was 1 */
4655 + if (!align)
4656 + align = 1;
4657 + margin_left = kmalloc(sizeof(*margin_left), GFP_KERNEL);
4658 + if (!margin_left)
4659 + goto err;
4660 + margin_right = kmalloc(sizeof(*margin_right), GFP_KERNEL);
4661 + if (!margin_right) {
4662 + kfree(margin_left);
4663 + goto err;
4664 + }
4665 + spin_lock_irq(&alloc->lock);
4666 + list_for_each_entry(i, &alloc->free, list) {
4667 + base = (i->base + align - 1) / align;
4668 + base *= align;
4669 + if ((base - i->base) >= i->num)
4670 + /* alignment is impossible, regardless of count */
4671 + continue;
4672 + num = i->num - (base - i->base);
4673 + if (num >= count) {
4674 + /* this one will do nicely */
4675 + num = count;
4676 + goto done;
4677 + }
4678 + if (num > next_best_num) {
4679 + next_best = i;
4680 + next_best_base = base;
4681 + next_best_num = num;
4682 + }
4683 + }
4684 + if (partial && next_best) {
4685 + i = next_best;
4686 + base = next_best_base;
4687 + num = next_best_num;
4688 + } else
4689 + i = NULL;
4690 +done:
4691 + if (i) {
4692 + if (base != i->base) {
4693 + margin_left->base = i->base;
4694 + margin_left->num = base - i->base;
4695 + list_add_tail(&margin_left->list, &i->list);
4696 + } else
4697 + kfree(margin_left);
4698 + if ((base + num) < (i->base + i->num)) {
4699 + margin_right->base = base + num;
4700 + margin_right->num = (i->base + i->num) -
4701 + (base + num);
4702 + list_add(&margin_right->list, &i->list);
4703 + } else
4704 + kfree(margin_right);
4705 + list_del(&i->list);
4706 + kfree(i);
4707 + *result = base;
4708 + } else {
4709 + spin_unlock_irq(&alloc->lock);
4710 + kfree(margin_left);
4711 + kfree(margin_right);
4712 + }
4713 +
4714 +err:
4715 + DPRINT("returning %d\n", i ? num : -ENOMEM);
4716 + DUMP(alloc);
4717 + if (!i)
4718 + return -ENOMEM;
4719 +
4720 + /* Add the allocation to the used list with a refcount of 1 */
4721 + used_node = kmalloc(sizeof(*used_node), GFP_KERNEL);
4722 + if (!used_node) {
4723 + spin_unlock_irq(&alloc->lock);
4724 + return -ENOMEM;
4725 + }
4726 + used_node->base = *result;
4727 + used_node->num = num;
4728 + used_node->refcount = 1;
4729 + used_node->is_alloced = 1;
4730 + list_add_tail(&used_node->list, &alloc->used);
4731 + spin_unlock_irq(&alloc->lock);
4732 + return (int)num;
4733 +}
4734 +
4735 +/* Allocate the list node using GFP_ATOMIC, because we *really* want to avoid
4736 + * forcing error-handling on to users in the deallocation path. */
4737 +static void _dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count)
4738 +{
4739 + struct alloc_node *i, *node = kmalloc(sizeof(*node), GFP_ATOMIC);
4740 + BUG_ON(!node);
4741 + DPRINT("release_range(%d,%d)\n", base_id, count);
4742 + DUMP(alloc);
4743 + BUG_ON(!count);
4744 + spin_lock_irq(&alloc->lock);
4745 +
4746 +
4747 + node->base = base_id;
4748 + node->num = count;
4749 + list_for_each_entry(i, &alloc->free, list) {
4750 + if (i->base >= node->base) {
4751 + /* BUG_ON(any overlapping) */
4752 + BUG_ON(i->base < (node->base + node->num));
4753 + list_add_tail(&node->list, &i->list);
4754 + goto done;
4755 + }
4756 + }
4757 + list_add_tail(&node->list, &alloc->free);
4758 +done:
4759 + /* Merge to the left */
4760 + i = list_entry(node->list.prev, struct alloc_node, list);
4761 + if (node->list.prev != &alloc->free) {
4762 + BUG_ON((i->base + i->num) > node->base);
4763 + if ((i->base + i->num) == node->base) {
4764 + node->base = i->base;
4765 + node->num += i->num;
4766 + list_del(&i->list);
4767 + kfree(i);
4768 + }
4769 + }
4770 + /* Merge to the right */
4771 + i = list_entry(node->list.next, struct alloc_node, list);
4772 + if (node->list.next != &alloc->free) {
4773 + BUG_ON((node->base + node->num) > i->base);
4774 + if ((node->base + node->num) == i->base) {
4775 + node->num += i->num;
4776 + list_del(&i->list);
4777 + kfree(i);
4778 + }
4779 + }
4780 + spin_unlock_irq(&alloc->lock);
4781 + DUMP(alloc);
4782 +}
4783 +
4784 +
4785 +void dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count)
4786 +{
4787 + struct alloc_node *i = NULL;
4788 + spin_lock_irq(&alloc->lock);
4789 +
4790 + /* First find the node in the used list and decrement its ref count */
4791 + list_for_each_entry(i, &alloc->used, list) {
4792 + if (i->base == base_id && i->num == count) {
4793 + --i->refcount;
4794 + if (i->refcount == 0) {
4795 + list_del(&i->list);
4796 + spin_unlock_irq(&alloc->lock);
4797 + if (i->is_alloced)
4798 + _dpa_alloc_free(alloc, base_id, count);
4799 + kfree(i);
4800 + return;
4801 + }
4802 + spin_unlock_irq(&alloc->lock);
4803 + return;
4804 + }
4805 + }
4806 + /* Couldn't find the allocation */
4807 + pr_err("Attempt to free ID 0x%x COUNT %d that wasn't alloc'd or reserved\n",
4808 + base_id, count);
4809 + spin_unlock_irq(&alloc->lock);
4810 +}
4811 +
4812 +void dpa_alloc_seed(struct dpa_alloc *alloc, u32 base_id, u32 count)
4813 +{
4814 + /* Same as free but no previous allocation checking is needed */
4815 + _dpa_alloc_free(alloc, base_id, count);
4816 +}
4817 +
4818 +
4819 +int dpa_alloc_reserve(struct dpa_alloc *alloc, u32 base, u32 num)
4820 +{
4821 + struct alloc_node *i = NULL, *used_node;
4822 +
4823 + DPRINT("alloc_reserve(%d,%d)\n", base, num);
4824 + DUMP(alloc);
4825 +
4826 + spin_lock_irq(&alloc->lock);
4827 +
4828 + /* Check for the node in the used list.
4829 + If found, increase it's refcount */
4830 + list_for_each_entry(i, &alloc->used, list) {
4831 + if ((i->base == base) && (i->num == num)) {
4832 + ++i->refcount;
4833 + spin_unlock_irq(&alloc->lock);
4834 + return 0;
4835 + }
4836 + if ((base >= i->base) && (base < (i->base + i->num))) {
4837 + /* This is an attempt to reserve a region that was
4838 + already reserved or alloced with a different
4839 + base or num */
4840 + pr_err("Cannot reserve %d - %d, it overlaps with"
4841 + " existing reservation from %d - %d\n",
4842 + base, base + num - 1, i->base,
4843 + i->base + i->num - 1);
4844 + spin_unlock_irq(&alloc->lock);
4845 + return -1;
4846 + }
4847 + }
4848 + /* Check to make sure this ID isn't in the free list */
4849 + list_for_each_entry(i, &alloc->free, list) {
4850 + if ((base >= i->base) && (base < (i->base + i->num))) {
4851 + /* yep, the reservation is within this node */
4852 + pr_err("Cannot reserve %d - %d, it overlaps with"
4853 + " free range %d - %d and must be alloced\n",
4854 + base, base + num - 1,
4855 + i->base, i->base + i->num - 1);
4856 + spin_unlock_irq(&alloc->lock);
4857 + return -1;
4858 + }
4859 + }
4860 + /* Add the allocation to the used list with a refcount of 1 */
4861 + used_node = kmalloc(sizeof(*used_node), GFP_KERNEL);
4862 + if (!used_node) {
4863 + spin_unlock_irq(&alloc->lock);
4864 + return -ENOMEM;
4865 +
4866 + }
4867 + used_node->base = base;
4868 + used_node->num = num;
4869 + used_node->refcount = 1;
4870 + used_node->is_alloced = 0;
4871 + list_add_tail(&used_node->list, &alloc->used);
4872 + spin_unlock_irq(&alloc->lock);
4873 + return 0;
4874 +}
4875 +
4876 +
4877 +int dpa_alloc_pop(struct dpa_alloc *alloc, u32 *result, u32 *count)
4878 +{
4879 + struct alloc_node *i = NULL;
4880 + DPRINT("alloc_pop()\n");
4881 + DUMP(alloc);
4882 + spin_lock_irq(&alloc->lock);
4883 + if (!list_empty(&alloc->free)) {
4884 + i = list_entry(alloc->free.next, struct alloc_node, list);
4885 + list_del(&i->list);
4886 + }
4887 + spin_unlock_irq(&alloc->lock);
4888 + DPRINT("returning %d\n", i ? 0 : -ENOMEM);
4889 + DUMP(alloc);
4890 + if (!i)
4891 + return -ENOMEM;
4892 + *result = i->base;
4893 + *count = i->num;
4894 + kfree(i);
4895 + return 0;
4896 +}
4897 +
4898 +int dpa_alloc_check(struct dpa_alloc *list_head, u32 item)
4899 +{
4900 + struct alloc_node *i = NULL;
4901 + int res = 0;
4902 + DPRINT("alloc_check()\n");
4903 + spin_lock_irq(&list_head->lock);
4904 +
4905 + list_for_each_entry(i, &list_head->free, list) {
4906 + if ((item >= i->base) && (item < (i->base + i->num))) {
4907 + res = 1;
4908 + break;
4909 + }
4910 + }
4911 + spin_unlock_irq(&list_head->lock);
4912 + return res;
4913 +}
4914 --- /dev/null
4915 +++ b/drivers/staging/fsl_qbman/dpa_sys.h
4916 @@ -0,0 +1,259 @@
4917 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
4918 + *
4919 + * Redistribution and use in source and binary forms, with or without
4920 + * modification, are permitted provided that the following conditions are met:
4921 + * * Redistributions of source code must retain the above copyright
4922 + * notice, this list of conditions and the following disclaimer.
4923 + * * Redistributions in binary form must reproduce the above copyright
4924 + * notice, this list of conditions and the following disclaimer in the
4925 + * documentation and/or other materials provided with the distribution.
4926 + * * Neither the name of Freescale Semiconductor nor the
4927 + * names of its contributors may be used to endorse or promote products
4928 + * derived from this software without specific prior written permission.
4929 + *
4930 + *
4931 + * ALTERNATIVELY, this software may be distributed under the terms of the
4932 + * GNU General Public License ("GPL") as published by the Free Software
4933 + * Foundation, either version 2 of that License or (at your option) any
4934 + * later version.
4935 + *
4936 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
4937 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
4938 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
4939 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
4940 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4941 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4942 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
4943 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
4944 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
4945 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4946 + */
4947 +
4948 +#ifndef DPA_SYS_H
4949 +#define DPA_SYS_H
4950 +
4951 +#include <linux/kernel.h>
4952 +#include <linux/errno.h>
4953 +#include <linux/io.h>
4954 +#include <linux/dma-mapping.h>
4955 +#include <linux/bootmem.h>
4956 +#include <linux/slab.h>
4957 +#include <linux/module.h>
4958 +#include <linux/init.h>
4959 +#include <linux/interrupt.h>
4960 +#include <linux/delay.h>
4961 +#include <linux/of_platform.h>
4962 +#include <linux/of_address.h>
4963 +#include <linux/of_irq.h>
4964 +#include <linux/kthread.h>
4965 +#include <linux/memblock.h>
4966 +#include <linux/completion.h>
4967 +#include <linux/log2.h>
4968 +#include <linux/types.h>
4969 +#include <linux/ioctl.h>
4970 +#include <linux/miscdevice.h>
4971 +#include <linux/uaccess.h>
4972 +#include <linux/debugfs.h>
4973 +#include <linux/seq_file.h>
4974 +#include <linux/device.h>
4975 +#include <linux/uio_driver.h>
4976 +#include <linux/smp.h>
4977 +#include <linux/fsl_hypervisor.h>
4978 +#include <linux/vmalloc.h>
4979 +#include <linux/ctype.h>
4980 +#include <linux/math64.h>
4981 +#include <linux/bitops.h>
4982 +
4983 +#include <linux/fsl_usdpaa.h>
4984 +
4985 +/* When copying aligned words or shorts, try to avoid memcpy() */
4986 +#define CONFIG_TRY_BETTER_MEMCPY
4987 +
4988 +/* For 2-element tables related to cache-inhibited and cache-enabled mappings */
4989 +#define DPA_PORTAL_CE 0
4990 +#define DPA_PORTAL_CI 1
4991 +
4992 +/***********************/
4993 +/* Misc inline assists */
4994 +/***********************/
4995 +
4996 +#if defined CONFIG_PPC32
4997 +#include "dpa_sys_ppc32.h"
4998 +#elif defined CONFIG_PPC64
4999 +#include "dpa_sys_ppc64.h"
5000 +#elif defined CONFIG_ARM
5001 +#include "dpa_sys_arm.h"
5002 +#elif defined CONFIG_ARM64
5003 +#include "dpa_sys_arm64.h"
5004 +#endif
5005 +
5006 +
5007 +#ifdef CONFIG_FSL_DPA_CHECKING
5008 +#define DPA_ASSERT(x) \
5009 + do { \
5010 + if (!(x)) { \
5011 + pr_crit("ASSERT: (%s:%d) %s\n", __FILE__, __LINE__, \
5012 + __stringify_1(x)); \
5013 + dump_stack(); \
5014 + panic("assertion failure"); \
5015 + } \
5016 + } while (0)
5017 +#else
5018 +#define DPA_ASSERT(x)
5019 +#endif
5020 +
5021 +/* memcpy() stuff - when you know alignments in advance */
5022 +#ifdef CONFIG_TRY_BETTER_MEMCPY
5023 +static inline void copy_words(void *dest, const void *src, size_t sz)
5024 +{
5025 + u32 *__dest = dest;
5026 + const u32 *__src = src;
5027 + size_t __sz = sz >> 2;
5028 + BUG_ON((unsigned long)dest & 0x3);
5029 + BUG_ON((unsigned long)src & 0x3);
5030 + BUG_ON(sz & 0x3);
5031 + while (__sz--)
5032 + *(__dest++) = *(__src++);
5033 +}
5034 +static inline void copy_shorts(void *dest, const void *src, size_t sz)
5035 +{
5036 + u16 *__dest = dest;
5037 + const u16 *__src = src;
5038 + size_t __sz = sz >> 1;
5039 + BUG_ON((unsigned long)dest & 0x1);
5040 + BUG_ON((unsigned long)src & 0x1);
5041 + BUG_ON(sz & 0x1);
5042 + while (__sz--)
5043 + *(__dest++) = *(__src++);
5044 +}
5045 +static inline void copy_bytes(void *dest, const void *src, size_t sz)
5046 +{
5047 + u8 *__dest = dest;
5048 + const u8 *__src = src;
5049 + while (sz--)
5050 + *(__dest++) = *(__src++);
5051 +}
5052 +#else
5053 +#define copy_words memcpy
5054 +#define copy_shorts memcpy
5055 +#define copy_bytes memcpy
5056 +#endif
5057 +
5058 +/************/
5059 +/* RB-trees */
5060 +/************/
5061 +
5062 +/* We encapsulate RB-trees so that its easier to use non-linux forms in
5063 + * non-linux systems. This also encapsulates the extra plumbing that linux code
5064 + * usually provides when using RB-trees. This encapsulation assumes that the
5065 + * data type held by the tree is u32. */
5066 +
5067 +struct dpa_rbtree {
5068 + struct rb_root root;
5069 +};
5070 +#define DPA_RBTREE { .root = RB_ROOT }
5071 +
5072 +static inline void dpa_rbtree_init(struct dpa_rbtree *tree)
5073 +{
5074 + tree->root = RB_ROOT;
5075 +}
5076 +
5077 +#define IMPLEMENT_DPA_RBTREE(name, type, node_field, val_field) \
5078 +static inline int name##_push(struct dpa_rbtree *tree, type *obj) \
5079 +{ \
5080 + struct rb_node *parent = NULL, **p = &tree->root.rb_node; \
5081 + while (*p) { \
5082 + u32 item; \
5083 + parent = *p; \
5084 + item = rb_entry(parent, type, node_field)->val_field; \
5085 + if (obj->val_field < item) \
5086 + p = &parent->rb_left; \
5087 + else if (obj->val_field > item) \
5088 + p = &parent->rb_right; \
5089 + else \
5090 + return -EBUSY; \
5091 + } \
5092 + rb_link_node(&obj->node_field, parent, p); \
5093 + rb_insert_color(&obj->node_field, &tree->root); \
5094 + return 0; \
5095 +} \
5096 +static inline void name##_del(struct dpa_rbtree *tree, type *obj) \
5097 +{ \
5098 + rb_erase(&obj->node_field, &tree->root); \
5099 +} \
5100 +static inline type *name##_find(struct dpa_rbtree *tree, u32 val) \
5101 +{ \
5102 + type *ret; \
5103 + struct rb_node *p = tree->root.rb_node; \
5104 + while (p) { \
5105 + ret = rb_entry(p, type, node_field); \
5106 + if (val < ret->val_field) \
5107 + p = p->rb_left; \
5108 + else if (val > ret->val_field) \
5109 + p = p->rb_right; \
5110 + else \
5111 + return ret; \
5112 + } \
5113 + return NULL; \
5114 +}
5115 +
5116 +/************/
5117 +/* Bootargs */
5118 +/************/
5119 +
5120 +/* Qman has "qportals=" and Bman has "bportals=", they use the same syntax
5121 + * though; a comma-separated list of items, each item being a cpu index and/or a
5122 + * range of cpu indices, and each item optionally be prefixed by "s" to indicate
5123 + * that the portal associated with that cpu should be shared. See bman_driver.c
5124 + * for more specifics. */
5125 +static int __parse_portals_cpu(const char **s, unsigned int *cpu)
5126 +{
5127 + *cpu = 0;
5128 + if (!isdigit(**s))
5129 + return -EINVAL;
5130 + while (isdigit(**s))
5131 + *cpu = *cpu * 10 + (*((*s)++) - '0');
5132 + return 0;
5133 +}
5134 +static inline int parse_portals_bootarg(char *str, struct cpumask *want_shared,
5135 + struct cpumask *want_unshared,
5136 + const char *argname)
5137 +{
5138 + const char *s = str;
5139 + unsigned int shared, cpu1, cpu2, loop;
5140 +
5141 +keep_going:
5142 + if (*s == 's') {
5143 + shared = 1;
5144 + s++;
5145 + } else
5146 + shared = 0;
5147 + if (__parse_portals_cpu(&s, &cpu1))
5148 + goto err;
5149 + if (*s == '-') {
5150 + s++;
5151 + if (__parse_portals_cpu(&s, &cpu2))
5152 + goto err;
5153 + if (cpu2 < cpu1)
5154 + goto err;
5155 + } else
5156 + cpu2 = cpu1;
5157 + for (loop = cpu1; loop <= cpu2; loop++)
5158 + cpumask_set_cpu(loop, shared ? want_shared : want_unshared);
5159 + if (*s == ',') {
5160 + s++;
5161 + goto keep_going;
5162 + } else if ((*s == '\0') || isspace(*s))
5163 + return 0;
5164 +err:
5165 + pr_crit("Malformed %s argument: %s, offset: %lu\n", argname, str,
5166 + (unsigned long)s - (unsigned long)str);
5167 + return -EINVAL;
5168 +}
5169 +
5170 +/* Hooks from fsl_usdpaa_irq.c to fsl_usdpaa.c */
5171 +int usdpaa_get_portal_config(struct file *filp, void *cinh,
5172 + enum usdpaa_portal_type ptype, unsigned int *irq,
5173 + void **iir_reg);
5174 +
5175 +#endif /* DPA_SYS_H */
5176 --- /dev/null
5177 +++ b/drivers/staging/fsl_qbman/dpa_sys_arm.h
5178 @@ -0,0 +1,95 @@
5179 +/* Copyright 2016 Freescale Semiconductor, Inc.
5180 + *
5181 + * Redistribution and use in source and binary forms, with or without
5182 + * modification, are permitted provided that the following conditions are met:
5183 + * * Redistributions of source code must retain the above copyright
5184 + * notice, this list of conditions and the following disclaimer.
5185 + * * Redistributions in binary form must reproduce the above copyright
5186 + * notice, this list of conditions and the following disclaimer in the
5187 + * documentation and/or other materials provided with the distribution.
5188 + * * Neither the name of Freescale Semiconductor nor the
5189 + * names of its contributors may be used to endorse or promote products
5190 + * derived from this software without specific prior written permission.
5191 + *
5192 + *
5193 + * ALTERNATIVELY, this software may be distributed under the terms of the
5194 + * GNU General Public License ("GPL") as published by the Free Software
5195 + * Foundation, either version 2 of that License or (at your option) any
5196 + * later version.
5197 + *
5198 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
5199 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5200 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5201 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
5202 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5203 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
5204 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5205 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5206 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
5207 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5208 + */
5209 +
5210 +#ifndef DPA_SYS_ARM_H
5211 +#define DPA_SYS_ARM_H
5212 +
5213 +#include <asm/cacheflush.h>
5214 +#include <asm/barrier.h>
5215 +
5216 +/* Implementation of ARM specific routines */
5217 +
5218 +/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
5219 + * barriers and that dcb*() won't fall victim to compiler or execution
5220 + * reordering with respect to other code/instructions that manipulate the same
5221 + * cacheline. */
5222 +#define hwsync() { asm volatile("dmb st" : : : "memory"); }
5223 +#define lwsync() { asm volatile("dmb st" : : : "memory"); }
5224 +#define dcbf(p) { asm volatile("mcr p15, 0, %0, c7, c10, 1" : : "r" (p) : "memory"); }
5225 +#define dcbt_ro(p) { asm volatile("pld [%0, #64];": : "r" (p)); }
5226 +#define dcbt_rw(p) { asm volatile("pldw [%0, #64];": : "r" (p)); }
5227 +#define dcbi(p) { asm volatile("mcr p15, 0, %0, c7, c6, 1" : : "r" (p) : "memory"); }
5228 +
5229 +#define dcbz_64(p) { memset(p, 0, sizeof(*p)); }
5230 +
5231 +#define dcbf_64(p) \
5232 + do { \
5233 + dcbf((u32)p); \
5234 + } while (0)
5235 +/* Commonly used combo */
5236 +#define dcbit_ro(p) \
5237 + do { \
5238 + dcbi((u32)p); \
5239 + dcbt_ro((u32)p); \
5240 + } while (0)
5241 +
5242 +static inline u64 mfatb(void)
5243 +{
5244 + return get_cycles();
5245 +}
5246 +
5247 +static inline u32 in_be32(volatile void *addr)
5248 +{
5249 + return be32_to_cpu(*((volatile u32 *) addr));
5250 +}
5251 +
5252 +static inline void out_be32(void *addr, u32 val)
5253 +{
5254 + *((u32 *) addr) = cpu_to_be32(val);
5255 +}
5256 +
5257 +
5258 +static inline void set_bits(unsigned long mask, volatile unsigned long *p)
5259 +{
5260 + *p |= mask;
5261 +}
5262 +static inline void clear_bits(unsigned long mask, volatile unsigned long *p)
5263 +{
5264 + *p &= ~mask;
5265 +}
5266 +
5267 +static inline void flush_dcache_range(unsigned long start, unsigned long stop)
5268 +{
5269 + __cpuc_flush_dcache_area((void *) start, stop - start);
5270 +}
5271 +
5272 +#define hard_smp_processor_id() raw_smp_processor_id()
5273 +#endif
5274 --- /dev/null
5275 +++ b/drivers/staging/fsl_qbman/dpa_sys_arm64.h
5276 @@ -0,0 +1,102 @@
5277 +/* Copyright 2014 Freescale Semiconductor, Inc.
5278 + *
5279 + * Redistribution and use in source and binary forms, with or without
5280 + * modification, are permitted provided that the following conditions are met:
5281 + * * Redistributions of source code must retain the above copyright
5282 + * notice, this list of conditions and the following disclaimer.
5283 + * * Redistributions in binary form must reproduce the above copyright
5284 + * notice, this list of conditions and the following disclaimer in the
5285 + * documentation and/or other materials provided with the distribution.
5286 + * * Neither the name of Freescale Semiconductor nor the
5287 + * names of its contributors may be used to endorse or promote products
5288 + * derived from this software without specific prior written permission.
5289 + *
5290 + *
5291 + * ALTERNATIVELY, this software may be distributed under the terms of the
5292 + * GNU General Public License ("GPL") as published by the Free Software
5293 + * Foundation, either version 2 of that License or (at your option) any
5294 + * later version.
5295 + *
5296 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
5297 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5298 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5299 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
5300 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5301 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
5302 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5303 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5304 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
5305 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5306 + */
5307 +
5308 +#ifndef DPA_SYS_ARM64_H
5309 +#define DPA_SYS_ARM64_H
5310 +
5311 +#include <asm/cacheflush.h>
5312 +#include <asm/barrier.h>
5313 +
5314 +/* Implementation of ARM 64 bit specific routines */
5315 +
5316 +/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
5317 + * barriers and that dcb*() won't fall victim to compiler or execution
5318 + * reordering with respect to other code/instructions that manipulate the same
5319 + * cacheline. */
5320 +#define hwsync() { asm volatile("dmb st" : : : "memory"); }
5321 +#define lwsync() { asm volatile("dmb st" : : : "memory"); }
5322 +#define dcbf(p) { asm volatile("dc cvac, %0;" : : "r" (p) : "memory"); }
5323 +#define dcbt_ro(p) { asm volatile("prfm pldl1keep, [%0, #64]" : : "r" (p)); }
5324 +#define dcbt_rw(p) { asm volatile("prfm pldl1keep, [%0, #64]" : : "r" (p)); }
5325 +#define dcbi(p) { asm volatile("dc ivac, %0" : : "r"(p) : "memory"); }
5326 +#define dcbz(p) { asm volatile("dc zva, %0" : : "r" (p) : "memory"); }
5327 +
5328 +#define dcbz_64(p) \
5329 + do { \
5330 + dcbz(p); \
5331 + } while (0)
5332 +
5333 +#define dcbf_64(p) \
5334 + do { \
5335 + dcbf(p); \
5336 + } while (0)
5337 +/* Commonly used combo */
5338 +#define dcbit_ro(p) \
5339 + do { \
5340 + dcbi(p); \
5341 + dcbt_ro(p); \
5342 + } while (0)
5343 +
5344 +static inline u64 mfatb(void)
5345 +{
5346 + return get_cycles();
5347 +}
5348 +
5349 +static inline u32 in_be32(volatile void *addr)
5350 +{
5351 + return be32_to_cpu(*((volatile u32 *) addr));
5352 +}
5353 +
5354 +static inline void out_be32(void *addr, u32 val)
5355 +{
5356 + *((u32 *) addr) = cpu_to_be32(val);
5357 +}
5358 +
5359 +
5360 +static inline void set_bits(unsigned long mask, volatile unsigned long *p)
5361 +{
5362 + *p |= mask;
5363 +}
5364 +static inline void clear_bits(unsigned long mask, volatile unsigned long *p)
5365 +{
5366 + *p &= ~mask;
5367 +}
5368 +
5369 +static inline void flush_dcache_range(unsigned long start, unsigned long stop)
5370 +{
5371 + __flush_dcache_area((void *) start, stop - start);
5372 +}
5373 +
5374 +#define hard_smp_processor_id() raw_smp_processor_id()
5375 +
5376 +
5377 +
5378 +#endif
5379 --- /dev/null
5380 +++ b/drivers/staging/fsl_qbman/dpa_sys_ppc32.h
5381 @@ -0,0 +1,70 @@
5382 +/* Copyright 2014 Freescale Semiconductor, Inc.
5383 + *
5384 + * Redistribution and use in source and binary forms, with or without
5385 + * modification, are permitted provided that the following conditions are met:
5386 + * * Redistributions of source code must retain the above copyright
5387 + * notice, this list of conditions and the following disclaimer.
5388 + * * Redistributions in binary form must reproduce the above copyright
5389 + * notice, this list of conditions and the following disclaimer in the
5390 + * documentation and/or other materials provided with the distribution.
5391 + * * Neither the name of Freescale Semiconductor nor the
5392 + * names of its contributors may be used to endorse or promote products
5393 + * derived from this software without specific prior written permission.
5394 + *
5395 + *
5396 + * ALTERNATIVELY, this software may be distributed under the terms of the
5397 + * GNU General Public License ("GPL") as published by the Free Software
5398 + * Foundation, either version 2 of that License or (at your option) any
5399 + * later version.
5400 + *
5401 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
5402 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5403 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5404 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
5405 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5406 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
5407 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5408 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5409 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
5410 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5411 + */
5412 +
5413 +#ifndef DPA_SYS_PPC32_H
5414 +#define DPA_SYS_PPC32_H
5415 +
5416 +/* Implementation of PowerPC 32 bit specific routines */
5417 +
5418 +/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
5419 + * barriers and that dcb*() won't fall victim to compiler or execution
5420 + * reordering with respect to other code/instructions that manipulate the same
5421 + * cacheline. */
5422 +#define hwsync() __asm__ __volatile__ ("sync" : : : "memory")
5423 +#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory")
5424 +#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory")
5425 +#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p))
5426 +#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p))
5427 +#define dcbi(p) dcbf(p)
5428 +
5429 +#define dcbzl(p) __asm__ __volatile__ ("dcbzl 0,%0" : : "r" (p))
5430 +#define dcbz_64(p) dcbzl(p)
5431 +#define dcbf_64(p) dcbf(p)
5432 +
5433 +/* Commonly used combo */
5434 +#define dcbit_ro(p) \
5435 + do { \
5436 + dcbi(p); \
5437 + dcbt_ro(p); \
5438 + } while (0)
5439 +
5440 +static inline u64 mfatb(void)
5441 +{
5442 + u32 hi, lo, chk;
5443 + do {
5444 + hi = mfspr(SPRN_ATBU);
5445 + lo = mfspr(SPRN_ATBL);
5446 + chk = mfspr(SPRN_ATBU);
5447 + } while (unlikely(hi != chk));
5448 + return ((u64)hi << 32) | (u64)lo;
5449 +}
5450 +
5451 +#endif
5452 --- /dev/null
5453 +++ b/drivers/staging/fsl_qbman/dpa_sys_ppc64.h
5454 @@ -0,0 +1,79 @@
5455 +/* Copyright 2014 Freescale Semiconductor, Inc.
5456 + *
5457 + * Redistribution and use in source and binary forms, with or without
5458 + * modification, are permitted provided that the following conditions are met:
5459 + * * Redistributions of source code must retain the above copyright
5460 + * notice, this list of conditions and the following disclaimer.
5461 + * * Redistributions in binary form must reproduce the above copyright
5462 + * notice, this list of conditions and the following disclaimer in the
5463 + * documentation and/or other materials provided with the distribution.
5464 + * * Neither the name of Freescale Semiconductor nor the
5465 + * names of its contributors may be used to endorse or promote products
5466 + * derived from this software without specific prior written permission.
5467 + *
5468 + *
5469 + * ALTERNATIVELY, this software may be distributed under the terms of the
5470 + * GNU General Public License ("GPL") as published by the Free Software
5471 + * Foundation, either version 2 of that License or (at your option) any
5472 + * later version.
5473 + *
5474 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
5475 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5476 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5477 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
5478 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
5479 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
5480 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
5481 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5482 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
5483 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5484 + */
5485 +
5486 +#ifndef DPA_SYS_PPC64_H
5487 +#define DPA_SYS_PPC64_H
5488 +
5489 +/* Implementation of PowerPC 64 bit specific routines */
5490 +
5491 +/* TODO: NB, we currently assume that hwsync() and lwsync() imply compiler
5492 + * barriers and that dcb*() won't fall victim to compiler or execution
5493 + * reordering with respect to other code/instructions that manipulate the same
5494 + * cacheline. */
5495 +#define hwsync() __asm__ __volatile__ ("sync" : : : "memory")
5496 +#define lwsync() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : : "memory")
5497 +#define dcbf(p) __asm__ __volatile__ ("dcbf 0,%0" : : "r" (p) : "memory")
5498 +#define dcbt_ro(p) __asm__ __volatile__ ("dcbt 0,%0" : : "r" (p))
5499 +#define dcbt_rw(p) __asm__ __volatile__ ("dcbtst 0,%0" : : "r" (p))
5500 +#define dcbi(p) dcbf(p)
5501 +
5502 +#define dcbz(p) __asm__ __volatile__ ("dcbz 0,%0" : : "r" (p))
5503 +#define dcbz_64(p) \
5504 + do { \
5505 + dcbz((void*)p + 32); \
5506 + dcbz(p); \
5507 + } while (0)
5508 +#define dcbf_64(p) \
5509 + do { \
5510 + dcbf((void*)p + 32); \
5511 + dcbf(p); \
5512 + } while (0)
5513 +/* Commonly used combo */
5514 +#define dcbit_ro(p) \
5515 + do { \
5516 + dcbi(p); \
5517 + dcbi((void*)p + 32); \
5518 + dcbt_ro(p); \
5519 + dcbt_ro((void*)p + 32); \
5520 + } while (0)
5521 +
5522 +static inline u64 mfatb(void)
5523 +{
5524 + u32 hi, lo, chk;
5525 + do {
5526 + hi = mfspr(SPRN_ATBU);
5527 + lo = mfspr(SPRN_ATBL);
5528 + chk = mfspr(SPRN_ATBU);
5529 + } while (unlikely(hi != chk));
5530 + return ((u64)hi << 32) | (u64)lo;
5531 +}
5532 +
5533 +#endif
5534 --- /dev/null
5535 +++ b/drivers/staging/fsl_qbman/fsl_usdpaa.c
5536 @@ -0,0 +1,1982 @@
5537 +/* Copyright (C) 2008-2012 Freescale Semiconductor, Inc.
5538 + * Authors: Andy Fleming <afleming@freescale.com>
5539 + * Timur Tabi <timur@freescale.com>
5540 + * Geoff Thorpe <Geoff.Thorpe@freescale.com>
5541 + *
5542 + * This file is licensed under the terms of the GNU General Public License
5543 + * version 2. This program is licensed "as is" without any warranty of any
5544 + * kind, whether express or implied.
5545 + */
5546 +
5547 +
5548 +#include <linux/miscdevice.h>
5549 +#include <linux/fs.h>
5550 +#include <linux/cdev.h>
5551 +#include <linux/mm.h>
5552 +#include <linux/of.h>
5553 +#include <linux/memblock.h>
5554 +#include <linux/slab.h>
5555 +#include <linux/mman.h>
5556 +#include <linux/of_reserved_mem.h>
5557 +
5558 +#if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64))
5559 +#include <mm/mmu_decl.h>
5560 +#endif
5561 +
5562 +#include "dpa_sys.h"
5563 +#include <linux/fsl_usdpaa.h>
5564 +#include "bman_low.h"
5565 +#include "qman_low.h"
5566 +
5567 +/* Physical address range of the memory reservation, exported for mm/mem.c */
5568 +static u64 phys_start;
5569 +static u64 phys_size;
5570 +static u64 arg_phys_size;
5571 +
5572 +/* PFN versions of the above */
5573 +static unsigned long pfn_start;
5574 +static unsigned long pfn_size;
5575 +
5576 +/* Memory reservations are manipulated under this spinlock (which is why 'refs'
5577 + * isn't atomic_t). */
5578 +static DEFINE_SPINLOCK(mem_lock);
5579 +
5580 +/* The range of TLB1 indices */
5581 +static unsigned int first_tlb;
5582 +static unsigned int num_tlb = 1;
5583 +static unsigned int current_tlb; /* loops around for fault handling */
5584 +
5585 +/* Memory reservation is represented as a list of 'mem_fragment's, some of which
5586 + * may be mapped. Unmapped fragments are always merged where possible. */
5587 +static LIST_HEAD(mem_list);
5588 +
5589 +struct mem_mapping;
5590 +
5591 +/* Memory fragments are in 'mem_list'. */
5592 +struct mem_fragment {
5593 + u64 base;
5594 + u64 len;
5595 + unsigned long pfn_base; /* PFN version of 'base' */
5596 + unsigned long pfn_len; /* PFN version of 'len' */
5597 + unsigned int refs; /* zero if unmapped */
5598 + u64 root_len; /* Size of the orignal fragment */
5599 + unsigned long root_pfn; /* PFN of the orignal fragment */
5600 + struct list_head list;
5601 + /* if mapped, flags+name captured at creation time */
5602 + u32 flags;
5603 + char name[USDPAA_DMA_NAME_MAX];
5604 + u64 map_len;
5605 + /* support multi-process locks per-memory-fragment. */
5606 + int has_locking;
5607 + wait_queue_head_t wq;
5608 + struct mem_mapping *owner;
5609 +};
5610 +
5611 +/* Mappings of memory fragments in 'struct ctx'. These are created from
5612 + * ioctl(USDPAA_IOCTL_DMA_MAP), though the actual mapping then happens via a
5613 + * mmap(). */
5614 +struct mem_mapping {
5615 + struct mem_fragment *root_frag;
5616 + u32 frag_count;
5617 + u64 total_size;
5618 + struct list_head list;
5619 + int refs;
5620 + void *virt_addr;
5621 +};
5622 +
5623 +struct portal_mapping {
5624 + struct usdpaa_ioctl_portal_map user;
5625 + union {
5626 + struct qm_portal_config *qportal;
5627 + struct bm_portal_config *bportal;
5628 + };
5629 + /* Declare space for the portals in case the process
5630 + exits unexpectedly and needs to be cleaned by the kernel */
5631 + union {
5632 + struct qm_portal qman_portal_low;
5633 + struct bm_portal bman_portal_low;
5634 + };
5635 + struct list_head list;
5636 + struct resource *phys;
5637 + struct iommu_domain *iommu_domain;
5638 +};
5639 +
5640 +/* Track the DPAA resources the process is using */
5641 +struct active_resource {
5642 + struct list_head list;
5643 + u32 id;
5644 + u32 num;
5645 + unsigned int refcount;
5646 +};
5647 +
5648 +/* Per-FD state (which should also be per-process but we don't enforce that) */
5649 +struct ctx {
5650 + /* Lock to protect the context */
5651 + spinlock_t lock;
5652 + /* Allocated resources get put here for accounting */
5653 + struct list_head resources[usdpaa_id_max];
5654 + /* list of DMA maps */
5655 + struct list_head maps;
5656 + /* list of portal maps */
5657 + struct list_head portals;
5658 +};
5659 +
5660 +/* Different resource classes */
5661 +static const struct alloc_backend {
5662 + enum usdpaa_id_type id_type;
5663 + int (*alloc)(u32 *, u32, u32, int);
5664 + void (*release)(u32 base, unsigned int count);
5665 + int (*reserve)(u32 base, unsigned int count);
5666 + const char *acronym;
5667 +} alloc_backends[] = {
5668 + {
5669 + .id_type = usdpaa_id_fqid,
5670 + .alloc = qman_alloc_fqid_range,
5671 + .release = qman_release_fqid_range,
5672 + .reserve = qman_reserve_fqid_range,
5673 + .acronym = "FQID"
5674 + },
5675 + {
5676 + .id_type = usdpaa_id_bpid,
5677 + .alloc = bman_alloc_bpid_range,
5678 + .release = bman_release_bpid_range,
5679 + .reserve = bman_reserve_bpid_range,
5680 + .acronym = "BPID"
5681 + },
5682 + {
5683 + .id_type = usdpaa_id_qpool,
5684 + .alloc = qman_alloc_pool_range,
5685 + .release = qman_release_pool_range,
5686 + .reserve = qman_reserve_pool_range,
5687 + .acronym = "QPOOL"
5688 + },
5689 + {
5690 + .id_type = usdpaa_id_cgrid,
5691 + .alloc = qman_alloc_cgrid_range,
5692 + .release = qman_release_cgrid_range,
5693 + .acronym = "CGRID"
5694 + },
5695 + {
5696 + .id_type = usdpaa_id_ceetm0_lfqid,
5697 + .alloc = qman_alloc_ceetm0_lfqid_range,
5698 + .release = qman_release_ceetm0_lfqid_range,
5699 + .acronym = "CEETM0_LFQID"
5700 + },
5701 + {
5702 + .id_type = usdpaa_id_ceetm0_channelid,
5703 + .alloc = qman_alloc_ceetm0_channel_range,
5704 + .release = qman_release_ceetm0_channel_range,
5705 + .acronym = "CEETM0_LFQID"
5706 + },
5707 + {
5708 + .id_type = usdpaa_id_ceetm1_lfqid,
5709 + .alloc = qman_alloc_ceetm1_lfqid_range,
5710 + .release = qman_release_ceetm1_lfqid_range,
5711 + .acronym = "CEETM1_LFQID"
5712 + },
5713 + {
5714 + .id_type = usdpaa_id_ceetm1_channelid,
5715 + .alloc = qman_alloc_ceetm1_channel_range,
5716 + .release = qman_release_ceetm1_channel_range,
5717 + .acronym = "CEETM1_LFQID"
5718 + },
5719 + {
5720 + /* This terminates the array */
5721 + .id_type = usdpaa_id_max
5722 + }
5723 +};
5724 +
5725 +/* Determines the largest acceptable page size for a given size
5726 + The sizes are determined by what the TLB1 acceptable page sizes are */
5727 +static u32 largest_page_size(u32 size)
5728 +{
5729 + int shift = 30; /* Start at 1G size */
5730 + if (size < 4096)
5731 + return 0;
5732 + do {
5733 + if (size >= (1<<shift))
5734 + return 1<<shift;
5735 + shift -= 2;
5736 + } while (shift >= 12); /* Up to 4k */
5737 + return 0;
5738 +}
5739 +
5740 +/* Determine if value is power of 4 */
5741 +static inline bool is_power_of_4(u64 x)
5742 +{
5743 + if (x == 0 || ((x & (x - 1)) != 0))
5744 + return false;
5745 + return !!(x & 0x5555555555555555ull);
5746 +}
5747 +
5748 +/* Helper for ioctl_dma_map() when we have a larger fragment than we need. This
5749 + * splits the fragment into 4 and returns the upper-most. (The caller can loop
5750 + * until it has a suitable fragment size.) */
5751 +static struct mem_fragment *split_frag(struct mem_fragment *frag)
5752 +{
5753 + struct mem_fragment *x[3];
5754 +
5755 + x[0] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC);
5756 + x[1] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC);
5757 + x[2] = kmalloc(sizeof(struct mem_fragment), GFP_ATOMIC);
5758 + if (!x[0] || !x[1] || !x[2]) {
5759 + kfree(x[0]);
5760 + kfree(x[1]);
5761 + kfree(x[2]);
5762 + return NULL;
5763 + }
5764 + BUG_ON(frag->refs);
5765 + frag->len >>= 2;
5766 + frag->pfn_len >>= 2;
5767 + x[0]->base = frag->base + frag->len;
5768 + x[1]->base = x[0]->base + frag->len;
5769 + x[2]->base = x[1]->base + frag->len;
5770 + x[0]->len = x[1]->len = x[2]->len = frag->len;
5771 + x[0]->pfn_base = frag->pfn_base + frag->pfn_len;
5772 + x[1]->pfn_base = x[0]->pfn_base + frag->pfn_len;
5773 + x[2]->pfn_base = x[1]->pfn_base + frag->pfn_len;
5774 + x[0]->pfn_len = x[1]->pfn_len = x[2]->pfn_len = frag->pfn_len;
5775 + x[0]->refs = x[1]->refs = x[2]->refs = 0;
5776 + x[0]->root_len = x[1]->root_len = x[2]->root_len = frag->root_len;
5777 + x[0]->root_pfn = x[1]->root_pfn = x[2]->root_pfn = frag->root_pfn;
5778 + x[0]->name[0] = x[1]->name[0] = x[2]->name[0] = 0;
5779 + list_add_tail(&x[0]->list, &frag->list);
5780 + list_add_tail(&x[1]->list, &x[0]->list);
5781 + list_add_tail(&x[2]->list, &x[1]->list);
5782 + return x[2];
5783 +}
5784 +
5785 +static __maybe_unused void dump_frags(void)
5786 +{
5787 + struct mem_fragment *frag;
5788 + int i = 0;
5789 + list_for_each_entry(frag, &mem_list, list) {
5790 + pr_info("FRAG %d: base 0x%llx pfn_base 0x%lx len 0x%llx root_len 0x%llx root_pfn 0x%lx refs %d name %s\n",
5791 + i, frag->base, frag->pfn_base,
5792 + frag->len, frag->root_len, frag->root_pfn,
5793 + frag->refs, frag->name);
5794 + ++i;
5795 + }
5796 +}
5797 +
5798 +/* Walk the list of fragments and adjoin neighbouring segments if possible */
5799 +static void compress_frags(void)
5800 +{
5801 + /* Walk the fragment list and combine fragments */
5802 + struct mem_fragment *frag, *nxtfrag;
5803 + u64 len = 0;
5804 +
5805 + int i, numfrags;
5806 +
5807 +
5808 + frag = list_entry(mem_list.next, struct mem_fragment, list);
5809 +
5810 + while (&frag->list != &mem_list) {
5811 + /* Must combine consecutive fragemenst with
5812 + same root_pfn such that they are power of 4 */
5813 + if (frag->refs != 0) {
5814 + frag = list_entry(frag->list.next,
5815 + struct mem_fragment, list);
5816 + continue; /* Not this window */
5817 + }
5818 + len = frag->len;
5819 + numfrags = 0;
5820 + nxtfrag = list_entry(frag->list.next,
5821 + struct mem_fragment, list);
5822 + while (true) {
5823 + if (&nxtfrag->list == &mem_list) {
5824 + numfrags = 0;
5825 + break; /* End of list */
5826 + }
5827 + if (nxtfrag->refs) {
5828 + numfrags = 0;
5829 + break; /* In use still */
5830 + }
5831 + if (nxtfrag->root_pfn != frag->root_pfn) {
5832 + numfrags = 0;
5833 + break; /* Crosses root fragment boundary */
5834 + }
5835 + len += nxtfrag->len;
5836 + numfrags++;
5837 + if (is_power_of_4(len)) {
5838 + /* These fragments can be combined */
5839 + break;
5840 + }
5841 + nxtfrag = list_entry(nxtfrag->list.next,
5842 + struct mem_fragment, list);
5843 + }
5844 + if (numfrags == 0) {
5845 + frag = list_entry(frag->list.next,
5846 + struct mem_fragment, list);
5847 + continue; /* try the next window */
5848 + }
5849 + for (i = 0; i < numfrags; i++) {
5850 + struct mem_fragment *todel =
5851 + list_entry(nxtfrag->list.prev,
5852 + struct mem_fragment, list);
5853 + nxtfrag->len += todel->len;
5854 + nxtfrag->pfn_len += todel->pfn_len;
5855 + list_del(&todel->list);
5856 + }
5857 + /* Re evaluate the list, things may merge now */
5858 + frag = list_entry(mem_list.next, struct mem_fragment, list);
5859 + }
5860 +}
5861 +
5862 +/* Hook from arch/powerpc/mm/mem.c */
5863 +int usdpaa_test_fault(unsigned long pfn, u64 *phys_addr, u64 *size)
5864 +{
5865 + struct mem_fragment *frag;
5866 + int idx = -1;
5867 + if ((pfn < pfn_start) || (pfn >= (pfn_start + pfn_size)))
5868 + return -1;
5869 + /* It's in-range, we need to find the fragment */
5870 + spin_lock(&mem_lock);
5871 + list_for_each_entry(frag, &mem_list, list) {
5872 + if ((pfn >= frag->pfn_base) && (pfn < (frag->pfn_base +
5873 + frag->pfn_len))) {
5874 + *phys_addr = frag->base;
5875 + *size = frag->len;
5876 + idx = current_tlb++;
5877 + if (current_tlb >= (first_tlb + num_tlb))
5878 + current_tlb = first_tlb;
5879 + break;
5880 + }
5881 + }
5882 + spin_unlock(&mem_lock);
5883 + return idx;
5884 +}
5885 +
5886 +static int usdpaa_open(struct inode *inode, struct file *filp)
5887 +{
5888 + const struct alloc_backend *backend = &alloc_backends[0];
5889 + struct ctx *ctx = kmalloc(sizeof(struct ctx), GFP_KERNEL);
5890 + if (!ctx)
5891 + return -ENOMEM;
5892 + filp->private_data = ctx;
5893 +
5894 + while (backend->id_type != usdpaa_id_max) {
5895 + INIT_LIST_HEAD(&ctx->resources[backend->id_type]);
5896 + backend++;
5897 + }
5898 +
5899 + INIT_LIST_HEAD(&ctx->maps);
5900 + INIT_LIST_HEAD(&ctx->portals);
5901 + spin_lock_init(&ctx->lock);
5902 +
5903 + //filp->f_mapping->backing_dev_info = &directly_mappable_cdev_bdi;
5904 +
5905 + return 0;
5906 +}
5907 +
5908 +#define DQRR_MAXFILL 15
5909 +
5910 +/* Reset a QMan portal to its default state */
5911 +static int init_qm_portal(struct qm_portal_config *config,
5912 + struct qm_portal *portal)
5913 +{
5914 + const struct qm_dqrr_entry *dqrr = NULL;
5915 + int i;
5916 +
5917 + portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
5918 + portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
5919 +
5920 + /* Make sure interrupts are inhibited */
5921 + qm_out(IIR, 1);
5922 +
5923 + /* Initialize the DQRR. This will stop any dequeue
5924 + commands that are in progress */
5925 + if (qm_dqrr_init(portal, config, qm_dqrr_dpush, qm_dqrr_pvb,
5926 + qm_dqrr_cdc, DQRR_MAXFILL)) {
5927 + pr_err("qm_dqrr_init() failed when trying to"
5928 + " recover portal, portal will be leaked\n");
5929 + return 1;
5930 + }
5931 +
5932 + /* Discard any entries on the DQRR */
5933 + /* If we consume the ring twice something is wrong */
5934 + for (i = 0; i < DQRR_MAXFILL * 2; i++) {
5935 + qm_dqrr_pvb_update(portal);
5936 + dqrr = qm_dqrr_current(portal);
5937 + if (!dqrr)
5938 + break;
5939 + qm_dqrr_cdc_consume_1ptr(portal, dqrr, 0);
5940 + qm_dqrr_pvb_update(portal);
5941 + qm_dqrr_next(portal);
5942 + }
5943 + /* Initialize the EQCR */
5944 + if (qm_eqcr_init(portal, qm_eqcr_pvb,
5945 + qm_eqcr_get_ci_stashing(portal), 1)) {
5946 + pr_err("Qman EQCR initialisation failed\n");
5947 + return 1;
5948 + }
5949 + /* initialize the MR */
5950 + if (qm_mr_init(portal, qm_mr_pvb, qm_mr_cci)) {
5951 + pr_err("Qman MR initialisation failed\n");
5952 + return 1;
5953 + }
5954 + qm_mr_pvb_update(portal);
5955 + while (qm_mr_current(portal)) {
5956 + qm_mr_next(portal);
5957 + qm_mr_cci_consume_to_current(portal);
5958 + qm_mr_pvb_update(portal);
5959 + }
5960 +
5961 + if (qm_mc_init(portal)) {
5962 + pr_err("Qman MC initialisation failed\n");
5963 + return 1;
5964 + }
5965 + return 0;
5966 +}
5967 +
5968 +static int init_bm_portal(struct bm_portal_config *config,
5969 + struct bm_portal *portal)
5970 +{
5971 + portal->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
5972 + portal->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
5973 +
5974 + if (bm_rcr_init(portal, bm_rcr_pvb, bm_rcr_cce)) {
5975 + pr_err("Bman RCR initialisation failed\n");
5976 + return 1;
5977 + }
5978 + if (bm_mc_init(portal)) {
5979 + pr_err("Bman MC initialisation failed\n");
5980 + return 1;
5981 + }
5982 + return 0;
5983 +}
5984 +
5985 +/* Function that will scan all FQ's in the system. For each FQ that is not
5986 + OOS it will call the check_channel helper to determine if the FQ should
5987 + be torn down. If the check_channel helper returns true the FQ will be
5988 + transitioned to the OOS state */
5989 +static int qm_check_and_destroy_fqs(struct qm_portal *portal, void *ctx,
5990 + bool (*check_channel)(void*, u32))
5991 +{
5992 + u32 fq_id = 0;
5993 + while (1) {
5994 + struct qm_mc_command *mcc;
5995 + struct qm_mc_result *mcr;
5996 + u8 state;
5997 + u32 channel;
5998 +
5999 + /* Determine the channel for the FQID */
6000 + mcc = qm_mc_start(portal);
6001 + mcc->queryfq.fqid = fq_id;
6002 + qm_mc_commit(portal, QM_MCC_VERB_QUERYFQ);
6003 + while (!(mcr = qm_mc_result(portal)))
6004 + cpu_relax();
6005 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK)
6006 + == QM_MCR_VERB_QUERYFQ);
6007 + if (mcr->result != QM_MCR_RESULT_OK)
6008 + break; /* End of valid FQIDs */
6009 +
6010 + channel = mcr->queryfq.fqd.dest.channel;
6011 + /* Determine the state of the FQID */
6012 + mcc = qm_mc_start(portal);
6013 + mcc->queryfq_np.fqid = fq_id;
6014 + qm_mc_commit(portal, QM_MCC_VERB_QUERYFQ_NP);
6015 + while (!(mcr = qm_mc_result(portal)))
6016 + cpu_relax();
6017 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK)
6018 + == QM_MCR_VERB_QUERYFQ_NP);
6019 + state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK;
6020 + if (state == QM_MCR_NP_STATE_OOS)
6021 + /* Already OOS, no need to do anymore checks */
6022 + goto next;
6023 +
6024 + if (check_channel(ctx, channel))
6025 + qm_shutdown_fq(&portal, 1, fq_id);
6026 + next:
6027 + ++fq_id;
6028 + }
6029 + return 0;
6030 +}
6031 +
6032 +static bool check_channel_device(void *_ctx, u32 channel)
6033 +{
6034 + struct ctx *ctx = _ctx;
6035 + struct portal_mapping *portal, *tmpportal;
6036 + struct active_resource *res;
6037 +
6038 + /* See if the FQ is destined for one of the portals we're cleaning up */
6039 + list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) {
6040 + if (portal->user.type == usdpaa_portal_qman) {
6041 + if (portal->qportal->public_cfg.channel == channel) {
6042 + /* This FQs destination is a portal
6043 + we're cleaning, send a retire */
6044 + return true;
6045 + }
6046 + }
6047 + }
6048 +
6049 + /* Check the pool channels that will be released as well */
6050 + list_for_each_entry(res, &ctx->resources[usdpaa_id_qpool], list) {
6051 + if ((res->id >= channel) &&
6052 + ((res->id + res->num - 1) <= channel))
6053 + return true;
6054 + }
6055 + return false;
6056 +}
6057 +
6058 +static bool check_portal_channel(void *ctx, u32 channel)
6059 +{
6060 + u32 portal_channel = *(u32 *)ctx;
6061 + if (portal_channel == channel) {
6062 + /* This FQs destination is a portal
6063 + we're cleaning, send a retire */
6064 + return true;
6065 + }
6066 + return false;
6067 +}
6068 +
6069 +
6070 +
6071 +
6072 +static int usdpaa_release(struct inode *inode, struct file *filp)
6073 +{
6074 + struct ctx *ctx = filp->private_data;
6075 + struct mem_mapping *map, *tmpmap;
6076 + struct portal_mapping *portal, *tmpportal;
6077 + const struct alloc_backend *backend = &alloc_backends[0];
6078 + struct active_resource *res;
6079 + struct qm_portal *qm_cleanup_portal = NULL;
6080 + struct bm_portal *bm_cleanup_portal = NULL;
6081 + struct qm_portal_config *qm_alloced_portal = NULL;
6082 + struct bm_portal_config *bm_alloced_portal = NULL;
6083 +
6084 + struct qm_portal *portal_array[qman_portal_max];
6085 + int portal_count = 0;
6086 +
6087 + /* Ensure the release operation cannot be migrated to another
6088 + CPU as CPU specific variables may be needed during cleanup */
6089 +#ifdef CONFIG_PREEMPT_RT_FULL
6090 + migrate_disable();
6091 +#endif
6092 + /* The following logic is used to recover resources that were not
6093 + correctly released by the process that is closing the FD.
6094 + Step 1: syncronize the HW with the qm_portal/bm_portal structures
6095 + in the kernel
6096 + */
6097 +
6098 + list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) {
6099 + /* Try to recover any portals that weren't shut down */
6100 + if (portal->user.type == usdpaa_portal_qman) {
6101 + portal_array[portal_count] = &portal->qman_portal_low;
6102 + ++portal_count;
6103 + init_qm_portal(portal->qportal,
6104 + &portal->qman_portal_low);
6105 + if (!qm_cleanup_portal) {
6106 + qm_cleanup_portal = &portal->qman_portal_low;
6107 + } else {
6108 + /* Clean FQs on the dedicated channel */
6109 + u32 chan = portal->qportal->public_cfg.channel;
6110 + qm_check_and_destroy_fqs(
6111 + &portal->qman_portal_low, &chan,
6112 + check_portal_channel);
6113 + }
6114 + } else {
6115 + /* BMAN */
6116 + init_bm_portal(portal->bportal,
6117 + &portal->bman_portal_low);
6118 + if (!bm_cleanup_portal)
6119 + bm_cleanup_portal = &portal->bman_portal_low;
6120 + }
6121 + }
6122 + /* If no portal was found, allocate one for cleanup */
6123 + if (!qm_cleanup_portal) {
6124 + qm_alloced_portal = qm_get_unused_portal();
6125 + if (!qm_alloced_portal) {
6126 + pr_crit("No QMan portal avalaible for cleanup\n");
6127 +#ifdef CONFIG_PREEMPT_RT_FULL
6128 + migrate_enable();
6129 +#endif
6130 + return -1;
6131 + }
6132 + qm_cleanup_portal = kmalloc(sizeof(struct qm_portal),
6133 + GFP_KERNEL);
6134 + if (!qm_cleanup_portal) {
6135 +#ifdef CONFIG_PREEMPT_RT_FULL
6136 + migrate_enable();
6137 +#endif
6138 + return -ENOMEM;
6139 + }
6140 + init_qm_portal(qm_alloced_portal, qm_cleanup_portal);
6141 + portal_array[portal_count] = qm_cleanup_portal;
6142 + ++portal_count;
6143 + }
6144 + if (!bm_cleanup_portal) {
6145 + bm_alloced_portal = bm_get_unused_portal();
6146 + if (!bm_alloced_portal) {
6147 + pr_crit("No BMan portal avalaible for cleanup\n");
6148 +#ifdef CONFIG_PREEMPT_RT_FULL
6149 + migrate_enable();
6150 +#endif
6151 + return -1;
6152 + }
6153 + bm_cleanup_portal = kmalloc(sizeof(struct bm_portal),
6154 + GFP_KERNEL);
6155 + if (!bm_cleanup_portal) {
6156 +#ifdef CONFIG_PREEMPT_RT_FULL
6157 + migrate_enable();
6158 +#endif
6159 + return -ENOMEM;
6160 + }
6161 + init_bm_portal(bm_alloced_portal, bm_cleanup_portal);
6162 + }
6163 +
6164 + /* OOS the FQs associated with this process */
6165 + qm_check_and_destroy_fqs(qm_cleanup_portal, ctx, check_channel_device);
6166 +
6167 + while (backend->id_type != usdpaa_id_max) {
6168 + int leaks = 0;
6169 + list_for_each_entry(res, &ctx->resources[backend->id_type],
6170 + list) {
6171 + if (backend->id_type == usdpaa_id_fqid) {
6172 + int i = 0;
6173 + for (; i < res->num; i++) {
6174 + /* Clean FQs with the cleanup portal */
6175 + qm_shutdown_fq(portal_array,
6176 + portal_count,
6177 + res->id + i);
6178 + }
6179 + }
6180 + leaks += res->num;
6181 + backend->release(res->id, res->num);
6182 + }
6183 + if (leaks)
6184 + pr_crit("USDPAA process leaking %d %s%s\n", leaks,
6185 + backend->acronym, (leaks > 1) ? "s" : "");
6186 + backend++;
6187 + }
6188 + /* Release any DMA regions */
6189 + spin_lock(&mem_lock);
6190 + list_for_each_entry_safe(map, tmpmap, &ctx->maps, list) {
6191 + struct mem_fragment *current_frag = map->root_frag;
6192 + int i;
6193 + if (map->root_frag->has_locking &&
6194 + (map->root_frag->owner == map)) {
6195 + map->root_frag->owner = NULL;
6196 + wake_up(&map->root_frag->wq);
6197 + }
6198 + /* Check each fragment and merge if the ref count is 0 */
6199 + for (i = 0; i < map->frag_count; i++) {
6200 + --current_frag->refs;
6201 + current_frag = list_entry(current_frag->list.prev,
6202 + struct mem_fragment, list);
6203 + }
6204 +
6205 + compress_frags();
6206 + list_del(&map->list);
6207 + kfree(map);
6208 + }
6209 + spin_unlock(&mem_lock);
6210 +
6211 + /* Return portals */
6212 + list_for_each_entry_safe(portal, tmpportal, &ctx->portals, list) {
6213 + if (portal->user.type == usdpaa_portal_qman) {
6214 + /* Give the portal back to the allocator */
6215 + init_qm_portal(portal->qportal,
6216 + &portal->qman_portal_low);
6217 + qm_put_unused_portal(portal->qportal);
6218 + } else {
6219 + init_bm_portal(portal->bportal,
6220 + &portal->bman_portal_low);
6221 + bm_put_unused_portal(portal->bportal);
6222 + }
6223 + list_del(&portal->list);
6224 + kfree(portal);
6225 + }
6226 + if (qm_alloced_portal) {
6227 + qm_put_unused_portal(qm_alloced_portal);
6228 + kfree(qm_cleanup_portal);
6229 + }
6230 + if (bm_alloced_portal) {
6231 + bm_put_unused_portal(bm_alloced_portal);
6232 + kfree(bm_cleanup_portal);
6233 + }
6234 +
6235 + kfree(ctx);
6236 +#ifdef CONFIG_PREEMPT_RT_FULL
6237 + migrate_enable();
6238 +#endif
6239 + return 0;
6240 +}
6241 +
6242 +static int check_mmap_dma(struct ctx *ctx, struct vm_area_struct *vma,
6243 + int *match, unsigned long *pfn)
6244 +{
6245 + struct mem_mapping *map;
6246 +
6247 + list_for_each_entry(map, &ctx->maps, list) {
6248 + int i;
6249 + struct mem_fragment *frag = map->root_frag;
6250 +
6251 + for (i = 0; i < map->frag_count; i++) {
6252 + if (frag->pfn_base == vma->vm_pgoff) {
6253 + *match = 1;
6254 + *pfn = frag->pfn_base;
6255 + return 0;
6256 + }
6257 + frag = list_entry(frag->list.next, struct mem_fragment,
6258 + list);
6259 + }
6260 + }
6261 + *match = 0;
6262 + return 0;
6263 +}
6264 +
6265 +static int check_mmap_resource(struct resource *res, struct vm_area_struct *vma,
6266 + int *match, unsigned long *pfn)
6267 +{
6268 + *pfn = res->start >> PAGE_SHIFT;
6269 + if (*pfn == vma->vm_pgoff) {
6270 + *match = 1;
6271 + if ((vma->vm_end - vma->vm_start) != resource_size(res))
6272 + return -EINVAL;
6273 + } else
6274 + *match = 0;
6275 + return 0;
6276 +}
6277 +
6278 +static int check_mmap_portal(struct ctx *ctx, struct vm_area_struct *vma,
6279 + int *match, unsigned long *pfn)
6280 +{
6281 + struct portal_mapping *portal;
6282 + int ret;
6283 +
6284 + list_for_each_entry(portal, &ctx->portals, list) {
6285 + ret = check_mmap_resource(&portal->phys[DPA_PORTAL_CE], vma,
6286 + match, pfn);
6287 + if (*match) {
6288 + vma->vm_page_prot =
6289 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
6290 + pgprot_cached_ns(vma->vm_page_prot);
6291 +#else
6292 + pgprot_cached_noncoherent(vma->vm_page_prot);
6293 +#endif
6294 + return ret;
6295 + }
6296 + ret = check_mmap_resource(&portal->phys[DPA_PORTAL_CI], vma,
6297 + match, pfn);
6298 + if (*match) {
6299 + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
6300 + return ret;
6301 + }
6302 + }
6303 + *match = 0;
6304 + return 0;
6305 +}
6306 +
6307 +static int usdpaa_mmap(struct file *filp, struct vm_area_struct *vma)
6308 +{
6309 + struct ctx *ctx = filp->private_data;
6310 + unsigned long pfn = 0;
6311 + int match, ret;
6312 +
6313 + spin_lock(&mem_lock);
6314 + ret = check_mmap_dma(ctx, vma, &match, &pfn);
6315 + if (!match)
6316 + ret = check_mmap_portal(ctx, vma, &match, &pfn);
6317 + spin_unlock(&mem_lock);
6318 + if (!match)
6319 + return -EINVAL;
6320 + if (!ret)
6321 + ret = remap_pfn_range(vma, vma->vm_start, pfn,
6322 + vma->vm_end - vma->vm_start,
6323 + vma->vm_page_prot);
6324 + return ret;
6325 +}
6326 +
6327 +/* Return the nearest rounded-up address >= 'addr' that is 'sz'-aligned. 'sz'
6328 + * must be a power of 2, but both 'addr' and 'sz' can be expressions. */
6329 +#define USDPAA_MEM_ROUNDUP(addr, sz) \
6330 + ({ \
6331 + unsigned long foo_align = (sz) - 1; \
6332 + ((addr) + foo_align) & ~foo_align; \
6333 + })
6334 +/* Searching for a size-aligned virtual address range starting from 'addr' */
6335 +static unsigned long usdpaa_get_unmapped_area(struct file *file,
6336 + unsigned long addr,
6337 + unsigned long len,
6338 + unsigned long pgoff,
6339 + unsigned long flags)
6340 +{
6341 + struct vm_area_struct *vma;
6342 +
6343 + if (len % PAGE_SIZE)
6344 + return -EINVAL;
6345 + if (!len)
6346 + return -EINVAL;
6347 +
6348 + /* Need to align the address to the largest pagesize of the mapping
6349 + * because the MMU requires the virtual address to have the same
6350 + * alignment as the physical address */
6351 + addr = USDPAA_MEM_ROUNDUP(addr, largest_page_size(len));
6352 + vma = find_vma(current->mm, addr);
6353 + /* Keep searching until we reach the end of currently-used virtual
6354 + * address-space or we find a big enough gap. */
6355 + while (vma) {
6356 + if ((addr + len) < vma->vm_start)
6357 + return addr;
6358 +
6359 + addr = USDPAA_MEM_ROUNDUP(vma->vm_end, largest_page_size(len));
6360 + vma = vma->vm_next;
6361 + }
6362 + if ((TASK_SIZE - len) < addr)
6363 + return -ENOMEM;
6364 + return addr;
6365 +}
6366 +
6367 +static long ioctl_id_alloc(struct ctx *ctx, void __user *arg)
6368 +{
6369 + struct usdpaa_ioctl_id_alloc i;
6370 + const struct alloc_backend *backend;
6371 + struct active_resource *res;
6372 + int ret = copy_from_user(&i, arg, sizeof(i));
6373 + if (ret)
6374 + return ret;
6375 + if ((i.id_type >= usdpaa_id_max) || !i.num)
6376 + return -EINVAL;
6377 + backend = &alloc_backends[i.id_type];
6378 + /* Allocate the required resource type */
6379 + ret = backend->alloc(&i.base, i.num, i.align, i.partial);
6380 + if (ret < 0)
6381 + return ret;
6382 + i.num = ret;
6383 + /* Copy the result to user-space */
6384 + ret = copy_to_user(arg, &i, sizeof(i));
6385 + if (ret) {
6386 + backend->release(i.base, i.num);
6387 + return ret;
6388 + }
6389 + /* Assign the allocated range to the FD accounting */
6390 + res = kmalloc(sizeof(*res), GFP_KERNEL);
6391 + if (!res) {
6392 + backend->release(i.base, i.num);
6393 + return -ENOMEM;
6394 + }
6395 + spin_lock(&ctx->lock);
6396 + res->id = i.base;
6397 + res->num = i.num;
6398 + res->refcount = 1;
6399 + list_add(&res->list, &ctx->resources[i.id_type]);
6400 + spin_unlock(&ctx->lock);
6401 + return 0;
6402 +}
6403 +
6404 +static long ioctl_id_release(struct ctx *ctx, void __user *arg)
6405 +{
6406 + struct usdpaa_ioctl_id_release i;
6407 + const struct alloc_backend *backend;
6408 + struct active_resource *tmp, *pos;
6409 +
6410 + int ret = copy_from_user(&i, arg, sizeof(i));
6411 + if (ret)
6412 + return ret;
6413 + if ((i.id_type >= usdpaa_id_max) || !i.num)
6414 + return -EINVAL;
6415 + backend = &alloc_backends[i.id_type];
6416 + /* Pull the range out of the FD accounting - the range is valid iff this
6417 + * succeeds. */
6418 + spin_lock(&ctx->lock);
6419 + list_for_each_entry_safe(pos, tmp, &ctx->resources[i.id_type], list) {
6420 + if (pos->id == i.base && pos->num == i.num) {
6421 + pos->refcount--;
6422 + if (pos->refcount) {
6423 + spin_unlock(&ctx->lock);
6424 + return 0; /* Still being used */
6425 + }
6426 + list_del(&pos->list);
6427 + kfree(pos);
6428 + spin_unlock(&ctx->lock);
6429 + goto found;
6430 + }
6431 + }
6432 + /* Failed to find the resource */
6433 + spin_unlock(&ctx->lock);
6434 + pr_err("Couldn't find resource type %d base 0x%x num %d\n",
6435 + i.id_type, i.base, i.num);
6436 + return -EINVAL;
6437 +found:
6438 + /* Release the resource to the backend */
6439 + backend->release(i.base, i.num);
6440 + return 0;
6441 +}
6442 +
6443 +static long ioctl_id_reserve(struct ctx *ctx, void __user *arg)
6444 +{
6445 + struct usdpaa_ioctl_id_reserve i;
6446 + const struct alloc_backend *backend;
6447 + struct active_resource *tmp, *pos;
6448 +
6449 + int ret = copy_from_user(&i, arg, sizeof(i));
6450 + if (ret)
6451 + return ret;
6452 + if ((i.id_type >= usdpaa_id_max) || !i.num)
6453 + return -EINVAL;
6454 + backend = &alloc_backends[i.id_type];
6455 + if (!backend->reserve)
6456 + return -EINVAL;
6457 + /* Pull the range out of the FD accounting - the range is valid iff this
6458 + * succeeds. */
6459 + spin_lock(&ctx->lock);
6460 + list_for_each_entry_safe(pos, tmp, &ctx->resources[i.id_type], list) {
6461 + if (pos->id == i.base && pos->num == i.num) {
6462 + pos->refcount++;
6463 + spin_unlock(&ctx->lock);
6464 + return 0;
6465 + }
6466 + }
6467 +
6468 + /* Failed to find the resource */
6469 + spin_unlock(&ctx->lock);
6470 +
6471 + /* Reserve the resource in the backend */
6472 + ret = backend->reserve(i.base, i.num);
6473 + if (ret)
6474 + return ret;
6475 + /* Assign the reserved range to the FD accounting */
6476 + pos = kmalloc(sizeof(*pos), GFP_KERNEL);
6477 + if (!pos) {
6478 + backend->release(i.base, i.num);
6479 + return -ENOMEM;
6480 + }
6481 + spin_lock(&ctx->lock);
6482 + pos->id = i.base;
6483 + pos->num = i.num;
6484 + pos->refcount = 1;
6485 + list_add(&pos->list, &ctx->resources[i.id_type]);
6486 + spin_unlock(&ctx->lock);
6487 + return 0;
6488 +}
6489 +
6490 +static long ioctl_dma_map(struct file *fp, struct ctx *ctx,
6491 + struct usdpaa_ioctl_dma_map *i)
6492 +{
6493 + struct mem_fragment *frag, *start_frag, *next_frag;
6494 + struct mem_mapping *map, *tmp;
6495 + int ret = 0;
6496 + u32 largest_page, so_far = 0;
6497 + int frag_count = 0;
6498 + unsigned long next_addr = PAGE_SIZE, populate;
6499 +
6500 + /* error checking to ensure values copied from user space are valid */
6501 + if (i->len % PAGE_SIZE)
6502 + return -EINVAL;
6503 +
6504 + map = kmalloc(sizeof(*map), GFP_KERNEL);
6505 + if (!map)
6506 + return -ENOMEM;
6507 +
6508 + spin_lock(&mem_lock);
6509 + if (i->flags & USDPAA_DMA_FLAG_SHARE) {
6510 + list_for_each_entry(frag, &mem_list, list) {
6511 + if (frag->refs && (frag->flags &
6512 + USDPAA_DMA_FLAG_SHARE) &&
6513 + !strncmp(i->name, frag->name,
6514 + USDPAA_DMA_NAME_MAX)) {
6515 + /* Matching entry */
6516 + if ((i->flags & USDPAA_DMA_FLAG_CREATE) &&
6517 + !(i->flags & USDPAA_DMA_FLAG_LAZY)) {
6518 + ret = -EBUSY;
6519 + goto out;
6520 + }
6521 +
6522 + /* Check to ensure size matches record */
6523 + if (i->len != frag->map_len && i->len) {
6524 + pr_err("ioctl_dma_map() Size requested does not match %s and is none zero. This usage will be disallowed in future release\n",
6525 + frag->name);
6526 + }
6527 +
6528 + /* Check if this has already been mapped
6529 + to this process */
6530 + list_for_each_entry(tmp, &ctx->maps, list)
6531 + if (tmp->root_frag == frag) {
6532 + /* Already mapped, just need to
6533 + inc ref count */
6534 + tmp->refs++;
6535 + kfree(map);
6536 + i->did_create = 0;
6537 + i->len = tmp->total_size;
6538 + i->phys_addr = frag->base;
6539 + i->ptr = tmp->virt_addr;
6540 + spin_unlock(&mem_lock);
6541 + return 0;
6542 + }
6543 + /* Matching entry - just need to map */
6544 + i->has_locking = frag->has_locking;
6545 + i->did_create = 0;
6546 + i->len = frag->map_len;
6547 + start_frag = frag;
6548 + goto do_map;
6549 + }
6550 + }
6551 + /* No matching entry */
6552 + if (!(i->flags & USDPAA_DMA_FLAG_CREATE)) {
6553 + pr_err("ioctl_dma_map() No matching entry\n");
6554 + ret = -ENOMEM;
6555 + goto out;
6556 + }
6557 + }
6558 + /* New fragment required, size must be provided. */
6559 + if (!i->len) {
6560 + ret = -EINVAL;
6561 + goto out;
6562 + }
6563 +
6564 + /* Find one of more contiguous fragments that satisfy the total length
6565 + trying to minimize the number of fragments
6566 + compute the largest page size that the allocation could use */
6567 + largest_page = largest_page_size(i->len);
6568 + start_frag = NULL;
6569 + while (largest_page &&
6570 + largest_page <= largest_page_size(phys_size) &&
6571 + start_frag == NULL) {
6572 + /* Search the list for a frag of that size */
6573 + list_for_each_entry(frag, &mem_list, list) {
6574 + if (!frag->refs && (frag->len == largest_page)) {
6575 + /* See if the next x fragments are free
6576 + and can accomidate the size */
6577 + u32 found_size = largest_page;
6578 + next_frag = list_entry(frag->list.prev,
6579 + struct mem_fragment,
6580 + list);
6581 + /* If the fragement is too small check
6582 + if the neighbours cab support it */
6583 + while (found_size < i->len) {
6584 + if (&mem_list == &next_frag->list)
6585 + break; /* End of list */
6586 + if (next_frag->refs != 0 ||
6587 + next_frag->len == 0)
6588 + break; /* not enough space */
6589 + found_size += next_frag->len;
6590 + next_frag = list_entry(
6591 + next_frag->list.prev,
6592 + struct mem_fragment,
6593 + list);
6594 + }
6595 + if (found_size >= i->len) {
6596 + /* Success! there is enough contigous
6597 + free space */
6598 + start_frag = frag;
6599 + break;
6600 + }
6601 + }
6602 + } /* next frag loop */
6603 + /* Couldn't statisfy the request with this
6604 + largest page size, try a smaller one */
6605 + largest_page <<= 2;
6606 + }
6607 + if (start_frag == NULL) {
6608 + /* Couldn't find proper amount of space */
6609 + ret = -ENOMEM;
6610 + goto out;
6611 + }
6612 + i->did_create = 1;
6613 +do_map:
6614 + /* Verify there is sufficient space to do the mapping */
6615 + down_write(&current->mm->mmap_sem);
6616 + next_addr = usdpaa_get_unmapped_area(fp, next_addr, i->len, 0, 0);
6617 + up_write(&current->mm->mmap_sem);
6618 +
6619 + if (next_addr & ~PAGE_MASK) {
6620 + ret = -ENOMEM;
6621 + goto out;
6622 + }
6623 +
6624 + /* We may need to divide the final fragment to accomidate the mapping */
6625 + next_frag = start_frag;
6626 + while (so_far != i->len) {
6627 + BUG_ON(next_frag->len == 0);
6628 + while ((next_frag->len + so_far) > i->len) {
6629 + /* Split frag until they match */
6630 + split_frag(next_frag);
6631 + }
6632 + so_far += next_frag->len;
6633 + next_frag->refs++;
6634 + ++frag_count;
6635 + next_frag = list_entry(next_frag->list.prev,
6636 + struct mem_fragment, list);
6637 + }
6638 + if (i->did_create) {
6639 + size_t name_len = 0;
6640 + start_frag->flags = i->flags;
6641 + strncpy(start_frag->name, i->name, USDPAA_DMA_NAME_MAX);
6642 + name_len = strnlen(start_frag->name, USDPAA_DMA_NAME_MAX);
6643 + if (name_len >= USDPAA_DMA_NAME_MAX) {
6644 + ret = -EFAULT;
6645 + goto out;
6646 + }
6647 + start_frag->map_len = i->len;
6648 + start_frag->has_locking = i->has_locking;
6649 + init_waitqueue_head(&start_frag->wq);
6650 + start_frag->owner = NULL;
6651 + }
6652 +
6653 + /* Setup the map entry */
6654 + map->root_frag = start_frag;
6655 + map->total_size = i->len;
6656 + map->frag_count = frag_count;
6657 + map->refs = 1;
6658 + list_add(&map->list, &ctx->maps);
6659 + i->phys_addr = start_frag->base;
6660 +out:
6661 + spin_unlock(&mem_lock);
6662 +
6663 + if (!ret) {
6664 + unsigned long longret;
6665 + down_write(&current->mm->mmap_sem);
6666 + longret = do_mmap_pgoff(fp, next_addr, map->total_size,
6667 + PROT_READ |
6668 + (i->flags &
6669 + USDPAA_DMA_FLAG_RDONLY ? 0
6670 + : PROT_WRITE),
6671 + MAP_SHARED,
6672 + start_frag->pfn_base,
6673 + &populate);
6674 + up_write(&current->mm->mmap_sem);
6675 + if (longret & ~PAGE_MASK) {
6676 + ret = (int)longret;
6677 + } else {
6678 + i->ptr = (void *)longret;
6679 + map->virt_addr = i->ptr;
6680 + }
6681 + } else
6682 + kfree(map);
6683 + return ret;
6684 +}
6685 +
6686 +static long ioctl_dma_unmap(struct ctx *ctx, void __user *arg)
6687 +{
6688 + struct mem_mapping *map;
6689 + struct vm_area_struct *vma;
6690 + int ret, i;
6691 + struct mem_fragment *current_frag;
6692 + size_t sz;
6693 + unsigned long base;
6694 + unsigned long vaddr;
6695 +
6696 + down_write(&current->mm->mmap_sem);
6697 + vma = find_vma(current->mm, (unsigned long)arg);
6698 + if (!vma || (vma->vm_start > (unsigned long)arg)) {
6699 + up_write(&current->mm->mmap_sem);
6700 + return -EFAULT;
6701 + }
6702 + spin_lock(&mem_lock);
6703 + list_for_each_entry(map, &ctx->maps, list) {
6704 + if (map->root_frag->pfn_base == vma->vm_pgoff) {
6705 + /* Drop the map lock if we hold it */
6706 + if (map->root_frag->has_locking &&
6707 + (map->root_frag->owner == map)) {
6708 + map->root_frag->owner = NULL;
6709 + wake_up(&map->root_frag->wq);
6710 + }
6711 + goto map_match;
6712 + }
6713 + }
6714 + /* Failed to find a matching mapping for this process */
6715 + ret = -EFAULT;
6716 + spin_unlock(&mem_lock);
6717 + goto out;
6718 +map_match:
6719 + map->refs--;
6720 + if (map->refs != 0) {
6721 + /* Another call the dma_map is referencing this */
6722 + ret = 0;
6723 + spin_unlock(&mem_lock);
6724 + goto out;
6725 + }
6726 +
6727 + current_frag = map->root_frag;
6728 + vaddr = (unsigned long) map->virt_addr;
6729 + for (i = 0; i < map->frag_count; i++) {
6730 + DPA_ASSERT(current_frag->refs > 0);
6731 + --current_frag->refs;
6732 +#if !(defined(CONFIG_ARM) || defined(CONFIG_ARM64))
6733 + /*
6734 + * Make sure we invalidate the TLB entry for
6735 + * this fragment, otherwise a remap of a different
6736 + * page to this vaddr would give acces to an
6737 + * incorrect piece of memory
6738 + */
6739 + cleartlbcam(vaddr, mfspr(SPRN_PID));
6740 +#endif
6741 + vaddr += current_frag->len;
6742 + current_frag = list_entry(current_frag->list.prev,
6743 + struct mem_fragment, list);
6744 + }
6745 + map->root_frag->name[0] = 0;
6746 + list_del(&map->list);
6747 + compress_frags();
6748 + spin_unlock(&mem_lock);
6749 +
6750 + base = vma->vm_start;
6751 + sz = vma->vm_end - vma->vm_start;
6752 + do_munmap(current->mm, base, sz);
6753 + ret = 0;
6754 + out:
6755 + up_write(&current->mm->mmap_sem);
6756 + return ret;
6757 +}
6758 +
6759 +static long ioctl_dma_stats(struct ctx *ctx, void __user *arg)
6760 +{
6761 + struct mem_fragment *frag;
6762 + struct usdpaa_ioctl_dma_used result;
6763 +
6764 + result.free_bytes = 0;
6765 + result.total_bytes = phys_size;
6766 +
6767 + list_for_each_entry(frag, &mem_list, list) {
6768 + if (frag->refs == 0)
6769 + result.free_bytes += frag->len;
6770 + }
6771 +
6772 + return copy_to_user(arg, &result, sizeof(result)); }
6773 +
6774 +static int test_lock(struct mem_mapping *map)
6775 +{
6776 + int ret = 0;
6777 + spin_lock(&mem_lock);
6778 + if (!map->root_frag->owner) {
6779 + map->root_frag->owner = map;
6780 + ret = 1;
6781 + }
6782 + spin_unlock(&mem_lock);
6783 + return ret;
6784 +}
6785 +
6786 +static long ioctl_dma_lock(struct ctx *ctx, void __user *arg)
6787 +{
6788 + struct mem_mapping *map;
6789 + struct vm_area_struct *vma;
6790 +
6791 + down_read(&current->mm->mmap_sem);
6792 + vma = find_vma(current->mm, (unsigned long)arg);
6793 + if (!vma || (vma->vm_start > (unsigned long)arg)) {
6794 + up_read(&current->mm->mmap_sem);
6795 + return -EFAULT;
6796 + }
6797 + spin_lock(&mem_lock);
6798 + list_for_each_entry(map, &ctx->maps, list) {
6799 + if (map->root_frag->pfn_base == vma->vm_pgoff)
6800 + goto map_match;
6801 + }
6802 + map = NULL;
6803 +map_match:
6804 + spin_unlock(&mem_lock);
6805 + up_read(&current->mm->mmap_sem);
6806 +
6807 + if (!map)
6808 + return -EFAULT;
6809 + if (!map->root_frag->has_locking)
6810 + return -ENODEV;
6811 + return wait_event_interruptible(map->root_frag->wq, test_lock(map));
6812 +}
6813 +
6814 +static long ioctl_dma_unlock(struct ctx *ctx, void __user *arg)
6815 +{
6816 + struct mem_mapping *map;
6817 + struct vm_area_struct *vma;
6818 + int ret;
6819 +
6820 + down_read(&current->mm->mmap_sem);
6821 + vma = find_vma(current->mm, (unsigned long)arg);
6822 + if (!vma || (vma->vm_start > (unsigned long)arg))
6823 + ret = -EFAULT;
6824 + else {
6825 + spin_lock(&mem_lock);
6826 + list_for_each_entry(map, &ctx->maps, list) {
6827 + if (map->root_frag->pfn_base == vma->vm_pgoff) {
6828 + if (!map->root_frag->has_locking)
6829 + ret = -ENODEV;
6830 + else if (map->root_frag->owner == map) {
6831 + map->root_frag->owner = NULL;
6832 + wake_up(&map->root_frag->wq);
6833 + ret = 0;
6834 + } else
6835 + ret = -EBUSY;
6836 + goto map_match;
6837 + }
6838 + }
6839 + ret = -EINVAL;
6840 +map_match:
6841 + spin_unlock(&mem_lock);
6842 + }
6843 + up_read(&current->mm->mmap_sem);
6844 + return ret;
6845 +}
6846 +
6847 +static int portal_mmap(struct file *fp, struct resource *res, void **ptr)
6848 +{
6849 + unsigned long longret = 0, populate;
6850 + resource_size_t len;
6851 +
6852 + down_write(&current->mm->mmap_sem);
6853 + len = resource_size(res);
6854 + if (len != (unsigned long)len)
6855 + return -EINVAL;
6856 + longret = do_mmap_pgoff(fp, PAGE_SIZE, (unsigned long)len,
6857 + PROT_READ | PROT_WRITE, MAP_SHARED,
6858 + res->start >> PAGE_SHIFT, &populate);
6859 + up_write(&current->mm->mmap_sem);
6860 +
6861 + if (longret & ~PAGE_MASK)
6862 + return (int)longret;
6863 +
6864 + *ptr = (void *) longret;
6865 + return 0;
6866 +}
6867 +
6868 +static void portal_munmap(struct resource *res, void *ptr)
6869 +{
6870 + down_write(&current->mm->mmap_sem);
6871 + do_munmap(current->mm, (unsigned long)ptr, resource_size(res));
6872 + up_write(&current->mm->mmap_sem);
6873 +}
6874 +
6875 +static long ioctl_portal_map(struct file *fp, struct ctx *ctx,
6876 + struct usdpaa_ioctl_portal_map *arg)
6877 +{
6878 + struct portal_mapping *mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
6879 + int ret;
6880 +
6881 + if (!mapping)
6882 + return -ENOMEM;
6883 +
6884 + mapping->user = *arg;
6885 + mapping->iommu_domain = NULL;
6886 +
6887 + if (mapping->user.type == usdpaa_portal_qman) {
6888 + mapping->qportal =
6889 + qm_get_unused_portal_idx(mapping->user.index);
6890 + if (!mapping->qportal) {
6891 + ret = -ENODEV;
6892 + goto err_get_portal;
6893 + }
6894 + mapping->phys = &mapping->qportal->addr_phys[0];
6895 + mapping->user.channel = mapping->qportal->public_cfg.channel;
6896 + mapping->user.pools = mapping->qportal->public_cfg.pools;
6897 + mapping->user.index = mapping->qportal->public_cfg.index;
6898 + } else if (mapping->user.type == usdpaa_portal_bman) {
6899 + mapping->bportal =
6900 + bm_get_unused_portal_idx(mapping->user.index);
6901 + if (!mapping->bportal) {
6902 + ret = -ENODEV;
6903 + goto err_get_portal;
6904 + }
6905 + mapping->phys = &mapping->bportal->addr_phys[0];
6906 + mapping->user.index = mapping->bportal->public_cfg.index;
6907 + } else {
6908 + ret = -EINVAL;
6909 + goto err_copy_from_user;
6910 + }
6911 + /* Need to put pcfg in ctx's list before the mmaps because the mmap
6912 + * handlers look it up. */
6913 + spin_lock(&mem_lock);
6914 + list_add(&mapping->list, &ctx->portals);
6915 + spin_unlock(&mem_lock);
6916 + ret = portal_mmap(fp, &mapping->phys[DPA_PORTAL_CE],
6917 + &mapping->user.addr.cena);
6918 + if (ret)
6919 + goto err_mmap_cena;
6920 + ret = portal_mmap(fp, &mapping->phys[DPA_PORTAL_CI],
6921 + &mapping->user.addr.cinh);
6922 + if (ret)
6923 + goto err_mmap_cinh;
6924 + *arg = mapping->user;
6925 + return ret;
6926 +
6927 +err_mmap_cinh:
6928 + portal_munmap(&mapping->phys[DPA_PORTAL_CE], mapping->user.addr.cena);
6929 +err_mmap_cena:
6930 + if ((mapping->user.type == usdpaa_portal_qman) && mapping->qportal)
6931 + qm_put_unused_portal(mapping->qportal);
6932 + else if ((mapping->user.type == usdpaa_portal_bman) && mapping->bportal)
6933 + bm_put_unused_portal(mapping->bportal);
6934 + spin_lock(&mem_lock);
6935 + list_del(&mapping->list);
6936 + spin_unlock(&mem_lock);
6937 +err_get_portal:
6938 +err_copy_from_user:
6939 + kfree(mapping);
6940 + return ret;
6941 +}
6942 +
6943 +static long ioctl_portal_unmap(struct ctx *ctx, struct usdpaa_portal_map *i)
6944 +{
6945 + struct portal_mapping *mapping;
6946 + struct vm_area_struct *vma;
6947 + unsigned long pfn;
6948 + u32 channel;
6949 +
6950 + /* Get the PFN corresponding to one of the virt addresses */
6951 + down_read(&current->mm->mmap_sem);
6952 + vma = find_vma(current->mm, (unsigned long)i->cinh);
6953 + if (!vma || (vma->vm_start > (unsigned long)i->cinh)) {
6954 + up_read(&current->mm->mmap_sem);
6955 + return -EFAULT;
6956 + }
6957 + pfn = vma->vm_pgoff;
6958 + up_read(&current->mm->mmap_sem);
6959 +
6960 + /* Find the corresponding portal */
6961 + spin_lock(&mem_lock);
6962 + list_for_each_entry(mapping, &ctx->portals, list) {
6963 + if (pfn == (mapping->phys[DPA_PORTAL_CI].start >> PAGE_SHIFT))
6964 + goto found;
6965 + }
6966 + mapping = NULL;
6967 +found:
6968 + if (mapping)
6969 + list_del(&mapping->list);
6970 + spin_unlock(&mem_lock);
6971 + if (!mapping)
6972 + return -ENODEV;
6973 + portal_munmap(&mapping->phys[DPA_PORTAL_CI], mapping->user.addr.cinh);
6974 + portal_munmap(&mapping->phys[DPA_PORTAL_CE], mapping->user.addr.cena);
6975 + if (mapping->user.type == usdpaa_portal_qman) {
6976 + init_qm_portal(mapping->qportal,
6977 + &mapping->qman_portal_low);
6978 +
6979 + /* Tear down any FQs this portal is referencing */
6980 + channel = mapping->qportal->public_cfg.channel;
6981 + qm_check_and_destroy_fqs(&mapping->qman_portal_low,
6982 + &channel,
6983 + check_portal_channel);
6984 + qm_put_unused_portal(mapping->qportal);
6985 + } else if (mapping->user.type == usdpaa_portal_bman) {
6986 + init_bm_portal(mapping->bportal,
6987 + &mapping->bman_portal_low);
6988 + bm_put_unused_portal(mapping->bportal);
6989 + }
6990 + kfree(mapping);
6991 + return 0;
6992 +}
6993 +
6994 +static void portal_config_pamu(struct qm_portal_config *pcfg, uint8_t sdest,
6995 + uint32_t cpu, uint32_t cache, uint32_t window)
6996 +{
6997 +#ifdef CONFIG_FSL_PAMU
6998 + int ret;
6999 + int window_count = 1;
7000 + struct iommu_domain_geometry geom_attr;
7001 + struct pamu_stash_attribute stash_attr;
7002 +
7003 + pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
7004 + if (!pcfg->iommu_domain) {
7005 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed",
7006 + __func__);
7007 + goto _no_iommu;
7008 + }
7009 + geom_attr.aperture_start = 0;
7010 + geom_attr.aperture_end =
7011 + ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1;
7012 + geom_attr.force_aperture = true;
7013 + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY,
7014 + &geom_attr);
7015 + if (ret < 0) {
7016 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
7017 + __func__, ret);
7018 + goto _iommu_domain_free;
7019 + }
7020 + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS,
7021 + &window_count);
7022 + if (ret < 0) {
7023 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
7024 + __func__, ret);
7025 + goto _iommu_domain_free;
7026 + }
7027 + stash_attr.cpu = cpu;
7028 + stash_attr.cache = cache;
7029 + /* set stash information for the window */
7030 + stash_attr.window = 0;
7031 +
7032 + ret = iommu_domain_set_attr(pcfg->iommu_domain,
7033 + DOMAIN_ATTR_FSL_PAMU_STASH,
7034 + &stash_attr);
7035 + if (ret < 0) {
7036 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
7037 + __func__, ret);
7038 + goto _iommu_domain_free;
7039 + }
7040 + ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36,
7041 + IOMMU_READ | IOMMU_WRITE);
7042 + if (ret < 0) {
7043 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d",
7044 + __func__, ret);
7045 + goto _iommu_domain_free;
7046 + }
7047 + ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev);
7048 + if (ret < 0) {
7049 + pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d",
7050 + __func__, ret);
7051 + goto _iommu_domain_free;
7052 + }
7053 + ret = iommu_domain_set_attr(pcfg->iommu_domain,
7054 + DOMAIN_ATTR_FSL_PAMU_ENABLE,
7055 + &window_count);
7056 + if (ret < 0) {
7057 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
7058 + __func__, ret);
7059 + goto _iommu_detach_device;
7060 + }
7061 +_no_iommu:
7062 +#endif
7063 +
7064 +#ifdef CONFIG_FSL_QMAN_CONFIG
7065 + if (qman_set_sdest(pcfg->public_cfg.channel, sdest))
7066 +#endif
7067 + pr_warn("Failed to set QMan portal's stash request queue\n");
7068 +
7069 + return;
7070 +
7071 +#ifdef CONFIG_FSL_PAMU
7072 +_iommu_detach_device:
7073 + iommu_detach_device(pcfg->iommu_domain, NULL);
7074 +_iommu_domain_free:
7075 + iommu_domain_free(pcfg->iommu_domain);
7076 +#endif
7077 +}
7078 +
7079 +static long ioctl_allocate_raw_portal(struct file *fp, struct ctx *ctx,
7080 + struct usdpaa_ioctl_raw_portal *arg)
7081 +{
7082 + struct portal_mapping *mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
7083 + int ret;
7084 +
7085 + if (!mapping)
7086 + return -ENOMEM;
7087 +
7088 + mapping->user.type = arg->type;
7089 + mapping->iommu_domain = NULL;
7090 + if (arg->type == usdpaa_portal_qman) {
7091 + mapping->qportal = qm_get_unused_portal_idx(arg->index);
7092 + if (!mapping->qportal) {
7093 + ret = -ENODEV;
7094 + goto err;
7095 + }
7096 + mapping->phys = &mapping->qportal->addr_phys[0];
7097 + arg->index = mapping->qportal->public_cfg.index;
7098 + arg->cinh = mapping->qportal->addr_phys[DPA_PORTAL_CI].start;
7099 + arg->cena = mapping->qportal->addr_phys[DPA_PORTAL_CE].start;
7100 + if (arg->enable_stash) {
7101 + /* Setup the PAMU with the supplied parameters */
7102 + portal_config_pamu(mapping->qportal, arg->sdest,
7103 + arg->cpu, arg->cache, arg->window);
7104 + }
7105 + } else if (mapping->user.type == usdpaa_portal_bman) {
7106 + mapping->bportal =
7107 + bm_get_unused_portal_idx(arg->index);
7108 + if (!mapping->bportal) {
7109 + ret = -ENODEV;
7110 + goto err;
7111 + }
7112 + mapping->phys = &mapping->bportal->addr_phys[0];
7113 + arg->index = mapping->bportal->public_cfg.index;
7114 + arg->cinh = mapping->bportal->addr_phys[DPA_PORTAL_CI].start;
7115 + arg->cena = mapping->bportal->addr_phys[DPA_PORTAL_CE].start;
7116 + } else {
7117 + ret = -EINVAL;
7118 + goto err;
7119 + }
7120 + /* Need to put pcfg in ctx's list before the mmaps because the mmap
7121 + * handlers look it up. */
7122 + spin_lock(&mem_lock);
7123 + list_add(&mapping->list, &ctx->portals);
7124 + spin_unlock(&mem_lock);
7125 + return 0;
7126 +err:
7127 + kfree(mapping);
7128 + return ret;
7129 +}
7130 +
7131 +static long ioctl_free_raw_portal(struct file *fp, struct ctx *ctx,
7132 + struct usdpaa_ioctl_raw_portal *arg)
7133 +{
7134 + struct portal_mapping *mapping;
7135 + u32 channel;
7136 +
7137 + /* Find the corresponding portal */
7138 + spin_lock(&mem_lock);
7139 + list_for_each_entry(mapping, &ctx->portals, list) {
7140 + if (mapping->phys[DPA_PORTAL_CI].start == arg->cinh)
7141 + goto found;
7142 + }
7143 + mapping = NULL;
7144 +found:
7145 + if (mapping)
7146 + list_del(&mapping->list);
7147 + spin_unlock(&mem_lock);
7148 + if (!mapping)
7149 + return -ENODEV;
7150 + if (mapping->user.type == usdpaa_portal_qman) {
7151 + init_qm_portal(mapping->qportal,
7152 + &mapping->qman_portal_low);
7153 +
7154 + /* Tear down any FQs this portal is referencing */
7155 + channel = mapping->qportal->public_cfg.channel;
7156 + qm_check_and_destroy_fqs(&mapping->qman_portal_low,
7157 + &channel,
7158 + check_portal_channel);
7159 + qm_put_unused_portal(mapping->qportal);
7160 + } else if (mapping->user.type == usdpaa_portal_bman) {
7161 + init_bm_portal(mapping->bportal,
7162 + &mapping->bman_portal_low);
7163 + bm_put_unused_portal(mapping->bportal);
7164 + }
7165 + kfree(mapping);
7166 + return 0;
7167 +}
7168 +
7169 +static long usdpaa_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
7170 +{
7171 + struct ctx *ctx = fp->private_data;
7172 + void __user *a = (void __user *)arg;
7173 + switch (cmd) {
7174 + case USDPAA_IOCTL_ID_ALLOC:
7175 + return ioctl_id_alloc(ctx, a);
7176 + case USDPAA_IOCTL_ID_RELEASE:
7177 + return ioctl_id_release(ctx, a);
7178 + case USDPAA_IOCTL_ID_RESERVE:
7179 + return ioctl_id_reserve(ctx, a);
7180 + case USDPAA_IOCTL_DMA_MAP:
7181 + {
7182 + struct usdpaa_ioctl_dma_map input;
7183 + int ret;
7184 + if (copy_from_user(&input, a, sizeof(input)))
7185 + return -EFAULT;
7186 + ret = ioctl_dma_map(fp, ctx, &input);
7187 + if (copy_to_user(a, &input, sizeof(input)))
7188 + return -EFAULT;
7189 + return ret;
7190 + }
7191 + case USDPAA_IOCTL_DMA_UNMAP:
7192 + return ioctl_dma_unmap(ctx, a);
7193 + case USDPAA_IOCTL_DMA_LOCK:
7194 + return ioctl_dma_lock(ctx, a);
7195 + case USDPAA_IOCTL_DMA_UNLOCK:
7196 + return ioctl_dma_unlock(ctx, a);
7197 + case USDPAA_IOCTL_PORTAL_MAP:
7198 + {
7199 + struct usdpaa_ioctl_portal_map input;
7200 + int ret;
7201 + if (copy_from_user(&input, a, sizeof(input)))
7202 + return -EFAULT;
7203 + ret = ioctl_portal_map(fp, ctx, &input);
7204 + if (copy_to_user(a, &input, sizeof(input)))
7205 + return -EFAULT;
7206 + return ret;
7207 + }
7208 + case USDPAA_IOCTL_PORTAL_UNMAP:
7209 + {
7210 + struct usdpaa_portal_map input;
7211 + if (copy_from_user(&input, a, sizeof(input)))
7212 + return -EFAULT;
7213 + return ioctl_portal_unmap(ctx, &input);
7214 + }
7215 + case USDPAA_IOCTL_DMA_USED:
7216 + return ioctl_dma_stats(ctx, a);
7217 + case USDPAA_IOCTL_ALLOC_RAW_PORTAL:
7218 + {
7219 + struct usdpaa_ioctl_raw_portal input;
7220 + int ret;
7221 + if (copy_from_user(&input, a, sizeof(input)))
7222 + return -EFAULT;
7223 + ret = ioctl_allocate_raw_portal(fp, ctx, &input);
7224 + if (copy_to_user(a, &input, sizeof(input)))
7225 + return -EFAULT;
7226 + return ret;
7227 + }
7228 + case USDPAA_IOCTL_FREE_RAW_PORTAL:
7229 + {
7230 + struct usdpaa_ioctl_raw_portal input;
7231 + if (copy_from_user(&input, a, sizeof(input)))
7232 + return -EFAULT;
7233 + return ioctl_free_raw_portal(fp, ctx, &input);
7234 + }
7235 + }
7236 + return -EINVAL;
7237 +}
7238 +
7239 +static long usdpaa_ioctl_compat(struct file *fp, unsigned int cmd,
7240 + unsigned long arg)
7241 +{
7242 +#ifdef CONFIG_COMPAT
7243 + struct ctx *ctx = fp->private_data;
7244 + void __user *a = (void __user *)arg;
7245 +#endif
7246 + switch (cmd) {
7247 +#ifdef CONFIG_COMPAT
7248 + case USDPAA_IOCTL_DMA_MAP_COMPAT:
7249 + {
7250 + int ret;
7251 + struct usdpaa_ioctl_dma_map_compat input;
7252 + struct usdpaa_ioctl_dma_map converted;
7253 +
7254 + if (copy_from_user(&input, a, sizeof(input)))
7255 + return -EFAULT;
7256 +
7257 + converted.ptr = compat_ptr(input.ptr);
7258 + converted.phys_addr = input.phys_addr;
7259 + converted.len = input.len;
7260 + converted.flags = input.flags;
7261 + strncpy(converted.name, input.name, USDPAA_DMA_NAME_MAX);
7262 + converted.has_locking = input.has_locking;
7263 + converted.did_create = input.did_create;
7264 +
7265 + ret = ioctl_dma_map(fp, ctx, &converted);
7266 + input.ptr = ptr_to_compat(converted.ptr);
7267 + input.phys_addr = converted.phys_addr;
7268 + input.len = converted.len;
7269 + input.flags = converted.flags;
7270 + strncpy(input.name, converted.name, USDPAA_DMA_NAME_MAX);
7271 + input.has_locking = converted.has_locking;
7272 + input.did_create = converted.did_create;
7273 + if (copy_to_user(a, &input, sizeof(input)))
7274 + return -EFAULT;
7275 + return ret;
7276 + }
7277 + case USDPAA_IOCTL_PORTAL_MAP_COMPAT:
7278 + {
7279 + int ret;
7280 + struct compat_usdpaa_ioctl_portal_map input;
7281 + struct usdpaa_ioctl_portal_map converted;
7282 + if (copy_from_user(&input, a, sizeof(input)))
7283 + return -EFAULT;
7284 + converted.type = input.type;
7285 + converted.index = input.index;
7286 + ret = ioctl_portal_map(fp, ctx, &converted);
7287 + input.addr.cinh = ptr_to_compat(converted.addr.cinh);
7288 + input.addr.cena = ptr_to_compat(converted.addr.cena);
7289 + input.channel = converted.channel;
7290 + input.pools = converted.pools;
7291 + input.index = converted.index;
7292 + if (copy_to_user(a, &input, sizeof(input)))
7293 + return -EFAULT;
7294 + return ret;
7295 + }
7296 + case USDPAA_IOCTL_PORTAL_UNMAP_COMPAT:
7297 + {
7298 + struct usdpaa_portal_map_compat input;
7299 + struct usdpaa_portal_map converted;
7300 +
7301 + if (copy_from_user(&input, a, sizeof(input)))
7302 + return -EFAULT;
7303 + converted.cinh = compat_ptr(input.cinh);
7304 + converted.cena = compat_ptr(input.cena);
7305 + return ioctl_portal_unmap(ctx, &converted);
7306 + }
7307 + case USDPAA_IOCTL_ALLOC_RAW_PORTAL_COMPAT:
7308 + {
7309 + int ret;
7310 + struct usdpaa_ioctl_raw_portal converted;
7311 + struct compat_ioctl_raw_portal input;
7312 + if (copy_from_user(&input, a, sizeof(input)))
7313 + return -EFAULT;
7314 + converted.type = input.type;
7315 + converted.index = input.index;
7316 + converted.enable_stash = input.enable_stash;
7317 + converted.cpu = input.cpu;
7318 + converted.cache = input.cache;
7319 + converted.window = input.window;
7320 + converted.sdest = input.sdest;
7321 + ret = ioctl_allocate_raw_portal(fp, ctx, &converted);
7322 +
7323 + input.cinh = converted.cinh;
7324 + input.cena = converted.cena;
7325 + input.index = converted.index;
7326 +
7327 + if (copy_to_user(a, &input, sizeof(input)))
7328 + return -EFAULT;
7329 + return ret;
7330 + }
7331 + case USDPAA_IOCTL_FREE_RAW_PORTAL_COMPAT:
7332 + {
7333 + struct usdpaa_ioctl_raw_portal converted;
7334 + struct compat_ioctl_raw_portal input;
7335 + if (copy_from_user(&input, a, sizeof(input)))
7336 + return -EFAULT;
7337 + converted.type = input.type;
7338 + converted.index = input.index;
7339 + converted.cinh = input.cinh;
7340 + converted.cena = input.cena;
7341 + return ioctl_free_raw_portal(fp, ctx, &converted);
7342 + }
7343 +#endif
7344 + default:
7345 + return usdpaa_ioctl(fp, cmd, arg);
7346 + }
7347 + return -EINVAL;
7348 +}
7349 +
7350 +int usdpaa_get_portal_config(struct file *filp, void *cinh,
7351 + enum usdpaa_portal_type ptype, unsigned int *irq,
7352 + void **iir_reg)
7353 +{
7354 + /* Walk the list of portals for filp and return the config
7355 + for the portal that matches the hint */
7356 + struct ctx *context;
7357 + struct portal_mapping *portal;
7358 +
7359 + /* First sanitize the filp */
7360 + if (filp->f_op->open != usdpaa_open)
7361 + return -ENODEV;
7362 + context = filp->private_data;
7363 + spin_lock(&context->lock);
7364 + list_for_each_entry(portal, &context->portals, list) {
7365 + if (portal->user.type == ptype &&
7366 + portal->user.addr.cinh == cinh) {
7367 + if (ptype == usdpaa_portal_qman) {
7368 + *irq = portal->qportal->public_cfg.irq;
7369 + *iir_reg = portal->qportal->addr_virt[1] +
7370 + QM_REG_IIR;
7371 + } else {
7372 + *irq = portal->bportal->public_cfg.irq;
7373 + *iir_reg = portal->bportal->addr_virt[1] +
7374 + BM_REG_IIR;
7375 + }
7376 + spin_unlock(&context->lock);
7377 + return 0;
7378 + }
7379 + }
7380 + spin_unlock(&context->lock);
7381 + return -EINVAL;
7382 +}
7383 +
7384 +static const struct file_operations usdpaa_fops = {
7385 + .open = usdpaa_open,
7386 + .release = usdpaa_release,
7387 + .mmap = usdpaa_mmap,
7388 + .get_unmapped_area = usdpaa_get_unmapped_area,
7389 + .unlocked_ioctl = usdpaa_ioctl,
7390 + .compat_ioctl = usdpaa_ioctl_compat
7391 +};
7392 +
7393 +static struct miscdevice usdpaa_miscdev = {
7394 + .name = "fsl-usdpaa",
7395 + .fops = &usdpaa_fops,
7396 + .minor = MISC_DYNAMIC_MINOR,
7397 +};
7398 +
7399 +/* Early-boot memory allocation. The boot-arg "usdpaa_mem=<x>" is used to
7400 + * indicate how much memory (if any) to allocate during early boot. If the
7401 + * format "usdpaa_mem=<x>,<y>" is used, then <y> will be interpreted as the
7402 + * number of TLB1 entries to reserve (default is 1). If there are more mappings
7403 + * than there are TLB1 entries, fault-handling will occur. */
7404 +
7405 +static __init int usdpaa_mem(char *arg)
7406 +{
7407 + pr_warn("uspdaa_mem argument is depracated\n");
7408 + arg_phys_size = memparse(arg, &arg);
7409 + num_tlb = 1;
7410 + if (*arg == ',') {
7411 + unsigned long ul;
7412 + int err = kstrtoul(arg + 1, 0, &ul);
7413 + if (err < 0) {
7414 + num_tlb = 1;
7415 + pr_warn("ERROR, usdpaa_mem arg is invalid\n");
7416 + } else
7417 + num_tlb = (unsigned int)ul;
7418 + }
7419 + return 0;
7420 +}
7421 +early_param("usdpaa_mem", usdpaa_mem);
7422 +
7423 +static int usdpaa_mem_init(struct reserved_mem *rmem)
7424 +{
7425 + phys_start = rmem->base;
7426 + phys_size = rmem->size;
7427 +
7428 + WARN_ON(!(phys_start && phys_size));
7429 +
7430 + return 0;
7431 +}
7432 +RESERVEDMEM_OF_DECLARE(usdpaa_mem_init, "fsl,usdpaa-mem", usdpaa_mem_init);
7433 +
7434 +__init int fsl_usdpaa_init_early(void)
7435 +{
7436 + if (!phys_size || !phys_start) {
7437 + pr_info("No USDPAA memory, no 'fsl,usdpaa-mem' in device-tree\n");
7438 + return 0;
7439 + }
7440 + if (phys_size % PAGE_SIZE) {
7441 + pr_err("'fsl,usdpaa-mem' size must be a multiple of page size\n");
7442 + phys_size = 0;
7443 + return 0;
7444 + }
7445 + if (arg_phys_size && phys_size != arg_phys_size) {
7446 + pr_err("'usdpaa_mem argument size (0x%llx) does not match device tree size (0x%llx)\n",
7447 + arg_phys_size, phys_size);
7448 + phys_size = 0;
7449 + return 0;
7450 + }
7451 + pfn_start = phys_start >> PAGE_SHIFT;
7452 + pfn_size = phys_size >> PAGE_SHIFT;
7453 +#ifdef CONFIG_PPC
7454 + first_tlb = current_tlb = tlbcam_index;
7455 + tlbcam_index += num_tlb;
7456 +#endif
7457 + pr_info("USDPAA region at %llx:%llx(%lx:%lx), %d TLB1 entries)\n",
7458 + phys_start, phys_size, pfn_start, pfn_size, num_tlb);
7459 + return 0;
7460 +}
7461 +subsys_initcall(fsl_usdpaa_init_early);
7462 +
7463 +
7464 +static int __init usdpaa_init(void)
7465 +{
7466 + struct mem_fragment *frag;
7467 + int ret;
7468 + u64 tmp_size = phys_size;
7469 + u64 tmp_start = phys_start;
7470 + u64 tmp_pfn_size = pfn_size;
7471 + u64 tmp_pfn_start = pfn_start;
7472 +
7473 + pr_info("Freescale USDPAA process driver\n");
7474 + if (!phys_start) {
7475 + pr_warn("fsl-usdpaa: no region found\n");
7476 + return 0;
7477 + }
7478 +
7479 + while (tmp_size != 0) {
7480 + u32 frag_size = largest_page_size(tmp_size);
7481 + frag = kmalloc(sizeof(*frag), GFP_KERNEL);
7482 + if (!frag) {
7483 + pr_err("Failed to setup USDPAA memory accounting\n");
7484 + return -ENOMEM;
7485 + }
7486 + frag->base = tmp_start;
7487 + frag->len = frag->root_len = frag_size;
7488 + frag->root_pfn = tmp_pfn_start;
7489 + frag->pfn_base = tmp_pfn_start;
7490 + frag->pfn_len = frag_size / PAGE_SIZE;
7491 + frag->refs = 0;
7492 + init_waitqueue_head(&frag->wq);
7493 + frag->owner = NULL;
7494 + list_add(&frag->list, &mem_list);
7495 +
7496 + /* Adjust for this frag */
7497 + tmp_start += frag_size;
7498 + tmp_size -= frag_size;
7499 + tmp_pfn_start += frag_size / PAGE_SIZE;
7500 + tmp_pfn_size -= frag_size / PAGE_SIZE;
7501 + }
7502 + ret = misc_register(&usdpaa_miscdev);
7503 + if (ret)
7504 + pr_err("fsl-usdpaa: failed to register misc device\n");
7505 + return ret;
7506 +}
7507 +
7508 +static void __exit usdpaa_exit(void)
7509 +{
7510 + misc_deregister(&usdpaa_miscdev);
7511 +}
7512 +
7513 +module_init(usdpaa_init);
7514 +module_exit(usdpaa_exit);
7515 +
7516 +MODULE_LICENSE("GPL");
7517 +MODULE_AUTHOR("Freescale Semiconductor");
7518 +MODULE_DESCRIPTION("Freescale USDPAA process driver");
7519 --- /dev/null
7520 +++ b/drivers/staging/fsl_qbman/fsl_usdpaa_irq.c
7521 @@ -0,0 +1,289 @@
7522 +/* Copyright (c) 2013 Freescale Semiconductor, Inc.
7523 + * All rights reserved.
7524 + *
7525 + * Redistribution and use in source and binary forms, with or without
7526 + * modification, are permitted provided that the following conditions are met:
7527 + * * Redistributions of source code must retain the above copyright
7528 + * notice, this list of conditions and the following disclaimer.
7529 + * * Redistributions in binary form must reproduce the above copyright
7530 + * notice, this list of conditions and the following disclaimer in the
7531 + * documentation and/or other materials provided with the distribution.
7532 + * * Neither the name of Freescale Semiconductor nor the
7533 + * names of its contributors may be used to endorse or promote products
7534 + * derived from this software without specific prior written permission.
7535 + *
7536 + *
7537 + * ALTERNATIVELY, this software may be distributed under the terms of the
7538 + * GNU General Public License ("GPL") as published by the Free Software
7539 + * Foundation, either version 2 of that License or (at your option) any
7540 + * later version.
7541 + *
7542 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
7543 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7544 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7545 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
7546 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7547 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7548 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
7549 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7550 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
7551 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7552 + */
7553 +
7554 +/* define a device that allows USPDAA processes to open a file
7555 + descriptor and specify which IRQ it wants to montior using an ioctl()
7556 + When an IRQ is received, the device becomes readable so that a process
7557 + can use read() or select() type calls to monitor for IRQs */
7558 +
7559 +#include <linux/miscdevice.h>
7560 +#include <linux/fs.h>
7561 +#include <linux/cdev.h>
7562 +#include <linux/slab.h>
7563 +#include <linux/interrupt.h>
7564 +#include <linux/poll.h>
7565 +#include <linux/uaccess.h>
7566 +#include <linux/fsl_usdpaa.h>
7567 +#include <linux/module.h>
7568 +#include <linux/fdtable.h>
7569 +#include <linux/file.h>
7570 +
7571 +#include "qman_low.h"
7572 +#include "bman_low.h"
7573 +
7574 +struct usdpaa_irq_ctx {
7575 + int irq_set; /* Set to true once the irq is set via ioctl */
7576 + unsigned int irq_num;
7577 + u32 last_irq_count; /* Last value returned from read */
7578 + u32 irq_count; /* Number of irqs since last read */
7579 + wait_queue_head_t wait_queue; /* Waiting processes */
7580 + spinlock_t lock;
7581 + void *inhibit_addr; /* inhibit register address */
7582 + struct file *usdpaa_filp;
7583 + char irq_name[128];
7584 +};
7585 +
7586 +static int usdpaa_irq_open(struct inode *inode, struct file *filp)
7587 +{
7588 + struct usdpaa_irq_ctx *ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
7589 + if (!ctx)
7590 + return -ENOMEM;
7591 + ctx->irq_set = 0;
7592 + ctx->irq_count = 0;
7593 + ctx->last_irq_count = 0;
7594 + init_waitqueue_head(&ctx->wait_queue);
7595 + spin_lock_init(&ctx->lock);
7596 + filp->private_data = ctx;
7597 + return 0;
7598 +}
7599 +
7600 +static int usdpaa_irq_release(struct inode *inode, struct file *filp)
7601 +{
7602 + struct usdpaa_irq_ctx *ctx = filp->private_data;
7603 + if (ctx->irq_set) {
7604 + /* Inhibit the IRQ */
7605 + out_be32(ctx->inhibit_addr, 0x1);
7606 + irq_set_affinity_hint(ctx->irq_num, NULL);
7607 + free_irq(ctx->irq_num, ctx);
7608 + ctx->irq_set = 0;
7609 + fput(ctx->usdpaa_filp);
7610 + }
7611 + kfree(filp->private_data);
7612 + return 0;
7613 +}
7614 +
7615 +static irqreturn_t usdpaa_irq_handler(int irq, void *_ctx)
7616 +{
7617 + unsigned long flags;
7618 + struct usdpaa_irq_ctx *ctx = _ctx;
7619 + spin_lock_irqsave(&ctx->lock, flags);
7620 + ++ctx->irq_count;
7621 + spin_unlock_irqrestore(&ctx->lock, flags);
7622 + wake_up_all(&ctx->wait_queue);
7623 + /* Set the inhibit register. This will be reenabled
7624 + once the USDPAA code handles the IRQ */
7625 + out_be32(ctx->inhibit_addr, 0x1);
7626 + pr_info("Inhibit at %p count %d", ctx->inhibit_addr, ctx->irq_count);
7627 + return IRQ_HANDLED;
7628 +}
7629 +
7630 +static int map_irq(struct file *fp, struct usdpaa_ioctl_irq_map *irq_map)
7631 +{
7632 + struct usdpaa_irq_ctx *ctx = fp->private_data;
7633 + int ret;
7634 +
7635 + if (ctx->irq_set) {
7636 + pr_debug("Setting USDPAA IRQ when it was already set!\n");
7637 + return -EBUSY;
7638 + }
7639 +
7640 + ctx->usdpaa_filp = fget(irq_map->fd);
7641 + if (!ctx->usdpaa_filp) {
7642 + pr_debug("USDPAA fget(%d) returned NULL\n", irq_map->fd);
7643 + return -EINVAL;
7644 + }
7645 +
7646 + ret = usdpaa_get_portal_config(ctx->usdpaa_filp, irq_map->portal_cinh,
7647 + irq_map->type, &ctx->irq_num,
7648 + &ctx->inhibit_addr);
7649 + if (ret) {
7650 + pr_debug("USDPAA IRQ couldn't identify portal\n");
7651 + fput(ctx->usdpaa_filp);
7652 + return ret;
7653 + }
7654 +
7655 + ctx->irq_set = 1;
7656 +
7657 + snprintf(ctx->irq_name, sizeof(ctx->irq_name),
7658 + "usdpaa_irq %d", ctx->irq_num);
7659 +
7660 + ret = request_irq(ctx->irq_num, usdpaa_irq_handler, 0,
7661 + ctx->irq_name, ctx);
7662 + if (ret) {
7663 + pr_err("USDPAA request_irq(%d) failed, ret= %d\n",
7664 + ctx->irq_num, ret);
7665 + ctx->irq_set = 0;
7666 + fput(ctx->usdpaa_filp);
7667 + return ret;
7668 + }
7669 + ret = irq_set_affinity(ctx->irq_num, tsk_cpus_allowed(current));
7670 + if (ret)
7671 + pr_err("USDPAA irq_set_affinity() failed, ret= %d\n", ret);
7672 +
7673 + ret = irq_set_affinity_hint(ctx->irq_num, tsk_cpus_allowed(current));
7674 + if (ret)
7675 + pr_err("USDPAA irq_set_affinity_hint() failed, ret= %d\n", ret);
7676 +
7677 + return 0;
7678 +}
7679 +
7680 +static long usdpaa_irq_ioctl(struct file *fp, unsigned int cmd,
7681 + unsigned long arg)
7682 +{
7683 + int ret;
7684 + struct usdpaa_ioctl_irq_map irq_map;
7685 +
7686 + if (cmd != USDPAA_IOCTL_PORTAL_IRQ_MAP) {
7687 + pr_debug("USDPAA IRQ unknown command 0x%x\n", cmd);
7688 + return -EINVAL;
7689 + }
7690 +
7691 + ret = copy_from_user(&irq_map, (void __user *)arg,
7692 + sizeof(irq_map));
7693 + if (ret)
7694 + return ret;
7695 + return map_irq(fp, &irq_map);
7696 +}
7697 +
7698 +static ssize_t usdpaa_irq_read(struct file *filp, char __user *buff,
7699 + size_t count, loff_t *offp)
7700 +{
7701 + struct usdpaa_irq_ctx *ctx = filp->private_data;
7702 + int ret;
7703 +
7704 + if (!ctx->irq_set) {
7705 + pr_debug("Reading USDPAA IRQ before it was set\n");
7706 + return -EINVAL;
7707 + }
7708 +
7709 + if (count < sizeof(ctx->irq_count)) {
7710 + pr_debug("USDPAA IRQ Read too small\n");
7711 + return -EINVAL;
7712 + }
7713 + if (ctx->irq_count == ctx->last_irq_count) {
7714 + if (filp->f_flags & O_NONBLOCK)
7715 + return -EAGAIN;
7716 +
7717 + ret = wait_event_interruptible(ctx->wait_queue,
7718 + ctx->irq_count != ctx->last_irq_count);
7719 + if (ret == -ERESTARTSYS)
7720 + return ret;
7721 + }
7722 +
7723 + ctx->last_irq_count = ctx->irq_count;
7724 +
7725 + if (copy_to_user(buff, &ctx->last_irq_count,
7726 + sizeof(ctx->last_irq_count)))
7727 + return -EFAULT;
7728 + return sizeof(ctx->irq_count);
7729 +}
7730 +
7731 +static unsigned int usdpaa_irq_poll(struct file *filp, poll_table *wait)
7732 +{
7733 + struct usdpaa_irq_ctx *ctx = filp->private_data;
7734 + unsigned int ret = 0;
7735 + unsigned long flags;
7736 +
7737 + if (!ctx->irq_set)
7738 + return POLLHUP;
7739 +
7740 + poll_wait(filp, &ctx->wait_queue, wait);
7741 +
7742 + spin_lock_irqsave(&ctx->lock, flags);
7743 + if (ctx->irq_count != ctx->last_irq_count)
7744 + ret |= POLLIN | POLLRDNORM;
7745 + spin_unlock_irqrestore(&ctx->lock, flags);
7746 + return ret;
7747 +}
7748 +
7749 +static long usdpaa_irq_ioctl_compat(struct file *fp, unsigned int cmd,
7750 + unsigned long arg)
7751 +{
7752 +#ifdef CONFIG_COMPAT
7753 + void __user *a = (void __user *)arg;
7754 +#endif
7755 + switch (cmd) {
7756 +#ifdef CONFIG_COMPAT
7757 + case USDPAA_IOCTL_PORTAL_IRQ_MAP_COMPAT:
7758 + {
7759 + struct compat_ioctl_irq_map input;
7760 + struct usdpaa_ioctl_irq_map converted;
7761 + if (copy_from_user(&input, a, sizeof(input)))
7762 + return -EFAULT;
7763 + converted.type = input.type;
7764 + converted.fd = input.fd;
7765 + converted.portal_cinh = compat_ptr(input.portal_cinh);
7766 + return map_irq(fp, &converted);
7767 + }
7768 +#endif
7769 + default:
7770 + return usdpaa_irq_ioctl(fp, cmd, arg);
7771 + }
7772 +}
7773 +
7774 +static const struct file_operations usdpaa_irq_fops = {
7775 + .open = usdpaa_irq_open,
7776 + .release = usdpaa_irq_release,
7777 + .unlocked_ioctl = usdpaa_irq_ioctl,
7778 + .compat_ioctl = usdpaa_irq_ioctl_compat,
7779 + .read = usdpaa_irq_read,
7780 + .poll = usdpaa_irq_poll
7781 +};
7782 +
7783 +static struct miscdevice usdpaa_miscdev = {
7784 + .name = "fsl-usdpaa-irq",
7785 + .fops = &usdpaa_irq_fops,
7786 + .minor = MISC_DYNAMIC_MINOR,
7787 +};
7788 +
7789 +static int __init usdpaa_irq_init(void)
7790 +{
7791 + int ret;
7792 +
7793 + pr_info("Freescale USDPAA process IRQ driver\n");
7794 + ret = misc_register(&usdpaa_miscdev);
7795 + if (ret)
7796 + pr_err("fsl-usdpaa-irq: failed to register misc device\n");
7797 + return ret;
7798 +}
7799 +
7800 +static void __exit usdpaa_irq_exit(void)
7801 +{
7802 + misc_deregister(&usdpaa_miscdev);
7803 +}
7804 +
7805 +module_init(usdpaa_irq_init);
7806 +module_exit(usdpaa_irq_exit);
7807 +
7808 +MODULE_LICENSE("GPL");
7809 +MODULE_AUTHOR("Freescale Semiconductor");
7810 +MODULE_DESCRIPTION("Freescale USDPAA process IRQ driver");
7811 --- /dev/null
7812 +++ b/drivers/staging/fsl_qbman/qbman_driver.c
7813 @@ -0,0 +1,88 @@
7814 +/* Copyright 2013 Freescale Semiconductor, Inc.
7815 + *
7816 + * Redistribution and use in source and binary forms, with or without
7817 + * modification, are permitted provided that the following conditions are met:
7818 + * * Redistributions of source code must retain the above copyright
7819 + * notice, this list of conditions and the following disclaimer.
7820 + * * Redistributions in binary form must reproduce the above copyright
7821 + * notice, this list of conditions and the following disclaimer in the
7822 + * documentation and/or other materials provided with the distribution.
7823 + * * Neither the name of Freescale Semiconductor nor the
7824 + * names of its contributors may be used to endorse or promote products
7825 + * derived from this software without specific prior written permission.
7826 + *
7827 + *
7828 + * ALTERNATIVELY, this software may be distributed under the terms of the
7829 + * GNU General Public License ("GPL") as published by the Free Software
7830 + * Foundation, either version 2 of that License or (at your option) any
7831 + * later version.
7832 + *
7833 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
7834 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7835 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7836 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
7837 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7838 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7839 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
7840 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7841 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
7842 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7843 + */
7844 +
7845 +#include <linux/time.h>
7846 +#include "qman_private.h"
7847 +#include "bman_private.h"
7848 +__init void qman_init_early(void);
7849 +__init void bman_init_early(void);
7850 +
7851 +static __init int qbman_init(void)
7852 +{
7853 + struct device_node *dn;
7854 + u32 is_portal_available;
7855 +
7856 + bman_init();
7857 + qman_init();
7858 +
7859 + is_portal_available = 0;
7860 + for_each_compatible_node(dn, NULL, "fsl,qman-portal") {
7861 + if (!of_device_is_available(dn))
7862 + continue;
7863 + else
7864 + is_portal_available = 1;
7865 + }
7866 +
7867 + if (!qman_have_ccsr() && is_portal_available) {
7868 + struct qman_fq fq = {
7869 + .fqid = 1
7870 + };
7871 + struct qm_mcr_queryfq_np np;
7872 + int err, retry = CONFIG_FSL_QMAN_INIT_TIMEOUT;
7873 + struct timespec nowts, diffts, startts = current_kernel_time();
7874 + /* Loop while querying given fqid succeeds or time out */
7875 + while (1) {
7876 + err = qman_query_fq_np(&fq, &np);
7877 + if (!err) {
7878 + /* success, control-plane has configured QMan */
7879 + break;
7880 + } else if (err != -ERANGE) {
7881 + pr_err("QMan: I/O error, continuing anyway\n");
7882 + break;
7883 + }
7884 + nowts = current_kernel_time();
7885 + diffts = timespec_sub(nowts, startts);
7886 + if (diffts.tv_sec > 0) {
7887 + if (!retry--) {
7888 + pr_err("QMan: time out, control-plane"
7889 + " dead?\n");
7890 + break;
7891 + }
7892 + pr_warn("QMan: polling for the control-plane"
7893 + " (%d)\n", retry);
7894 + }
7895 + }
7896 + }
7897 + bman_resource_init();
7898 + qman_resource_init();
7899 + return 0;
7900 +}
7901 +subsys_initcall(qbman_init);
7902 --- /dev/null
7903 +++ b/drivers/staging/fsl_qbman/qman_config.c
7904 @@ -0,0 +1,1199 @@
7905 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
7906 + *
7907 + * Redistribution and use in source and binary forms, with or without
7908 + * modification, are permitted provided that the following conditions are met:
7909 + * * Redistributions of source code must retain the above copyright
7910 + * notice, this list of conditions and the following disclaimer.
7911 + * * Redistributions in binary form must reproduce the above copyright
7912 + * notice, this list of conditions and the following disclaimer in the
7913 + * documentation and/or other materials provided with the distribution.
7914 + * * Neither the name of Freescale Semiconductor nor the
7915 + * names of its contributors may be used to endorse or promote products
7916 + * derived from this software without specific prior written permission.
7917 + *
7918 + *
7919 + * ALTERNATIVELY, this software may be distributed under the terms of the
7920 + * GNU General Public License ("GPL") as published by the Free Software
7921 + * Foundation, either version 2 of that License or (at your option) any
7922 + * later version.
7923 + *
7924 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
7925 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
7926 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
7927 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
7928 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
7929 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
7930 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
7931 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
7932 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
7933 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7934 + */
7935 +
7936 +#include <asm/cacheflush.h>
7937 +#include "qman_private.h"
7938 +#include <linux/highmem.h>
7939 +#include <linux/of_reserved_mem.h>
7940 +
7941 +/* Last updated for v00.800 of the BG */
7942 +
7943 +/* Register offsets */
7944 +#define REG_QCSP_LIO_CFG(n) (0x0000 + ((n) * 0x10))
7945 +#define REG_QCSP_IO_CFG(n) (0x0004 + ((n) * 0x10))
7946 +#define REG_QCSP_DD_CFG(n) (0x000c + ((n) * 0x10))
7947 +#define REG_DD_CFG 0x0200
7948 +#define REG_DCP_CFG(n) (0x0300 + ((n) * 0x10))
7949 +#define REG_DCP_DD_CFG(n) (0x0304 + ((n) * 0x10))
7950 +#define REG_DCP_DLM_AVG(n) (0x030c + ((n) * 0x10))
7951 +#define REG_PFDR_FPC 0x0400
7952 +#define REG_PFDR_FP_HEAD 0x0404
7953 +#define REG_PFDR_FP_TAIL 0x0408
7954 +#define REG_PFDR_FP_LWIT 0x0410
7955 +#define REG_PFDR_CFG 0x0414
7956 +#define REG_SFDR_CFG 0x0500
7957 +#define REG_SFDR_IN_USE 0x0504
7958 +#define REG_WQ_CS_CFG(n) (0x0600 + ((n) * 0x04))
7959 +#define REG_WQ_DEF_ENC_WQID 0x0630
7960 +#define REG_WQ_SC_DD_CFG(n) (0x640 + ((n) * 0x04))
7961 +#define REG_WQ_PC_DD_CFG(n) (0x680 + ((n) * 0x04))
7962 +#define REG_WQ_DC0_DD_CFG(n) (0x6c0 + ((n) * 0x04))
7963 +#define REG_WQ_DC1_DD_CFG(n) (0x700 + ((n) * 0x04))
7964 +#define REG_WQ_DCn_DD_CFG(n) (0x6c0 + ((n) * 0x40)) /* n=2,3 */
7965 +#define REG_CM_CFG 0x0800
7966 +#define REG_ECSR 0x0a00
7967 +#define REG_ECIR 0x0a04
7968 +#define REG_EADR 0x0a08
7969 +#define REG_ECIR2 0x0a0c
7970 +#define REG_EDATA(n) (0x0a10 + ((n) * 0x04))
7971 +#define REG_SBEC(n) (0x0a80 + ((n) * 0x04))
7972 +#define REG_MCR 0x0b00
7973 +#define REG_MCP(n) (0x0b04 + ((n) * 0x04))
7974 +#define REG_MISC_CFG 0x0be0
7975 +#define REG_HID_CFG 0x0bf0
7976 +#define REG_IDLE_STAT 0x0bf4
7977 +#define REG_IP_REV_1 0x0bf8
7978 +#define REG_IP_REV_2 0x0bfc
7979 +#define REG_FQD_BARE 0x0c00
7980 +#define REG_PFDR_BARE 0x0c20
7981 +#define REG_offset_BAR 0x0004 /* relative to REG_[FQD|PFDR]_BARE */
7982 +#define REG_offset_AR 0x0010 /* relative to REG_[FQD|PFDR]_BARE */
7983 +#define REG_QCSP_BARE 0x0c80
7984 +#define REG_QCSP_BAR 0x0c84
7985 +#define REG_CI_SCHED_CFG 0x0d00
7986 +#define REG_SRCIDR 0x0d04
7987 +#define REG_LIODNR 0x0d08
7988 +#define REG_CI_RLM_AVG 0x0d14
7989 +#define REG_ERR_ISR 0x0e00 /* + "enum qm_isr_reg" */
7990 +#define REG_REV3_QCSP_LIO_CFG(n) (0x1000 + ((n) * 0x10))
7991 +#define REG_REV3_QCSP_IO_CFG(n) (0x1004 + ((n) * 0x10))
7992 +#define REG_REV3_QCSP_DD_CFG(n) (0x100c + ((n) * 0x10))
7993 +#define REG_CEETM_CFG_IDX 0x900
7994 +#define REG_CEETM_CFG_PRES 0x904
7995 +#define REG_CEETM_XSFDR_IN_USE 0x908
7996 +
7997 +/* Assists for QMAN_MCR */
7998 +#define MCR_INIT_PFDR 0x01000000
7999 +#define MCR_get_rslt(v) (u8)((v) >> 24)
8000 +#define MCR_rslt_idle(r) (!rslt || (rslt >= 0xf0))
8001 +#define MCR_rslt_ok(r) (rslt == 0xf0)
8002 +#define MCR_rslt_eaccess(r) (rslt == 0xf8)
8003 +#define MCR_rslt_inval(r) (rslt == 0xff)
8004 +
8005 +struct qman;
8006 +
8007 +/* Follows WQ_CS_CFG0-5 */
8008 +enum qm_wq_class {
8009 + qm_wq_portal = 0,
8010 + qm_wq_pool = 1,
8011 + qm_wq_fman0 = 2,
8012 + qm_wq_fman1 = 3,
8013 + qm_wq_caam = 4,
8014 + qm_wq_pme = 5,
8015 + qm_wq_first = qm_wq_portal,
8016 + qm_wq_last = qm_wq_pme
8017 +};
8018 +
8019 +/* Follows FQD_[BARE|BAR|AR] and PFDR_[BARE|BAR|AR] */
8020 +enum qm_memory {
8021 + qm_memory_fqd,
8022 + qm_memory_pfdr
8023 +};
8024 +
8025 +/* Used by all error interrupt registers except 'inhibit' */
8026 +#define QM_EIRQ_CIDE 0x20000000 /* Corenet Initiator Data Error */
8027 +#define QM_EIRQ_CTDE 0x10000000 /* Corenet Target Data Error */
8028 +#define QM_EIRQ_CITT 0x08000000 /* Corenet Invalid Target Transaction */
8029 +#define QM_EIRQ_PLWI 0x04000000 /* PFDR Low Watermark */
8030 +#define QM_EIRQ_MBEI 0x02000000 /* Multi-bit ECC Error */
8031 +#define QM_EIRQ_SBEI 0x01000000 /* Single-bit ECC Error */
8032 +#define QM_EIRQ_PEBI 0x00800000 /* PFDR Enqueues Blocked Interrupt */
8033 +#define QM_EIRQ_IFSI 0x00020000 /* Invalid FQ Flow Control State */
8034 +#define QM_EIRQ_ICVI 0x00010000 /* Invalid Command Verb */
8035 +#define QM_EIRQ_IDDI 0x00000800 /* Invalid Dequeue (Direct-connect) */
8036 +#define QM_EIRQ_IDFI 0x00000400 /* Invalid Dequeue FQ */
8037 +#define QM_EIRQ_IDSI 0x00000200 /* Invalid Dequeue Source */
8038 +#define QM_EIRQ_IDQI 0x00000100 /* Invalid Dequeue Queue */
8039 +#define QM_EIRQ_IECE 0x00000010 /* Invalid Enqueue Configuration */
8040 +#define QM_EIRQ_IEOI 0x00000008 /* Invalid Enqueue Overflow */
8041 +#define QM_EIRQ_IESI 0x00000004 /* Invalid Enqueue State */
8042 +#define QM_EIRQ_IECI 0x00000002 /* Invalid Enqueue Channel */
8043 +#define QM_EIRQ_IEQI 0x00000001 /* Invalid Enqueue Queue */
8044 +
8045 +/* QMAN_ECIR valid error bit */
8046 +#define PORTAL_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IESI | QM_EIRQ_IEOI | \
8047 + QM_EIRQ_IDQI | QM_EIRQ_IDSI | QM_EIRQ_IDFI | \
8048 + QM_EIRQ_IDDI | QM_EIRQ_ICVI | QM_EIRQ_IFSI)
8049 +#define FQID_ECSR_ERR (QM_EIRQ_IEQI | QM_EIRQ_IECI | QM_EIRQ_IESI | \
8050 + QM_EIRQ_IEOI | QM_EIRQ_IDQI | QM_EIRQ_IDFI | \
8051 + QM_EIRQ_IFSI)
8052 +
8053 +union qman_ecir {
8054 + u32 ecir_raw;
8055 + struct {
8056 + u32 __reserved:2;
8057 + u32 portal_type:1;
8058 + u32 portal_num:5;
8059 + u32 fqid:24;
8060 + } __packed info;
8061 +};
8062 +
8063 +union qman_ecir2 {
8064 + u32 ecir2_raw;
8065 + struct {
8066 + u32 portal_type:1;
8067 + u32 __reserved:21;
8068 + u32 portal_num:10;
8069 + } __packed info;
8070 +};
8071 +
8072 +union qman_eadr {
8073 + u32 eadr_raw;
8074 + struct {
8075 + u32 __reserved1:4;
8076 + u32 memid:4;
8077 + u32 __reserved2:12;
8078 + u32 eadr:12;
8079 + } __packed info;
8080 + struct {
8081 + u32 __reserved1:3;
8082 + u32 memid:5;
8083 + u32 __reserved:8;
8084 + u32 eadr:16;
8085 + } __packed info_rev3;
8086 +};
8087 +
8088 +struct qman_hwerr_txt {
8089 + u32 mask;
8090 + const char *txt;
8091 +};
8092 +
8093 +#define QMAN_HWE_TXT(a, b) { .mask = QM_EIRQ_##a, .txt = b }
8094 +
8095 +static const struct qman_hwerr_txt qman_hwerr_txts[] = {
8096 + QMAN_HWE_TXT(CIDE, "Corenet Initiator Data Error"),
8097 + QMAN_HWE_TXT(CTDE, "Corenet Target Data Error"),
8098 + QMAN_HWE_TXT(CITT, "Corenet Invalid Target Transaction"),
8099 + QMAN_HWE_TXT(PLWI, "PFDR Low Watermark"),
8100 + QMAN_HWE_TXT(MBEI, "Multi-bit ECC Error"),
8101 + QMAN_HWE_TXT(SBEI, "Single-bit ECC Error"),
8102 + QMAN_HWE_TXT(PEBI, "PFDR Enqueues Blocked Interrupt"),
8103 + QMAN_HWE_TXT(ICVI, "Invalid Command Verb"),
8104 + QMAN_HWE_TXT(IFSI, "Invalid Flow Control State"),
8105 + QMAN_HWE_TXT(IDDI, "Invalid Dequeue (Direct-connect)"),
8106 + QMAN_HWE_TXT(IDFI, "Invalid Dequeue FQ"),
8107 + QMAN_HWE_TXT(IDSI, "Invalid Dequeue Source"),
8108 + QMAN_HWE_TXT(IDQI, "Invalid Dequeue Queue"),
8109 + QMAN_HWE_TXT(IECE, "Invalid Enqueue Configuration"),
8110 + QMAN_HWE_TXT(IEOI, "Invalid Enqueue Overflow"),
8111 + QMAN_HWE_TXT(IESI, "Invalid Enqueue State"),
8112 + QMAN_HWE_TXT(IECI, "Invalid Enqueue Channel"),
8113 + QMAN_HWE_TXT(IEQI, "Invalid Enqueue Queue")
8114 +};
8115 +#define QMAN_HWE_COUNT (sizeof(qman_hwerr_txts)/sizeof(struct qman_hwerr_txt))
8116 +
8117 +struct qman_error_info_mdata {
8118 + u16 addr_mask;
8119 + u16 bits;
8120 + const char *txt;
8121 +};
8122 +
8123 +#define QMAN_ERR_MDATA(a, b, c) { .addr_mask = a, .bits = b, .txt = c}
8124 +static const struct qman_error_info_mdata error_mdata[] = {
8125 + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 0"),
8126 + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 1"),
8127 + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 2"),
8128 + QMAN_ERR_MDATA(0x01FF, 24, "FQD cache tag memory 3"),
8129 + QMAN_ERR_MDATA(0x0FFF, 512, "FQD cache memory"),
8130 + QMAN_ERR_MDATA(0x07FF, 128, "SFDR memory"),
8131 + QMAN_ERR_MDATA(0x01FF, 72, "WQ context memory"),
8132 + QMAN_ERR_MDATA(0x00FF, 240, "CGR memory"),
8133 + QMAN_ERR_MDATA(0x00FF, 302, "Internal Order Restoration List memory"),
8134 + QMAN_ERR_MDATA(0x01FF, 256, "SW portal ring memory"),
8135 + QMAN_ERR_MDATA(0x07FF, 181, "CEETM class queue descriptor memory"),
8136 + QMAN_ERR_MDATA(0x0FFF, 140, "CEETM extended SFDR memory"),
8137 + QMAN_ERR_MDATA(0x0FFF, 25, "CEETM logical FQ mapping memory"),
8138 + QMAN_ERR_MDATA(0x0FFF, 96, "CEETM dequeue context memory"),
8139 + QMAN_ERR_MDATA(0x07FF, 396, "CEETM ccgr memory"),
8140 + QMAN_ERR_MDATA(0x00FF, 146, "CEETM CQ channel shaping memory"),
8141 + QMAN_ERR_MDATA(0x007F, 256, "CEETM CQ channel scheduling memory"),
8142 + QMAN_ERR_MDATA(0x01FF, 88, "CEETM dequeue statistics memory"),
8143 +};
8144 +#define QMAN_ERR_MDATA_COUNT \
8145 + (sizeof(error_mdata)/sizeof(struct qman_error_info_mdata))
8146 +
8147 +/* Add this in Kconfig */
8148 +#define QMAN_ERRS_TO_UNENABLE (QM_EIRQ_PLWI | QM_EIRQ_PEBI)
8149 +
8150 +/**
8151 + * qm_err_isr_<reg>_<verb> - Manipulate global interrupt registers
8152 + * @v: for accessors that write values, this is the 32-bit value
8153 + *
8154 + * Manipulates QMAN_ERR_ISR, QMAN_ERR_IER, QMAN_ERR_ISDR, QMAN_ERR_IIR. All
8155 + * manipulations except qm_err_isr_[un]inhibit() use 32-bit masks composed of
8156 + * the QM_EIRQ_*** definitions. Note that "qm_err_isr_enable_write" means
8157 + * "write the enable register" rather than "enable the write register"!
8158 + */
8159 +#define qm_err_isr_status_read(qm) \
8160 + __qm_err_isr_read(qm, qm_isr_status)
8161 +#define qm_err_isr_status_clear(qm, m) \
8162 + __qm_err_isr_write(qm, qm_isr_status, m)
8163 +#define qm_err_isr_enable_read(qm) \
8164 + __qm_err_isr_read(qm, qm_isr_enable)
8165 +#define qm_err_isr_enable_write(qm, v) \
8166 + __qm_err_isr_write(qm, qm_isr_enable, v)
8167 +#define qm_err_isr_disable_read(qm) \
8168 + __qm_err_isr_read(qm, qm_isr_disable)
8169 +#define qm_err_isr_disable_write(qm, v) \
8170 + __qm_err_isr_write(qm, qm_isr_disable, v)
8171 +#define qm_err_isr_inhibit(qm) \
8172 + __qm_err_isr_write(qm, qm_isr_inhibit, 1)
8173 +#define qm_err_isr_uninhibit(qm) \
8174 + __qm_err_isr_write(qm, qm_isr_inhibit, 0)
8175 +
8176 +/*
8177 + * TODO: unimplemented registers
8178 + *
8179 + * Keeping a list here of Qman registers I have not yet covered;
8180 + * QCSP_DD_IHRSR, QCSP_DD_IHRFR, QCSP_DD_HASR,
8181 + * DCP_DD_IHRSR, DCP_DD_IHRFR, DCP_DD_HASR, CM_CFG,
8182 + * QMAN_EECC, QMAN_SBET, QMAN_EINJ, QMAN_SBEC0-12
8183 + */
8184 +
8185 +/* Encapsulate "struct qman *" as a cast of the register space address. */
8186 +
8187 +static struct qman *qm_create(void *regs)
8188 +{
8189 + return (struct qman *)regs;
8190 +}
8191 +
8192 +static inline u32 __qm_in(struct qman *qm, u32 offset)
8193 +{
8194 + return in_be32((void *)qm + offset);
8195 +}
8196 +static inline void __qm_out(struct qman *qm, u32 offset, u32 val)
8197 +{
8198 + out_be32((void *)qm + offset, val);
8199 +}
8200 +#define qm_in(reg) __qm_in(qm, REG_##reg)
8201 +#define qm_out(reg, val) __qm_out(qm, REG_##reg, val)
8202 +
8203 +static u32 __qm_err_isr_read(struct qman *qm, enum qm_isr_reg n)
8204 +{
8205 + return __qm_in(qm, REG_ERR_ISR + (n << 2));
8206 +}
8207 +
8208 +static void __qm_err_isr_write(struct qman *qm, enum qm_isr_reg n, u32 val)
8209 +{
8210 + __qm_out(qm, REG_ERR_ISR + (n << 2), val);
8211 +}
8212 +
8213 +static void qm_set_dc(struct qman *qm, enum qm_dc_portal portal,
8214 + int ed, u8 sernd)
8215 +{
8216 + DPA_ASSERT(!ed || (portal == qm_dc_portal_fman0) ||
8217 + (portal == qm_dc_portal_fman1));
8218 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
8219 + qm_out(DCP_CFG(portal), (ed ? 0x1000 : 0) | (sernd & 0x3ff));
8220 + else
8221 + qm_out(DCP_CFG(portal), (ed ? 0x100 : 0) | (sernd & 0x1f));
8222 +}
8223 +
8224 +static void qm_set_wq_scheduling(struct qman *qm, enum qm_wq_class wq_class,
8225 + u8 cs_elev, u8 csw2, u8 csw3, u8 csw4, u8 csw5,
8226 + u8 csw6, u8 csw7)
8227 +{
8228 + qm_out(WQ_CS_CFG(wq_class), ((cs_elev & 0xff) << 24) |
8229 + ((csw2 & 0x7) << 20) | ((csw3 & 0x7) << 16) |
8230 + ((csw4 & 0x7) << 12) | ((csw5 & 0x7) << 8) |
8231 + ((csw6 & 0x7) << 4) | (csw7 & 0x7));
8232 +}
8233 +
8234 +static void qm_set_hid(struct qman *qm)
8235 +{
8236 + qm_out(HID_CFG, 0);
8237 +}
8238 +
8239 +static void qm_set_corenet_initiator(struct qman *qm)
8240 +{
8241 + qm_out(CI_SCHED_CFG,
8242 + 0x80000000 | /* write srcciv enable */
8243 + (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRCCIV << 24) |
8244 + (CONFIG_FSL_QMAN_CI_SCHED_CFG_SRQ_W << 8) |
8245 + (CONFIG_FSL_QMAN_CI_SCHED_CFG_RW_W << 4) |
8246 + CONFIG_FSL_QMAN_CI_SCHED_CFG_BMAN_W);
8247 +}
8248 +
8249 +static void qm_get_version(struct qman *qm, u16 *id, u8 *major, u8 *minor,
8250 + u8 *cfg)
8251 +{
8252 + u32 v = qm_in(IP_REV_1);
8253 + u32 v2 = qm_in(IP_REV_2);
8254 + *id = (v >> 16);
8255 + *major = (v >> 8) & 0xff;
8256 + *minor = v & 0xff;
8257 + *cfg = v2 & 0xff;
8258 +}
8259 +
8260 +static void qm_set_memory(struct qman *qm, enum qm_memory memory, u64 ba,
8261 + int enable, int prio, int stash, u32 size)
8262 +{
8263 + u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE;
8264 + u32 exp = ilog2(size);
8265 + /* choke if size isn't within range */
8266 + DPA_ASSERT((size >= 4096) && (size <= 1073741824) &&
8267 + is_power_of_2(size));
8268 + /* choke if 'ba' has lower-alignment than 'size' */
8269 + DPA_ASSERT(!(ba & (size - 1)));
8270 + __qm_out(qm, offset, upper_32_bits(ba));
8271 + __qm_out(qm, offset + REG_offset_BAR, lower_32_bits(ba));
8272 + __qm_out(qm, offset + REG_offset_AR,
8273 + (enable ? 0x80000000 : 0) |
8274 + (prio ? 0x40000000 : 0) |
8275 + (stash ? 0x20000000 : 0) |
8276 + (exp - 1));
8277 +}
8278 +
8279 +static void qm_set_pfdr_threshold(struct qman *qm, u32 th, u8 k)
8280 +{
8281 + qm_out(PFDR_FP_LWIT, th & 0xffffff);
8282 + qm_out(PFDR_CFG, k);
8283 +}
8284 +
8285 +static void qm_set_sfdr_threshold(struct qman *qm, u16 th)
8286 +{
8287 + qm_out(SFDR_CFG, th & 0x3ff);
8288 +}
8289 +
8290 +static int qm_init_pfdr(struct qman *qm, u32 pfdr_start, u32 num)
8291 +{
8292 + u8 rslt = MCR_get_rslt(qm_in(MCR));
8293 +
8294 + DPA_ASSERT(pfdr_start && !(pfdr_start & 7) && !(num & 7) && num);
8295 + /* Make sure the command interface is 'idle' */
8296 + if (!MCR_rslt_idle(rslt))
8297 + panic("QMAN_MCR isn't idle");
8298 +
8299 + /* Write the MCR command params then the verb */
8300 + qm_out(MCP(0), pfdr_start);
8301 + /* TODO: remove this - it's a workaround for a model bug that is
8302 + * corrected in more recent versions. We use the workaround until
8303 + * everyone has upgraded. */
8304 + qm_out(MCP(1), (pfdr_start + num - 16));
8305 + lwsync();
8306 + qm_out(MCR, MCR_INIT_PFDR);
8307 + /* Poll for the result */
8308 + do {
8309 + rslt = MCR_get_rslt(qm_in(MCR));
8310 + } while (!MCR_rslt_idle(rslt));
8311 + if (MCR_rslt_ok(rslt))
8312 + return 0;
8313 + if (MCR_rslt_eaccess(rslt))
8314 + return -EACCES;
8315 + if (MCR_rslt_inval(rslt))
8316 + return -EINVAL;
8317 + pr_crit("Unexpected result from MCR_INIT_PFDR: %02x\n", rslt);
8318 + return -ENOSYS;
8319 +}
8320 +
8321 +/*****************/
8322 +/* Config driver */
8323 +/*****************/
8324 +
8325 +#define DEFAULT_FQD_SZ (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ)
8326 +#define DEFAULT_PFDR_SZ (PAGE_SIZE << CONFIG_FSL_QMAN_PFDR_SZ)
8327 +
8328 +/* We support only one of these */
8329 +static struct qman *qm;
8330 +static struct device_node *qm_node;
8331 +
8332 +/* And this state belongs to 'qm'. It is set during fsl_qman_init(), but used
8333 + * during qman_init_ccsr(). */
8334 +static dma_addr_t fqd_a, pfdr_a;
8335 +static size_t fqd_sz = DEFAULT_FQD_SZ, pfdr_sz = DEFAULT_PFDR_SZ;
8336 +
8337 +static int qman_fqd(struct reserved_mem *rmem)
8338 +{
8339 + fqd_a = rmem->base;
8340 + fqd_sz = rmem->size;
8341 +
8342 + WARN_ON(!(fqd_a && fqd_sz));
8343 +
8344 + return 0;
8345 +}
8346 +RESERVEDMEM_OF_DECLARE(qman_fqd, "fsl,qman-fqd", qman_fqd);
8347 +
8348 +static int qman_pfdr(struct reserved_mem *rmem)
8349 +{
8350 + pfdr_a = rmem->base;
8351 + pfdr_sz = rmem->size;
8352 +
8353 + WARN_ON(!(pfdr_a && pfdr_sz));
8354 +
8355 + return 0;
8356 +}
8357 +RESERVEDMEM_OF_DECLARE(qman_fbpr, "fsl,qman-pfdr", qman_pfdr);
8358 +
8359 +size_t get_qman_fqd_size()
8360 +{
8361 + return fqd_sz;
8362 +}
8363 +
8364 +/* Parse the <name> property to extract the memory location and size and
8365 + * memblock_reserve() it. If it isn't supplied, memblock_alloc() the default
8366 + * size. Also flush this memory range from data cache so that QMAN originated
8367 + * transactions for this memory region could be marked non-coherent.
8368 + */
8369 +static __init int parse_mem_property(struct device_node *node, const char *name,
8370 + dma_addr_t *addr, size_t *sz, int zero)
8371 +{
8372 + int ret;
8373 +
8374 + /* If using a "zero-pma", don't try to zero it, even if you asked */
8375 + if (zero && of_find_property(node, "zero-pma", &ret)) {
8376 + pr_info(" it's a 'zero-pma', not zeroing from s/w\n");
8377 + zero = 0;
8378 + }
8379 +
8380 + if (zero) {
8381 + /* map as cacheable, non-guarded */
8382 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
8383 + void __iomem *tmpp = ioremap_cache(*addr, *sz);
8384 +#else
8385 + void __iomem *tmpp = ioremap(*addr, *sz);
8386 +#endif
8387 +
8388 + if (!tmpp)
8389 + return -ENOMEM;
8390 + memset_io(tmpp, 0, *sz);
8391 + flush_dcache_range((unsigned long)tmpp,
8392 + (unsigned long)tmpp + *sz);
8393 + iounmap(tmpp);
8394 + }
8395 +
8396 + return 0;
8397 +}
8398 +
8399 +/* TODO:
8400 + * - there is obviously no handling of errors,
8401 + * - the calls to qm_set_memory() hard-code the priority and CPC-stashing for
8402 + * both memory resources to zero.
8403 + */
8404 +static int __init fsl_qman_init(struct device_node *node)
8405 +{
8406 + struct resource res;
8407 + resource_size_t len;
8408 + u32 __iomem *regs;
8409 + const char *s;
8410 + int ret, standby = 0;
8411 + u16 id;
8412 + u8 major, minor, cfg;
8413 + ret = of_address_to_resource(node, 0, &res);
8414 + if (ret) {
8415 + pr_err("Can't get %s property '%s'\n", node->full_name, "reg");
8416 + return ret;
8417 + }
8418 + s = of_get_property(node, "fsl,hv-claimable", &ret);
8419 + if (s && !strcmp(s, "standby"))
8420 + standby = 1;
8421 + if (!standby) {
8422 + ret = parse_mem_property(node, "fsl,qman-fqd",
8423 + &fqd_a, &fqd_sz, 1);
8424 + pr_info("qman-fqd addr 0x%llx size 0x%zx\n",
8425 + (unsigned long long)fqd_a, fqd_sz);
8426 + BUG_ON(ret);
8427 + ret = parse_mem_property(node, "fsl,qman-pfdr",
8428 + &pfdr_a, &pfdr_sz, 0);
8429 + pr_info("qman-pfdr addr 0x%llx size 0x%zx\n",
8430 + (unsigned long long)pfdr_a, pfdr_sz);
8431 + BUG_ON(ret);
8432 + }
8433 + /* Global configuration */
8434 + len = resource_size(&res);
8435 + if (len != (unsigned long)len)
8436 + return -EINVAL;
8437 + regs = ioremap(res.start, (unsigned long)len);
8438 + qm = qm_create(regs);
8439 + qm_node = node;
8440 + qm_get_version(qm, &id, &major, &minor, &cfg);
8441 + pr_info("Qman ver:%04x,%02x,%02x,%02x\n", id, major, minor, cfg);
8442 + if (!qman_ip_rev) {
8443 + if ((major == 1) && (minor == 0)) {
8444 + pr_err("QMAN rev1.0 on P4080 rev1 is not supported!\n");
8445 + iounmap(regs);
8446 + return -ENODEV;
8447 + } else if ((major == 1) && (minor == 1))
8448 + qman_ip_rev = QMAN_REV11;
8449 + else if ((major == 1) && (minor == 2))
8450 + qman_ip_rev = QMAN_REV12;
8451 + else if ((major == 2) && (minor == 0))
8452 + qman_ip_rev = QMAN_REV20;
8453 + else if ((major == 3) && (minor == 0))
8454 + qman_ip_rev = QMAN_REV30;
8455 + else if ((major == 3) && (minor == 1))
8456 + qman_ip_rev = QMAN_REV31;
8457 + else if ((major == 3) && (minor == 2))
8458 + qman_ip_rev = QMAN_REV32;
8459 + else {
8460 + pr_warn("unknown Qman version, default to rev1.1\n");
8461 + qman_ip_rev = QMAN_REV11;
8462 + }
8463 + qman_ip_cfg = cfg;
8464 + }
8465 +
8466 + if (standby) {
8467 + pr_info(" -> in standby mode\n");
8468 + return 0;
8469 + }
8470 + return 0;
8471 +}
8472 +
8473 +int qman_have_ccsr(void)
8474 +{
8475 + return qm ? 1 : 0;
8476 +}
8477 +
8478 +__init int qman_init_early(void)
8479 +{
8480 + struct device_node *dn;
8481 + int ret;
8482 +
8483 + for_each_compatible_node(dn, NULL, "fsl,qman") {
8484 + if (qm)
8485 + pr_err("%s: only one 'fsl,qman' allowed\n",
8486 + dn->full_name);
8487 + else {
8488 + if (!of_device_is_available(dn))
8489 + continue;
8490 +
8491 + ret = fsl_qman_init(dn);
8492 + BUG_ON(ret);
8493 + }
8494 + }
8495 + return 0;
8496 +}
8497 +postcore_initcall_sync(qman_init_early);
8498 +
8499 +static void log_edata_bits(u32 bit_count)
8500 +{
8501 + u32 i, j, mask = 0xffffffff;
8502 +
8503 + pr_warn("Qman ErrInt, EDATA:\n");
8504 + i = bit_count/32;
8505 + if (bit_count%32) {
8506 + i++;
8507 + mask = ~(mask << bit_count%32);
8508 + }
8509 + j = 16-i;
8510 + pr_warn(" 0x%08x\n", qm_in(EDATA(j)) & mask);
8511 + j++;
8512 + for (; j < 16; j++)
8513 + pr_warn(" 0x%08x\n", qm_in(EDATA(j)));
8514 +}
8515 +
8516 +static void log_additional_error_info(u32 isr_val, u32 ecsr_val)
8517 +{
8518 + union qman_ecir ecir_val;
8519 + union qman_eadr eadr_val;
8520 +
8521 + ecir_val.ecir_raw = qm_in(ECIR);
8522 + /* Is portal info valid */
8523 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) {
8524 + union qman_ecir2 ecir2_val;
8525 + ecir2_val.ecir2_raw = qm_in(ECIR2);
8526 + if (ecsr_val & PORTAL_ECSR_ERR) {
8527 + pr_warn("Qman ErrInt: %s id %d\n",
8528 + (ecir2_val.info.portal_type) ?
8529 + "DCP" : "SWP", ecir2_val.info.portal_num);
8530 + }
8531 + if (ecsr_val & (FQID_ECSR_ERR | QM_EIRQ_IECE)) {
8532 + pr_warn("Qman ErrInt: ecir.fqid 0x%x\n",
8533 + ecir_val.info.fqid);
8534 + }
8535 + if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) {
8536 + eadr_val.eadr_raw = qm_in(EADR);
8537 + pr_warn("Qman ErrInt: EADR Memory: %s, 0x%x\n",
8538 + error_mdata[eadr_val.info_rev3.memid].txt,
8539 + error_mdata[eadr_val.info_rev3.memid].addr_mask
8540 + & eadr_val.info_rev3.eadr);
8541 + log_edata_bits(
8542 + error_mdata[eadr_val.info_rev3.memid].bits);
8543 + }
8544 + } else {
8545 + if (ecsr_val & PORTAL_ECSR_ERR) {
8546 + pr_warn("Qman ErrInt: %s id %d\n",
8547 + (ecir_val.info.portal_type) ?
8548 + "DCP" : "SWP", ecir_val.info.portal_num);
8549 + }
8550 + if (ecsr_val & FQID_ECSR_ERR) {
8551 + pr_warn("Qman ErrInt: ecir.fqid 0x%x\n",
8552 + ecir_val.info.fqid);
8553 + }
8554 + if (ecsr_val & (QM_EIRQ_SBEI|QM_EIRQ_MBEI)) {
8555 + eadr_val.eadr_raw = qm_in(EADR);
8556 + pr_warn("Qman ErrInt: EADR Memory: %s, 0x%x\n",
8557 + error_mdata[eadr_val.info.memid].txt,
8558 + error_mdata[eadr_val.info.memid].addr_mask
8559 + & eadr_val.info.eadr);
8560 + log_edata_bits(error_mdata[eadr_val.info.memid].bits);
8561 + }
8562 + }
8563 +}
8564 +
8565 +/* Qman interrupt handler */
8566 +static irqreturn_t qman_isr(int irq, void *ptr)
8567 +{
8568 + u32 isr_val, ier_val, ecsr_val, isr_mask, i;
8569 +
8570 + ier_val = qm_err_isr_enable_read(qm);
8571 + isr_val = qm_err_isr_status_read(qm);
8572 + ecsr_val = qm_in(ECSR);
8573 + isr_mask = isr_val & ier_val;
8574 +
8575 + if (!isr_mask)
8576 + return IRQ_NONE;
8577 + for (i = 0; i < QMAN_HWE_COUNT; i++) {
8578 + if (qman_hwerr_txts[i].mask & isr_mask) {
8579 + pr_warn("Qman ErrInt: %s\n", qman_hwerr_txts[i].txt);
8580 + if (qman_hwerr_txts[i].mask & ecsr_val) {
8581 + log_additional_error_info(isr_mask, ecsr_val);
8582 + /* Re-arm error capture registers */
8583 + qm_out(ECSR, ecsr_val);
8584 + }
8585 + if (qman_hwerr_txts[i].mask & QMAN_ERRS_TO_UNENABLE) {
8586 + pr_devel("Qman un-enabling error 0x%x\n",
8587 + qman_hwerr_txts[i].mask);
8588 + ier_val &= ~qman_hwerr_txts[i].mask;
8589 + qm_err_isr_enable_write(qm, ier_val);
8590 + }
8591 + }
8592 + }
8593 + qm_err_isr_status_clear(qm, isr_val);
8594 + return IRQ_HANDLED;
8595 +}
8596 +
8597 +static int __bind_irq(void)
8598 +{
8599 + int ret, err_irq;
8600 +
8601 + err_irq = of_irq_to_resource(qm_node, 0, NULL);
8602 + if (err_irq == 0) {
8603 + pr_info("Can't get %s property '%s'\n", qm_node->full_name,
8604 + "interrupts");
8605 + return -ENODEV;
8606 + }
8607 + ret = request_irq(err_irq, qman_isr, IRQF_SHARED, "qman-err", qm_node);
8608 + if (ret) {
8609 + pr_err("request_irq() failed %d for '%s'\n", ret,
8610 + qm_node->full_name);
8611 + return -ENODEV;
8612 + }
8613 + /* Write-to-clear any stale bits, (eg. starvation being asserted prior
8614 + * to resource allocation during driver init). */
8615 + qm_err_isr_status_clear(qm, 0xffffffff);
8616 + /* Enable Error Interrupts */
8617 + qm_err_isr_enable_write(qm, 0xffffffff);
8618 + return 0;
8619 +}
8620 +
8621 +int qman_init_ccsr(struct device_node *node)
8622 +{
8623 + int ret;
8624 + if (!qman_have_ccsr())
8625 + return 0;
8626 + if (node != qm_node)
8627 + return -EINVAL;
8628 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
8629 + /* TEMP for LS1043 : should be done in uboot */
8630 + qm_out(QCSP_BARE, 0x5);
8631 + qm_out(QCSP_BAR, 0x0);
8632 +#endif
8633 + /* FQD memory */
8634 + qm_set_memory(qm, qm_memory_fqd, fqd_a, 1, 0, 0, fqd_sz);
8635 + /* PFDR memory */
8636 + qm_set_memory(qm, qm_memory_pfdr, pfdr_a, 1, 0, 0, pfdr_sz);
8637 + qm_init_pfdr(qm, 8, pfdr_sz / 64 - 8);
8638 + /* thresholds */
8639 + qm_set_pfdr_threshold(qm, 512, 64);
8640 + qm_set_sfdr_threshold(qm, 128);
8641 + /* clear stale PEBI bit from interrupt status register */
8642 + qm_err_isr_status_clear(qm, QM_EIRQ_PEBI);
8643 + /* corenet initiator settings */
8644 + qm_set_corenet_initiator(qm);
8645 + /* HID settings */
8646 + qm_set_hid(qm);
8647 + /* Set scheduling weights to defaults */
8648 + for (ret = qm_wq_first; ret <= qm_wq_last; ret++)
8649 + qm_set_wq_scheduling(qm, ret, 0, 0, 0, 0, 0, 0, 0);
8650 + /* We are not prepared to accept ERNs for hardware enqueues */
8651 + qm_set_dc(qm, qm_dc_portal_fman0, 1, 0);
8652 + qm_set_dc(qm, qm_dc_portal_fman1, 1, 0);
8653 + /* Initialise Error Interrupt Handler */
8654 + ret = __bind_irq();
8655 + if (ret)
8656 + return ret;
8657 + return 0;
8658 +}
8659 +
8660 +#define LIO_CFG_LIODN_MASK 0x0fff0000
8661 +void qman_liodn_fixup(u16 channel)
8662 +{
8663 + static int done;
8664 + static u32 liodn_offset;
8665 + u32 before, after;
8666 + int idx = channel - QM_CHANNEL_SWPORTAL0;
8667 +
8668 + if (!qman_have_ccsr())
8669 + return;
8670 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
8671 + before = qm_in(REV3_QCSP_LIO_CFG(idx));
8672 + else
8673 + before = qm_in(QCSP_LIO_CFG(idx));
8674 + if (!done) {
8675 + liodn_offset = before & LIO_CFG_LIODN_MASK;
8676 + done = 1;
8677 + return;
8678 + }
8679 + after = (before & (~LIO_CFG_LIODN_MASK)) | liodn_offset;
8680 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
8681 + qm_out(REV3_QCSP_LIO_CFG(idx), after);
8682 + else
8683 + qm_out(QCSP_LIO_CFG(idx), after);
8684 +}
8685 +
8686 +#define IO_CFG_SDEST_MASK 0x00ff0000
8687 +int qman_set_sdest(u16 channel, unsigned int cpu_idx)
8688 +{
8689 + int idx = channel - QM_CHANNEL_SWPORTAL0;
8690 + u32 before, after;
8691 +
8692 + if (!qman_have_ccsr())
8693 + return -ENODEV;
8694 + if ((qman_ip_rev & 0xFF00) == QMAN_REV31) {
8695 + /* LS1043A - only one L2 cache */
8696 + cpu_idx = 0;
8697 + }
8698 +
8699 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) {
8700 + before = qm_in(REV3_QCSP_IO_CFG(idx));
8701 + /* Each pair of vcpu share the same SRQ(SDEST) */
8702 + cpu_idx /= 2;
8703 + after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16);
8704 + qm_out(REV3_QCSP_IO_CFG(idx), after);
8705 + } else {
8706 + before = qm_in(QCSP_IO_CFG(idx));
8707 + after = (before & (~IO_CFG_SDEST_MASK)) | (cpu_idx << 16);
8708 + qm_out(QCSP_IO_CFG(idx), after);
8709 + }
8710 + return 0;
8711 +}
8712 +
8713 +#define MISC_CFG_WPM_MASK 0x00000002
8714 +int qm_set_wpm(int wpm)
8715 +{
8716 + u32 before;
8717 + u32 after;
8718 +
8719 + if (!qman_have_ccsr())
8720 + return -ENODEV;
8721 +
8722 + before = qm_in(MISC_CFG);
8723 + after = (before & (~MISC_CFG_WPM_MASK)) | (wpm << 1);
8724 + qm_out(MISC_CFG, after);
8725 + return 0;
8726 +}
8727 +
8728 +int qm_get_wpm(int *wpm)
8729 +{
8730 + u32 before;
8731 +
8732 + if (!qman_have_ccsr())
8733 + return -ENODEV;
8734 +
8735 + before = qm_in(MISC_CFG);
8736 + *wpm = (before & MISC_CFG_WPM_MASK) >> 1;
8737 + return 0;
8738 +}
8739 +
8740 +/* CEETM_CFG_PRES register has PRES field which is calculated by:
8741 + * PRES = (2^22 / credit update reference period) * QMan clock period
8742 + * = (2^22 * 10^9)/ CONFIG_QMAN_CEETM_UPDATE_PERIOD) / qman_clk
8743 + */
8744 +
8745 +int qman_ceetm_set_prescaler(enum qm_dc_portal portal)
8746 +{
8747 + u64 temp;
8748 + u16 pres;
8749 +
8750 + if (!qman_have_ccsr())
8751 + return -ENODEV;
8752 +
8753 + temp = 0x400000 * 100;
8754 + do_div(temp, CONFIG_QMAN_CEETM_UPDATE_PERIOD);
8755 + temp *= 10000000;
8756 + do_div(temp, qman_clk);
8757 + pres = (u16) temp;
8758 + qm_out(CEETM_CFG_IDX, portal);
8759 + qm_out(CEETM_CFG_PRES, pres);
8760 + return 0;
8761 +}
8762 +
8763 +int qman_ceetm_get_prescaler(u16 *pres)
8764 +{
8765 + if (!qman_have_ccsr())
8766 + return -ENODEV;
8767 + *pres = (u16)qm_in(CEETM_CFG_PRES);
8768 + return 0;
8769 +}
8770 +
8771 +#define DCP_CFG_CEETME_MASK 0xFFFF0000
8772 +#define QM_SP_ENABLE_CEETM(n) (0x80000000 >> (n))
8773 +int qman_sp_enable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal)
8774 +{
8775 + u32 dcp_cfg;
8776 +
8777 + if (!qman_have_ccsr())
8778 + return -ENODEV;
8779 +
8780 + dcp_cfg = qm_in(DCP_CFG(portal));
8781 + dcp_cfg |= QM_SP_ENABLE_CEETM(sub_portal);
8782 + qm_out(DCP_CFG(portal), dcp_cfg);
8783 + return 0;
8784 +}
8785 +
8786 +int qman_sp_disable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal)
8787 +{
8788 + u32 dcp_cfg;
8789 +
8790 + if (!qman_have_ccsr())
8791 + return -ENODEV;
8792 + dcp_cfg = qm_in(DCP_CFG(portal));
8793 + dcp_cfg &= ~(QM_SP_ENABLE_CEETM(sub_portal));
8794 + qm_out(DCP_CFG(portal), dcp_cfg);
8795 + return 0;
8796 +}
8797 +
8798 +int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num)
8799 +{
8800 + if (!qman_have_ccsr())
8801 + return -ENODEV;
8802 + *num = qm_in(CEETM_XSFDR_IN_USE);
8803 + return 0;
8804 +}
8805 +EXPORT_SYMBOL(qman_ceetm_get_xsfdr);
8806 +
8807 +#ifdef CONFIG_SYSFS
8808 +
8809 +#define DRV_NAME "fsl-qman"
8810 +#define DCP_MAX_ID 3
8811 +#define DCP_MIN_ID 0
8812 +
8813 +static ssize_t show_pfdr_fpc(struct device *dev,
8814 + struct device_attribute *dev_attr, char *buf)
8815 +{
8816 + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_FPC));
8817 +};
8818 +
8819 +static ssize_t show_dlm_avg(struct device *dev,
8820 + struct device_attribute *dev_attr, char *buf)
8821 +{
8822 + u32 data;
8823 + int i;
8824 +
8825 + if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i))
8826 + return -EINVAL;
8827 + if (i < DCP_MIN_ID || i > DCP_MAX_ID)
8828 + return -EINVAL;
8829 + data = qm_in(DCP_DLM_AVG(i));
8830 + return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8,
8831 + (data & 0x000000ff)*390625);
8832 +};
8833 +
8834 +static ssize_t set_dlm_avg(struct device *dev,
8835 + struct device_attribute *dev_attr, const char *buf, size_t count)
8836 +{
8837 + unsigned long val;
8838 + int i;
8839 +
8840 + if (!sscanf(dev_attr->attr.name, "dcp%d_dlm_avg", &i))
8841 + return -EINVAL;
8842 + if (i < DCP_MIN_ID || i > DCP_MAX_ID)
8843 + return -EINVAL;
8844 + if (kstrtoul(buf, 0, &val)) {
8845 + dev_dbg(dev, "invalid input %s\n", buf);
8846 + return -EINVAL;
8847 + }
8848 + qm_out(DCP_DLM_AVG(i), val);
8849 + return count;
8850 +};
8851 +
8852 +static ssize_t show_pfdr_cfg(struct device *dev,
8853 + struct device_attribute *dev_attr, char *buf)
8854 +{
8855 + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(PFDR_CFG));
8856 +};
8857 +
8858 +static ssize_t set_pfdr_cfg(struct device *dev,
8859 + struct device_attribute *dev_attr, const char *buf, size_t count)
8860 +{
8861 + unsigned long val;
8862 +
8863 + if (kstrtoul(buf, 0, &val)) {
8864 + dev_dbg(dev, "invalid input %s\n", buf);
8865 + return -EINVAL;
8866 + }
8867 + qm_out(PFDR_CFG, val);
8868 + return count;
8869 +};
8870 +
8871 +static ssize_t show_sfdr_in_use(struct device *dev,
8872 + struct device_attribute *dev_attr, char *buf)
8873 +{
8874 + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SFDR_IN_USE));
8875 +};
8876 +
8877 +static ssize_t show_idle_stat(struct device *dev,
8878 + struct device_attribute *dev_attr, char *buf)
8879 +{
8880 + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(IDLE_STAT));
8881 +};
8882 +
8883 +static ssize_t show_ci_rlm_avg(struct device *dev,
8884 + struct device_attribute *dev_attr, char *buf)
8885 +{
8886 + u32 data = qm_in(CI_RLM_AVG);
8887 + return snprintf(buf, PAGE_SIZE, "%d.%08d\n", data>>8,
8888 + (data & 0x000000ff)*390625);
8889 +};
8890 +
8891 +static ssize_t set_ci_rlm_avg(struct device *dev,
8892 + struct device_attribute *dev_attr, const char *buf, size_t count)
8893 +{
8894 + unsigned long val;
8895 +
8896 + if (kstrtoul(buf, 0, &val)) {
8897 + dev_dbg(dev, "invalid input %s\n", buf);
8898 + return -EINVAL;
8899 + }
8900 + qm_out(CI_RLM_AVG, val);
8901 + return count;
8902 +};
8903 +
8904 +static ssize_t show_err_isr(struct device *dev,
8905 + struct device_attribute *dev_attr, char *buf)
8906 +{
8907 + return snprintf(buf, PAGE_SIZE, "0x%08x\n", qm_in(ERR_ISR));
8908 +};
8909 +
8910 +#define SBEC_MAX_ID 14
8911 +#define SBEC_MIN_ID 0
8912 +
8913 +static ssize_t show_sbec(struct device *dev,
8914 + struct device_attribute *dev_attr, char *buf)
8915 +{
8916 + int i;
8917 +
8918 + if (!sscanf(dev_attr->attr.name, "sbec_%d", &i))
8919 + return -EINVAL;
8920 + if (i < SBEC_MIN_ID || i > SBEC_MAX_ID)
8921 + return -EINVAL;
8922 + return snprintf(buf, PAGE_SIZE, "%u\n", qm_in(SBEC(i)));
8923 +};
8924 +
8925 +static DEVICE_ATTR(pfdr_fpc, S_IRUSR, show_pfdr_fpc, NULL);
8926 +static DEVICE_ATTR(pfdr_cfg, S_IRUSR, show_pfdr_cfg, set_pfdr_cfg);
8927 +static DEVICE_ATTR(idle_stat, S_IRUSR, show_idle_stat, NULL);
8928 +static DEVICE_ATTR(ci_rlm_avg, (S_IRUSR|S_IWUSR),
8929 + show_ci_rlm_avg, set_ci_rlm_avg);
8930 +static DEVICE_ATTR(err_isr, S_IRUSR, show_err_isr, NULL);
8931 +static DEVICE_ATTR(sfdr_in_use, S_IRUSR, show_sfdr_in_use, NULL);
8932 +
8933 +static DEVICE_ATTR(dcp0_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
8934 +static DEVICE_ATTR(dcp1_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
8935 +static DEVICE_ATTR(dcp2_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
8936 +static DEVICE_ATTR(dcp3_dlm_avg, (S_IRUSR|S_IWUSR), show_dlm_avg, set_dlm_avg);
8937 +
8938 +static DEVICE_ATTR(sbec_0, S_IRUSR, show_sbec, NULL);
8939 +static DEVICE_ATTR(sbec_1, S_IRUSR, show_sbec, NULL);
8940 +static DEVICE_ATTR(sbec_2, S_IRUSR, show_sbec, NULL);
8941 +static DEVICE_ATTR(sbec_3, S_IRUSR, show_sbec, NULL);
8942 +static DEVICE_ATTR(sbec_4, S_IRUSR, show_sbec, NULL);
8943 +static DEVICE_ATTR(sbec_5, S_IRUSR, show_sbec, NULL);
8944 +static DEVICE_ATTR(sbec_6, S_IRUSR, show_sbec, NULL);
8945 +static DEVICE_ATTR(sbec_7, S_IRUSR, show_sbec, NULL);
8946 +static DEVICE_ATTR(sbec_8, S_IRUSR, show_sbec, NULL);
8947 +static DEVICE_ATTR(sbec_9, S_IRUSR, show_sbec, NULL);
8948 +static DEVICE_ATTR(sbec_10, S_IRUSR, show_sbec, NULL);
8949 +static DEVICE_ATTR(sbec_11, S_IRUSR, show_sbec, NULL);
8950 +static DEVICE_ATTR(sbec_12, S_IRUSR, show_sbec, NULL);
8951 +static DEVICE_ATTR(sbec_13, S_IRUSR, show_sbec, NULL);
8952 +static DEVICE_ATTR(sbec_14, S_IRUSR, show_sbec, NULL);
8953 +
8954 +static struct attribute *qman_dev_attributes[] = {
8955 + &dev_attr_pfdr_fpc.attr,
8956 + &dev_attr_pfdr_cfg.attr,
8957 + &dev_attr_idle_stat.attr,
8958 + &dev_attr_ci_rlm_avg.attr,
8959 + &dev_attr_err_isr.attr,
8960 + &dev_attr_dcp0_dlm_avg.attr,
8961 + &dev_attr_dcp1_dlm_avg.attr,
8962 + &dev_attr_dcp2_dlm_avg.attr,
8963 + &dev_attr_dcp3_dlm_avg.attr,
8964 + /* sfdr_in_use will be added if necessary */
8965 + NULL
8966 +};
8967 +
8968 +static struct attribute *qman_dev_ecr_attributes[] = {
8969 + &dev_attr_sbec_0.attr,
8970 + &dev_attr_sbec_1.attr,
8971 + &dev_attr_sbec_2.attr,
8972 + &dev_attr_sbec_3.attr,
8973 + &dev_attr_sbec_4.attr,
8974 + &dev_attr_sbec_5.attr,
8975 + &dev_attr_sbec_6.attr,
8976 + &dev_attr_sbec_7.attr,
8977 + &dev_attr_sbec_8.attr,
8978 + &dev_attr_sbec_9.attr,
8979 + &dev_attr_sbec_10.attr,
8980 + &dev_attr_sbec_11.attr,
8981 + &dev_attr_sbec_12.attr,
8982 + &dev_attr_sbec_13.attr,
8983 + &dev_attr_sbec_14.attr,
8984 + NULL
8985 +};
8986 +
8987 +/* root level */
8988 +static const struct attribute_group qman_dev_attr_grp = {
8989 + .name = NULL,
8990 + .attrs = qman_dev_attributes
8991 +};
8992 +static const struct attribute_group qman_dev_ecr_grp = {
8993 + .name = "error_capture",
8994 + .attrs = qman_dev_ecr_attributes
8995 +};
8996 +
8997 +static int of_fsl_qman_remove(struct platform_device *ofdev)
8998 +{
8999 + sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp);
9000 + return 0;
9001 +};
9002 +
9003 +static int of_fsl_qman_probe(struct platform_device *ofdev)
9004 +{
9005 + int ret;
9006 +
9007 + ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_attr_grp);
9008 + if (ret)
9009 + goto done;
9010 + ret = sysfs_add_file_to_group(&ofdev->dev.kobj,
9011 + &dev_attr_sfdr_in_use.attr, qman_dev_attr_grp.name);
9012 + if (ret)
9013 + goto del_group_0;
9014 + ret = sysfs_create_group(&ofdev->dev.kobj, &qman_dev_ecr_grp);
9015 + if (ret)
9016 + goto del_group_0;
9017 +
9018 + goto done;
9019 +
9020 +del_group_0:
9021 + sysfs_remove_group(&ofdev->dev.kobj, &qman_dev_attr_grp);
9022 +done:
9023 + if (ret)
9024 + dev_err(&ofdev->dev,
9025 + "Cannot create dev attributes ret=%d\n", ret);
9026 + return ret;
9027 +};
9028 +
9029 +static struct of_device_id of_fsl_qman_ids[] = {
9030 + {
9031 + .compatible = "fsl,qman",
9032 + },
9033 + {}
9034 +};
9035 +MODULE_DEVICE_TABLE(of, of_fsl_qman_ids);
9036 +
9037 +#ifdef CONFIG_SUSPEND
9038 +
9039 +static u32 saved_isdr;
9040 +static int qman_pm_suspend_noirq(struct device *dev)
9041 +{
9042 + uint32_t idle_state;
9043 +
9044 + suspend_unused_qportal();
9045 + /* save isdr, disable all, clear isr */
9046 + saved_isdr = qm_err_isr_disable_read(qm);
9047 + qm_err_isr_disable_write(qm, 0xffffffff);
9048 + qm_err_isr_status_clear(qm, 0xffffffff);
9049 + idle_state = qm_in(IDLE_STAT);
9050 + if (!(idle_state & 0x1)) {
9051 + pr_err("Qman not idle 0x%x aborting\n", idle_state);
9052 + qm_err_isr_disable_write(qm, saved_isdr);
9053 + resume_unused_qportal();
9054 + return -EBUSY;
9055 + }
9056 +#ifdef CONFIG_PM_DEBUG
9057 + pr_info("Qman suspend code, IDLE_STAT = 0x%x\n", idle_state);
9058 +#endif
9059 + return 0;
9060 +}
9061 +
9062 +static int qman_pm_resume_noirq(struct device *dev)
9063 +{
9064 + /* restore isdr */
9065 + qm_err_isr_disable_write(qm, saved_isdr);
9066 + resume_unused_qportal();
9067 + return 0;
9068 +}
9069 +#else
9070 +#define qman_pm_suspend_noirq NULL
9071 +#define qman_pm_resume_noirq NULL
9072 +#endif
9073 +
9074 +static const struct dev_pm_ops qman_pm_ops = {
9075 + .suspend_noirq = qman_pm_suspend_noirq,
9076 + .resume_noirq = qman_pm_resume_noirq,
9077 +};
9078 +
9079 +static struct platform_driver of_fsl_qman_driver = {
9080 + .driver = {
9081 + .owner = THIS_MODULE,
9082 + .name = DRV_NAME,
9083 + .of_match_table = of_fsl_qman_ids,
9084 + .pm = &qman_pm_ops,
9085 + },
9086 + .probe = of_fsl_qman_probe,
9087 + .remove = of_fsl_qman_remove,
9088 +};
9089 +
9090 +static int qman_ctrl_init(void)
9091 +{
9092 + return platform_driver_register(&of_fsl_qman_driver);
9093 +}
9094 +
9095 +static void qman_ctrl_exit(void)
9096 +{
9097 + platform_driver_unregister(&of_fsl_qman_driver);
9098 +}
9099 +
9100 +module_init(qman_ctrl_init);
9101 +module_exit(qman_ctrl_exit);
9102 +
9103 +#endif /* CONFIG_SYSFS */
9104 --- /dev/null
9105 +++ b/drivers/staging/fsl_qbman/qman_debugfs.c
9106 @@ -0,0 +1,1594 @@
9107 +/* Copyright 2010-2011 Freescale Semiconductor, Inc.
9108 + *
9109 + * Redistribution and use in source and binary forms, with or without
9110 + * modification, are permitted provided that the following conditions are met:
9111 + * * Redistributions of source code must retain the above copyright
9112 + * notice, this list of conditions and the following disclaimer.
9113 + * * Redistributions in binary form must reproduce the above copyright
9114 + * notice, this list of conditions and the following disclaimer in the
9115 + * documentation and/or other materials provided with the distribution.
9116 + * * Neither the name of Freescale Semiconductor nor the
9117 + * names of its contributors may be used to endorse or promote products
9118 + * derived from this software without specific prior written permission.
9119 + *
9120 + *
9121 + * ALTERNATIVELY, this software may be distributed under the terms of the
9122 + * GNU General Public License ("GPL") as published by the Free Software
9123 + * Foundation, either version 2 of that License or (at your option) any
9124 + * later version.
9125 + *
9126 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
9127 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9128 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9129 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
9130 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
9131 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
9132 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
9133 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
9134 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
9135 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9136 + */
9137 +#include "qman_private.h"
9138 +
9139 +#define MAX_FQID (0x00ffffff)
9140 +#define QM_FQD_BLOCK_SIZE 64
9141 +#define QM_FQD_AR (0xC10)
9142 +
9143 +static u32 fqid_max;
9144 +static u64 qman_ccsr_start;
9145 +static u64 qman_ccsr_size;
9146 +
9147 +static const char * const state_txt[] = {
9148 + "Out of Service",
9149 + "Retired",
9150 + "Tentatively Scheduled",
9151 + "Truly Scheduled",
9152 + "Parked",
9153 + "Active, Active Held or Held Suspended",
9154 + "Unknown State 6",
9155 + "Unknown State 7",
9156 + NULL,
9157 +};
9158 +
9159 +static const u8 fqd_states[] = {
9160 + QM_MCR_NP_STATE_OOS, QM_MCR_NP_STATE_RETIRED, QM_MCR_NP_STATE_TEN_SCHED,
9161 + QM_MCR_NP_STATE_TRU_SCHED, QM_MCR_NP_STATE_PARKED,
9162 + QM_MCR_NP_STATE_ACTIVE};
9163 +
9164 +struct mask_to_text {
9165 + u16 mask;
9166 + const char *txt;
9167 +};
9168 +
9169 +struct mask_filter_s {
9170 + u16 mask;
9171 + u8 filter;
9172 +};
9173 +
9174 +static const struct mask_filter_s mask_filter[] = {
9175 + {QM_FQCTRL_PREFERINCACHE, 0},
9176 + {QM_FQCTRL_PREFERINCACHE, 1},
9177 + {QM_FQCTRL_HOLDACTIVE, 0},
9178 + {QM_FQCTRL_HOLDACTIVE, 1},
9179 + {QM_FQCTRL_AVOIDBLOCK, 0},
9180 + {QM_FQCTRL_AVOIDBLOCK, 1},
9181 + {QM_FQCTRL_FORCESFDR, 0},
9182 + {QM_FQCTRL_FORCESFDR, 1},
9183 + {QM_FQCTRL_CPCSTASH, 0},
9184 + {QM_FQCTRL_CPCSTASH, 1},
9185 + {QM_FQCTRL_CTXASTASHING, 0},
9186 + {QM_FQCTRL_CTXASTASHING, 1},
9187 + {QM_FQCTRL_ORP, 0},
9188 + {QM_FQCTRL_ORP, 1},
9189 + {QM_FQCTRL_TDE, 0},
9190 + {QM_FQCTRL_TDE, 1},
9191 + {QM_FQCTRL_CGE, 0},
9192 + {QM_FQCTRL_CGE, 1}
9193 +};
9194 +
9195 +static const struct mask_to_text fq_ctrl_text_list[] = {
9196 + {
9197 + .mask = QM_FQCTRL_PREFERINCACHE,
9198 + .txt = "Prefer in cache",
9199 + },
9200 + {
9201 + .mask = QM_FQCTRL_HOLDACTIVE,
9202 + .txt = "Hold active in portal",
9203 + },
9204 + {
9205 + .mask = QM_FQCTRL_AVOIDBLOCK,
9206 + .txt = "Avoid Blocking",
9207 + },
9208 + {
9209 + .mask = QM_FQCTRL_FORCESFDR,
9210 + .txt = "High-priority SFDRs",
9211 + },
9212 + {
9213 + .mask = QM_FQCTRL_CPCSTASH,
9214 + .txt = "CPC Stash Enable",
9215 + },
9216 + {
9217 + .mask = QM_FQCTRL_CTXASTASHING,
9218 + .txt = "Context-A stashing",
9219 + },
9220 + {
9221 + .mask = QM_FQCTRL_ORP,
9222 + .txt = "ORP Enable",
9223 + },
9224 + {
9225 + .mask = QM_FQCTRL_TDE,
9226 + .txt = "Tail-Drop Enable",
9227 + },
9228 + {
9229 + .mask = QM_FQCTRL_CGE,
9230 + .txt = "Congestion Group Enable",
9231 + },
9232 + {
9233 + .mask = 0,
9234 + .txt = NULL,
9235 + }
9236 +};
9237 +
9238 +static const char *get_fqd_ctrl_text(u16 mask)
9239 +{
9240 + int i = 0;
9241 +
9242 + while (fq_ctrl_text_list[i].txt != NULL) {
9243 + if (fq_ctrl_text_list[i].mask == mask)
9244 + return fq_ctrl_text_list[i].txt;
9245 + i++;
9246 + }
9247 + return NULL;
9248 +}
9249 +
9250 +static const struct mask_to_text stashing_text_list[] = {
9251 + {
9252 + .mask = QM_STASHING_EXCL_CTX,
9253 + .txt = "FQ Ctx Stash"
9254 + },
9255 + {
9256 + .mask = QM_STASHING_EXCL_DATA,
9257 + .txt = "Frame Data Stash",
9258 + },
9259 + {
9260 + .mask = QM_STASHING_EXCL_ANNOTATION,
9261 + .txt = "Frame Annotation Stash",
9262 + },
9263 + {
9264 + .mask = 0,
9265 + .txt = NULL,
9266 + },
9267 +};
9268 +
9269 +static int user_input_convert(const char __user *user_buf, size_t count,
9270 + unsigned long *val)
9271 +{
9272 + char buf[12];
9273 +
9274 + if (count > sizeof(buf) - 1)
9275 + return -EINVAL;
9276 + if (copy_from_user(buf, user_buf, count))
9277 + return -EFAULT;
9278 + buf[count] = '\0';
9279 + if (kstrtoul(buf, 0, val))
9280 + return -EINVAL;
9281 + return 0;
9282 +}
9283 +
9284 +struct line_buffer_fq {
9285 + u32 buf[8];
9286 + u32 buf_cnt;
9287 + int line_cnt;
9288 +};
9289 +
9290 +static void add_to_line_buffer(struct line_buffer_fq *line_buf, u32 fqid,
9291 + struct seq_file *file)
9292 +{
9293 + line_buf->buf[line_buf->buf_cnt] = fqid;
9294 + line_buf->buf_cnt++;
9295 + if (line_buf->buf_cnt == 8) {
9296 + /* Buffer is full, flush it */
9297 + if (line_buf->line_cnt != 0)
9298 + seq_puts(file, ",\n");
9299 + seq_printf(file, "0x%06x,0x%06x,0x%06x,0x%06x,0x%06x,"
9300 + "0x%06x,0x%06x,0x%06x",
9301 + line_buf->buf[0], line_buf->buf[1], line_buf->buf[2],
9302 + line_buf->buf[3], line_buf->buf[4], line_buf->buf[5],
9303 + line_buf->buf[6], line_buf->buf[7]);
9304 + line_buf->buf_cnt = 0;
9305 + line_buf->line_cnt++;
9306 + }
9307 +}
9308 +
9309 +static void flush_line_buffer(struct line_buffer_fq *line_buf,
9310 + struct seq_file *file)
9311 +{
9312 + if (line_buf->buf_cnt) {
9313 + int y = 0;
9314 + if (line_buf->line_cnt != 0)
9315 + seq_puts(file, ",\n");
9316 + while (y != line_buf->buf_cnt) {
9317 + if (y+1 == line_buf->buf_cnt)
9318 + seq_printf(file, "0x%06x", line_buf->buf[y]);
9319 + else
9320 + seq_printf(file, "0x%06x,", line_buf->buf[y]);
9321 + y++;
9322 + }
9323 + line_buf->line_cnt++;
9324 + }
9325 + if (line_buf->line_cnt)
9326 + seq_putc(file, '\n');
9327 +}
9328 +
9329 +static struct dentry *dfs_root; /* debugfs root directory */
9330 +
9331 +/*******************************************************************************
9332 + * Query Frame Queue Non Programmable Fields
9333 + ******************************************************************************/
9334 +struct query_fq_np_fields_data_s {
9335 + u32 fqid;
9336 +};
9337 +static struct query_fq_np_fields_data_s query_fq_np_fields_data = {
9338 + .fqid = 1,
9339 +};
9340 +
9341 +static int query_fq_np_fields_show(struct seq_file *file, void *offset)
9342 +{
9343 + int ret;
9344 + struct qm_mcr_queryfq_np np;
9345 + struct qman_fq fq;
9346 +
9347 + fq.fqid = query_fq_np_fields_data.fqid;
9348 + ret = qman_query_fq_np(&fq, &np);
9349 + if (ret)
9350 + return ret;
9351 + /* Print state */
9352 + seq_printf(file, "Query FQ Non Programmable Fields Result fqid 0x%x\n",
9353 + fq.fqid);
9354 + seq_printf(file, " force eligible pending: %s\n",
9355 + (np.state & QM_MCR_NP_STATE_FE) ? "yes" : "no");
9356 + seq_printf(file, " retirement pending: %s\n",
9357 + (np.state & QM_MCR_NP_STATE_R) ? "yes" : "no");
9358 + seq_printf(file, " state: %s\n",
9359 + state_txt[np.state & QM_MCR_NP_STATE_MASK]);
9360 + seq_printf(file, " fq_link: 0x%x\n", np.fqd_link);
9361 + seq_printf(file, " odp_seq: %u\n", np.odp_seq);
9362 + seq_printf(file, " orp_nesn: %u\n", np.orp_nesn);
9363 + seq_printf(file, " orp_ea_hseq: %u\n", np.orp_ea_hseq);
9364 + seq_printf(file, " orp_ea_tseq: %u\n", np.orp_ea_tseq);
9365 + seq_printf(file, " orp_ea_hptr: 0x%x\n", np.orp_ea_hptr);
9366 + seq_printf(file, " orp_ea_tptr: 0x%x\n", np.orp_ea_tptr);
9367 + seq_printf(file, " pfdr_hptr: 0x%x\n", np.pfdr_hptr);
9368 + seq_printf(file, " pfdr_tptr: 0x%x\n", np.pfdr_tptr);
9369 + seq_printf(file, " is: ics_surp contains a %s\n",
9370 + (np.is) ? "deficit" : "surplus");
9371 + seq_printf(file, " ics_surp: %u\n", np.ics_surp);
9372 + seq_printf(file, " byte_cnt: %u\n", np.byte_cnt);
9373 + seq_printf(file, " frm_cnt: %u\n", np.frm_cnt);
9374 + seq_printf(file, " ra1_sfdr: 0x%x\n", np.ra1_sfdr);
9375 + seq_printf(file, " ra2_sfdr: 0x%x\n", np.ra2_sfdr);
9376 + seq_printf(file, " od1_sfdr: 0x%x\n", np.od1_sfdr);
9377 + seq_printf(file, " od2_sfdr: 0x%x\n", np.od2_sfdr);
9378 + seq_printf(file, " od3_sfdr: 0x%x\n", np.od3_sfdr);
9379 + return 0;
9380 +}
9381 +
9382 +static int query_fq_np_fields_open(struct inode *inode,
9383 + struct file *file)
9384 +{
9385 + return single_open(file, query_fq_np_fields_show, NULL);
9386 +}
9387 +
9388 +static ssize_t query_fq_np_fields_write(struct file *f,
9389 + const char __user *buf, size_t count, loff_t *off)
9390 +{
9391 + int ret;
9392 + unsigned long val;
9393 +
9394 + ret = user_input_convert(buf, count, &val);
9395 + if (ret)
9396 + return ret;
9397 + if (val > MAX_FQID)
9398 + return -EINVAL;
9399 + query_fq_np_fields_data.fqid = (u32)val;
9400 + return count;
9401 +}
9402 +
9403 +static const struct file_operations query_fq_np_fields_fops = {
9404 + .owner = THIS_MODULE,
9405 + .open = query_fq_np_fields_open,
9406 + .read = seq_read,
9407 + .write = query_fq_np_fields_write,
9408 + .release = single_release,
9409 +};
9410 +
9411 +/*******************************************************************************
9412 + * Frame Queue Programmable Fields
9413 + ******************************************************************************/
9414 +struct query_fq_fields_data_s {
9415 + u32 fqid;
9416 +};
9417 +
9418 +static struct query_fq_fields_data_s query_fq_fields_data = {
9419 + .fqid = 1,
9420 +};
9421 +
9422 +static int query_fq_fields_show(struct seq_file *file, void *offset)
9423 +{
9424 + int ret;
9425 + struct qm_fqd fqd;
9426 + struct qman_fq fq;
9427 + int i = 0;
9428 +
9429 + memset(&fqd, 0, sizeof(struct qm_fqd));
9430 + fq.fqid = query_fq_fields_data.fqid;
9431 + ret = qman_query_fq(&fq, &fqd);
9432 + if (ret)
9433 + return ret;
9434 + seq_printf(file, "Query FQ Programmable Fields Result fqid 0x%x\n",
9435 + fq.fqid);
9436 + seq_printf(file, " orprws: %u\n", fqd.orprws);
9437 + seq_printf(file, " oa: %u\n", fqd.oa);
9438 + seq_printf(file, " olws: %u\n", fqd.olws);
9439 +
9440 + seq_printf(file, " cgid: %u\n", fqd.cgid);
9441 +
9442 + if ((fqd.fq_ctrl & QM_FQCTRL_MASK) == 0)
9443 + seq_puts(file, " fq_ctrl: None\n");
9444 + else {
9445 + i = 0;
9446 + seq_puts(file, " fq_ctrl:\n");
9447 + while (fq_ctrl_text_list[i].txt != NULL) {
9448 + if ((fqd.fq_ctrl & QM_FQCTRL_MASK) &
9449 + fq_ctrl_text_list[i].mask)
9450 + seq_printf(file, " %s\n",
9451 + fq_ctrl_text_list[i].txt);
9452 + i++;
9453 + }
9454 + }
9455 + seq_printf(file, " dest_channel: %u\n", fqd.dest.channel);
9456 + seq_printf(file, " dest_wq: %u\n", fqd.dest.wq);
9457 + seq_printf(file, " ics_cred: %u\n", fqd.ics_cred);
9458 + seq_printf(file, " td_mant: %u\n", fqd.td.mant);
9459 + seq_printf(file, " td_exp: %u\n", fqd.td.exp);
9460 +
9461 + seq_printf(file, " ctx_b: 0x%x\n", fqd.context_b);
9462 +
9463 + seq_printf(file, " ctx_a: 0x%llx\n", qm_fqd_stashing_get64(&fqd));
9464 + /* Any stashing configured */
9465 + if ((fqd.context_a.stashing.exclusive & 0x7) == 0)
9466 + seq_puts(file, " ctx_a_stash_exclusive: None\n");
9467 + else {
9468 + seq_puts(file, " ctx_a_stash_exclusive:\n");
9469 + i = 0;
9470 + while (stashing_text_list[i].txt != NULL) {
9471 + if ((fqd.fq_ctrl & 0x7) & stashing_text_list[i].mask)
9472 + seq_printf(file, " %s\n",
9473 + stashing_text_list[i].txt);
9474 + i++;
9475 + }
9476 + }
9477 + seq_printf(file, " ctx_a_stash_annotation_cl: %u\n",
9478 + fqd.context_a.stashing.annotation_cl);
9479 + seq_printf(file, " ctx_a_stash_data_cl: %u\n",
9480 + fqd.context_a.stashing.data_cl);
9481 + seq_printf(file, " ctx_a_stash_context_cl: %u\n",
9482 + fqd.context_a.stashing.context_cl);
9483 + return 0;
9484 +}
9485 +
9486 +static int query_fq_fields_open(struct inode *inode,
9487 + struct file *file)
9488 +{
9489 + return single_open(file, query_fq_fields_show, NULL);
9490 +}
9491 +
9492 +static ssize_t query_fq_fields_write(struct file *f,
9493 + const char __user *buf, size_t count, loff_t *off)
9494 +{
9495 + int ret;
9496 + unsigned long val;
9497 +
9498 + ret = user_input_convert(buf, count, &val);
9499 + if (ret)
9500 + return ret;
9501 + if (val > MAX_FQID)
9502 + return -EINVAL;
9503 + query_fq_fields_data.fqid = (u32)val;
9504 + return count;
9505 +}
9506 +
9507 +static const struct file_operations query_fq_fields_fops = {
9508 + .owner = THIS_MODULE,
9509 + .open = query_fq_fields_open,
9510 + .read = seq_read,
9511 + .write = query_fq_fields_write,
9512 + .release = single_release,
9513 +};
9514 +
9515 +/*******************************************************************************
9516 + * Query WQ lengths
9517 + ******************************************************************************/
9518 +struct query_wq_lengths_data_s {
9519 + union {
9520 + u16 channel_wq; /* ignores wq (3 lsbits) */
9521 + struct {
9522 + u16 id:13; /* qm_channel */
9523 + u16 __reserved:3;
9524 + } __packed channel;
9525 + };
9526 +};
9527 +static struct query_wq_lengths_data_s query_wq_lengths_data;
9528 +static int query_wq_lengths_show(struct seq_file *file, void *offset)
9529 +{
9530 + int ret;
9531 + struct qm_mcr_querywq wq;
9532 + int i;
9533 +
9534 + memset(&wq, 0, sizeof(struct qm_mcr_querywq));
9535 + wq.channel.id = query_wq_lengths_data.channel.id;
9536 + ret = qman_query_wq(0, &wq);
9537 + if (ret)
9538 + return ret;
9539 + seq_printf(file, "Query Result For Channel: 0x%x\n", wq.channel.id);
9540 + for (i = 0; i < 8; i++)
9541 + /* mask out upper 4 bits since they are not part of length */
9542 + seq_printf(file, " wq%d_len : %u\n", i, wq.wq_len[i] & 0x0fff);
9543 + return 0;
9544 +}
9545 +
9546 +static int query_wq_lengths_open(struct inode *inode,
9547 + struct file *file)
9548 +{
9549 + return single_open(file, query_wq_lengths_show, NULL);
9550 +}
9551 +
9552 +static ssize_t query_wq_lengths_write(struct file *f,
9553 + const char __user *buf, size_t count, loff_t *off)
9554 +{
9555 + int ret;
9556 + unsigned long val;
9557 +
9558 + ret = user_input_convert(buf, count, &val);
9559 + if (ret)
9560 + return ret;
9561 + if (val > 0xfff8)
9562 + return -EINVAL;
9563 + query_wq_lengths_data.channel.id = (u16)val;
9564 + return count;
9565 +}
9566 +
9567 +static const struct file_operations query_wq_lengths_fops = {
9568 + .owner = THIS_MODULE,
9569 + .open = query_wq_lengths_open,
9570 + .read = seq_read,
9571 + .write = query_wq_lengths_write,
9572 + .release = single_release,
9573 +};
9574 +
9575 +/*******************************************************************************
9576 + * Query CGR
9577 + ******************************************************************************/
9578 +struct query_cgr_s {
9579 + u8 cgid;
9580 +};
9581 +static struct query_cgr_s query_cgr_data;
9582 +
9583 +static int query_cgr_show(struct seq_file *file, void *offset)
9584 +{
9585 + int ret;
9586 + struct qm_mcr_querycgr cgrd;
9587 + struct qman_cgr cgr;
9588 + int i, j;
9589 + u32 mask;
9590 +
9591 + memset(&cgr, 0, sizeof(cgr));
9592 + memset(&cgrd, 0, sizeof(cgrd));
9593 + cgr.cgrid = query_cgr_data.cgid;
9594 + ret = qman_query_cgr(&cgr, &cgrd);
9595 + if (ret)
9596 + return ret;
9597 + seq_printf(file, "Query CGR id 0x%x\n", cgr.cgrid);
9598 + seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9599 + cgrd.cgr.wr_parm_g.MA, cgrd.cgr.wr_parm_g.Mn,
9600 + cgrd.cgr.wr_parm_g.SA, cgrd.cgr.wr_parm_g.Sn,
9601 + cgrd.cgr.wr_parm_g.Pn);
9602 +
9603 + seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9604 + cgrd.cgr.wr_parm_y.MA, cgrd.cgr.wr_parm_y.Mn,
9605 + cgrd.cgr.wr_parm_y.SA, cgrd.cgr.wr_parm_y.Sn,
9606 + cgrd.cgr.wr_parm_y.Pn);
9607 +
9608 + seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9609 + cgrd.cgr.wr_parm_r.MA, cgrd.cgr.wr_parm_r.Mn,
9610 + cgrd.cgr.wr_parm_r.SA, cgrd.cgr.wr_parm_r.Sn,
9611 + cgrd.cgr.wr_parm_r.Pn);
9612 +
9613 + seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n",
9614 + cgrd.cgr.wr_en_g, cgrd.cgr.wr_en_y, cgrd.cgr.wr_en_r);
9615 +
9616 + seq_printf(file, " cscn_en: %u\n", cgrd.cgr.cscn_en);
9617 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) {
9618 + seq_puts(file, " cscn_targ_dcp:\n");
9619 + mask = 0x80000000;
9620 + for (i = 0; i < 32; i++) {
9621 + if (cgrd.cgr.cscn_targ & mask)
9622 + seq_printf(file, " send CSCN to dcp %u\n",
9623 + (31 - i));
9624 + mask >>= 1;
9625 + }
9626 +
9627 + seq_puts(file, " cscn_targ_swp:\n");
9628 + for (i = 0; i < 4; i++) {
9629 + mask = 0x80000000;
9630 + for (j = 0; j < 32; j++) {
9631 + if (cgrd.cscn_targ_swp[i] & mask)
9632 + seq_printf(file, " send CSCN to swp"
9633 + " %u\n", (127 - (i * 32) - j));
9634 + mask >>= 1;
9635 + }
9636 + }
9637 + } else {
9638 + seq_printf(file, " cscn_targ: %u\n", cgrd.cgr.cscn_targ);
9639 + }
9640 + seq_printf(file, " cstd_en: %u\n", cgrd.cgr.cstd_en);
9641 + seq_printf(file, " cs: %u\n", cgrd.cgr.cs);
9642 +
9643 + seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n",
9644 + cgrd.cgr.cs_thres.TA, cgrd.cgr.cs_thres.Tn);
9645 +
9646 + seq_printf(file, " mode: %s\n",
9647 + (cgrd.cgr.mode & QMAN_CGR_MODE_FRAME) ?
9648 + "frame count" : "byte count");
9649 + seq_printf(file, " i_bcnt: %llu\n", qm_mcr_querycgr_i_get64(&cgrd));
9650 + seq_printf(file, " a_bcnt: %llu\n", qm_mcr_querycgr_a_get64(&cgrd));
9651 +
9652 + return 0;
9653 +}
9654 +
9655 +static int query_cgr_open(struct inode *inode, struct file *file)
9656 +{
9657 + return single_open(file, query_cgr_show, NULL);
9658 +}
9659 +
9660 +static ssize_t query_cgr_write(struct file *f, const char __user *buf,
9661 + size_t count, loff_t *off)
9662 +{
9663 + int ret;
9664 + unsigned long val;
9665 +
9666 + ret = user_input_convert(buf, count, &val);
9667 + if (ret)
9668 + return ret;
9669 + if (val > 0xff)
9670 + return -EINVAL;
9671 + query_cgr_data.cgid = (u8)val;
9672 + return count;
9673 +}
9674 +
9675 +static const struct file_operations query_cgr_fops = {
9676 + .owner = THIS_MODULE,
9677 + .open = query_cgr_open,
9678 + .read = seq_read,
9679 + .write = query_cgr_write,
9680 + .release = single_release,
9681 +};
9682 +
9683 +/*******************************************************************************
9684 + * Test Write CGR
9685 + ******************************************************************************/
9686 +struct test_write_cgr_s {
9687 + u64 i_bcnt;
9688 + u8 cgid;
9689 +};
9690 +static struct test_write_cgr_s test_write_cgr_data;
9691 +
9692 +static int testwrite_cgr_show(struct seq_file *file, void *offset)
9693 +{
9694 + int ret;
9695 + struct qm_mcr_cgrtestwrite result;
9696 + struct qman_cgr cgr;
9697 + u64 i_bcnt;
9698 +
9699 + memset(&cgr, 0, sizeof(struct qman_cgr));
9700 + memset(&result, 0, sizeof(struct qm_mcr_cgrtestwrite));
9701 + cgr.cgrid = test_write_cgr_data.cgid;
9702 + i_bcnt = test_write_cgr_data.i_bcnt;
9703 + ret = qman_testwrite_cgr(&cgr, i_bcnt, &result);
9704 + if (ret)
9705 + return ret;
9706 + seq_printf(file, "CGR Test Write CGR id 0x%x\n", cgr.cgrid);
9707 + seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9708 + result.cgr.wr_parm_g.MA, result.cgr.wr_parm_g.Mn,
9709 + result.cgr.wr_parm_g.SA, result.cgr.wr_parm_g.Sn,
9710 + result.cgr.wr_parm_g.Pn);
9711 + seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9712 + result.cgr.wr_parm_y.MA, result.cgr.wr_parm_y.Mn,
9713 + result.cgr.wr_parm_y.SA, result.cgr.wr_parm_y.Sn,
9714 + result.cgr.wr_parm_y.Pn);
9715 + seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9716 + result.cgr.wr_parm_r.MA, result.cgr.wr_parm_r.Mn,
9717 + result.cgr.wr_parm_r.SA, result.cgr.wr_parm_r.Sn,
9718 + result.cgr.wr_parm_r.Pn);
9719 + seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n",
9720 + result.cgr.wr_en_g, result.cgr.wr_en_y, result.cgr.wr_en_r);
9721 + seq_printf(file, " cscn_en: %u\n", result.cgr.cscn_en);
9722 + seq_printf(file, " cscn_targ: %u\n", result.cgr.cscn_targ);
9723 + seq_printf(file, " cstd_en: %u\n", result.cgr.cstd_en);
9724 + seq_printf(file, " cs: %u\n", result.cgr.cs);
9725 + seq_printf(file, " cs_thresh_TA: %u, cs_thresh_Tn: %u\n",
9726 + result.cgr.cs_thres.TA, result.cgr.cs_thres.Tn);
9727 +
9728 + /* Add Mode for Si 2 */
9729 + seq_printf(file, " mode: %s\n",
9730 + (result.cgr.mode & QMAN_CGR_MODE_FRAME) ?
9731 + "frame count" : "byte count");
9732 +
9733 + seq_printf(file, " i_bcnt: %llu\n",
9734 + qm_mcr_cgrtestwrite_i_get64(&result));
9735 + seq_printf(file, " a_bcnt: %llu\n",
9736 + qm_mcr_cgrtestwrite_a_get64(&result));
9737 + seq_printf(file, " wr_prob_g: %u\n", result.wr_prob_g);
9738 + seq_printf(file, " wr_prob_y: %u\n", result.wr_prob_y);
9739 + seq_printf(file, " wr_prob_r: %u\n", result.wr_prob_r);
9740 + return 0;
9741 +}
9742 +
9743 +static int testwrite_cgr_open(struct inode *inode, struct file *file)
9744 +{
9745 + return single_open(file, testwrite_cgr_show, NULL);
9746 +}
9747 +
9748 +static const struct file_operations testwrite_cgr_fops = {
9749 + .owner = THIS_MODULE,
9750 + .open = testwrite_cgr_open,
9751 + .read = seq_read,
9752 + .release = single_release,
9753 +};
9754 +
9755 +
9756 +static int testwrite_cgr_ibcnt_show(struct seq_file *file, void *offset)
9757 +{
9758 + seq_printf(file, "i_bcnt: %llu\n", test_write_cgr_data.i_bcnt);
9759 + return 0;
9760 +}
9761 +static int testwrite_cgr_ibcnt_open(struct inode *inode, struct file *file)
9762 +{
9763 + return single_open(file, testwrite_cgr_ibcnt_show, NULL);
9764 +}
9765 +
9766 +static ssize_t testwrite_cgr_ibcnt_write(struct file *f, const char __user *buf,
9767 + size_t count, loff_t *off)
9768 +{
9769 + int ret;
9770 + unsigned long val;
9771 +
9772 + ret = user_input_convert(buf, count, &val);
9773 + if (ret)
9774 + return ret;
9775 + test_write_cgr_data.i_bcnt = val;
9776 + return count;
9777 +}
9778 +
9779 +static const struct file_operations teswrite_cgr_ibcnt_fops = {
9780 + .owner = THIS_MODULE,
9781 + .open = testwrite_cgr_ibcnt_open,
9782 + .read = seq_read,
9783 + .write = testwrite_cgr_ibcnt_write,
9784 + .release = single_release,
9785 +};
9786 +
9787 +static int testwrite_cgr_cgrid_show(struct seq_file *file, void *offset)
9788 +{
9789 + seq_printf(file, "cgrid: %u\n", (u32)test_write_cgr_data.cgid);
9790 + return 0;
9791 +}
9792 +static int testwrite_cgr_cgrid_open(struct inode *inode, struct file *file)
9793 +{
9794 + return single_open(file, testwrite_cgr_cgrid_show, NULL);
9795 +}
9796 +
9797 +static ssize_t testwrite_cgr_cgrid_write(struct file *f, const char __user *buf,
9798 + size_t count, loff_t *off)
9799 +{
9800 + int ret;
9801 + unsigned long val;
9802 +
9803 + ret = user_input_convert(buf, count, &val);
9804 + if (ret)
9805 + return ret;
9806 + if (val > 0xff)
9807 + return -EINVAL;
9808 + test_write_cgr_data.cgid = (u8)val;
9809 + return count;
9810 +}
9811 +
9812 +static const struct file_operations teswrite_cgr_cgrid_fops = {
9813 + .owner = THIS_MODULE,
9814 + .open = testwrite_cgr_cgrid_open,
9815 + .read = seq_read,
9816 + .write = testwrite_cgr_cgrid_write,
9817 + .release = single_release,
9818 +};
9819 +
9820 +/*******************************************************************************
9821 + * Query Congestion State
9822 + ******************************************************************************/
9823 +static int query_congestion_show(struct seq_file *file, void *offset)
9824 +{
9825 + int ret;
9826 + struct qm_mcr_querycongestion cs;
9827 + int i, j, in_cong = 0;
9828 + u32 mask;
9829 +
9830 + memset(&cs, 0, sizeof(struct qm_mcr_querycongestion));
9831 + ret = qman_query_congestion(&cs);
9832 + if (ret)
9833 + return ret;
9834 + seq_puts(file, "Query Congestion Result\n");
9835 + for (i = 0; i < 8; i++) {
9836 + mask = 0x80000000;
9837 + for (j = 0; j < 32; j++) {
9838 + if (cs.state.__state[i] & mask) {
9839 + in_cong = 1;
9840 + seq_printf(file, " cg %u: %s\n", (i*32)+j,
9841 + "in congestion");
9842 + }
9843 + mask >>= 1;
9844 + }
9845 + }
9846 + if (!in_cong)
9847 + seq_puts(file, " All congestion groups not congested.\n");
9848 + return 0;
9849 +}
9850 +
9851 +static int query_congestion_open(struct inode *inode, struct file *file)
9852 +{
9853 + return single_open(file, query_congestion_show, NULL);
9854 +}
9855 +
9856 +static const struct file_operations query_congestion_fops = {
9857 + .owner = THIS_MODULE,
9858 + .open = query_congestion_open,
9859 + .read = seq_read,
9860 + .release = single_release,
9861 +};
9862 +
9863 +/*******************************************************************************
9864 + * Query CCGR
9865 + ******************************************************************************/
9866 +struct query_ccgr_s {
9867 + u32 ccgid;
9868 +};
9869 +static struct query_ccgr_s query_ccgr_data;
9870 +
9871 +static int query_ccgr_show(struct seq_file *file, void *offset)
9872 +{
9873 + int ret;
9874 + struct qm_mcr_ceetm_ccgr_query ccgr_query;
9875 + struct qm_mcc_ceetm_ccgr_query query_opts;
9876 + int i, j;
9877 + u32 mask;
9878 +
9879 + memset(&ccgr_query, 0, sizeof(struct qm_mcr_ceetm_ccgr_query));
9880 + memset(&query_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_query));
9881 +
9882 + if ((qman_ip_rev & 0xFF00) < QMAN_REV30)
9883 + return -EINVAL;
9884 +
9885 + seq_printf(file, "Query CCGID %x\n", query_ccgr_data.ccgid);
9886 + query_opts.dcpid = ((query_ccgr_data.ccgid & 0xFF000000) >> 24);
9887 + query_opts.ccgrid = query_ccgr_data.ccgid & 0x000001FF;
9888 + ret = qman_ceetm_query_ccgr(&query_opts, &ccgr_query);
9889 + if (ret)
9890 + return ret;
9891 + seq_printf(file, "Query CCGR id %x in DCP %d\n", query_opts.ccgrid,
9892 + query_opts.dcpid);
9893 + seq_printf(file, " wr_parm_g MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9894 + ccgr_query.cm_query.wr_parm_g.MA,
9895 + ccgr_query.cm_query.wr_parm_g.Mn,
9896 + ccgr_query.cm_query.wr_parm_g.SA,
9897 + ccgr_query.cm_query.wr_parm_g.Sn,
9898 + ccgr_query.cm_query.wr_parm_g.Pn);
9899 +
9900 + seq_printf(file, " wr_parm_y MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9901 + ccgr_query.cm_query.wr_parm_y.MA,
9902 + ccgr_query.cm_query.wr_parm_y.Mn,
9903 + ccgr_query.cm_query.wr_parm_y.SA,
9904 + ccgr_query.cm_query.wr_parm_y.Sn,
9905 + ccgr_query.cm_query.wr_parm_y.Pn);
9906 +
9907 + seq_printf(file, " wr_parm_r MA: %u, Mn: %u, SA: %u, Sn: %u, Pn: %u\n",
9908 + ccgr_query.cm_query.wr_parm_r.MA,
9909 + ccgr_query.cm_query.wr_parm_r.Mn,
9910 + ccgr_query.cm_query.wr_parm_r.SA,
9911 + ccgr_query.cm_query.wr_parm_r.Sn,
9912 + ccgr_query.cm_query.wr_parm_r.Pn);
9913 +
9914 + seq_printf(file, " wr_en_g: %u, wr_en_y: %u, we_en_r: %u\n",
9915 + ccgr_query.cm_query.ctl_wr_en_g,
9916 + ccgr_query.cm_query.ctl_wr_en_y,
9917 + ccgr_query.cm_query.ctl_wr_en_r);
9918 +
9919 + seq_printf(file, " cscn_en: %u\n", ccgr_query.cm_query.ctl_cscn_en);
9920 + seq_puts(file, " cscn_targ_dcp:\n");
9921 + mask = 0x80000000;
9922 + for (i = 0; i < 32; i++) {
9923 + if (ccgr_query.cm_query.cscn_targ_dcp & mask)
9924 + seq_printf(file, " send CSCN to dcp %u\n", (31 - i));
9925 + mask >>= 1;
9926 + }
9927 +
9928 + seq_puts(file, " cscn_targ_swp:\n");
9929 + for (i = 0; i < 4; i++) {
9930 + mask = 0x80000000;
9931 + for (j = 0; j < 32; j++) {
9932 + if (ccgr_query.cm_query.cscn_targ_swp[i] & mask)
9933 + seq_printf(file, " send CSCN to swp"
9934 + "%u\n", (127 - (i * 32) - j));
9935 + mask >>= 1;
9936 + }
9937 + }
9938 +
9939 + seq_printf(file, " td_en: %u\n", ccgr_query.cm_query.ctl_td_en);
9940 +
9941 + seq_printf(file, " cs_thresh_in_TA: %u, cs_thresh_in_Tn: %u\n",
9942 + ccgr_query.cm_query.cs_thres.TA,
9943 + ccgr_query.cm_query.cs_thres.Tn);
9944 +
9945 + seq_printf(file, " cs_thresh_out_TA: %u, cs_thresh_out_Tn: %u\n",
9946 + ccgr_query.cm_query.cs_thres_x.TA,
9947 + ccgr_query.cm_query.cs_thres_x.Tn);
9948 +
9949 + seq_printf(file, " td_thresh_TA: %u, td_thresh_Tn: %u\n",
9950 + ccgr_query.cm_query.td_thres.TA,
9951 + ccgr_query.cm_query.td_thres.Tn);
9952 +
9953 + seq_printf(file, " mode: %s\n",
9954 + (ccgr_query.cm_query.ctl_mode &
9955 + QMAN_CGR_MODE_FRAME) ?
9956 + "frame count" : "byte count");
9957 + seq_printf(file, " i_cnt: %llu\n", (u64)ccgr_query.cm_query.i_cnt);
9958 + seq_printf(file, " a_cnt: %llu\n", (u64)ccgr_query.cm_query.a_cnt);
9959 +
9960 + return 0;
9961 +}
9962 +
9963 +static int query_ccgr_open(struct inode *inode, struct file *file)
9964 +{
9965 + return single_open(file, query_ccgr_show, NULL);
9966 +}
9967 +
9968 +static ssize_t query_ccgr_write(struct file *f, const char __user *buf,
9969 + size_t count, loff_t *off)
9970 +{
9971 + int ret;
9972 + unsigned long val;
9973 +
9974 + ret = user_input_convert(buf, count, &val);
9975 + if (ret)
9976 + return ret;
9977 + query_ccgr_data.ccgid = val;
9978 + return count;
9979 +}
9980 +
9981 +static const struct file_operations query_ccgr_fops = {
9982 + .owner = THIS_MODULE,
9983 + .open = query_ccgr_open,
9984 + .read = seq_read,
9985 + .write = query_ccgr_write,
9986 + .release = single_release,
9987 +};
9988 +/*******************************************************************************
9989 + * QMan register
9990 + ******************************************************************************/
9991 +struct qman_register_s {
9992 + u32 val;
9993 +};
9994 +static struct qman_register_s qman_register_data;
9995 +
9996 +static void init_ccsrmempeek(void)
9997 +{
9998 + struct device_node *dn;
9999 + const u32 *regaddr_p;
10000 +
10001 + dn = of_find_compatible_node(NULL, NULL, "fsl,qman");
10002 + if (!dn) {
10003 + pr_info("No fsl,qman node\n");
10004 + return;
10005 + }
10006 + regaddr_p = of_get_address(dn, 0, &qman_ccsr_size, NULL);
10007 + if (!regaddr_p) {
10008 + of_node_put(dn);
10009 + return;
10010 + }
10011 + qman_ccsr_start = of_translate_address(dn, regaddr_p);
10012 + of_node_put(dn);
10013 +}
10014 +/* This function provides access to QMan ccsr memory map */
10015 +static int qman_ccsrmempeek(u32 *val, u32 offset)
10016 +{
10017 + void __iomem *addr;
10018 + u64 phys_addr;
10019 +
10020 + if (!qman_ccsr_start)
10021 + return -EINVAL;
10022 +
10023 + if (offset > (qman_ccsr_size - sizeof(u32)))
10024 + return -EINVAL;
10025 +
10026 + phys_addr = qman_ccsr_start + offset;
10027 + addr = ioremap(phys_addr, sizeof(u32));
10028 + if (!addr) {
10029 + pr_err("ccsrmempeek, ioremap failed\n");
10030 + return -EINVAL;
10031 + }
10032 + *val = in_be32(addr);
10033 + iounmap(addr);
10034 + return 0;
10035 +}
10036 +
10037 +static int qman_ccsrmempeek_show(struct seq_file *file, void *offset)
10038 +{
10039 + u32 b;
10040 +
10041 + qman_ccsrmempeek(&b, qman_register_data.val);
10042 + seq_printf(file, "QMan register offset = 0x%x\n",
10043 + qman_register_data.val);
10044 + seq_printf(file, "value = 0x%08x\n", b);
10045 +
10046 + return 0;
10047 +}
10048 +
10049 +static int qman_ccsrmempeek_open(struct inode *inode, struct file *file)
10050 +{
10051 + return single_open(file, qman_ccsrmempeek_show, NULL);
10052 +}
10053 +
10054 +static ssize_t qman_ccsrmempeek_write(struct file *f, const char __user *buf,
10055 + size_t count, loff_t *off)
10056 +{
10057 + int ret;
10058 + unsigned long val;
10059 +
10060 + ret = user_input_convert(buf, count, &val);
10061 + if (ret)
10062 + return ret;
10063 + /* multiple of 4 */
10064 + if (val > (qman_ccsr_size - sizeof(u32))) {
10065 + pr_info("Input 0x%lx > 0x%llx\n",
10066 + val, (qman_ccsr_size - sizeof(u32)));
10067 + return -EINVAL;
10068 + }
10069 + if (val & 0x3) {
10070 + pr_info("Input 0x%lx not multiple of 4\n", val);
10071 + return -EINVAL;
10072 + }
10073 + qman_register_data.val = val;
10074 + return count;
10075 +}
10076 +
10077 +static const struct file_operations qman_ccsrmempeek_fops = {
10078 + .owner = THIS_MODULE,
10079 + .open = qman_ccsrmempeek_open,
10080 + .read = seq_read,
10081 + .write = qman_ccsrmempeek_write,
10082 +};
10083 +
10084 +/*******************************************************************************
10085 + * QMan state
10086 + ******************************************************************************/
10087 +static int qman_fqd_state_show(struct seq_file *file, void *offset)
10088 +{
10089 + struct qm_mcr_queryfq_np np;
10090 + struct qman_fq fq;
10091 + struct line_buffer_fq line_buf;
10092 + int ret, i;
10093 + u8 *state = file->private;
10094 + u32 qm_fq_state_cnt[ARRAY_SIZE(fqd_states)];
10095 +
10096 + memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt));
10097 + memset(&line_buf, 0, sizeof(line_buf));
10098 +
10099 + seq_printf(file, "List of fq ids in state: %s\n", state_txt[*state]);
10100 +
10101 + for (i = 1; i < fqid_max; i++) {
10102 + fq.fqid = i;
10103 + ret = qman_query_fq_np(&fq, &np);
10104 + if (ret)
10105 + return ret;
10106 + if (*state == (np.state & QM_MCR_NP_STATE_MASK))
10107 + add_to_line_buffer(&line_buf, fq.fqid, file);
10108 + /* Keep a summary count of all states */
10109 + if ((np.state & QM_MCR_NP_STATE_MASK) < ARRAY_SIZE(fqd_states))
10110 + qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++;
10111 + }
10112 + flush_line_buffer(&line_buf, file);
10113 +
10114 + for (i = 0; i < ARRAY_SIZE(fqd_states); i++) {
10115 + seq_printf(file, "%s count = %u\n", state_txt[i],
10116 + qm_fq_state_cnt[i]);
10117 + }
10118 + return 0;
10119 +}
10120 +
10121 +static int qman_fqd_state_open(struct inode *inode, struct file *file)
10122 +{
10123 + return single_open(file, qman_fqd_state_show, inode->i_private);
10124 +}
10125 +
10126 +static const struct file_operations qman_fqd_state_fops = {
10127 + .owner = THIS_MODULE,
10128 + .open = qman_fqd_state_open,
10129 + .read = seq_read,
10130 +};
10131 +
10132 +static int qman_fqd_ctrl_show(struct seq_file *file, void *offset)
10133 +{
10134 + struct qm_fqd fqd;
10135 + struct qman_fq fq;
10136 + u32 fq_en_cnt = 0, fq_di_cnt = 0;
10137 + int ret, i;
10138 + struct mask_filter_s *data = file->private;
10139 + const char *ctrl_txt = get_fqd_ctrl_text(data->mask);
10140 + struct line_buffer_fq line_buf;
10141 +
10142 + memset(&line_buf, 0, sizeof(line_buf));
10143 + seq_printf(file, "List of fq ids with: %s :%s\n",
10144 + ctrl_txt, (data->filter) ? "enabled" : "disabled");
10145 + for (i = 1; i < fqid_max; i++) {
10146 + fq.fqid = i;
10147 + memset(&fqd, 0, sizeof(struct qm_fqd));
10148 + ret = qman_query_fq(&fq, &fqd);
10149 + if (ret)
10150 + return ret;
10151 + if (data->filter) {
10152 + if (fqd.fq_ctrl & data->mask)
10153 + add_to_line_buffer(&line_buf, fq.fqid, file);
10154 + } else {
10155 + if (!(fqd.fq_ctrl & data->mask))
10156 + add_to_line_buffer(&line_buf, fq.fqid, file);
10157 + }
10158 + if (fqd.fq_ctrl & data->mask)
10159 + fq_en_cnt++;
10160 + else
10161 + fq_di_cnt++;
10162 + }
10163 + flush_line_buffer(&line_buf, file);
10164 +
10165 + seq_printf(file, "Total FQD with: %s : enabled = %u\n",
10166 + ctrl_txt, fq_en_cnt);
10167 + seq_printf(file, "Total FQD with: %s : disabled = %u\n",
10168 + ctrl_txt, fq_di_cnt);
10169 + return 0;
10170 +}
10171 +
10172 +/*******************************************************************************
10173 + * QMan ctrl CGE, TDE, ORP, CTX, CPC, SFDR, BLOCK, HOLD, CACHE
10174 + ******************************************************************************/
10175 +static int qman_fqd_ctrl_open(struct inode *inode, struct file *file)
10176 +{
10177 + return single_open(file, qman_fqd_ctrl_show, inode->i_private);
10178 +}
10179 +
10180 +static const struct file_operations qman_fqd_ctrl_fops = {
10181 + .owner = THIS_MODULE,
10182 + .open = qman_fqd_ctrl_open,
10183 + .read = seq_read,
10184 +};
10185 +
10186 +/*******************************************************************************
10187 + * QMan ctrl summary
10188 + ******************************************************************************/
10189 +/*******************************************************************************
10190 + * QMan summary state
10191 + ******************************************************************************/
10192 +static int qman_fqd_non_prog_summary_show(struct seq_file *file, void *offset)
10193 +{
10194 + struct qm_mcr_queryfq_np np;
10195 + struct qman_fq fq;
10196 + int ret, i;
10197 + u32 qm_fq_state_cnt[ARRAY_SIZE(fqd_states)];
10198 +
10199 + memset(qm_fq_state_cnt, 0, sizeof(qm_fq_state_cnt));
10200 +
10201 + for (i = 1; i < fqid_max; i++) {
10202 + fq.fqid = i;
10203 + ret = qman_query_fq_np(&fq, &np);
10204 + if (ret)
10205 + return ret;
10206 + /* Keep a summary count of all states */
10207 + if ((np.state & QM_MCR_NP_STATE_MASK) < ARRAY_SIZE(fqd_states))
10208 + qm_fq_state_cnt[(np.state & QM_MCR_NP_STATE_MASK)]++;
10209 + }
10210 +
10211 + for (i = 0; i < ARRAY_SIZE(fqd_states); i++) {
10212 + seq_printf(file, "%s count = %u\n", state_txt[i],
10213 + qm_fq_state_cnt[i]);
10214 + }
10215 + return 0;
10216 +}
10217 +
10218 +static int qman_fqd_prog_summary_show(struct seq_file *file, void *offset)
10219 +{
10220 + struct qm_fqd fqd;
10221 + struct qman_fq fq;
10222 + int ret, i , j;
10223 + u32 qm_prog_cnt[ARRAY_SIZE(mask_filter)/2];
10224 +
10225 + memset(qm_prog_cnt, 0, sizeof(qm_prog_cnt));
10226 +
10227 + for (i = 1; i < fqid_max; i++) {
10228 + memset(&fqd, 0, sizeof(struct qm_fqd));
10229 + fq.fqid = i;
10230 + ret = qman_query_fq(&fq, &fqd);
10231 + if (ret)
10232 + return ret;
10233 + /* Keep a summary count of all states */
10234 + for (j = 0; j < ARRAY_SIZE(mask_filter); j += 2)
10235 + if ((fqd.fq_ctrl & QM_FQCTRL_MASK) &
10236 + mask_filter[j].mask)
10237 + qm_prog_cnt[j/2]++;
10238 + }
10239 + for (i = 0; i < ARRAY_SIZE(mask_filter) / 2; i++) {
10240 + seq_printf(file, "%s count = %u\n",
10241 + get_fqd_ctrl_text(mask_filter[i*2].mask),
10242 + qm_prog_cnt[i]);
10243 + }
10244 + return 0;
10245 +}
10246 +
10247 +static int qman_fqd_summary_show(struct seq_file *file, void *offset)
10248 +{
10249 + int ret;
10250 +
10251 + /* Display summary of non programmable fields */
10252 + ret = qman_fqd_non_prog_summary_show(file, offset);
10253 + if (ret)
10254 + return ret;
10255 + seq_puts(file, "-----------------------------------------\n");
10256 + /* Display programmable fields */
10257 + ret = qman_fqd_prog_summary_show(file, offset);
10258 + if (ret)
10259 + return ret;
10260 + return 0;
10261 +}
10262 +
10263 +static int qman_fqd_summary_open(struct inode *inode, struct file *file)
10264 +{
10265 + return single_open(file, qman_fqd_summary_show, NULL);
10266 +}
10267 +
10268 +static const struct file_operations qman_fqd_summary_fops = {
10269 + .owner = THIS_MODULE,
10270 + .open = qman_fqd_summary_open,
10271 + .read = seq_read,
10272 +};
10273 +
10274 +/*******************************************************************************
10275 + * QMan destination work queue
10276 + ******************************************************************************/
10277 +struct qman_dest_wq_s {
10278 + u16 wq_id;
10279 +};
10280 +static struct qman_dest_wq_s qman_dest_wq_data = {
10281 + .wq_id = 0,
10282 +};
10283 +
10284 +static int qman_fqd_dest_wq_show(struct seq_file *file, void *offset)
10285 +{
10286 + struct qm_fqd fqd;
10287 + struct qman_fq fq;
10288 + int ret, i;
10289 + u16 *wq, wq_id = qman_dest_wq_data.wq_id;
10290 + struct line_buffer_fq line_buf;
10291 +
10292 + memset(&line_buf, 0, sizeof(line_buf));
10293 + /* use vmalloc : need to allocate large memory region and don't
10294 + * require the memory to be physically contiguous. */
10295 + wq = vzalloc(sizeof(u16) * (0xFFFF+1));
10296 + if (!wq)
10297 + return -ENOMEM;
10298 +
10299 + seq_printf(file, "List of fq ids with destination work queue id"
10300 + " = 0x%x\n", wq_id);
10301 +
10302 + for (i = 1; i < fqid_max; i++) {
10303 + fq.fqid = i;
10304 + memset(&fqd, 0, sizeof(struct qm_fqd));
10305 + ret = qman_query_fq(&fq, &fqd);
10306 + if (ret) {
10307 + vfree(wq);
10308 + return ret;
10309 + }
10310 + if (wq_id == fqd.dest_wq)
10311 + add_to_line_buffer(&line_buf, fq.fqid, file);
10312 + wq[fqd.dest_wq]++;
10313 + }
10314 + flush_line_buffer(&line_buf, file);
10315 +
10316 + seq_puts(file, "Summary of all FQD destination work queue values\n");
10317 + for (i = 0; i < 0xFFFF; i++) {
10318 + if (wq[i])
10319 + seq_printf(file, "Channel: 0x%x WQ: 0x%x WQ_ID: 0x%x, "
10320 + "count = %u\n", i >> 3, i & 0x3, i, wq[i]);
10321 + }
10322 + vfree(wq);
10323 + return 0;
10324 +}
10325 +
10326 +static ssize_t qman_fqd_dest_wq_write(struct file *f, const char __user *buf,
10327 + size_t count, loff_t *off)
10328 +{
10329 + int ret;
10330 + unsigned long val;
10331 +
10332 + ret = user_input_convert(buf, count, &val);
10333 + if (ret)
10334 + return ret;
10335 + if (val > 0xFFFF)
10336 + return -EINVAL;
10337 + qman_dest_wq_data.wq_id = val;
10338 + return count;
10339 +}
10340 +
10341 +static int qman_fqd_dest_wq_open(struct inode *inode, struct file *file)
10342 +{
10343 + return single_open(file, qman_fqd_dest_wq_show, NULL);
10344 +}
10345 +
10346 +static const struct file_operations qman_fqd_dest_wq_fops = {
10347 + .owner = THIS_MODULE,
10348 + .open = qman_fqd_dest_wq_open,
10349 + .read = seq_read,
10350 + .write = qman_fqd_dest_wq_write,
10351 +};
10352 +
10353 +/*******************************************************************************
10354 + * QMan Intra-Class Scheduling Credit
10355 + ******************************************************************************/
10356 +static int qman_fqd_cred_show(struct seq_file *file, void *offset)
10357 +{
10358 + struct qm_fqd fqd;
10359 + struct qman_fq fq;
10360 + int ret, i;
10361 + u32 fq_cnt = 0;
10362 + struct line_buffer_fq line_buf;
10363 +
10364 + memset(&line_buf, 0, sizeof(line_buf));
10365 + seq_puts(file, "List of fq ids with Intra-Class Scheduling Credit > 0"
10366 + "\n");
10367 +
10368 + for (i = 1; i < fqid_max; i++) {
10369 + fq.fqid = i;
10370 + memset(&fqd, 0, sizeof(struct qm_fqd));
10371 + ret = qman_query_fq(&fq, &fqd);
10372 + if (ret)
10373 + return ret;
10374 + if (fqd.ics_cred > 0) {
10375 + add_to_line_buffer(&line_buf, fq.fqid, file);
10376 + fq_cnt++;
10377 + }
10378 + }
10379 + flush_line_buffer(&line_buf, file);
10380 +
10381 + seq_printf(file, "Total FQD with ics_cred > 0 = %d\n", fq_cnt);
10382 + return 0;
10383 +}
10384 +
10385 +static int qman_fqd_cred_open(struct inode *inode, struct file *file)
10386 +{
10387 + return single_open(file, qman_fqd_cred_show, NULL);
10388 +}
10389 +
10390 +static const struct file_operations qman_fqd_cred_fops = {
10391 + .owner = THIS_MODULE,
10392 + .open = qman_fqd_cred_open,
10393 + .read = seq_read,
10394 +};
10395 +
10396 +/*******************************************************************************
10397 + * Class Queue Fields
10398 + ******************************************************************************/
10399 +struct query_cq_fields_data_s {
10400 + u32 cqid;
10401 +};
10402 +
10403 +static struct query_cq_fields_data_s query_cq_fields_data = {
10404 + .cqid = 1,
10405 +};
10406 +
10407 +static int query_cq_fields_show(struct seq_file *file, void *offset)
10408 +{
10409 + int ret;
10410 + struct qm_mcr_ceetm_cq_query query_result;
10411 + unsigned int cqid;
10412 + unsigned int portal;
10413 +
10414 + if ((qman_ip_rev & 0xFF00) < QMAN_REV30)
10415 + return -EINVAL;
10416 +
10417 + cqid = query_cq_fields_data.cqid & 0x00FFFFFF;
10418 + portal = query_cq_fields_data.cqid >> 24;
10419 + if (portal > qm_dc_portal_fman1)
10420 + return -EINVAL;
10421 +
10422 + ret = qman_ceetm_query_cq(cqid, portal, &query_result);
10423 + if (ret)
10424 + return ret;
10425 + seq_printf(file, "Query CQ Fields Result cqid 0x%x on DCP %d\n",
10426 + cqid, portal);
10427 + seq_printf(file, " ccgid: %u\n", query_result.ccgid);
10428 + seq_printf(file, " state: %u\n", query_result.state);
10429 + seq_printf(file, " pfdr_hptr: %u\n", query_result.pfdr_hptr);
10430 + seq_printf(file, " pfdr_tptr: %u\n", query_result.pfdr_tptr);
10431 + seq_printf(file, " od1_xsfdr: %u\n", query_result.od1_xsfdr);
10432 + seq_printf(file, " od2_xsfdr: %u\n", query_result.od2_xsfdr);
10433 + seq_printf(file, " od3_xsfdr: %u\n", query_result.od3_xsfdr);
10434 + seq_printf(file, " od4_xsfdr: %u\n", query_result.od4_xsfdr);
10435 + seq_printf(file, " od5_xsfdr: %u\n", query_result.od5_xsfdr);
10436 + seq_printf(file, " od6_xsfdr: %u\n", query_result.od6_xsfdr);
10437 + seq_printf(file, " ra1_xsfdr: %u\n", query_result.ra1_xsfdr);
10438 + seq_printf(file, " ra2_xsfdr: %u\n", query_result.ra2_xsfdr);
10439 + seq_printf(file, " frame_count: %u\n", query_result.frm_cnt);
10440 +
10441 + return 0;
10442 +}
10443 +
10444 +static int query_cq_fields_open(struct inode *inode,
10445 + struct file *file)
10446 +{
10447 + return single_open(file, query_cq_fields_show, NULL);
10448 +}
10449 +
10450 +static ssize_t query_cq_fields_write(struct file *f,
10451 + const char __user *buf, size_t count, loff_t *off)
10452 +{
10453 + int ret;
10454 + unsigned long val;
10455 +
10456 + ret = user_input_convert(buf, count, &val);
10457 + if (ret)
10458 + return ret;
10459 + query_cq_fields_data.cqid = (u32)val;
10460 + return count;
10461 +}
10462 +
10463 +static const struct file_operations query_cq_fields_fops = {
10464 + .owner = THIS_MODULE,
10465 + .open = query_cq_fields_open,
10466 + .read = seq_read,
10467 + .write = query_cq_fields_write,
10468 + .release = single_release,
10469 +};
10470 +
10471 +/*******************************************************************************
10472 + * READ CEETM_XSFDR_IN_USE
10473 + ******************************************************************************/
10474 +struct query_ceetm_xsfdr_data_s {
10475 + enum qm_dc_portal dcp_portal;
10476 +};
10477 +
10478 +static struct query_ceetm_xsfdr_data_s query_ceetm_xsfdr_data;
10479 +
10480 +static int query_ceetm_xsfdr_show(struct seq_file *file, void *offset)
10481 +{
10482 + int ret;
10483 + unsigned int xsfdr_in_use;
10484 + enum qm_dc_portal portal;
10485 +
10486 +
10487 + if (qman_ip_rev < QMAN_REV31)
10488 + return -EINVAL;
10489 +
10490 + portal = query_ceetm_xsfdr_data.dcp_portal;
10491 + ret = qman_ceetm_get_xsfdr(portal, &xsfdr_in_use);
10492 + if (ret) {
10493 + seq_printf(file, "Read CEETM_XSFDR_IN_USE on DCP %d failed\n",
10494 + portal);
10495 + return ret;
10496 + }
10497 +
10498 + seq_printf(file, "DCP%d: CEETM_XSFDR_IN_USE number is %u\n", portal,
10499 + (xsfdr_in_use & 0x1FFF));
10500 + return 0;
10501 +}
10502 +
10503 +static int query_ceetm_xsfdr_open(struct inode *inode,
10504 + struct file *file)
10505 +{
10506 + return single_open(file, query_ceetm_xsfdr_show, NULL);
10507 +}
10508 +
10509 +static ssize_t query_ceetm_xsfdr_write(struct file *f,
10510 + const char __user *buf, size_t count, loff_t *off)
10511 +{
10512 + int ret;
10513 + unsigned long val;
10514 +
10515 + ret = user_input_convert(buf, count, &val);
10516 + if (ret)
10517 + return ret;
10518 + if (val > qm_dc_portal_fman1)
10519 + return -EINVAL;
10520 + query_ceetm_xsfdr_data.dcp_portal = (u32)val;
10521 + return count;
10522 +}
10523 +
10524 +static const struct file_operations query_ceetm_xsfdr_fops = {
10525 + .owner = THIS_MODULE,
10526 + .open = query_ceetm_xsfdr_open,
10527 + .read = seq_read,
10528 + .write = query_ceetm_xsfdr_write,
10529 + .release = single_release,
10530 +};
10531 +
10532 +/* helper macros used in qman_debugfs_module_init */
10533 +#define QMAN_DBGFS_ENTRY(name, mode, parent, data, fops) \
10534 + do { \
10535 + d = debugfs_create_file(name, \
10536 + mode, parent, \
10537 + data, \
10538 + fops); \
10539 + if (d == NULL) { \
10540 + ret = -ENOMEM; \
10541 + goto _return; \
10542 + } \
10543 + } while (0)
10544 +
10545 +/* dfs_root as parent */
10546 +#define QMAN_DBGFS_ENTRY_ROOT(name, mode, data, fops) \
10547 + QMAN_DBGFS_ENTRY(name, mode, dfs_root, data, fops)
10548 +
10549 +/* fqd_root as parent */
10550 +#define QMAN_DBGFS_ENTRY_FQDROOT(name, mode, data, fops) \
10551 + QMAN_DBGFS_ENTRY(name, mode, fqd_root, data, fops)
10552 +
10553 +/* fqd state */
10554 +#define QMAN_DBGFS_ENTRY_FQDSTATE(name, index) \
10555 + QMAN_DBGFS_ENTRY_FQDROOT(name, S_IRUGO, \
10556 + (void *)&mask_filter[index], &qman_fqd_ctrl_fops)
10557 +
10558 +static int __init qman_debugfs_module_init(void)
10559 +{
10560 + int ret = 0;
10561 + struct dentry *d, *fqd_root;
10562 + u32 reg;
10563 +
10564 + fqid_max = 0;
10565 + init_ccsrmempeek();
10566 + if (qman_ccsr_start) {
10567 + if (!qman_ccsrmempeek(&reg, QM_FQD_AR)) {
10568 + /* extract the size of the FQD window */
10569 + reg = reg & 0x3f;
10570 + /* calculate valid frame queue descriptor range */
10571 + fqid_max = (1 << (reg + 1)) / QM_FQD_BLOCK_SIZE;
10572 + }
10573 + }
10574 + dfs_root = debugfs_create_dir("qman", NULL);
10575 + fqd_root = debugfs_create_dir("fqd", dfs_root);
10576 + if (dfs_root == NULL || fqd_root == NULL) {
10577 + ret = -ENOMEM;
10578 + pr_err("Cannot create qman/fqd debugfs dir\n");
10579 + goto _return;
10580 + }
10581 + if (fqid_max) {
10582 + QMAN_DBGFS_ENTRY_ROOT("ccsrmempeek", S_IRUGO | S_IWUGO,
10583 + NULL, &qman_ccsrmempeek_fops);
10584 + }
10585 + QMAN_DBGFS_ENTRY_ROOT("query_fq_np_fields", S_IRUGO | S_IWUGO,
10586 + &query_fq_np_fields_data, &query_fq_np_fields_fops);
10587 +
10588 + QMAN_DBGFS_ENTRY_ROOT("query_fq_fields", S_IRUGO | S_IWUGO,
10589 + &query_fq_fields_data, &query_fq_fields_fops);
10590 +
10591 + QMAN_DBGFS_ENTRY_ROOT("query_wq_lengths", S_IRUGO | S_IWUGO,
10592 + &query_wq_lengths_data, &query_wq_lengths_fops);
10593 +
10594 + QMAN_DBGFS_ENTRY_ROOT("query_cgr", S_IRUGO | S_IWUGO,
10595 + &query_cgr_data, &query_cgr_fops);
10596 +
10597 + QMAN_DBGFS_ENTRY_ROOT("query_congestion", S_IRUGO,
10598 + NULL, &query_congestion_fops);
10599 +
10600 + QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr", S_IRUGO,
10601 + NULL, &testwrite_cgr_fops);
10602 +
10603 + QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_cgrid", S_IRUGO | S_IWUGO,
10604 + NULL, &teswrite_cgr_cgrid_fops);
10605 +
10606 + QMAN_DBGFS_ENTRY_ROOT("testwrite_cgr_ibcnt", S_IRUGO | S_IWUGO,
10607 + NULL, &teswrite_cgr_ibcnt_fops);
10608 +
10609 + QMAN_DBGFS_ENTRY_ROOT("query_ceetm_ccgr", S_IRUGO | S_IWUGO,
10610 + &query_ccgr_data, &query_ccgr_fops);
10611 + /* Create files with fqd_root as parent */
10612 +
10613 + QMAN_DBGFS_ENTRY_FQDROOT("stateoos", S_IRUGO,
10614 + (void *)&fqd_states[QM_MCR_NP_STATE_OOS], &qman_fqd_state_fops);
10615 +
10616 + QMAN_DBGFS_ENTRY_FQDROOT("state_retired", S_IRUGO,
10617 + (void *)&fqd_states[QM_MCR_NP_STATE_RETIRED],
10618 + &qman_fqd_state_fops);
10619 +
10620 + QMAN_DBGFS_ENTRY_FQDROOT("state_tentatively_sched", S_IRUGO,
10621 + (void *)&fqd_states[QM_MCR_NP_STATE_TEN_SCHED],
10622 + &qman_fqd_state_fops);
10623 +
10624 + QMAN_DBGFS_ENTRY_FQDROOT("state_truly_sched", S_IRUGO,
10625 + (void *)&fqd_states[QM_MCR_NP_STATE_TRU_SCHED],
10626 + &qman_fqd_state_fops);
10627 +
10628 + QMAN_DBGFS_ENTRY_FQDROOT("state_parked", S_IRUGO,
10629 + (void *)&fqd_states[QM_MCR_NP_STATE_PARKED],
10630 + &qman_fqd_state_fops);
10631 +
10632 + QMAN_DBGFS_ENTRY_FQDROOT("state_active", S_IRUGO,
10633 + (void *)&fqd_states[QM_MCR_NP_STATE_ACTIVE],
10634 + &qman_fqd_state_fops);
10635 + QMAN_DBGFS_ENTRY_ROOT("query_cq_fields", S_IRUGO | S_IWUGO,
10636 + &query_cq_fields_data, &query_cq_fields_fops);
10637 + QMAN_DBGFS_ENTRY_ROOT("query_ceetm_xsfdr_in_use", S_IRUGO | S_IWUGO,
10638 + &query_ceetm_xsfdr_data, &query_ceetm_xsfdr_fops);
10639 +
10640 +
10641 + QMAN_DBGFS_ENTRY_FQDSTATE("cge_enable", 17);
10642 +
10643 + QMAN_DBGFS_ENTRY_FQDSTATE("cge_disable", 16);
10644 +
10645 + QMAN_DBGFS_ENTRY_FQDSTATE("tde_enable", 15);
10646 +
10647 + QMAN_DBGFS_ENTRY_FQDSTATE("tde_disable", 14);
10648 +
10649 + QMAN_DBGFS_ENTRY_FQDSTATE("orp_enable", 13);
10650 +
10651 + QMAN_DBGFS_ENTRY_FQDSTATE("orp_disable", 12);
10652 +
10653 + QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_enable", 11);
10654 +
10655 + QMAN_DBGFS_ENTRY_FQDSTATE("ctx_a_stashing_disable", 10);
10656 +
10657 + QMAN_DBGFS_ENTRY_FQDSTATE("cpc_enable", 9);
10658 +
10659 + QMAN_DBGFS_ENTRY_FQDSTATE("cpc_disable", 8);
10660 +
10661 + QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_enable", 7);
10662 +
10663 + QMAN_DBGFS_ENTRY_FQDSTATE("sfdr_disable", 6);
10664 +
10665 + QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_enable", 5);
10666 +
10667 + QMAN_DBGFS_ENTRY_FQDSTATE("avoid_blocking_disable", 4);
10668 +
10669 + QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_enable", 3);
10670 +
10671 + QMAN_DBGFS_ENTRY_FQDSTATE("hold_active_disable", 2);
10672 +
10673 + QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_enable", 1);
10674 +
10675 + QMAN_DBGFS_ENTRY_FQDSTATE("prefer_in_cache_disable", 0);
10676 +
10677 + QMAN_DBGFS_ENTRY_FQDROOT("summary", S_IRUGO,
10678 + NULL, &qman_fqd_summary_fops);
10679 +
10680 + QMAN_DBGFS_ENTRY_FQDROOT("wq", S_IRUGO | S_IWUGO,
10681 + NULL, &qman_fqd_dest_wq_fops);
10682 +
10683 + QMAN_DBGFS_ENTRY_FQDROOT("cred", S_IRUGO,
10684 + NULL, &qman_fqd_cred_fops);
10685 +
10686 + return 0;
10687 +
10688 +_return:
10689 + debugfs_remove_recursive(dfs_root);
10690 + return ret;
10691 +}
10692 +
10693 +static void __exit qman_debugfs_module_exit(void)
10694 +{
10695 + debugfs_remove_recursive(dfs_root);
10696 +}
10697 +
10698 +module_init(qman_debugfs_module_init);
10699 +module_exit(qman_debugfs_module_exit);
10700 +MODULE_LICENSE("Dual BSD/GPL");
10701 --- /dev/null
10702 +++ b/drivers/staging/fsl_qbman/qman_driver.c
10703 @@ -0,0 +1,980 @@
10704 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
10705 + *
10706 + * Redistribution and use in source and binary forms, with or without
10707 + * modification, are permitted provided that the following conditions are met:
10708 + * * Redistributions of source code must retain the above copyright
10709 + * notice, this list of conditions and the following disclaimer.
10710 + * * Redistributions in binary form must reproduce the above copyright
10711 + * notice, this list of conditions and the following disclaimer in the
10712 + * documentation and/or other materials provided with the distribution.
10713 + * * Neither the name of Freescale Semiconductor nor the
10714 + * names of its contributors may be used to endorse or promote products
10715 + * derived from this software without specific prior written permission.
10716 + *
10717 + *
10718 + * ALTERNATIVELY, this software may be distributed under the terms of the
10719 + * GNU General Public License ("GPL") as published by the Free Software
10720 + * Foundation, either version 2 of that License or (at your option) any
10721 + * later version.
10722 + *
10723 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
10724 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
10725 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10726 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
10727 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
10728 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
10729 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
10730 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
10731 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
10732 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10733 + */
10734 +
10735 +#include "qman_private.h"
10736 +
10737 +#include <asm/smp.h> /* hard_smp_processor_id() if !CONFIG_SMP */
10738 +#ifdef CONFIG_HOTPLUG_CPU
10739 +#include <linux/cpu.h>
10740 +#endif
10741 +
10742 +/* Global variable containing revision id (even on non-control plane systems
10743 + * where CCSR isn't available) */
10744 +u16 qman_ip_rev;
10745 +EXPORT_SYMBOL(qman_ip_rev);
10746 +u8 qman_ip_cfg;
10747 +EXPORT_SYMBOL(qman_ip_cfg);
10748 +u16 qm_channel_pool1 = QMAN_CHANNEL_POOL1;
10749 +EXPORT_SYMBOL(qm_channel_pool1);
10750 +u16 qm_channel_caam = QMAN_CHANNEL_CAAM;
10751 +EXPORT_SYMBOL(qm_channel_caam);
10752 +u16 qm_channel_pme = QMAN_CHANNEL_PME;
10753 +EXPORT_SYMBOL(qm_channel_pme);
10754 +u16 qm_channel_dce = QMAN_CHANNEL_DCE;
10755 +EXPORT_SYMBOL(qm_channel_dce);
10756 +u16 qman_portal_max;
10757 +EXPORT_SYMBOL(qman_portal_max);
10758 +
10759 +u32 qman_clk;
10760 +struct qm_ceetm qman_ceetms[QMAN_CEETM_MAX];
10761 +/* the qman ceetm instances on the given SoC */
10762 +u8 num_ceetms;
10763 +
10764 +/* For these variables, and the portal-initialisation logic, the
10765 + * comments in bman_driver.c apply here so won't be repeated. */
10766 +static struct qman_portal *shared_portals[NR_CPUS];
10767 +static int num_shared_portals;
10768 +static int shared_portals_idx;
10769 +static LIST_HEAD(unused_pcfgs);
10770 +static DEFINE_SPINLOCK(unused_pcfgs_lock);
10771 +
10772 +/* A SDQCR mask comprising all the available/visible pool channels */
10773 +static u32 pools_sdqcr;
10774 +
10775 +#define STR_ERR_NOPROP "No '%s' property in node %s\n"
10776 +#define STR_ERR_CELL "'%s' is not a %d-cell range in node %s\n"
10777 +#define STR_FQID_RANGE "fsl,fqid-range"
10778 +#define STR_POOL_CHAN_RANGE "fsl,pool-channel-range"
10779 +#define STR_CGRID_RANGE "fsl,cgrid-range"
10780 +
10781 +/* A "fsl,fqid-range" node; release the given range to the allocator */
10782 +static __init int fsl_fqid_range_init(struct device_node *node)
10783 +{
10784 + int ret;
10785 + const u32 *range = of_get_property(node, STR_FQID_RANGE, &ret);
10786 + if (!range) {
10787 + pr_err(STR_ERR_NOPROP, STR_FQID_RANGE, node->full_name);
10788 + return -EINVAL;
10789 + }
10790 + if (ret != 8) {
10791 + pr_err(STR_ERR_CELL, STR_FQID_RANGE, 2, node->full_name);
10792 + return -EINVAL;
10793 + }
10794 + qman_seed_fqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10795 + pr_info("Qman: FQID allocator includes range %d:%d\n",
10796 + be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10797 + return 0;
10798 +}
10799 +
10800 +/* A "fsl,pool-channel-range" node; add to the SDQCR mask only */
10801 +static __init int fsl_pool_channel_range_sdqcr(struct device_node *node)
10802 +{
10803 + int ret;
10804 + const u32 *chanid = of_get_property(node, STR_POOL_CHAN_RANGE, &ret);
10805 + if (!chanid) {
10806 + pr_err(STR_ERR_NOPROP, STR_POOL_CHAN_RANGE, node->full_name);
10807 + return -EINVAL;
10808 + }
10809 + if (ret != 8) {
10810 + pr_err(STR_ERR_CELL, STR_POOL_CHAN_RANGE, 1, node->full_name);
10811 + return -EINVAL;
10812 + }
10813 + for (ret = 0; ret < be32_to_cpu(chanid[1]); ret++)
10814 + pools_sdqcr |= QM_SDQCR_CHANNELS_POOL_CONV(be32_to_cpu(chanid[0]) + ret);
10815 + return 0;
10816 +}
10817 +
10818 +/* A "fsl,pool-channel-range" node; release the given range to the allocator */
10819 +static __init int fsl_pool_channel_range_init(struct device_node *node)
10820 +{
10821 + int ret;
10822 + const u32 *chanid = of_get_property(node, STR_POOL_CHAN_RANGE, &ret);
10823 + if (!chanid) {
10824 + pr_err(STR_ERR_NOPROP, STR_POOL_CHAN_RANGE, node->full_name);
10825 + return -EINVAL;
10826 + }
10827 + if (ret != 8) {
10828 + pr_err(STR_ERR_CELL, STR_POOL_CHAN_RANGE, 1, node->full_name);
10829 + return -EINVAL;
10830 + }
10831 + qman_seed_pool_range(be32_to_cpu(chanid[0]), be32_to_cpu(chanid[1]));
10832 + pr_info("Qman: pool channel allocator includes range %d:%d\n",
10833 + be32_to_cpu(chanid[0]), be32_to_cpu(chanid[1]));
10834 + return 0;
10835 +}
10836 +
10837 +/* A "fsl,cgrid-range" node; release the given range to the allocator */
10838 +static __init int fsl_cgrid_range_init(struct device_node *node)
10839 +{
10840 + struct qman_cgr cgr;
10841 + int ret, errors = 0;
10842 + const u32 *range = of_get_property(node, STR_CGRID_RANGE, &ret);
10843 + if (!range) {
10844 + pr_err(STR_ERR_NOPROP, STR_CGRID_RANGE, node->full_name);
10845 + return -EINVAL;
10846 + }
10847 + if (ret != 8) {
10848 + pr_err(STR_ERR_CELL, STR_CGRID_RANGE, 2, node->full_name);
10849 + return -EINVAL;
10850 + }
10851 + qman_seed_cgrid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10852 + pr_info("Qman: CGRID allocator includes range %d:%d\n",
10853 + be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10854 + for (cgr.cgrid = 0; cgr.cgrid < __CGR_NUM; cgr.cgrid++) {
10855 + ret = qman_modify_cgr(&cgr, QMAN_CGR_FLAG_USE_INIT, NULL);
10856 + if (ret)
10857 + errors++;
10858 + }
10859 + if (errors)
10860 + pr_err("Warning: %d error%s while initialising CGRs %d:%d\n",
10861 + errors, (errors > 1) ? "s" : "", range[0], range[1]);
10862 + return 0;
10863 +}
10864 +
10865 +static __init int fsl_ceetm_init(struct device_node *node)
10866 +{
10867 + enum qm_dc_portal dcp_portal;
10868 + struct qm_ceetm_sp *sp;
10869 + struct qm_ceetm_lni *lni;
10870 + int ret, i;
10871 + const u32 *range;
10872 +
10873 + /* Find LFQID range */
10874 + range = of_get_property(node, "fsl,ceetm-lfqid-range", &ret);
10875 + if (!range) {
10876 + pr_err("No fsl,ceetm-lfqid-range in node %s\n",
10877 + node->full_name);
10878 + return -EINVAL;
10879 + }
10880 + if (ret != 8) {
10881 + pr_err("fsl,ceetm-lfqid-range is not a 2-cell range in node"
10882 + " %s\n", node->full_name);
10883 + return -EINVAL;
10884 + }
10885 +
10886 + dcp_portal = (be32_to_cpu(range[0]) & 0x0F0000) >> 16;
10887 + if (dcp_portal > qm_dc_portal_fman1) {
10888 + pr_err("The DCP portal %d doesn't support CEETM\n", dcp_portal);
10889 + return -EINVAL;
10890 + }
10891 +
10892 + if (dcp_portal == qm_dc_portal_fman0)
10893 + qman_seed_ceetm0_lfqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10894 + if (dcp_portal == qm_dc_portal_fman1)
10895 + qman_seed_ceetm1_lfqid_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10896 + pr_debug("Qman: The lfqid allocator of CEETM %d includes range"
10897 + " 0x%x:0x%x\n", dcp_portal, be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10898 +
10899 + qman_ceetms[dcp_portal].idx = dcp_portal;
10900 + INIT_LIST_HEAD(&qman_ceetms[dcp_portal].sub_portals);
10901 + INIT_LIST_HEAD(&qman_ceetms[dcp_portal].lnis);
10902 +
10903 + /* Find Sub-portal range */
10904 + range = of_get_property(node, "fsl,ceetm-sp-range", &ret);
10905 + if (!range) {
10906 + pr_err("No fsl,ceetm-sp-range in node %s\n", node->full_name);
10907 + return -EINVAL;
10908 + }
10909 + if (ret != 8) {
10910 + pr_err("fsl,ceetm-sp-range is not a 2-cell range in node %s\n",
10911 + node->full_name);
10912 + return -EINVAL;
10913 + }
10914 +
10915 + for (i = 0; i < be32_to_cpu(range[1]); i++) {
10916 + sp = kzalloc(sizeof(*sp), GFP_KERNEL);
10917 + if (!sp) {
10918 + pr_err("Can't alloc memory for sub-portal %d\n",
10919 + range[0] + i);
10920 + return -ENOMEM;
10921 + }
10922 + sp->idx = be32_to_cpu(range[0]) + i;
10923 + sp->dcp_idx = dcp_portal;
10924 + sp->is_claimed = 0;
10925 + list_add_tail(&sp->node, &qman_ceetms[dcp_portal].sub_portals);
10926 + sp++;
10927 + }
10928 + pr_debug("Qman: Reserve sub-portal %d:%d for CEETM %d\n",
10929 + be32_to_cpu(range[0]), be32_to_cpu(range[1]), dcp_portal);
10930 + qman_ceetms[dcp_portal].sp_range[0] = be32_to_cpu(range[0]);
10931 + qman_ceetms[dcp_portal].sp_range[1] = be32_to_cpu(range[1]);
10932 +
10933 + /* Find LNI range */
10934 + range = of_get_property(node, "fsl,ceetm-lni-range", &ret);
10935 + if (!range) {
10936 + pr_err("No fsl,ceetm-lni-range in node %s\n", node->full_name);
10937 + return -EINVAL;
10938 + }
10939 + if (ret != 8) {
10940 + pr_err("fsl,ceetm-lni-range is not a 2-cell range in node %s\n",
10941 + node->full_name);
10942 + return -EINVAL;
10943 + }
10944 +
10945 + for (i = 0; i < be32_to_cpu(range[1]); i++) {
10946 + lni = kzalloc(sizeof(*lni), GFP_KERNEL);
10947 + if (!lni) {
10948 + pr_err("Can't alloc memory for LNI %d\n",
10949 + range[0] + i);
10950 + return -ENOMEM;
10951 + }
10952 + lni->idx = be32_to_cpu(range[0]) + i;
10953 + lni->dcp_idx = dcp_portal;
10954 + lni->is_claimed = 0;
10955 + INIT_LIST_HEAD(&lni->channels);
10956 + list_add_tail(&lni->node, &qman_ceetms[dcp_portal].lnis);
10957 + lni++;
10958 + }
10959 + pr_debug("Qman: Reserve LNI %d:%d for CEETM %d\n",
10960 + be32_to_cpu(range[0]), be32_to_cpu(range[1]), dcp_portal);
10961 + qman_ceetms[dcp_portal].lni_range[0] = be32_to_cpu(range[0]);
10962 + qman_ceetms[dcp_portal].lni_range[1] = be32_to_cpu(range[1]);
10963 +
10964 + /* Find CEETM channel range */
10965 + range = of_get_property(node, "fsl,ceetm-channel-range", &ret);
10966 + if (!range) {
10967 + pr_err("No fsl,ceetm-channel-range in node %s\n",
10968 + node->full_name);
10969 + return -EINVAL;
10970 + }
10971 + if (ret != 8) {
10972 + pr_err("fsl,ceetm-channel-range is not a 2-cell range in node"
10973 + "%s\n", node->full_name);
10974 + return -EINVAL;
10975 + }
10976 +
10977 + if (dcp_portal == qm_dc_portal_fman0)
10978 + qman_seed_ceetm0_channel_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10979 + if (dcp_portal == qm_dc_portal_fman1)
10980 + qman_seed_ceetm1_channel_range(be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10981 + pr_debug("Qman: The channel allocator of CEETM %d includes"
10982 + " range %d:%d\n", dcp_portal, be32_to_cpu(range[0]), be32_to_cpu(range[1]));
10983 +
10984 + /* Set CEETM PRES register */
10985 + ret = qman_ceetm_set_prescaler(dcp_portal);
10986 + if (ret)
10987 + return ret;
10988 + return 0;
10989 +}
10990 +
10991 +static void qman_get_ip_revision(struct device_node *dn)
10992 +{
10993 + u16 ip_rev = 0;
10994 + u8 ip_cfg = QMAN_REV_CFG_0;
10995 + for_each_compatible_node(dn, NULL, "fsl,qman-portal") {
10996 + if (!of_device_is_available(dn))
10997 + continue;
10998 + if (of_device_is_compatible(dn, "fsl,qman-portal-1.0") ||
10999 + of_device_is_compatible(dn, "fsl,qman-portal-1.0.0")) {
11000 + pr_err("QMAN rev1.0 on P4080 rev1 is not supported!\n");
11001 + BUG_ON(1);
11002 + } else if (of_device_is_compatible(dn, "fsl,qman-portal-1.1") ||
11003 + of_device_is_compatible(dn, "fsl,qman-portal-1.1.0")) {
11004 + ip_rev = QMAN_REV11;
11005 + qman_portal_max = 10;
11006 + } else if (of_device_is_compatible(dn, "fsl,qman-portal-1.2") ||
11007 + of_device_is_compatible(dn, "fsl,qman-portal-1.2.0")) {
11008 + ip_rev = QMAN_REV12;
11009 + qman_portal_max = 10;
11010 + } else if (of_device_is_compatible(dn, "fsl,qman-portal-2.0") ||
11011 + of_device_is_compatible(dn, "fsl,qman-portal-2.0.0")) {
11012 + ip_rev = QMAN_REV20;
11013 + qman_portal_max = 3;
11014 + } else if (of_device_is_compatible(dn,
11015 + "fsl,qman-portal-3.0.0")) {
11016 + ip_rev = QMAN_REV30;
11017 + qman_portal_max = 50;
11018 + } else if (of_device_is_compatible(dn,
11019 + "fsl,qman-portal-3.0.1")) {
11020 + ip_rev = QMAN_REV30;
11021 + qman_portal_max = 25;
11022 + ip_cfg = QMAN_REV_CFG_1;
11023 + } else if (of_device_is_compatible(dn,
11024 + "fsl,qman-portal-3.1.0")) {
11025 + ip_rev = QMAN_REV31;
11026 + qman_portal_max = 50;
11027 + } else if (of_device_is_compatible(dn,
11028 + "fsl,qman-portal-3.1.1")) {
11029 + ip_rev = QMAN_REV31;
11030 + qman_portal_max = 25;
11031 + ip_cfg = QMAN_REV_CFG_1;
11032 + } else if (of_device_is_compatible(dn,
11033 + "fsl,qman-portal-3.1.2")) {
11034 + ip_rev = QMAN_REV31;
11035 + qman_portal_max = 18;
11036 + ip_cfg = QMAN_REV_CFG_2;
11037 + } else if (of_device_is_compatible(dn,
11038 + "fsl,qman-portal-3.1.3")) {
11039 + ip_rev = QMAN_REV31;
11040 + qman_portal_max = 10;
11041 + ip_cfg = QMAN_REV_CFG_3;
11042 + } else if (of_device_is_compatible(dn,
11043 + "fsl,qman-portal-3.2.0")) {
11044 + ip_rev = QMAN_REV32;
11045 + qman_portal_max = 10;
11046 + ip_cfg = QMAN_REV_CFG_3; // TODO: Verify for ls1043
11047 + } else {
11048 + pr_warn("unknown QMan version in portal node,"
11049 + "default to rev1.1\n");
11050 + ip_rev = QMAN_REV11;
11051 + qman_portal_max = 10;
11052 + }
11053 +
11054 + if (!qman_ip_rev) {
11055 + if (ip_rev) {
11056 + qman_ip_rev = ip_rev;
11057 + qman_ip_cfg = ip_cfg;
11058 + } else {
11059 + pr_warn("unknown Qman version,"
11060 + " default to rev1.1\n");
11061 + qman_ip_rev = QMAN_REV11;
11062 + qman_ip_cfg = QMAN_REV_CFG_0;
11063 + }
11064 + } else if (ip_rev && (qman_ip_rev != ip_rev))
11065 + pr_warn("Revision=0x%04x, but portal '%s' has"
11066 + " 0x%04x\n",
11067 + qman_ip_rev, dn->full_name, ip_rev);
11068 + if (qman_ip_rev == ip_rev)
11069 + break;
11070 + }
11071 +}
11072 +
11073 +/* Parse a portal node, perform generic mapping duties and return the config. It
11074 + * is not known at this stage for what purpose (or even if) the portal will be
11075 + * used. */
11076 +static struct qm_portal_config * __init parse_pcfg(struct device_node *node)
11077 +{
11078 + struct qm_portal_config *pcfg;
11079 + const u32 *index_p, *channel_p;
11080 + u32 index, channel;
11081 + int irq, ret;
11082 + resource_size_t len;
11083 +
11084 + pcfg = kmalloc(sizeof(*pcfg), GFP_KERNEL);
11085 + if (!pcfg) {
11086 + pr_err("can't allocate portal config");
11087 + return NULL;
11088 + }
11089 +
11090 + /*
11091 + * This is a *horrible hack*, but the IOMMU/PAMU driver needs a
11092 + * 'struct device' in order to get the PAMU stashing setup and the QMan
11093 + * portal [driver] won't function at all without ring stashing
11094 + *
11095 + * Making the QMan portal driver nice and proper is part of the
11096 + * upstreaming effort
11097 + */
11098 + pcfg->dev.bus = &platform_bus_type;
11099 + pcfg->dev.of_node = node;
11100 +#ifdef CONFIG_FSL_PAMU
11101 + pcfg->dev.archdata.iommu_domain = NULL;
11102 +#endif
11103 +
11104 + ret = of_address_to_resource(node, DPA_PORTAL_CE,
11105 + &pcfg->addr_phys[DPA_PORTAL_CE]);
11106 + if (ret) {
11107 + pr_err("Can't get %s property '%s'\n", node->full_name,
11108 + "reg::CE");
11109 + goto err;
11110 + }
11111 + ret = of_address_to_resource(node, DPA_PORTAL_CI,
11112 + &pcfg->addr_phys[DPA_PORTAL_CI]);
11113 + if (ret) {
11114 + pr_err("Can't get %s property '%s'\n", node->full_name,
11115 + "reg::CI");
11116 + goto err;
11117 + }
11118 + index_p = of_get_property(node, "cell-index", &ret);
11119 + if (!index_p || (ret != 4)) {
11120 + pr_err("Can't get %s property '%s'\n", node->full_name,
11121 + "cell-index");
11122 + goto err;
11123 + }
11124 + index = be32_to_cpu(*index_p);
11125 + if (index >= qman_portal_max) {
11126 + pr_err("QMan portal index %d is beyond max (%d)\n",
11127 + index, qman_portal_max);
11128 + goto err;
11129 + }
11130 +
11131 + channel_p = of_get_property(node, "fsl,qman-channel-id", &ret);
11132 + if (!channel_p || (ret != 4)) {
11133 + pr_err("Can't get %s property '%s'\n", node->full_name,
11134 + "fsl,qman-channel-id");
11135 + goto err;
11136 + }
11137 + channel = be32_to_cpu(*channel_p);
11138 + if (channel != (index + QM_CHANNEL_SWPORTAL0))
11139 + pr_err("Warning: node %s has mismatched %s and %s\n",
11140 + node->full_name, "cell-index", "fsl,qman-channel-id");
11141 + pcfg->public_cfg.channel = channel;
11142 + pcfg->public_cfg.cpu = -1;
11143 + irq = irq_of_parse_and_map(node, 0);
11144 + if (irq == 0) {
11145 + pr_err("Can't get %s property '%s'\n", node->full_name,
11146 + "interrupts");
11147 + goto err;
11148 + }
11149 + pcfg->public_cfg.irq = irq;
11150 + pcfg->public_cfg.index = index;
11151 +#ifdef CONFIG_FSL_QMAN_CONFIG
11152 + /* We need the same LIODN offset for all portals */
11153 + qman_liodn_fixup(pcfg->public_cfg.channel);
11154 +#endif
11155 +
11156 + len = resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]);
11157 + if (len != (unsigned long)len)
11158 + goto err;
11159 +
11160 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
11161 + pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_cache_ns(
11162 + pcfg->addr_phys[DPA_PORTAL_CE].start,
11163 + resource_size(&pcfg->addr_phys[DPA_PORTAL_CE]));
11164 +
11165 + pcfg->addr_virt[DPA_PORTAL_CI] = ioremap(
11166 + pcfg->addr_phys[DPA_PORTAL_CI].start,
11167 + resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]));
11168 +#else
11169 + pcfg->addr_virt[DPA_PORTAL_CE] = ioremap_prot(
11170 + pcfg->addr_phys[DPA_PORTAL_CE].start,
11171 + (unsigned long)len,
11172 + 0);
11173 + pcfg->addr_virt[DPA_PORTAL_CI] = ioremap_prot(
11174 + pcfg->addr_phys[DPA_PORTAL_CI].start,
11175 + resource_size(&pcfg->addr_phys[DPA_PORTAL_CI]),
11176 + _PAGE_GUARDED | _PAGE_NO_CACHE);
11177 +#endif
11178 + return pcfg;
11179 +err:
11180 + kfree(pcfg);
11181 + return NULL;
11182 +}
11183 +
11184 +static struct qm_portal_config *get_pcfg(struct list_head *list)
11185 +{
11186 + struct qm_portal_config *pcfg;
11187 + if (list_empty(list))
11188 + return NULL;
11189 + pcfg = list_entry(list->prev, struct qm_portal_config, list);
11190 + list_del(&pcfg->list);
11191 + return pcfg;
11192 +}
11193 +
11194 +static struct qm_portal_config *get_pcfg_idx(struct list_head *list, u32 idx)
11195 +{
11196 + struct qm_portal_config *pcfg;
11197 + if (list_empty(list))
11198 + return NULL;
11199 + list_for_each_entry(pcfg, list, list) {
11200 + if (pcfg->public_cfg.index == idx) {
11201 + list_del(&pcfg->list);
11202 + return pcfg;
11203 + }
11204 + }
11205 + return NULL;
11206 +}
11207 +
11208 +static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu)
11209 +{
11210 +#ifdef CONFIG_FSL_PAMU
11211 + int ret;
11212 + int window_count = 1;
11213 + struct iommu_domain_geometry geom_attr;
11214 + struct pamu_stash_attribute stash_attr;
11215 +
11216 + pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
11217 + if (!pcfg->iommu_domain) {
11218 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_alloc() failed",
11219 + __func__);
11220 + goto _no_iommu;
11221 + }
11222 + geom_attr.aperture_start = 0;
11223 + geom_attr.aperture_end =
11224 + ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1;
11225 + geom_attr.force_aperture = true;
11226 + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY,
11227 + &geom_attr);
11228 + if (ret < 0) {
11229 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
11230 + __func__, ret);
11231 + goto _iommu_domain_free;
11232 + }
11233 + ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS,
11234 + &window_count);
11235 + if (ret < 0) {
11236 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
11237 + __func__, ret);
11238 + goto _iommu_domain_free;
11239 + }
11240 + stash_attr.cpu = cpu;
11241 + stash_attr.cache = PAMU_ATTR_CACHE_L1;
11242 + /* set stash information for the window */
11243 + stash_attr.window = 0;
11244 + ret = iommu_domain_set_attr(pcfg->iommu_domain,
11245 + DOMAIN_ATTR_FSL_PAMU_STASH,
11246 + &stash_attr);
11247 + if (ret < 0) {
11248 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
11249 + __func__, ret);
11250 + goto _iommu_domain_free;
11251 + }
11252 + ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36,
11253 + IOMMU_READ | IOMMU_WRITE);
11254 + if (ret < 0) {
11255 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_window_enable() = %d",
11256 + __func__, ret);
11257 + goto _iommu_domain_free;
11258 + }
11259 + ret = iommu_attach_device(pcfg->iommu_domain, &pcfg->dev);
11260 + if (ret < 0) {
11261 + pr_err(KBUILD_MODNAME ":%s(): iommu_device_attach() = %d",
11262 + __func__, ret);
11263 + goto _iommu_domain_free;
11264 + }
11265 + ret = iommu_domain_set_attr(pcfg->iommu_domain,
11266 + DOMAIN_ATTR_FSL_PAMU_ENABLE,
11267 + &window_count);
11268 + if (ret < 0) {
11269 + pr_err(KBUILD_MODNAME ":%s(): iommu_domain_set_attr() = %d",
11270 + __func__, ret);
11271 + goto _iommu_detach_device;
11272 + }
11273 +
11274 +_no_iommu:
11275 +#endif
11276 +#ifdef CONFIG_FSL_QMAN_CONFIG
11277 + if (qman_set_sdest(pcfg->public_cfg.channel, cpu))
11278 +#endif
11279 + pr_warn("Failed to set QMan portal's stash request queue\n");
11280 +
11281 + return;
11282 +
11283 +#ifdef CONFIG_FSL_PAMU
11284 +_iommu_detach_device:
11285 + iommu_detach_device(pcfg->iommu_domain, NULL);
11286 +_iommu_domain_free:
11287 + iommu_domain_free(pcfg->iommu_domain);
11288 +#endif
11289 +}
11290 +
11291 +struct qm_portal_config *qm_get_unused_portal_idx(u32 idx)
11292 +{
11293 + struct qm_portal_config *ret;
11294 + spin_lock(&unused_pcfgs_lock);
11295 + if (idx == QBMAN_ANY_PORTAL_IDX)
11296 + ret = get_pcfg(&unused_pcfgs);
11297 + else
11298 + ret = get_pcfg_idx(&unused_pcfgs, idx);
11299 + spin_unlock(&unused_pcfgs_lock);
11300 + /* Bind stashing LIODNs to the CPU we are currently executing on, and
11301 + * set the portal to use the stashing request queue corresonding to the
11302 + * cpu as well. The user-space driver assumption is that the pthread has
11303 + * to already be affine to one cpu only before opening a portal. If that
11304 + * check is circumvented, the only risk is a performance degradation -
11305 + * stashing will go to whatever cpu they happened to be running on when
11306 + * opening the device file, and if that isn't the cpu they subsequently
11307 + * bind to and do their polling on, tough. */
11308 + if (ret)
11309 + portal_set_cpu(ret, hard_smp_processor_id());
11310 + return ret;
11311 +}
11312 +
11313 +struct qm_portal_config *qm_get_unused_portal(void)
11314 +{
11315 + return qm_get_unused_portal_idx(QBMAN_ANY_PORTAL_IDX);
11316 +}
11317 +
11318 +void qm_put_unused_portal(struct qm_portal_config *pcfg)
11319 +{
11320 + spin_lock(&unused_pcfgs_lock);
11321 + list_add(&pcfg->list, &unused_pcfgs);
11322 + spin_unlock(&unused_pcfgs_lock);
11323 +}
11324 +
11325 +static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg)
11326 +{
11327 + struct qman_portal *p;
11328 +
11329 + pcfg->iommu_domain = NULL;
11330 + portal_set_cpu(pcfg, pcfg->public_cfg.cpu);
11331 + p = qman_create_affine_portal(pcfg, NULL);
11332 + if (p) {
11333 + u32 irq_sources = 0;
11334 + /* Determine what should be interrupt-vs-poll driven */
11335 +#ifdef CONFIG_FSL_DPA_PIRQ_SLOW
11336 + irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI |
11337 + QM_PIRQ_CSCI | QM_PIRQ_CCSCI;
11338 +#endif
11339 +#ifdef CONFIG_FSL_DPA_PIRQ_FAST
11340 + irq_sources |= QM_PIRQ_DQRI;
11341 +#endif
11342 + qman_p_irqsource_add(p, irq_sources);
11343 + pr_info("Qman portal %sinitialised, cpu %d\n",
11344 + pcfg->public_cfg.is_shared ? "(shared) " : "",
11345 + pcfg->public_cfg.cpu);
11346 + } else
11347 + pr_crit("Qman portal failure on cpu %d\n",
11348 + pcfg->public_cfg.cpu);
11349 + return p;
11350 +}
11351 +
11352 +static void init_slave(int cpu)
11353 +{
11354 + struct qman_portal *p;
11355 + struct cpumask oldmask = *tsk_cpus_allowed(current);
11356 + set_cpus_allowed_ptr(current, get_cpu_mask(cpu));
11357 + p = qman_create_affine_slave(shared_portals[shared_portals_idx++], cpu);
11358 + if (!p)
11359 + pr_err("Qman slave portal failure on cpu %d\n", cpu);
11360 + else
11361 + pr_info("Qman portal %sinitialised, cpu %d\n", "(slave) ", cpu);
11362 + set_cpus_allowed_ptr(current, &oldmask);
11363 + if (shared_portals_idx >= num_shared_portals)
11364 + shared_portals_idx = 0;
11365 +}
11366 +
11367 +static struct cpumask want_unshared __initdata;
11368 +static struct cpumask want_shared __initdata;
11369 +
11370 +static int __init parse_qportals(char *str)
11371 +{
11372 + return parse_portals_bootarg(str, &want_shared, &want_unshared,
11373 + "qportals");
11374 +}
11375 +__setup("qportals=", parse_qportals);
11376 +
11377 +static void qman_portal_update_sdest(const struct qm_portal_config *pcfg,
11378 + unsigned int cpu)
11379 +{
11380 +#ifdef CONFIG_FSL_PAMU
11381 + struct pamu_stash_attribute stash_attr;
11382 + int ret;
11383 +
11384 + if (pcfg->iommu_domain) {
11385 + stash_attr.cpu = cpu;
11386 + stash_attr.cache = PAMU_ATTR_CACHE_L1;
11387 + /* set stash information for the window */
11388 + stash_attr.window = 0;
11389 + ret = iommu_domain_set_attr(pcfg->iommu_domain,
11390 + DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr);
11391 + if (ret < 0) {
11392 + pr_err("Failed to update pamu stash setting\n");
11393 + return;
11394 + }
11395 + }
11396 +#endif
11397 +#ifdef CONFIG_FSL_QMAN_CONFIG
11398 + if (qman_set_sdest(pcfg->public_cfg.channel, cpu))
11399 + pr_warn("Failed to update portal's stash request queue\n");
11400 +#endif
11401 +}
11402 +
11403 +static void qman_offline_cpu(unsigned int cpu)
11404 +{
11405 + struct qman_portal *p;
11406 + const struct qm_portal_config *pcfg;
11407 + p = (struct qman_portal *)affine_portals[cpu];
11408 + if (p) {
11409 + pcfg = qman_get_qm_portal_config(p);
11410 + if (pcfg) {
11411 + irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(0));
11412 + qman_portal_update_sdest(pcfg, 0);
11413 + }
11414 + }
11415 +}
11416 +
11417 +#ifdef CONFIG_HOTPLUG_CPU
11418 +static void qman_online_cpu(unsigned int cpu)
11419 +{
11420 + struct qman_portal *p;
11421 + const struct qm_portal_config *pcfg;
11422 + p = (struct qman_portal *)affine_portals[cpu];
11423 + if (p) {
11424 + pcfg = qman_get_qm_portal_config(p);
11425 + if (pcfg) {
11426 + irq_set_affinity(pcfg->public_cfg.irq, cpumask_of(cpu));
11427 + qman_portal_update_sdest(pcfg, cpu);
11428 + }
11429 + }
11430 +}
11431 +
11432 +static int qman_hotplug_cpu_callback(struct notifier_block *nfb,
11433 + unsigned long action, void *hcpu)
11434 +{
11435 + unsigned int cpu = (unsigned long)hcpu;
11436 +
11437 + switch (action) {
11438 + case CPU_ONLINE:
11439 + case CPU_ONLINE_FROZEN:
11440 + qman_online_cpu(cpu);
11441 + break;
11442 + case CPU_DOWN_PREPARE:
11443 + case CPU_DOWN_PREPARE_FROZEN:
11444 + qman_offline_cpu(cpu);
11445 + default:
11446 + break;
11447 + }
11448 + return NOTIFY_OK;
11449 +}
11450 +
11451 +static struct notifier_block qman_hotplug_cpu_notifier = {
11452 + .notifier_call = qman_hotplug_cpu_callback,
11453 +};
11454 +#endif /* CONFIG_HOTPLUG_CPU */
11455 +
11456 +__init int qman_init(void)
11457 +{
11458 + struct cpumask slave_cpus;
11459 + struct cpumask unshared_cpus = *cpu_none_mask;
11460 + struct cpumask shared_cpus = *cpu_none_mask;
11461 + LIST_HEAD(unshared_pcfgs);
11462 + LIST_HEAD(shared_pcfgs);
11463 + struct device_node *dn;
11464 + struct qm_portal_config *pcfg;
11465 + struct qman_portal *p;
11466 + int cpu, ret;
11467 + const u32 *clk;
11468 + struct cpumask offline_cpus;
11469 +
11470 + /* Initialise the Qman (CCSR) device */
11471 + for_each_compatible_node(dn, NULL, "fsl,qman") {
11472 + if (!qman_init_ccsr(dn))
11473 + pr_info("Qman err interrupt handler present\n");
11474 + else
11475 + pr_err("Qman CCSR setup failed\n");
11476 +
11477 + clk = of_get_property(dn, "clock-frequency", NULL);
11478 + if (!clk)
11479 + pr_warn("Can't find Qman clock frequency\n");
11480 + else
11481 + qman_clk = be32_to_cpu(*clk);
11482 + }
11483 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
11484 + /* Setup lookup table for FQ demux */
11485 + ret = qman_setup_fq_lookup_table(get_qman_fqd_size()/64);
11486 + if (ret)
11487 + return ret;
11488 +#endif
11489 +
11490 + /* Get qman ip revision */
11491 + qman_get_ip_revision(dn);
11492 + if ((qman_ip_rev & 0xff00) >= QMAN_REV30) {
11493 + qm_channel_pool1 = QMAN_CHANNEL_POOL1_REV3;
11494 + qm_channel_caam = QMAN_CHANNEL_CAAM_REV3;
11495 + qm_channel_pme = QMAN_CHANNEL_PME_REV3;
11496 + }
11497 +
11498 + if ((qman_ip_rev == QMAN_REV31) && (qman_ip_cfg == QMAN_REV_CFG_2))
11499 + qm_channel_dce = QMAN_CHANNEL_DCE_QMANREV312;
11500 +
11501 + /*
11502 + * Parse the ceetm node to get how many ceetm instances are supported
11503 + * on the current silicon. num_ceetms must be confirmed before portals
11504 + * are intiailized.
11505 + */
11506 + num_ceetms = 0;
11507 + for_each_compatible_node(dn, NULL, "fsl,qman-ceetm")
11508 + num_ceetms++;
11509 +
11510 + /* Parse pool channels into the SDQCR mask. (Must happen before portals
11511 + * are initialised.) */
11512 + for_each_compatible_node(dn, NULL, "fsl,pool-channel-range") {
11513 + ret = fsl_pool_channel_range_sdqcr(dn);
11514 + if (ret)
11515 + return ret;
11516 + }
11517 +
11518 + memset(affine_portals, 0, sizeof(void *) * num_possible_cpus());
11519 + /* Initialise portals. See bman_driver.c for comments */
11520 + for_each_compatible_node(dn, NULL, "fsl,qman-portal") {
11521 + if (!of_device_is_available(dn))
11522 + continue;
11523 + pcfg = parse_pcfg(dn);
11524 + if (pcfg) {
11525 + pcfg->public_cfg.pools = pools_sdqcr;
11526 + list_add_tail(&pcfg->list, &unused_pcfgs);
11527 + }
11528 + }
11529 + for_each_possible_cpu(cpu) {
11530 + if (cpumask_test_cpu(cpu, &want_shared)) {
11531 + pcfg = get_pcfg(&unused_pcfgs);
11532 + if (!pcfg)
11533 + break;
11534 + pcfg->public_cfg.cpu = cpu;
11535 + list_add_tail(&pcfg->list, &shared_pcfgs);
11536 + cpumask_set_cpu(cpu, &shared_cpus);
11537 + }
11538 + if (cpumask_test_cpu(cpu, &want_unshared)) {
11539 + if (cpumask_test_cpu(cpu, &shared_cpus))
11540 + continue;
11541 + pcfg = get_pcfg(&unused_pcfgs);
11542 + if (!pcfg)
11543 + break;
11544 + pcfg->public_cfg.cpu = cpu;
11545 + list_add_tail(&pcfg->list, &unshared_pcfgs);
11546 + cpumask_set_cpu(cpu, &unshared_cpus);
11547 + }
11548 + }
11549 + if (list_empty(&shared_pcfgs) && list_empty(&unshared_pcfgs)) {
11550 + for_each_online_cpu(cpu) {
11551 + pcfg = get_pcfg(&unused_pcfgs);
11552 + if (!pcfg)
11553 + break;
11554 + pcfg->public_cfg.cpu = cpu;
11555 + list_add_tail(&pcfg->list, &unshared_pcfgs);
11556 + cpumask_set_cpu(cpu, &unshared_cpus);
11557 + }
11558 + }
11559 + cpumask_andnot(&slave_cpus, cpu_possible_mask, &shared_cpus);
11560 + cpumask_andnot(&slave_cpus, &slave_cpus, &unshared_cpus);
11561 + if (cpumask_empty(&slave_cpus)) {
11562 + if (!list_empty(&shared_pcfgs)) {
11563 + cpumask_or(&unshared_cpus, &unshared_cpus,
11564 + &shared_cpus);
11565 + cpumask_clear(&shared_cpus);
11566 + list_splice_tail(&shared_pcfgs, &unshared_pcfgs);
11567 + INIT_LIST_HEAD(&shared_pcfgs);
11568 + }
11569 + } else {
11570 + if (list_empty(&shared_pcfgs)) {
11571 + pcfg = get_pcfg(&unshared_pcfgs);
11572 + if (!pcfg) {
11573 + pr_crit("No QMan portals available!\n");
11574 + return 0;
11575 + }
11576 + cpumask_clear_cpu(pcfg->public_cfg.cpu, &unshared_cpus);
11577 + cpumask_set_cpu(pcfg->public_cfg.cpu, &shared_cpus);
11578 + list_add_tail(&pcfg->list, &shared_pcfgs);
11579 + }
11580 + }
11581 + list_for_each_entry(pcfg, &unshared_pcfgs, list) {
11582 + pcfg->public_cfg.is_shared = 0;
11583 + p = init_pcfg(pcfg);
11584 + if (!p) {
11585 + pr_crit("Unable to configure portals\n");
11586 + return 0;
11587 + }
11588 + }
11589 + list_for_each_entry(pcfg, &shared_pcfgs, list) {
11590 + pcfg->public_cfg.is_shared = 1;
11591 + p = init_pcfg(pcfg);
11592 + if (p)
11593 + shared_portals[num_shared_portals++] = p;
11594 + }
11595 + if (!cpumask_empty(&slave_cpus))
11596 + for_each_cpu(cpu, &slave_cpus)
11597 + init_slave(cpu);
11598 + pr_info("Qman portals initialised\n");
11599 + cpumask_andnot(&offline_cpus, cpu_possible_mask, cpu_online_mask);
11600 + for_each_cpu(cpu, &offline_cpus)
11601 + qman_offline_cpu(cpu);
11602 +#ifdef CONFIG_HOTPLUG_CPU
11603 + register_hotcpu_notifier(&qman_hotplug_cpu_notifier);
11604 +#endif
11605 + return 0;
11606 +}
11607 +
11608 +__init int qman_resource_init(void)
11609 +{
11610 + struct device_node *dn;
11611 + int ret;
11612 +
11613 + /* Initialise FQID allocation ranges */
11614 + for_each_compatible_node(dn, NULL, "fsl,fqid-range") {
11615 + ret = fsl_fqid_range_init(dn);
11616 + if (ret)
11617 + return ret;
11618 + }
11619 + /* Initialise CGRID allocation ranges */
11620 + for_each_compatible_node(dn, NULL, "fsl,cgrid-range") {
11621 + ret = fsl_cgrid_range_init(dn);
11622 + if (ret)
11623 + return ret;
11624 + }
11625 + /* Parse pool channels into the allocator. (Must happen after portals
11626 + * are initialised.) */
11627 + for_each_compatible_node(dn, NULL, "fsl,pool-channel-range") {
11628 + ret = fsl_pool_channel_range_init(dn);
11629 + if (ret)
11630 + return ret;
11631 + }
11632 +
11633 + /* Parse CEETM */
11634 + for_each_compatible_node(dn, NULL, "fsl,qman-ceetm") {
11635 + ret = fsl_ceetm_init(dn);
11636 + if (ret)
11637 + return ret;
11638 + }
11639 + return 0;
11640 +}
11641 +
11642 +#ifdef CONFIG_SUSPEND
11643 +void suspend_unused_qportal(void)
11644 +{
11645 + struct qm_portal_config *pcfg;
11646 +
11647 + if (list_empty(&unused_pcfgs))
11648 + return;
11649 +
11650 + list_for_each_entry(pcfg, &unused_pcfgs, list) {
11651 +#ifdef CONFIG_PM_DEBUG
11652 + pr_info("Need to save qportal %d\n", pcfg->public_cfg.index);
11653 +#endif
11654 + /* save isdr, disable all via isdr, clear isr */
11655 + pcfg->saved_isdr =
11656 + __raw_readl(pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
11657 + __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
11658 + 0xe08);
11659 + __raw_writel(0xffffffff, pcfg->addr_virt[DPA_PORTAL_CI] +
11660 + 0xe00);
11661 + }
11662 + return;
11663 +}
11664 +
11665 +void resume_unused_qportal(void)
11666 +{
11667 + struct qm_portal_config *pcfg;
11668 +
11669 + if (list_empty(&unused_pcfgs))
11670 + return;
11671 +
11672 + list_for_each_entry(pcfg, &unused_pcfgs, list) {
11673 +#ifdef CONFIG_PM_DEBUG
11674 + pr_info("Need to resume qportal %d\n", pcfg->public_cfg.index);
11675 +#endif
11676 + /* restore isdr */
11677 + __raw_writel(pcfg->saved_isdr,
11678 + pcfg->addr_virt[DPA_PORTAL_CI] + 0xe08);
11679 + }
11680 + return;
11681 +}
11682 +#endif
11683 +
11684 --- /dev/null
11685 +++ b/drivers/staging/fsl_qbman/qman_high.c
11686 @@ -0,0 +1,5568 @@
11687 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
11688 + *
11689 + * Redistribution and use in source and binary forms, with or without
11690 + * modification, are permitted provided that the following conditions are met:
11691 + * * Redistributions of source code must retain the above copyright
11692 + * notice, this list of conditions and the following disclaimer.
11693 + * * Redistributions in binary form must reproduce the above copyright
11694 + * notice, this list of conditions and the following disclaimer in the
11695 + * documentation and/or other materials provided with the distribution.
11696 + * * Neither the name of Freescale Semiconductor nor the
11697 + * names of its contributors may be used to endorse or promote products
11698 + * derived from this software without specific prior written permission.
11699 + *
11700 + *
11701 + * ALTERNATIVELY, this software may be distributed under the terms of the
11702 + * GNU General Public License ("GPL") as published by the Free Software
11703 + * Foundation, either version 2 of that License or (at your option) any
11704 + * later version.
11705 + *
11706 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
11707 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
11708 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11709 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
11710 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
11711 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
11712 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
11713 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
11714 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
11715 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11716 + */
11717 +
11718 +#include "qman_low.h"
11719 +
11720 +/* Compilation constants */
11721 +#define DQRR_MAXFILL 15
11722 +#define EQCR_ITHRESH 4 /* if EQCR congests, interrupt threshold */
11723 +#define IRQNAME "QMan portal %d"
11724 +#define MAX_IRQNAME 16 /* big enough for "QMan portal %d" */
11725 +
11726 +/* Divide 'n' by 'd', rounding down if 'r' is negative, rounding up if it's
11727 + * positive, and rounding to the closest value if it's zero. NB, this macro
11728 + * implicitly upgrades parameters to unsigned 64-bit, so feed it with types
11729 + * that are compatible with this. NB, these arguments should not be expressions
11730 + * unless it is safe for them to be evaluated multiple times. Eg. do not pass
11731 + * in "some_value++" as a parameter to the macro! */
11732 +#define ROUNDING(n, d, r) \
11733 + (((r) < 0) ? div64_u64((n), (d)) : \
11734 + (((r) > 0) ? div64_u64(((n) + (d) - 1), (d)) : \
11735 + div64_u64(((n) + ((d) / 2)), (d))))
11736 +
11737 +/* Lock/unlock frame queues, subject to the "LOCKED" flag. This is about
11738 + * inter-processor locking only. Note, FQLOCK() is always called either under a
11739 + * local_irq_save() or from interrupt context - hence there's no need for irq
11740 + * protection (and indeed, attempting to nest irq-protection doesn't work, as
11741 + * the "irq en/disable" machinery isn't recursive...). */
11742 +#define FQLOCK(fq) \
11743 + do { \
11744 + struct qman_fq *__fq478 = (fq); \
11745 + if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \
11746 + spin_lock(&__fq478->fqlock); \
11747 + } while (0)
11748 +#define FQUNLOCK(fq) \
11749 + do { \
11750 + struct qman_fq *__fq478 = (fq); \
11751 + if (fq_isset(__fq478, QMAN_FQ_FLAG_LOCKED)) \
11752 + spin_unlock(&__fq478->fqlock); \
11753 + } while (0)
11754 +
11755 +static inline void fq_set(struct qman_fq *fq, u32 mask)
11756 +{
11757 + set_bits(mask, &fq->flags);
11758 +}
11759 +static inline void fq_clear(struct qman_fq *fq, u32 mask)
11760 +{
11761 + clear_bits(mask, &fq->flags);
11762 +}
11763 +static inline int fq_isset(struct qman_fq *fq, u32 mask)
11764 +{
11765 + return fq->flags & mask;
11766 +}
11767 +static inline int fq_isclear(struct qman_fq *fq, u32 mask)
11768 +{
11769 + return !(fq->flags & mask);
11770 +}
11771 +
11772 +struct qman_portal {
11773 + struct qm_portal p;
11774 + unsigned long bits; /* PORTAL_BITS_*** - dynamic, strictly internal */
11775 + unsigned long irq_sources;
11776 + u32 use_eqcr_ci_stashing;
11777 + u32 slowpoll; /* only used when interrupts are off */
11778 + struct qman_fq *vdqcr_owned; /* only 1 volatile dequeue at a time */
11779 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
11780 + struct qman_fq *eqci_owned; /* only 1 enqueue WAIT_SYNC at a time */
11781 +#endif
11782 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
11783 + raw_spinlock_t sharing_lock; /* only used if is_shared */
11784 + int is_shared;
11785 + struct qman_portal *sharing_redirect;
11786 +#endif
11787 + u32 sdqcr;
11788 + int dqrr_disable_ref;
11789 + /* A portal-specific handler for DCP ERNs. If this is NULL, the global
11790 + * handler is called instead. */
11791 + qman_cb_dc_ern cb_dc_ern;
11792 + /* When the cpu-affine portal is activated, this is non-NULL */
11793 + const struct qm_portal_config *config;
11794 + /* This is needed for providing a non-NULL device to dma_map_***() */
11795 + struct platform_device *pdev;
11796 + struct dpa_rbtree retire_table;
11797 + char irqname[MAX_IRQNAME];
11798 + /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */
11799 + struct qman_cgrs *cgrs;
11800 + /* linked-list of CSCN handlers. */
11801 + struct list_head cgr_cbs;
11802 + /* list lock */
11803 + spinlock_t cgr_lock;
11804 + /* 2-element array. ccgrs[0] is mask, ccgrs[1] is snapshot. */
11805 + struct qman_ccgrs *ccgrs[QMAN_CEETM_MAX];
11806 + /* 256-element array, each is a linked-list of CCSCN handlers. */
11807 + struct list_head ccgr_cbs[QMAN_CEETM_MAX];
11808 + /* list lock */
11809 + spinlock_t ccgr_lock;
11810 + /* track if memory was allocated by the driver */
11811 + u8 alloced;
11812 + /* power management data */
11813 + u32 save_isdr;
11814 +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
11815 + /* Keep a shadow copy of the DQRR on LE systems
11816 + as the SW needs to do byteswaps of read only
11817 + memory. Must be aligned to the size of the
11818 + ring to ensure easy index calcualtions based
11819 + on address */
11820 + struct qm_dqrr_entry shadow_dqrr[QM_DQRR_SIZE]
11821 + __attribute__((aligned(512)));
11822 +#endif
11823 +};
11824 +
11825 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
11826 +#define PORTAL_IRQ_LOCK(p, irqflags) \
11827 + do { \
11828 + if ((p)->is_shared) \
11829 + raw_spin_lock_irqsave(&(p)->sharing_lock, irqflags); \
11830 + else \
11831 + local_irq_save(irqflags); \
11832 + } while (0)
11833 +#define PORTAL_IRQ_UNLOCK(p, irqflags) \
11834 + do { \
11835 + if ((p)->is_shared) \
11836 + raw_spin_unlock_irqrestore(&(p)->sharing_lock, \
11837 + irqflags); \
11838 + else \
11839 + local_irq_restore(irqflags); \
11840 + } while (0)
11841 +#else
11842 +#define PORTAL_IRQ_LOCK(p, irqflags) local_irq_save(irqflags)
11843 +#define PORTAL_IRQ_UNLOCK(p, irqflags) local_irq_restore(irqflags)
11844 +#endif
11845 +
11846 +/* Global handler for DCP ERNs. Used when the portal receiving the message does
11847 + * not have a portal-specific handler. */
11848 +static qman_cb_dc_ern cb_dc_ern;
11849 +
11850 +static cpumask_t affine_mask;
11851 +static DEFINE_SPINLOCK(affine_mask_lock);
11852 +static u16 affine_channels[NR_CPUS];
11853 +static DEFINE_PER_CPU(struct qman_portal, qman_affine_portal);
11854 +void *affine_portals[NR_CPUS];
11855 +
11856 +/* "raw" gets the cpu-local struct whether it's a redirect or not. */
11857 +static inline struct qman_portal *get_raw_affine_portal(void)
11858 +{
11859 + return &get_cpu_var(qman_affine_portal);
11860 +}
11861 +/* For ops that can redirect, this obtains the portal to use */
11862 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
11863 +static inline struct qman_portal *get_affine_portal(void)
11864 +{
11865 + struct qman_portal *p = get_raw_affine_portal();
11866 + if (p->sharing_redirect)
11867 + return p->sharing_redirect;
11868 + return p;
11869 +}
11870 +#else
11871 +#define get_affine_portal() get_raw_affine_portal()
11872 +#endif
11873 +/* For every "get", there must be a "put" */
11874 +static inline void put_affine_portal(void)
11875 +{
11876 + put_cpu_var(qman_affine_portal);
11877 +}
11878 +/* Exception: poll functions assume the caller is cpu-affine and in no risk of
11879 + * re-entrance, which are the two reasons we usually use the get/put_cpu_var()
11880 + * semantic - ie. to disable pre-emption. Some use-cases expect the execution
11881 + * context to remain as non-atomic during poll-triggered callbacks as it was
11882 + * when the poll API was first called (eg. NAPI), so we go out of our way in
11883 + * this case to not disable pre-emption. */
11884 +static inline struct qman_portal *get_poll_portal(void)
11885 +{
11886 + return &get_cpu_var(qman_affine_portal);
11887 +}
11888 +#define put_poll_portal()
11889 +
11890 +/* This gives a FQID->FQ lookup to cover the fact that we can't directly demux
11891 + * retirement notifications (the fact they are sometimes h/w-consumed means that
11892 + * contextB isn't always a s/w demux - and as we can't know which case it is
11893 + * when looking at the notification, we have to use the slow lookup for all of
11894 + * them). NB, it's possible to have multiple FQ objects refer to the same FQID
11895 + * (though at most one of them should be the consumer), so this table isn't for
11896 + * all FQs - FQs are added when retirement commands are issued, and removed when
11897 + * they complete, which also massively reduces the size of this table. */
11898 +IMPLEMENT_DPA_RBTREE(fqtree, struct qman_fq, node, fqid);
11899 +
11900 +/* This is what everything can wait on, even if it migrates to a different cpu
11901 + * to the one whose affine portal it is waiting on. */
11902 +static DECLARE_WAIT_QUEUE_HEAD(affine_queue);
11903 +
11904 +static inline int table_push_fq(struct qman_portal *p, struct qman_fq *fq)
11905 +{
11906 + int ret = fqtree_push(&p->retire_table, fq);
11907 + if (ret)
11908 + pr_err("ERROR: double FQ-retirement %d\n", fq->fqid);
11909 + return ret;
11910 +}
11911 +
11912 +static inline void table_del_fq(struct qman_portal *p, struct qman_fq *fq)
11913 +{
11914 + fqtree_del(&p->retire_table, fq);
11915 +}
11916 +
11917 +static inline struct qman_fq *table_find_fq(struct qman_portal *p, u32 fqid)
11918 +{
11919 + return fqtree_find(&p->retire_table, fqid);
11920 +}
11921 +
11922 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
11923 +static void **qman_fq_lookup_table;
11924 +static size_t qman_fq_lookup_table_size;
11925 +
11926 +int qman_setup_fq_lookup_table(size_t num_entries)
11927 +{
11928 + num_entries++;
11929 + /* Allocate 1 more entry since the first entry is not used */
11930 + qman_fq_lookup_table = vzalloc((num_entries * sizeof(void *)));
11931 + if (!qman_fq_lookup_table) {
11932 + pr_err("QMan: Could not allocate fq lookup table\n");
11933 + return -ENOMEM;
11934 + }
11935 + qman_fq_lookup_table_size = num_entries;
11936 + pr_info("QMan: Allocated lookup table at %p, entry count %lu\n",
11937 + qman_fq_lookup_table,
11938 + (unsigned long)qman_fq_lookup_table_size);
11939 + return 0;
11940 +}
11941 +
11942 +/* global structure that maintains fq object mapping */
11943 +static DEFINE_SPINLOCK(fq_hash_table_lock);
11944 +
11945 +static int find_empty_fq_table_entry(u32 *entry, struct qman_fq *fq)
11946 +{
11947 + u32 i;
11948 +
11949 + spin_lock(&fq_hash_table_lock);
11950 + /* Can't use index zero because this has special meaning
11951 + * in context_b field. */
11952 + for (i = 1; i < qman_fq_lookup_table_size; i++) {
11953 + if (qman_fq_lookup_table[i] == NULL) {
11954 + *entry = i;
11955 + qman_fq_lookup_table[i] = fq;
11956 + spin_unlock(&fq_hash_table_lock);
11957 + return 0;
11958 + }
11959 + }
11960 + spin_unlock(&fq_hash_table_lock);
11961 + return -ENOMEM;
11962 +}
11963 +
11964 +static void clear_fq_table_entry(u32 entry)
11965 +{
11966 + spin_lock(&fq_hash_table_lock);
11967 + BUG_ON(entry >= qman_fq_lookup_table_size);
11968 + qman_fq_lookup_table[entry] = NULL;
11969 + spin_unlock(&fq_hash_table_lock);
11970 +}
11971 +
11972 +static inline struct qman_fq *get_fq_table_entry(u32 entry)
11973 +{
11974 + BUG_ON(entry >= qman_fq_lookup_table_size);
11975 + return qman_fq_lookup_table[entry];
11976 +}
11977 +#endif
11978 +
11979 +static inline void cpu_to_hw_fqd(struct qm_fqd *fqd)
11980 +{
11981 + /* Byteswap the FQD to HW format */
11982 + fqd->fq_ctrl = cpu_to_be16(fqd->fq_ctrl);
11983 + fqd->dest_wq = cpu_to_be16(fqd->dest_wq);
11984 + fqd->ics_cred = cpu_to_be16(fqd->ics_cred);
11985 + fqd->context_b = cpu_to_be32(fqd->context_b);
11986 + fqd->context_a.opaque = cpu_to_be64(fqd->context_a.opaque);
11987 +}
11988 +
11989 +static inline void hw_fqd_to_cpu(struct qm_fqd *fqd)
11990 +{
11991 + /* Byteswap the FQD to CPU format */
11992 + fqd->fq_ctrl = be16_to_cpu(fqd->fq_ctrl);
11993 + fqd->dest_wq = be16_to_cpu(fqd->dest_wq);
11994 + fqd->ics_cred = be16_to_cpu(fqd->ics_cred);
11995 + fqd->context_b = be32_to_cpu(fqd->context_b);
11996 + fqd->context_a.opaque = be64_to_cpu(fqd->context_a.opaque);
11997 +}
11998 +
11999 +/* Swap a 40 bit address */
12000 +static inline u64 cpu_to_be40(u64 in)
12001 +{
12002 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
12003 + return in;
12004 +#else
12005 + u64 out = 0;
12006 + u8 *p = (u8 *) &out;
12007 + p[0] = in >> 32;
12008 + p[1] = in >> 24;
12009 + p[2] = in >> 16;
12010 + p[3] = in >> 8;
12011 + p[4] = in >> 0;
12012 + return out;
12013 +#endif
12014 +}
12015 +static inline u64 be40_to_cpu(u64 in)
12016 +{
12017 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
12018 + return in;
12019 +#else
12020 + u64 out = 0;
12021 + u8 *pout = (u8 *) &out;
12022 + u8 *pin = (u8 *) &in;
12023 + pout[0] = pin[4];
12024 + pout[1] = pin[3];
12025 + pout[2] = pin[2];
12026 + pout[3] = pin[1];
12027 + pout[4] = pin[0];
12028 + return out;
12029 +#endif
12030 +}
12031 +
12032 +/* Swap a 24 bit value */
12033 +static inline u32 cpu_to_be24(u32 in)
12034 +{
12035 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
12036 + return in;
12037 +#else
12038 + u32 out = 0;
12039 + u8 *p = (u8 *) &out;
12040 + p[0] = in >> 16;
12041 + p[1] = in >> 8;
12042 + p[2] = in >> 0;
12043 + return out;
12044 +#endif
12045 +}
12046 +
12047 +static inline u32 be24_to_cpu(u32 in)
12048 +{
12049 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
12050 + return in;
12051 +#else
12052 + u32 out = 0;
12053 + u8 *pout = (u8 *) &out;
12054 + u8 *pin = (u8 *) &in;
12055 + pout[0] = pin[2];
12056 + pout[1] = pin[1];
12057 + pout[2] = pin[0];
12058 + return out;
12059 +#endif
12060 +}
12061 +
12062 +static inline u64 be48_to_cpu(u64 in)
12063 +{
12064 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
12065 + return in;
12066 +#else
12067 + u64 out = 0;
12068 + u8 *pout = (u8 *) &out;
12069 + u8 *pin = (u8 *) &in;
12070 +
12071 + pout[0] = pin[5];
12072 + pout[1] = pin[4];
12073 + pout[2] = pin[3];
12074 + pout[3] = pin[2];
12075 + pout[4] = pin[1];
12076 + pout[5] = pin[0];
12077 + return out;
12078 +#endif
12079 +}
12080 +static inline void cpu_to_hw_fd(struct qm_fd *fd)
12081 +{
12082 + fd->addr = cpu_to_be40(fd->addr);
12083 + fd->status = cpu_to_be32(fd->status);
12084 + fd->opaque = cpu_to_be32(fd->opaque);
12085 +}
12086 +
12087 +static inline void hw_fd_to_cpu(struct qm_fd *fd)
12088 +{
12089 + fd->addr = be40_to_cpu(fd->addr);
12090 + fd->status = be32_to_cpu(fd->status);
12091 + fd->opaque = be32_to_cpu(fd->opaque);
12092 +}
12093 +
12094 +static inline void hw_cq_query_to_cpu(struct qm_mcr_ceetm_cq_query *cq_query)
12095 +{
12096 + cq_query->ccgid = be16_to_cpu(cq_query->ccgid);
12097 + cq_query->state = be16_to_cpu(cq_query->state);
12098 + cq_query->pfdr_hptr = be24_to_cpu(cq_query->pfdr_hptr);
12099 + cq_query->pfdr_tptr = be24_to_cpu(cq_query->pfdr_tptr);
12100 + cq_query->od1_xsfdr = be16_to_cpu(cq_query->od1_xsfdr);
12101 + cq_query->od2_xsfdr = be16_to_cpu(cq_query->od2_xsfdr);
12102 + cq_query->od3_xsfdr = be16_to_cpu(cq_query->od3_xsfdr);
12103 + cq_query->od4_xsfdr = be16_to_cpu(cq_query->od4_xsfdr);
12104 + cq_query->od5_xsfdr = be16_to_cpu(cq_query->od5_xsfdr);
12105 + cq_query->od6_xsfdr = be16_to_cpu(cq_query->od6_xsfdr);
12106 + cq_query->ra1_xsfdr = be16_to_cpu(cq_query->ra1_xsfdr);
12107 + cq_query->ra2_xsfdr = be16_to_cpu(cq_query->ra2_xsfdr);
12108 + cq_query->frm_cnt = be24_to_cpu(cq_query->frm_cnt);
12109 +}
12110 +
12111 +static inline void hw_ccgr_query_to_cpu(struct qm_mcr_ceetm_ccgr_query *ccgr_q)
12112 +{
12113 + int i;
12114 +
12115 + ccgr_q->cm_query.cscn_targ_dcp =
12116 + be16_to_cpu(ccgr_q->cm_query.cscn_targ_dcp);
12117 + ccgr_q->cm_query.i_cnt = be40_to_cpu(ccgr_q->cm_query.i_cnt);
12118 + ccgr_q->cm_query.a_cnt = be40_to_cpu(ccgr_q->cm_query.a_cnt);
12119 + for (i = 0; i < ARRAY_SIZE(ccgr_q->cm_query.cscn_targ_swp); i++)
12120 + ccgr_q->cm_query.cscn_targ_swp[i] =
12121 + be32_to_cpu(ccgr_q->cm_query.cscn_targ_swp[i]);
12122 +}
12123 +
12124 +/* In the case that slow- and fast-path handling are both done by qman_poll()
12125 + * (ie. because there is no interrupt handling), we ought to balance how often
12126 + * we do the fast-path poll versus the slow-path poll. We'll use two decrementer
12127 + * sources, so we call the fast poll 'n' times before calling the slow poll
12128 + * once. The idle decrementer constant is used when the last slow-poll detected
12129 + * no work to do, and the busy decrementer constant when the last slow-poll had
12130 + * work to do. */
12131 +#define SLOW_POLL_IDLE 1000
12132 +#define SLOW_POLL_BUSY 10
12133 +static u32 __poll_portal_slow(struct qman_portal *p, u32 is);
12134 +static inline unsigned int __poll_portal_fast(struct qman_portal *p,
12135 + unsigned int poll_limit);
12136 +
12137 +/* Portal interrupt handler */
12138 +static irqreturn_t portal_isr(__always_unused int irq, void *ptr)
12139 +{
12140 + struct qman_portal *p = ptr;
12141 + /*
12142 + * The CSCI/CCSCI source is cleared inside __poll_portal_slow(), because
12143 + * it could race against a Query Congestion State command also given
12144 + * as part of the handling of this interrupt source. We mustn't
12145 + * clear it a second time in this top-level function.
12146 + */
12147 + u32 clear = QM_DQAVAIL_MASK | (p->irq_sources &
12148 + ~(QM_PIRQ_CSCI | QM_PIRQ_CCSCI));
12149 + u32 is = qm_isr_status_read(&p->p) & p->irq_sources;
12150 + /* DQRR-handling if it's interrupt-driven */
12151 + if (is & QM_PIRQ_DQRI)
12152 + __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT);
12153 + /* Handling of anything else that's interrupt-driven */
12154 + clear |= __poll_portal_slow(p, is);
12155 + qm_isr_status_clear(&p->p, clear);
12156 + return IRQ_HANDLED;
12157 +}
12158 +
12159 +/* This inner version is used privately by qman_create_affine_portal(), as well
12160 + * as by the exported qman_stop_dequeues(). */
12161 +static inline void qman_stop_dequeues_ex(struct qman_portal *p)
12162 +{
12163 + unsigned long irqflags __maybe_unused;
12164 + PORTAL_IRQ_LOCK(p, irqflags);
12165 + if (!(p->dqrr_disable_ref++))
12166 + qm_dqrr_set_maxfill(&p->p, 0);
12167 + PORTAL_IRQ_UNLOCK(p, irqflags);
12168 +}
12169 +
12170 +static int drain_mr(struct qm_portal *p)
12171 +{
12172 + const struct qm_mr_entry *msg;
12173 +loop:
12174 + msg = qm_mr_current(p);
12175 + if (!msg) {
12176 + /* if MR was full and h/w had other FQRNI entries to produce, we
12177 + * need to allow it time to produce those entries once the
12178 + * existing entries are consumed. A worst-case situation
12179 + * (fully-loaded system) means h/w sequencers may have to do 3-4
12180 + * other things before servicing the portal's MR pump, each of
12181 + * which (if slow) may take ~50 qman cycles (which is ~200
12182 + * processor cycles). So rounding up and then multiplying this
12183 + * worst-case estimate by a factor of 10, just to be
12184 + * ultra-paranoid, goes as high as 10,000 cycles. NB, we consume
12185 + * one entry at a time, so h/w has an opportunity to produce new
12186 + * entries well before the ring has been fully consumed, so
12187 + * we're being *really* paranoid here. */
12188 + u64 now, then = mfatb();
12189 + do {
12190 + now = mfatb();
12191 + } while ((then + 10000) > now);
12192 + msg = qm_mr_current(p);
12193 + if (!msg)
12194 + return 0;
12195 + }
12196 + qm_mr_next(p);
12197 + qm_mr_cci_consume(p, 1);
12198 + goto loop;
12199 +}
12200 +
12201 +#ifdef CONFIG_SUSPEND
12202 +static int _qman_portal_suspend_noirq(struct device *dev)
12203 +{
12204 + struct qman_portal *p = (struct qman_portal *)dev->platform_data;
12205 +#ifdef CONFIG_PM_DEBUG
12206 + struct platform_device *pdev = to_platform_device(dev);
12207 +#endif
12208 +
12209 + p->save_isdr = qm_isr_disable_read(&p->p);
12210 + qm_isr_disable_write(&p->p, 0xffffffff);
12211 + qm_isr_status_clear(&p->p, 0xffffffff);
12212 +#ifdef CONFIG_PM_DEBUG
12213 + pr_info("Suspend for %s\n", pdev->name);
12214 +#endif
12215 + return 0;
12216 +}
12217 +
12218 +static int _qman_portal_resume_noirq(struct device *dev)
12219 +{
12220 + struct qman_portal *p = (struct qman_portal *)dev->platform_data;
12221 +
12222 + /* restore isdr */
12223 + qm_isr_disable_write(&p->p, p->save_isdr);
12224 + return 0;
12225 +}
12226 +#else
12227 +#define _qman_portal_suspend_noirq NULL
12228 +#define _qman_portal_resume_noirq NULL
12229 +#endif
12230 +
12231 +struct dev_pm_domain qman_portal_device_pm_domain = {
12232 + .ops = {
12233 + USE_PLATFORM_PM_SLEEP_OPS
12234 + .suspend_noirq = _qman_portal_suspend_noirq,
12235 + .resume_noirq = _qman_portal_resume_noirq,
12236 + }
12237 +};
12238 +
12239 +struct qman_portal *qman_create_portal(
12240 + struct qman_portal *portal,
12241 + const struct qm_portal_config *config,
12242 + const struct qman_cgrs *cgrs)
12243 +{
12244 + struct qm_portal *__p;
12245 + char buf[16];
12246 + int ret;
12247 + u32 isdr;
12248 +
12249 + if (!portal) {
12250 + portal = kmalloc(sizeof(*portal), GFP_KERNEL);
12251 + if (!portal)
12252 + return portal;
12253 + portal->alloced = 1;
12254 + } else
12255 + portal->alloced = 0;
12256 +
12257 + __p = &portal->p;
12258 +
12259 +#ifdef CONFIG_FSL_PAMU
12260 + /* PAMU is required for stashing */
12261 + portal->use_eqcr_ci_stashing = ((qman_ip_rev >= QMAN_REV30) ?
12262 + 1 : 0);
12263 +#else
12264 + portal->use_eqcr_ci_stashing = 0;
12265 +#endif
12266 +
12267 + /* prep the low-level portal struct with the mapped addresses from the
12268 + * config, everything that follows depends on it and "config" is more
12269 + * for (de)reference... */
12270 + __p->addr.addr_ce = config->addr_virt[DPA_PORTAL_CE];
12271 + __p->addr.addr_ci = config->addr_virt[DPA_PORTAL_CI];
12272 + /*
12273 + * If CI-stashing is used, the current defaults use a threshold of 3,
12274 + * and stash with high-than-DQRR priority.
12275 + */
12276 + if (qm_eqcr_init(__p, qm_eqcr_pvb,
12277 + portal->use_eqcr_ci_stashing ? 3 : 0, 1)) {
12278 + pr_err("Qman EQCR initialisation failed\n");
12279 + goto fail_eqcr;
12280 + }
12281 + if (qm_dqrr_init(__p, config, qm_dqrr_dpush, qm_dqrr_pvb,
12282 + qm_dqrr_cdc, DQRR_MAXFILL)) {
12283 + pr_err("Qman DQRR initialisation failed\n");
12284 + goto fail_dqrr;
12285 + }
12286 + if (qm_mr_init(__p, qm_mr_pvb, qm_mr_cci)) {
12287 + pr_err("Qman MR initialisation failed\n");
12288 + goto fail_mr;
12289 + }
12290 + if (qm_mc_init(__p)) {
12291 + pr_err("Qman MC initialisation failed\n");
12292 + goto fail_mc;
12293 + }
12294 + if (qm_isr_init(__p)) {
12295 + pr_err("Qman ISR initialisation failed\n");
12296 + goto fail_isr;
12297 + }
12298 + /* static interrupt-gating controls */
12299 + qm_dqrr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_DQRR_ITHRESH);
12300 + qm_mr_set_ithresh(__p, CONFIG_FSL_QMAN_PIRQ_MR_ITHRESH);
12301 + qm_isr_set_iperiod(__p, CONFIG_FSL_QMAN_PIRQ_IPERIOD);
12302 + portal->cgrs = kmalloc(2 * sizeof(*cgrs), GFP_KERNEL);
12303 + if (!portal->cgrs)
12304 + goto fail_cgrs;
12305 + /* initial snapshot is no-depletion */
12306 + qman_cgrs_init(&portal->cgrs[1]);
12307 + if (cgrs)
12308 + portal->cgrs[0] = *cgrs;
12309 + else
12310 + /* if the given mask is NULL, assume all CGRs can be seen */
12311 + qman_cgrs_fill(&portal->cgrs[0]);
12312 + INIT_LIST_HEAD(&portal->cgr_cbs);
12313 + spin_lock_init(&portal->cgr_lock);
12314 + if (num_ceetms) {
12315 + for (ret = 0; ret < num_ceetms; ret++) {
12316 + portal->ccgrs[ret] = kmalloc(2 *
12317 + sizeof(struct qman_ccgrs), GFP_KERNEL);
12318 + if (!portal->ccgrs[ret])
12319 + goto fail_ccgrs;
12320 + qman_ccgrs_init(&portal->ccgrs[ret][1]);
12321 + qman_ccgrs_fill(&portal->ccgrs[ret][0]);
12322 + INIT_LIST_HEAD(&portal->ccgr_cbs[ret]);
12323 + }
12324 + }
12325 + spin_lock_init(&portal->ccgr_lock);
12326 + portal->bits = 0;
12327 + portal->slowpoll = 0;
12328 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
12329 + portal->eqci_owned = NULL;
12330 +#endif
12331 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
12332 + raw_spin_lock_init(&portal->sharing_lock);
12333 + portal->is_shared = config->public_cfg.is_shared;
12334 + portal->sharing_redirect = NULL;
12335 +#endif
12336 + portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 |
12337 + QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS |
12338 + QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED;
12339 + portal->dqrr_disable_ref = 0;
12340 + portal->cb_dc_ern = NULL;
12341 + sprintf(buf, "qportal-%d", config->public_cfg.channel);
12342 + portal->pdev = platform_device_alloc(buf, -1);
12343 + if (!portal->pdev) {
12344 + pr_err("qman_portal - platform_device_alloc() failed\n");
12345 + goto fail_devalloc;
12346 + }
12347 +#ifdef CONFIG_ARM
12348 + portal->pdev->dev.coherent_dma_mask = DMA_BIT_MASK(40);
12349 + portal->pdev->dev.dma_mask = &portal->pdev->dev.coherent_dma_mask;
12350 +#else
12351 + if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) {
12352 + pr_err("qman_portal - dma_set_mask() failed\n");
12353 + goto fail_devadd;
12354 + }
12355 +#endif
12356 + portal->pdev->dev.pm_domain = &qman_portal_device_pm_domain;
12357 + portal->pdev->dev.platform_data = portal;
12358 + ret = platform_device_add(portal->pdev);
12359 + if (ret) {
12360 + pr_err("qman_portal - platform_device_add() failed\n");
12361 + goto fail_devadd;
12362 + }
12363 + dpa_rbtree_init(&portal->retire_table);
12364 + isdr = 0xffffffff;
12365 + qm_isr_disable_write(__p, isdr);
12366 + portal->irq_sources = 0;
12367 + qm_isr_enable_write(__p, portal->irq_sources);
12368 + qm_isr_status_clear(__p, 0xffffffff);
12369 + snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, config->public_cfg.cpu);
12370 + if (request_irq(config->public_cfg.irq, portal_isr, 0, portal->irqname,
12371 + portal)) {
12372 + pr_err("request_irq() failed\n");
12373 + goto fail_irq;
12374 + }
12375 + if ((config->public_cfg.cpu != -1) &&
12376 + irq_can_set_affinity(config->public_cfg.irq) &&
12377 + irq_set_affinity(config->public_cfg.irq,
12378 + cpumask_of(config->public_cfg.cpu))) {
12379 + pr_err("irq_set_affinity() failed\n");
12380 + goto fail_affinity;
12381 + }
12382 +
12383 + /* Need EQCR to be empty before continuing */
12384 + isdr ^= QM_PIRQ_EQCI;
12385 + qm_isr_disable_write(__p, isdr);
12386 + ret = qm_eqcr_get_fill(__p);
12387 + if (ret) {
12388 + pr_err("Qman EQCR unclean\n");
12389 + goto fail_eqcr_empty;
12390 + }
12391 + isdr ^= (QM_PIRQ_DQRI | QM_PIRQ_MRI);
12392 + qm_isr_disable_write(__p, isdr);
12393 + while (qm_dqrr_current(__p) != NULL)
12394 + qm_dqrr_cdc_consume_n(__p, 0xffff);
12395 + drain_mr(__p);
12396 + /* Success */
12397 + portal->config = config;
12398 + qm_isr_disable_write(__p, 0);
12399 + qm_isr_uninhibit(__p);
12400 + /* Write a sane SDQCR */
12401 + qm_dqrr_sdqcr_set(__p, portal->sdqcr);
12402 + return portal;
12403 +fail_eqcr_empty:
12404 +fail_affinity:
12405 + free_irq(config->public_cfg.irq, portal);
12406 +fail_irq:
12407 + platform_device_del(portal->pdev);
12408 +fail_devadd:
12409 + platform_device_put(portal->pdev);
12410 +fail_devalloc:
12411 + if (num_ceetms)
12412 + for (ret = 0; ret < num_ceetms; ret++)
12413 + kfree(portal->ccgrs[ret]);
12414 +fail_ccgrs:
12415 + kfree(portal->cgrs);
12416 +fail_cgrs:
12417 + qm_isr_finish(__p);
12418 +fail_isr:
12419 + qm_mc_finish(__p);
12420 +fail_mc:
12421 + qm_mr_finish(__p);
12422 +fail_mr:
12423 + qm_dqrr_finish(__p);
12424 +fail_dqrr:
12425 + qm_eqcr_finish(__p);
12426 +fail_eqcr:
12427 + if (portal->alloced)
12428 + kfree(portal);
12429 + return NULL;
12430 +}
12431 +
12432 +struct qman_portal *qman_create_affine_portal(
12433 + const struct qm_portal_config *config,
12434 + const struct qman_cgrs *cgrs)
12435 +{
12436 + struct qman_portal *res;
12437 + struct qman_portal *portal;
12438 +
12439 + portal = &per_cpu(qman_affine_portal, config->public_cfg.cpu);
12440 + res = qman_create_portal(portal, config, cgrs);
12441 + if (res) {
12442 + spin_lock(&affine_mask_lock);
12443 + cpumask_set_cpu(config->public_cfg.cpu, &affine_mask);
12444 + affine_channels[config->public_cfg.cpu] =
12445 + config->public_cfg.channel;
12446 + affine_portals[config->public_cfg.cpu] = portal;
12447 + spin_unlock(&affine_mask_lock);
12448 + }
12449 + return res;
12450 +}
12451 +
12452 +/* These checks are BUG_ON()s because the driver is already supposed to avoid
12453 + * these cases. */
12454 +struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect,
12455 + int cpu)
12456 +{
12457 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
12458 + struct qman_portal *p;
12459 + p = &per_cpu(qman_affine_portal, cpu);
12460 + /* Check that we don't already have our own portal */
12461 + BUG_ON(p->config);
12462 + /* Check that we aren't already slaving to another portal */
12463 + BUG_ON(p->is_shared);
12464 + /* Check that 'redirect' is prepared to have us */
12465 + BUG_ON(!redirect->config->public_cfg.is_shared);
12466 + /* These are the only elements to initialise when redirecting */
12467 + p->irq_sources = 0;
12468 + p->sharing_redirect = redirect;
12469 + affine_portals[cpu] = p;
12470 + return p;
12471 +#else
12472 + BUG();
12473 + return NULL;
12474 +#endif
12475 +}
12476 +
12477 +void qman_destroy_portal(struct qman_portal *qm)
12478 +{
12479 + const struct qm_portal_config *pcfg;
12480 + int i;
12481 +
12482 + /* Stop dequeues on the portal */
12483 + qm_dqrr_sdqcr_set(&qm->p, 0);
12484 +
12485 + /* NB we do this to "quiesce" EQCR. If we add enqueue-completions or
12486 + * something related to QM_PIRQ_EQCI, this may need fixing.
12487 + * Also, due to the prefetching model used for CI updates in the enqueue
12488 + * path, this update will only invalidate the CI cacheline *after*
12489 + * working on it, so we need to call this twice to ensure a full update
12490 + * irrespective of where the enqueue processing was at when the teardown
12491 + * began. */
12492 + qm_eqcr_cce_update(&qm->p);
12493 + qm_eqcr_cce_update(&qm->p);
12494 + pcfg = qm->config;
12495 +
12496 + free_irq(pcfg->public_cfg.irq, qm);
12497 +
12498 + kfree(qm->cgrs);
12499 + if (num_ceetms)
12500 + for (i = 0; i < num_ceetms; i++)
12501 + kfree(qm->ccgrs[i]);
12502 + qm_isr_finish(&qm->p);
12503 + qm_mc_finish(&qm->p);
12504 + qm_mr_finish(&qm->p);
12505 + qm_dqrr_finish(&qm->p);
12506 + qm_eqcr_finish(&qm->p);
12507 +
12508 + platform_device_del(qm->pdev);
12509 + platform_device_put(qm->pdev);
12510 +
12511 + qm->config = NULL;
12512 + if (qm->alloced)
12513 + kfree(qm);
12514 +}
12515 +
12516 +const struct qm_portal_config *qman_destroy_affine_portal(void)
12517 +{
12518 + /* We don't want to redirect if we're a slave, use "raw" */
12519 + struct qman_portal *qm = get_raw_affine_portal();
12520 + const struct qm_portal_config *pcfg;
12521 + int cpu;
12522 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
12523 + if (qm->sharing_redirect) {
12524 + qm->sharing_redirect = NULL;
12525 + put_affine_portal();
12526 + return NULL;
12527 + }
12528 + qm->is_shared = 0;
12529 +#endif
12530 + pcfg = qm->config;
12531 + cpu = pcfg->public_cfg.cpu;
12532 +
12533 + qman_destroy_portal(qm);
12534 +
12535 + spin_lock(&affine_mask_lock);
12536 + cpumask_clear_cpu(cpu, &affine_mask);
12537 + spin_unlock(&affine_mask_lock);
12538 + put_affine_portal();
12539 + return pcfg;
12540 +}
12541 +
12542 +const struct qman_portal_config *qman_p_get_portal_config(struct qman_portal *p)
12543 +{
12544 + return &p->config->public_cfg;
12545 +}
12546 +EXPORT_SYMBOL(qman_p_get_portal_config);
12547 +
12548 +const struct qman_portal_config *qman_get_portal_config(void)
12549 +{
12550 + struct qman_portal *p = get_affine_portal();
12551 + const struct qman_portal_config *ret = qman_p_get_portal_config(p);
12552 + put_affine_portal();
12553 + return ret;
12554 +}
12555 +EXPORT_SYMBOL(qman_get_portal_config);
12556 +
12557 +/* Inline helper to reduce nesting in __poll_portal_slow() */
12558 +static inline void fq_state_change(struct qman_portal *p, struct qman_fq *fq,
12559 + const struct qm_mr_entry *msg, u8 verb)
12560 +{
12561 + FQLOCK(fq);
12562 + switch (verb) {
12563 + case QM_MR_VERB_FQRL:
12564 + DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_ORL));
12565 + fq_clear(fq, QMAN_FQ_STATE_ORL);
12566 + table_del_fq(p, fq);
12567 + break;
12568 + case QM_MR_VERB_FQRN:
12569 + DPA_ASSERT((fq->state == qman_fq_state_parked) ||
12570 + (fq->state == qman_fq_state_sched));
12571 + DPA_ASSERT(fq_isset(fq, QMAN_FQ_STATE_CHANGING));
12572 + fq_clear(fq, QMAN_FQ_STATE_CHANGING);
12573 + if (msg->fq.fqs & QM_MR_FQS_NOTEMPTY)
12574 + fq_set(fq, QMAN_FQ_STATE_NE);
12575 + if (msg->fq.fqs & QM_MR_FQS_ORLPRESENT)
12576 + fq_set(fq, QMAN_FQ_STATE_ORL);
12577 + else
12578 + table_del_fq(p, fq);
12579 + fq->state = qman_fq_state_retired;
12580 + break;
12581 + case QM_MR_VERB_FQPN:
12582 + DPA_ASSERT(fq->state == qman_fq_state_sched);
12583 + DPA_ASSERT(fq_isclear(fq, QMAN_FQ_STATE_CHANGING));
12584 + fq->state = qman_fq_state_parked;
12585 + }
12586 + FQUNLOCK(fq);
12587 +}
12588 +
12589 +static u32 __poll_portal_slow(struct qman_portal *p, u32 is)
12590 +{
12591 + const struct qm_mr_entry *msg;
12592 +
12593 + if (is & QM_PIRQ_CSCI) {
12594 + struct qman_cgrs rr, c;
12595 + struct qm_mc_result *mcr;
12596 + struct qman_cgr *cgr;
12597 + unsigned long irqflags __maybe_unused;
12598 +
12599 + spin_lock_irqsave(&p->cgr_lock, irqflags);
12600 + /*
12601 + * The CSCI bit must be cleared _before_ issuing the
12602 + * Query Congestion State command, to ensure that a long
12603 + * CGR State Change callback cannot miss an intervening
12604 + * state change.
12605 + */
12606 + qm_isr_status_clear(&p->p, QM_PIRQ_CSCI);
12607 + qm_mc_start(&p->p);
12608 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION);
12609 + while (!(mcr = qm_mc_result(&p->p)))
12610 + cpu_relax();
12611 + /* mask out the ones I'm not interested in */
12612 + qman_cgrs_and(&rr, (const struct qman_cgrs *)
12613 + &mcr->querycongestion.state, &p->cgrs[0]);
12614 + /* check previous snapshot for delta, enter/exit congestion */
12615 + qman_cgrs_xor(&c, &rr, &p->cgrs[1]);
12616 + /* update snapshot */
12617 + qman_cgrs_cp(&p->cgrs[1], &rr);
12618 + /* Invoke callback */
12619 + list_for_each_entry(cgr, &p->cgr_cbs, node)
12620 + if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid))
12621 + cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid));
12622 + spin_unlock_irqrestore(&p->cgr_lock, irqflags);
12623 + }
12624 + if (is & QM_PIRQ_CCSCI) {
12625 + struct qman_ccgrs rr, c, congestion_result;
12626 + struct qm_mc_result *mcr;
12627 + struct qm_mc_command *mcc;
12628 + struct qm_ceetm_ccg *ccg;
12629 + unsigned long irqflags __maybe_unused;
12630 + int i, j, k;
12631 +
12632 + spin_lock_irqsave(&p->ccgr_lock, irqflags);
12633 + /*
12634 + * The CCSCI bit must be cleared _before_ issuing the
12635 + * Query Congestion State command, to ensure that a long
12636 + * CCGR State Change callback cannot miss an intervening
12637 + * state change.
12638 + */
12639 + qm_isr_status_clear(&p->p, QM_PIRQ_CCSCI);
12640 +
12641 + for (i = 0; i < num_ceetms; i++) {
12642 + for (j = 0; j < 2; j++) {
12643 + mcc = qm_mc_start(&p->p);
12644 + mcc->ccgr_query.ccgrid = cpu_to_be16(
12645 + CEETM_QUERY_CONGESTION_STATE | j);
12646 + mcc->ccgr_query.dcpid = i;
12647 + qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY);
12648 + while (!(mcr = qm_mc_result(&p->p)))
12649 + cpu_relax();
12650 + for (k = 0; k < 8; k++)
12651 + mcr->ccgr_query.congestion_state.state.
12652 + __state[k] = be32_to_cpu(
12653 + mcr->ccgr_query.
12654 + congestion_state.state.
12655 + __state[k]);
12656 + congestion_result.q[j] =
12657 + mcr->ccgr_query.congestion_state.state;
12658 + }
12659 + /* mask out the ones I'm not interested in */
12660 + qman_ccgrs_and(&rr, &congestion_result,
12661 + &p->ccgrs[i][0]);
12662 + /*
12663 + * check previous snapshot for delta, enter/exit
12664 + * congestion.
12665 + */
12666 + qman_ccgrs_xor(&c, &rr, &p->ccgrs[i][1]);
12667 + /* update snapshot */
12668 + qman_ccgrs_cp(&p->ccgrs[i][1], &rr);
12669 + /* Invoke callback */
12670 + list_for_each_entry(ccg, &p->ccgr_cbs[i], cb_node)
12671 + if (ccg->cb && qman_ccgrs_get(&c,
12672 + (ccg->parent->idx << 4) | ccg->idx))
12673 + ccg->cb(ccg, ccg->cb_ctx,
12674 + qman_ccgrs_get(&rr,
12675 + (ccg->parent->idx << 4)
12676 + | ccg->idx));
12677 + }
12678 + spin_unlock_irqrestore(&p->ccgr_lock, irqflags);
12679 + }
12680 +
12681 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
12682 + if (is & QM_PIRQ_EQCI) {
12683 + unsigned long irqflags;
12684 + PORTAL_IRQ_LOCK(p, irqflags);
12685 + p->eqci_owned = NULL;
12686 + PORTAL_IRQ_UNLOCK(p, irqflags);
12687 + wake_up(&affine_queue);
12688 + }
12689 +#endif
12690 +
12691 + if (is & QM_PIRQ_EQRI) {
12692 + unsigned long irqflags __maybe_unused;
12693 + PORTAL_IRQ_LOCK(p, irqflags);
12694 + qm_eqcr_cce_update(&p->p);
12695 + qm_eqcr_set_ithresh(&p->p, 0);
12696 + PORTAL_IRQ_UNLOCK(p, irqflags);
12697 + wake_up(&affine_queue);
12698 + }
12699 +
12700 + if (is & QM_PIRQ_MRI) {
12701 + struct qman_fq *fq;
12702 + u8 verb, num = 0;
12703 +mr_loop:
12704 + qm_mr_pvb_update(&p->p);
12705 + msg = qm_mr_current(&p->p);
12706 + if (!msg)
12707 + goto mr_done;
12708 + verb = msg->verb & QM_MR_VERB_TYPE_MASK;
12709 + /* The message is a software ERN iff the 0x20 bit is set */
12710 + if (verb & 0x20) {
12711 + switch (verb) {
12712 + case QM_MR_VERB_FQRNI:
12713 + /* nada, we drop FQRNIs on the floor */
12714 + break;
12715 + case QM_MR_VERB_FQRN:
12716 + case QM_MR_VERB_FQRL:
12717 + /* Lookup in the retirement table */
12718 + fq = table_find_fq(p, be32_to_cpu(msg->fq.fqid));
12719 + BUG_ON(!fq);
12720 + fq_state_change(p, fq, msg, verb);
12721 + if (fq->cb.fqs)
12722 + fq->cb.fqs(p, fq, msg);
12723 + break;
12724 + case QM_MR_VERB_FQPN:
12725 + /* Parked */
12726 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
12727 + fq = get_fq_table_entry(
12728 + be32_to_cpu(msg->fq.contextB));
12729 +#else
12730 + fq = (void *)(uintptr_t)
12731 + be32_to_cpu(msg->fq.contextB);
12732 +#endif
12733 + fq_state_change(p, fq, msg, verb);
12734 + if (fq->cb.fqs)
12735 + fq->cb.fqs(p, fq, msg);
12736 + break;
12737 + case QM_MR_VERB_DC_ERN:
12738 + /* DCP ERN */
12739 + if (p->cb_dc_ern)
12740 + p->cb_dc_ern(p, msg);
12741 + else if (cb_dc_ern)
12742 + cb_dc_ern(p, msg);
12743 + else {
12744 + static int warn_once;
12745 + if (!warn_once) {
12746 + pr_crit("Leaking DCP ERNs!\n");
12747 + warn_once = 1;
12748 + }
12749 + }
12750 + break;
12751 + default:
12752 + pr_crit("Invalid MR verb 0x%02x\n", verb);
12753 + }
12754 + } else {
12755 + /* Its a software ERN */
12756 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
12757 + pr_info("ROY\n");
12758 + fq = get_fq_table_entry(be32_to_cpu(msg->ern.tag));
12759 +#else
12760 + fq = (void *)(uintptr_t)be32_to_cpu(msg->ern.tag);
12761 +#endif
12762 + fq->cb.ern(p, fq, msg);
12763 + }
12764 + num++;
12765 + qm_mr_next(&p->p);
12766 + goto mr_loop;
12767 +mr_done:
12768 + qm_mr_cci_consume(&p->p, num);
12769 + }
12770 + /*
12771 + * QM_PIRQ_CSCI/CCSCI has already been cleared, as part of its specific
12772 + * processing. If that interrupt source has meanwhile been re-asserted,
12773 + * we mustn't clear it here (or in the top-level interrupt handler).
12774 + */
12775 + return is & (QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI);
12776 +}
12777 +
12778 +/* remove some slowish-path stuff from the "fast path" and make sure it isn't
12779 + * inlined. */
12780 +static noinline void clear_vdqcr(struct qman_portal *p, struct qman_fq *fq)
12781 +{
12782 + p->vdqcr_owned = NULL;
12783 + FQLOCK(fq);
12784 + fq_clear(fq, QMAN_FQ_STATE_VDQCR);
12785 + FQUNLOCK(fq);
12786 + wake_up(&affine_queue);
12787 +}
12788 +
12789 +/* Look: no locks, no irq_save()s, no preempt_disable()s! :-) The only states
12790 + * that would conflict with other things if they ran at the same time on the
12791 + * same cpu are;
12792 + *
12793 + * (i) setting/clearing vdqcr_owned, and
12794 + * (ii) clearing the NE (Not Empty) flag.
12795 + *
12796 + * Both are safe. Because;
12797 + *
12798 + * (i) this clearing can only occur after qman_volatile_dequeue() has set the
12799 + * vdqcr_owned field (which it does before setting VDQCR), and
12800 + * qman_volatile_dequeue() blocks interrupts and preemption while this is
12801 + * done so that we can't interfere.
12802 + * (ii) the NE flag is only cleared after qman_retire_fq() has set it, and as
12803 + * with (i) that API prevents us from interfering until it's safe.
12804 + *
12805 + * The good thing is that qman_volatile_dequeue() and qman_retire_fq() run far
12806 + * less frequently (ie. per-FQ) than __poll_portal_fast() does, so the nett
12807 + * advantage comes from this function not having to "lock" anything at all.
12808 + *
12809 + * Note also that the callbacks are invoked at points which are safe against the
12810 + * above potential conflicts, but that this function itself is not re-entrant
12811 + * (this is because the function tracks one end of each FIFO in the portal and
12812 + * we do *not* want to lock that). So the consequence is that it is safe for
12813 + * user callbacks to call into any Qman API *except* qman_poll() (as that's the
12814 + * sole API that could be invoking the callback through this function).
12815 + */
12816 +static inline unsigned int __poll_portal_fast(struct qman_portal *p,
12817 + unsigned int poll_limit)
12818 +{
12819 + const struct qm_dqrr_entry *dq;
12820 + struct qman_fq *fq;
12821 + enum qman_cb_dqrr_result res;
12822 + unsigned int limit = 0;
12823 +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
12824 + struct qm_dqrr_entry *shadow;
12825 +#endif
12826 +loop:
12827 + qm_dqrr_pvb_update(&p->p);
12828 + dq = qm_dqrr_current(&p->p);
12829 + if (!dq)
12830 + goto done;
12831 +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
12832 + /* If running on an LE system the fields of the
12833 + dequeue entry must be swapped. Because the
12834 + QMan HW will ignore writes the DQRR entry is
12835 + copied and the index stored within the copy */
12836 + shadow = &p->shadow_dqrr[DQRR_PTR2IDX(dq)];
12837 + *shadow = *dq;
12838 + dq = shadow;
12839 + shadow->fqid = be32_to_cpu(shadow->fqid);
12840 + shadow->contextB = be32_to_cpu(shadow->contextB);
12841 + shadow->seqnum = be16_to_cpu(shadow->seqnum);
12842 + hw_fd_to_cpu(&shadow->fd);
12843 +#endif
12844 + if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) {
12845 + /* VDQCR: don't trust contextB as the FQ may have been
12846 + * configured for h/w consumption and we're draining it
12847 + * post-retirement. */
12848 + fq = p->vdqcr_owned;
12849 + /* We only set QMAN_FQ_STATE_NE when retiring, so we only need
12850 + * to check for clearing it when doing volatile dequeues. It's
12851 + * one less thing to check in the critical path (SDQCR). */
12852 + if (dq->stat & QM_DQRR_STAT_FQ_EMPTY)
12853 + fq_clear(fq, QMAN_FQ_STATE_NE);
12854 + /* this is duplicated from the SDQCR code, but we have stuff to
12855 + * do before *and* after this callback, and we don't want
12856 + * multiple if()s in the critical path (SDQCR). */
12857 + res = fq->cb.dqrr(p, fq, dq);
12858 + if (res == qman_cb_dqrr_stop)
12859 + goto done;
12860 + /* Check for VDQCR completion */
12861 + if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED)
12862 + clear_vdqcr(p, fq);
12863 + } else {
12864 + /* SDQCR: contextB points to the FQ */
12865 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
12866 + fq = get_fq_table_entry(dq->contextB);
12867 +#else
12868 + fq = (void *)(uintptr_t)dq->contextB;
12869 +#endif
12870 + /* Now let the callback do its stuff */
12871 + res = fq->cb.dqrr(p, fq, dq);
12872 +
12873 + /* The callback can request that we exit without consuming this
12874 + * entry nor advancing; */
12875 + if (res == qman_cb_dqrr_stop)
12876 + goto done;
12877 + }
12878 + /* Interpret 'dq' from a driver perspective. */
12879 + /* Parking isn't possible unless HELDACTIVE was set. NB,
12880 + * FORCEELIGIBLE implies HELDACTIVE, so we only need to
12881 + * check for HELDACTIVE to cover both. */
12882 + DPA_ASSERT((dq->stat & QM_DQRR_STAT_FQ_HELDACTIVE) ||
12883 + (res != qman_cb_dqrr_park));
12884 + /* Defer just means "skip it, I'll consume it myself later on" */
12885 + if (res != qman_cb_dqrr_defer)
12886 + qm_dqrr_cdc_consume_1ptr(&p->p, dq, (res == qman_cb_dqrr_park));
12887 + /* Move forward */
12888 + qm_dqrr_next(&p->p);
12889 + /* Entry processed and consumed, increment our counter. The callback can
12890 + * request that we exit after consuming the entry, and we also exit if
12891 + * we reach our processing limit, so loop back only if neither of these
12892 + * conditions is met. */
12893 + if ((++limit < poll_limit) && (res != qman_cb_dqrr_consume_stop))
12894 + goto loop;
12895 +done:
12896 + return limit;
12897 +}
12898 +
12899 +u32 qman_irqsource_get(void)
12900 +{
12901 + /* "irqsource" and "poll" APIs mustn't redirect when sharing, they
12902 + * should shut the user out if they are not the primary CPU hosting the
12903 + * portal. That's why we use the "raw" interface. */
12904 + struct qman_portal *p = get_raw_affine_portal();
12905 + u32 ret = p->irq_sources & QM_PIRQ_VISIBLE;
12906 + put_affine_portal();
12907 + return ret;
12908 +}
12909 +EXPORT_SYMBOL(qman_irqsource_get);
12910 +
12911 +int qman_p_irqsource_add(struct qman_portal *p, u32 bits __maybe_unused)
12912 +{
12913 + __maybe_unused unsigned long irqflags;
12914 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
12915 + if (p->sharing_redirect)
12916 + return -EINVAL;
12917 + else
12918 +#endif
12919 + {
12920 + PORTAL_IRQ_LOCK(p, irqflags);
12921 + set_bits(bits & QM_PIRQ_VISIBLE, &p->irq_sources);
12922 + qm_isr_enable_write(&p->p, p->irq_sources);
12923 + PORTAL_IRQ_UNLOCK(p, irqflags);
12924 + }
12925 + return 0;
12926 +}
12927 +EXPORT_SYMBOL(qman_p_irqsource_add);
12928 +
12929 +int qman_irqsource_add(u32 bits __maybe_unused)
12930 +{
12931 + struct qman_portal *p = get_raw_affine_portal();
12932 + int ret;
12933 + ret = qman_p_irqsource_add(p, bits);
12934 + put_affine_portal();
12935 + return ret;
12936 +}
12937 +EXPORT_SYMBOL(qman_irqsource_add);
12938 +
12939 +int qman_p_irqsource_remove(struct qman_portal *p, u32 bits)
12940 +{
12941 + __maybe_unused unsigned long irqflags;
12942 + u32 ier;
12943 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
12944 + if (p->sharing_redirect) {
12945 + put_affine_portal();
12946 + return -EINVAL;
12947 + }
12948 +#endif
12949 + /* Our interrupt handler only processes+clears status register bits that
12950 + * are in p->irq_sources. As we're trimming that mask, if one of them
12951 + * were to assert in the status register just before we remove it from
12952 + * the enable register, there would be an interrupt-storm when we
12953 + * release the IRQ lock. So we wait for the enable register update to
12954 + * take effect in h/w (by reading it back) and then clear all other bits
12955 + * in the status register. Ie. we clear them from ISR once it's certain
12956 + * IER won't allow them to reassert. */
12957 + PORTAL_IRQ_LOCK(p, irqflags);
12958 + bits &= QM_PIRQ_VISIBLE;
12959 + clear_bits(bits, &p->irq_sources);
12960 + qm_isr_enable_write(&p->p, p->irq_sources);
12961 +
12962 + ier = qm_isr_enable_read(&p->p);
12963 + /* Using "~ier" (rather than "bits" or "~p->irq_sources") creates a
12964 + * data-dependency, ie. to protect against re-ordering. */
12965 + qm_isr_status_clear(&p->p, ~ier);
12966 + PORTAL_IRQ_UNLOCK(p, irqflags);
12967 + return 0;
12968 +}
12969 +EXPORT_SYMBOL(qman_p_irqsource_remove);
12970 +
12971 +int qman_irqsource_remove(u32 bits)
12972 +{
12973 + struct qman_portal *p = get_raw_affine_portal();
12974 + int ret;
12975 + ret = qman_p_irqsource_remove(p, bits);
12976 + put_affine_portal();
12977 + return ret;
12978 +}
12979 +EXPORT_SYMBOL(qman_irqsource_remove);
12980 +
12981 +const cpumask_t *qman_affine_cpus(void)
12982 +{
12983 + return &affine_mask;
12984 +}
12985 +EXPORT_SYMBOL(qman_affine_cpus);
12986 +
12987 +u16 qman_affine_channel(int cpu)
12988 +{
12989 + if (cpu < 0) {
12990 + struct qman_portal *portal = get_raw_affine_portal();
12991 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
12992 + BUG_ON(portal->sharing_redirect);
12993 +#endif
12994 + cpu = portal->config->public_cfg.cpu;
12995 + put_affine_portal();
12996 + }
12997 + BUG_ON(!cpumask_test_cpu(cpu, &affine_mask));
12998 + return affine_channels[cpu];
12999 +}
13000 +EXPORT_SYMBOL(qman_affine_channel);
13001 +
13002 +void *qman_get_affine_portal(int cpu)
13003 +{
13004 + return affine_portals[cpu];
13005 +}
13006 +EXPORT_SYMBOL(qman_get_affine_portal);
13007 +
13008 +int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit)
13009 +{
13010 + int ret;
13011 +
13012 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
13013 + if (unlikely(p->sharing_redirect))
13014 + ret = -EINVAL;
13015 + else
13016 +#endif
13017 + {
13018 + BUG_ON(p->irq_sources & QM_PIRQ_DQRI);
13019 + ret = __poll_portal_fast(p, limit);
13020 + }
13021 + return ret;
13022 +}
13023 +EXPORT_SYMBOL(qman_p_poll_dqrr);
13024 +
13025 +int qman_poll_dqrr(unsigned int limit)
13026 +{
13027 + struct qman_portal *p = get_poll_portal();
13028 + int ret;
13029 + ret = qman_p_poll_dqrr(p, limit);
13030 + put_poll_portal();
13031 + return ret;
13032 +}
13033 +EXPORT_SYMBOL(qman_poll_dqrr);
13034 +
13035 +u32 qman_p_poll_slow(struct qman_portal *p)
13036 +{
13037 + u32 ret;
13038 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
13039 + if (unlikely(p->sharing_redirect))
13040 + ret = (u32)-1;
13041 + else
13042 +#endif
13043 + {
13044 + u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources;
13045 + ret = __poll_portal_slow(p, is);
13046 + qm_isr_status_clear(&p->p, ret);
13047 + }
13048 + return ret;
13049 +}
13050 +EXPORT_SYMBOL(qman_p_poll_slow);
13051 +
13052 +u32 qman_poll_slow(void)
13053 +{
13054 + struct qman_portal *p = get_poll_portal();
13055 + u32 ret;
13056 + ret = qman_p_poll_slow(p);
13057 + put_poll_portal();
13058 + return ret;
13059 +}
13060 +EXPORT_SYMBOL(qman_poll_slow);
13061 +
13062 +/* Legacy wrapper */
13063 +void qman_p_poll(struct qman_portal *p)
13064 +{
13065 +#ifdef CONFIG_FSL_DPA_PORTAL_SHARE
13066 + if (unlikely(p->sharing_redirect))
13067 + return;
13068 +#endif
13069 + if ((~p->irq_sources) & QM_PIRQ_SLOW) {
13070 + if (!(p->slowpoll--)) {
13071 + u32 is = qm_isr_status_read(&p->p) & ~p->irq_sources;
13072 + u32 active = __poll_portal_slow(p, is);
13073 + if (active) {
13074 + qm_isr_status_clear(&p->p, active);
13075 + p->slowpoll = SLOW_POLL_BUSY;
13076 + } else
13077 + p->slowpoll = SLOW_POLL_IDLE;
13078 + }
13079 + }
13080 + if ((~p->irq_sources) & QM_PIRQ_DQRI)
13081 + __poll_portal_fast(p, CONFIG_FSL_QMAN_POLL_LIMIT);
13082 +}
13083 +EXPORT_SYMBOL(qman_p_poll);
13084 +
13085 +void qman_poll(void)
13086 +{
13087 + struct qman_portal *p = get_poll_portal();
13088 + qman_p_poll(p);
13089 + put_poll_portal();
13090 +}
13091 +EXPORT_SYMBOL(qman_poll);
13092 +
13093 +void qman_p_stop_dequeues(struct qman_portal *p)
13094 +{
13095 + qman_stop_dequeues_ex(p);
13096 +}
13097 +EXPORT_SYMBOL(qman_p_stop_dequeues);
13098 +
13099 +void qman_stop_dequeues(void)
13100 +{
13101 + struct qman_portal *p = get_affine_portal();
13102 + qman_p_stop_dequeues(p);
13103 + put_affine_portal();
13104 +}
13105 +EXPORT_SYMBOL(qman_stop_dequeues);
13106 +
13107 +void qman_p_start_dequeues(struct qman_portal *p)
13108 +{
13109 + unsigned long irqflags __maybe_unused;
13110 + PORTAL_IRQ_LOCK(p, irqflags);
13111 + DPA_ASSERT(p->dqrr_disable_ref > 0);
13112 + if (!(--p->dqrr_disable_ref))
13113 + qm_dqrr_set_maxfill(&p->p, DQRR_MAXFILL);
13114 + PORTAL_IRQ_UNLOCK(p, irqflags);
13115 +}
13116 +EXPORT_SYMBOL(qman_p_start_dequeues);
13117 +
13118 +void qman_start_dequeues(void)
13119 +{
13120 + struct qman_portal *p = get_affine_portal();
13121 + qman_p_start_dequeues(p);
13122 + put_affine_portal();
13123 +}
13124 +EXPORT_SYMBOL(qman_start_dequeues);
13125 +
13126 +void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools)
13127 +{
13128 + unsigned long irqflags __maybe_unused;
13129 + PORTAL_IRQ_LOCK(p, irqflags);
13130 + pools &= p->config->public_cfg.pools;
13131 + p->sdqcr |= pools;
13132 + qm_dqrr_sdqcr_set(&p->p, p->sdqcr);
13133 + PORTAL_IRQ_UNLOCK(p, irqflags);
13134 +}
13135 +EXPORT_SYMBOL(qman_p_static_dequeue_add);
13136 +
13137 +void qman_static_dequeue_add(u32 pools)
13138 +{
13139 + struct qman_portal *p = get_affine_portal();
13140 + qman_p_static_dequeue_add(p, pools);
13141 + put_affine_portal();
13142 +}
13143 +EXPORT_SYMBOL(qman_static_dequeue_add);
13144 +
13145 +void qman_p_static_dequeue_del(struct qman_portal *p, u32 pools)
13146 +{
13147 + unsigned long irqflags __maybe_unused;
13148 + PORTAL_IRQ_LOCK(p, irqflags);
13149 + pools &= p->config->public_cfg.pools;
13150 + p->sdqcr &= ~pools;
13151 + qm_dqrr_sdqcr_set(&p->p, p->sdqcr);
13152 + PORTAL_IRQ_UNLOCK(p, irqflags);
13153 +}
13154 +EXPORT_SYMBOL(qman_p_static_dequeue_del);
13155 +
13156 +void qman_static_dequeue_del(u32 pools)
13157 +{
13158 + struct qman_portal *p = get_affine_portal();
13159 + qman_p_static_dequeue_del(p, pools);
13160 + put_affine_portal();
13161 +}
13162 +EXPORT_SYMBOL(qman_static_dequeue_del);
13163 +
13164 +u32 qman_p_static_dequeue_get(struct qman_portal *p)
13165 +{
13166 + return p->sdqcr;
13167 +}
13168 +EXPORT_SYMBOL(qman_p_static_dequeue_get);
13169 +
13170 +u32 qman_static_dequeue_get(void)
13171 +{
13172 + struct qman_portal *p = get_affine_portal();
13173 + u32 ret = qman_p_static_dequeue_get(p);
13174 + put_affine_portal();
13175 + return ret;
13176 +}
13177 +EXPORT_SYMBOL(qman_static_dequeue_get);
13178 +
13179 +void qman_p_dca(struct qman_portal *p, struct qm_dqrr_entry *dq,
13180 + int park_request)
13181 +{
13182 + qm_dqrr_cdc_consume_1ptr(&p->p, dq, park_request);
13183 +}
13184 +EXPORT_SYMBOL(qman_p_dca);
13185 +
13186 +void qman_dca(struct qm_dqrr_entry *dq, int park_request)
13187 +{
13188 + struct qman_portal *p = get_affine_portal();
13189 + qman_p_dca(p, dq, park_request);
13190 + put_affine_portal();
13191 +}
13192 +EXPORT_SYMBOL(qman_dca);
13193 +
13194 +/*******************/
13195 +/* Frame queue API */
13196 +/*******************/
13197 +
13198 +static const char *mcr_result_str(u8 result)
13199 +{
13200 + switch (result) {
13201 + case QM_MCR_RESULT_NULL:
13202 + return "QM_MCR_RESULT_NULL";
13203 + case QM_MCR_RESULT_OK:
13204 + return "QM_MCR_RESULT_OK";
13205 + case QM_MCR_RESULT_ERR_FQID:
13206 + return "QM_MCR_RESULT_ERR_FQID";
13207 + case QM_MCR_RESULT_ERR_FQSTATE:
13208 + return "QM_MCR_RESULT_ERR_FQSTATE";
13209 + case QM_MCR_RESULT_ERR_NOTEMPTY:
13210 + return "QM_MCR_RESULT_ERR_NOTEMPTY";
13211 + case QM_MCR_RESULT_PENDING:
13212 + return "QM_MCR_RESULT_PENDING";
13213 + case QM_MCR_RESULT_ERR_BADCOMMAND:
13214 + return "QM_MCR_RESULT_ERR_BADCOMMAND";
13215 + }
13216 + return "<unknown MCR result>";
13217 +}
13218 +
13219 +int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq)
13220 +{
13221 + struct qm_fqd fqd;
13222 + struct qm_mcr_queryfq_np np;
13223 + struct qm_mc_command *mcc;
13224 + struct qm_mc_result *mcr;
13225 + struct qman_portal *p;
13226 + unsigned long irqflags __maybe_unused;
13227 +
13228 + if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID) {
13229 + int ret = qman_alloc_fqid(&fqid);
13230 + if (ret)
13231 + return ret;
13232 + }
13233 + spin_lock_init(&fq->fqlock);
13234 + fq->fqid = fqid;
13235 + fq->flags = flags;
13236 + fq->state = qman_fq_state_oos;
13237 + fq->cgr_groupid = 0;
13238 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
13239 + if (unlikely(find_empty_fq_table_entry(&fq->key, fq)))
13240 + return -ENOMEM;
13241 +#endif
13242 + if (!(flags & QMAN_FQ_FLAG_AS_IS) || (flags & QMAN_FQ_FLAG_NO_MODIFY))
13243 + return 0;
13244 + /* Everything else is AS_IS support */
13245 + p = get_affine_portal();
13246 + PORTAL_IRQ_LOCK(p, irqflags);
13247 + mcc = qm_mc_start(&p->p);
13248 + mcc->queryfq.fqid = cpu_to_be32(fqid);
13249 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ);
13250 + while (!(mcr = qm_mc_result(&p->p)))
13251 + cpu_relax();
13252 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ);
13253 + if (mcr->result != QM_MCR_RESULT_OK) {
13254 + pr_err("QUERYFQ failed: %s\n", mcr_result_str(mcr->result));
13255 + goto err;
13256 + }
13257 + fqd = mcr->queryfq.fqd;
13258 + hw_fqd_to_cpu(&fqd);
13259 + mcc = qm_mc_start(&p->p);
13260 + mcc->queryfq_np.fqid = cpu_to_be32(fqid);
13261 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP);
13262 + while (!(mcr = qm_mc_result(&p->p)))
13263 + cpu_relax();
13264 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYFQ_NP);
13265 + if (mcr->result != QM_MCR_RESULT_OK) {
13266 + pr_err("QUERYFQ_NP failed: %s\n", mcr_result_str(mcr->result));
13267 + goto err;
13268 + }
13269 + np = mcr->queryfq_np;
13270 + /* Phew, have queryfq and queryfq_np results, stitch together
13271 + * the FQ object from those. */
13272 + fq->cgr_groupid = fqd.cgid;
13273 + switch (np.state & QM_MCR_NP_STATE_MASK) {
13274 + case QM_MCR_NP_STATE_OOS:
13275 + break;
13276 + case QM_MCR_NP_STATE_RETIRED:
13277 + fq->state = qman_fq_state_retired;
13278 + if (np.frm_cnt)
13279 + fq_set(fq, QMAN_FQ_STATE_NE);
13280 + break;
13281 + case QM_MCR_NP_STATE_TEN_SCHED:
13282 + case QM_MCR_NP_STATE_TRU_SCHED:
13283 + case QM_MCR_NP_STATE_ACTIVE:
13284 + fq->state = qman_fq_state_sched;
13285 + if (np.state & QM_MCR_NP_STATE_R)
13286 + fq_set(fq, QMAN_FQ_STATE_CHANGING);
13287 + break;
13288 + case QM_MCR_NP_STATE_PARKED:
13289 + fq->state = qman_fq_state_parked;
13290 + break;
13291 + default:
13292 + DPA_ASSERT(NULL == "invalid FQ state");
13293 + }
13294 + if (fqd.fq_ctrl & QM_FQCTRL_CGE)
13295 + fq->state |= QMAN_FQ_STATE_CGR_EN;
13296 + PORTAL_IRQ_UNLOCK(p, irqflags);
13297 + put_affine_portal();
13298 + return 0;
13299 +err:
13300 + PORTAL_IRQ_UNLOCK(p, irqflags);
13301 + put_affine_portal();
13302 + if (flags & QMAN_FQ_FLAG_DYNAMIC_FQID)
13303 + qman_release_fqid(fqid);
13304 + return -EIO;
13305 +}
13306 +EXPORT_SYMBOL(qman_create_fq);
13307 +
13308 +void qman_destroy_fq(struct qman_fq *fq, u32 flags __maybe_unused)
13309 +{
13310 +
13311 + /* We don't need to lock the FQ as it is a pre-condition that the FQ be
13312 + * quiesced. Instead, run some checks. */
13313 + switch (fq->state) {
13314 + case qman_fq_state_parked:
13315 + DPA_ASSERT(flags & QMAN_FQ_DESTROY_PARKED);
13316 + case qman_fq_state_oos:
13317 + if (fq_isset(fq, QMAN_FQ_FLAG_DYNAMIC_FQID))
13318 + qman_release_fqid(fq->fqid);
13319 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
13320 + clear_fq_table_entry(fq->key);
13321 +#endif
13322 + return;
13323 + default:
13324 + break;
13325 + }
13326 + DPA_ASSERT(NULL == "qman_free_fq() on unquiesced FQ!");
13327 +}
13328 +EXPORT_SYMBOL(qman_destroy_fq);
13329 +
13330 +u32 qman_fq_fqid(struct qman_fq *fq)
13331 +{
13332 + return fq->fqid;
13333 +}
13334 +EXPORT_SYMBOL(qman_fq_fqid);
13335 +
13336 +void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags)
13337 +{
13338 + if (state)
13339 + *state = fq->state;
13340 + if (flags)
13341 + *flags = fq->flags;
13342 +}
13343 +EXPORT_SYMBOL(qman_fq_state);
13344 +
13345 +int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts)
13346 +{
13347 + struct qm_mc_command *mcc;
13348 + struct qm_mc_result *mcr;
13349 + struct qman_portal *p;
13350 + unsigned long irqflags __maybe_unused;
13351 + u8 res, myverb = (flags & QMAN_INITFQ_FLAG_SCHED) ?
13352 + QM_MCC_VERB_INITFQ_SCHED : QM_MCC_VERB_INITFQ_PARKED;
13353 +
13354 + if ((fq->state != qman_fq_state_oos) &&
13355 + (fq->state != qman_fq_state_parked))
13356 + return -EINVAL;
13357 +#ifdef CONFIG_FSL_DPA_CHECKING
13358 + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
13359 + return -EINVAL;
13360 +#endif
13361 + if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) {
13362 + /* And can't be set at the same time as TDTHRESH */
13363 + if (opts->we_mask & QM_INITFQ_WE_TDTHRESH)
13364 + return -EINVAL;
13365 + }
13366 + /* Issue an INITFQ_[PARKED|SCHED] management command */
13367 + p = get_affine_portal();
13368 + PORTAL_IRQ_LOCK(p, irqflags);
13369 + FQLOCK(fq);
13370 + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
13371 + ((fq->state != qman_fq_state_oos) &&
13372 + (fq->state != qman_fq_state_parked)))) {
13373 + FQUNLOCK(fq);
13374 + PORTAL_IRQ_UNLOCK(p, irqflags);
13375 + put_affine_portal();
13376 + return -EBUSY;
13377 + }
13378 + mcc = qm_mc_start(&p->p);
13379 + if (opts)
13380 + mcc->initfq = *opts;
13381 + mcc->initfq.fqid = cpu_to_be32(fq->fqid);
13382 + mcc->initfq.count = 0;
13383 +
13384 + /* If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a
13385 + * demux pointer. Otherwise, the caller-provided value is allowed to
13386 + * stand, don't overwrite it. */
13387 + if (fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) {
13388 + dma_addr_t phys_fq;
13389 + mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB;
13390 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
13391 + mcc->initfq.fqd.context_b = fq->key;
13392 +#else
13393 + mcc->initfq.fqd.context_b = (u32)(uintptr_t)fq;
13394 +#endif
13395 + /* and the physical address - NB, if the user wasn't trying to
13396 + * set CONTEXTA, clear the stashing settings. */
13397 + if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) {
13398 + mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA;
13399 + memset(&mcc->initfq.fqd.context_a, 0,
13400 + sizeof(mcc->initfq.fqd.context_a));
13401 + } else {
13402 + phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq),
13403 + DMA_TO_DEVICE);
13404 + qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq);
13405 + }
13406 + }
13407 + if (flags & QMAN_INITFQ_FLAG_LOCAL) {
13408 + mcc->initfq.fqd.dest.channel = p->config->public_cfg.channel;
13409 + if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) {
13410 + mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ;
13411 + mcc->initfq.fqd.dest.wq = 4;
13412 + }
13413 + }
13414 + mcc->initfq.we_mask = cpu_to_be16(mcc->initfq.we_mask);
13415 + cpu_to_hw_fqd(&mcc->initfq.fqd);
13416 + qm_mc_commit(&p->p, myverb);
13417 + while (!(mcr = qm_mc_result(&p->p)))
13418 + cpu_relax();
13419 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb);
13420 + res = mcr->result;
13421 + if (res != QM_MCR_RESULT_OK) {
13422 + FQUNLOCK(fq);
13423 + PORTAL_IRQ_UNLOCK(p, irqflags);
13424 + put_affine_portal();
13425 + return -EIO;
13426 + }
13427 + if (opts) {
13428 + if (opts->we_mask & QM_INITFQ_WE_FQCTRL) {
13429 + if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE)
13430 + fq_set(fq, QMAN_FQ_STATE_CGR_EN);
13431 + else
13432 + fq_clear(fq, QMAN_FQ_STATE_CGR_EN);
13433 + }
13434 + if (opts->we_mask & QM_INITFQ_WE_CGID)
13435 + fq->cgr_groupid = opts->fqd.cgid;
13436 + }
13437 + fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ?
13438 + qman_fq_state_sched : qman_fq_state_parked;
13439 + FQUNLOCK(fq);
13440 + PORTAL_IRQ_UNLOCK(p, irqflags);
13441 + put_affine_portal();
13442 + return 0;
13443 +}
13444 +EXPORT_SYMBOL(qman_init_fq);
13445 +
13446 +int qman_schedule_fq(struct qman_fq *fq)
13447 +{
13448 + struct qm_mc_command *mcc;
13449 + struct qm_mc_result *mcr;
13450 + struct qman_portal *p;
13451 + unsigned long irqflags __maybe_unused;
13452 + int ret = 0;
13453 + u8 res;
13454 +
13455 + if (fq->state != qman_fq_state_parked)
13456 + return -EINVAL;
13457 +#ifdef CONFIG_FSL_DPA_CHECKING
13458 + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
13459 + return -EINVAL;
13460 +#endif
13461 + /* Issue a ALTERFQ_SCHED management command */
13462 + p = get_affine_portal();
13463 + PORTAL_IRQ_LOCK(p, irqflags);
13464 + FQLOCK(fq);
13465 + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
13466 + (fq->state != qman_fq_state_parked))) {
13467 + ret = -EBUSY;
13468 + goto out;
13469 + }
13470 + mcc = qm_mc_start(&p->p);
13471 + mcc->alterfq.fqid = cpu_to_be32(fq->fqid);
13472 + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED);
13473 + while (!(mcr = qm_mc_result(&p->p)))
13474 + cpu_relax();
13475 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_SCHED);
13476 + res = mcr->result;
13477 + if (res != QM_MCR_RESULT_OK) {
13478 + ret = -EIO;
13479 + goto out;
13480 + }
13481 + fq->state = qman_fq_state_sched;
13482 +out:
13483 + FQUNLOCK(fq);
13484 + PORTAL_IRQ_UNLOCK(p, irqflags);
13485 + put_affine_portal();
13486 + return ret;
13487 +}
13488 +EXPORT_SYMBOL(qman_schedule_fq);
13489 +
13490 +int qman_retire_fq(struct qman_fq *fq, u32 *flags)
13491 +{
13492 + struct qm_mc_command *mcc;
13493 + struct qm_mc_result *mcr;
13494 + struct qman_portal *p;
13495 + unsigned long irqflags __maybe_unused;
13496 + int rval;
13497 + u8 res;
13498 +
13499 + if ((fq->state != qman_fq_state_parked) &&
13500 + (fq->state != qman_fq_state_sched))
13501 + return -EINVAL;
13502 +#ifdef CONFIG_FSL_DPA_CHECKING
13503 + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
13504 + return -EINVAL;
13505 +#endif
13506 + p = get_affine_portal();
13507 + PORTAL_IRQ_LOCK(p, irqflags);
13508 + FQLOCK(fq);
13509 + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
13510 + (fq->state == qman_fq_state_retired) ||
13511 + (fq->state == qman_fq_state_oos))) {
13512 + rval = -EBUSY;
13513 + goto out;
13514 + }
13515 + rval = table_push_fq(p, fq);
13516 + if (rval)
13517 + goto out;
13518 + mcc = qm_mc_start(&p->p);
13519 + mcc->alterfq.fqid = cpu_to_be32(fq->fqid);
13520 + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE);
13521 + while (!(mcr = qm_mc_result(&p->p)))
13522 + cpu_relax();
13523 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_RETIRE);
13524 + res = mcr->result;
13525 + /* "Elegant" would be to treat OK/PENDING the same way; set CHANGING,
13526 + * and defer the flags until FQRNI or FQRN (respectively) show up. But
13527 + * "Friendly" is to process OK immediately, and not set CHANGING. We do
13528 + * friendly, otherwise the caller doesn't necessarily have a fully
13529 + * "retired" FQ on return even if the retirement was immediate. However
13530 + * this does mean some code duplication between here and
13531 + * fq_state_change(). */
13532 + if (likely(res == QM_MCR_RESULT_OK)) {
13533 + rval = 0;
13534 + /* Process 'fq' right away, we'll ignore FQRNI */
13535 + if (mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY)
13536 + fq_set(fq, QMAN_FQ_STATE_NE);
13537 + if (mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)
13538 + fq_set(fq, QMAN_FQ_STATE_ORL);
13539 + else
13540 + table_del_fq(p, fq);
13541 + if (flags)
13542 + *flags = fq->flags;
13543 + fq->state = qman_fq_state_retired;
13544 + if (fq->cb.fqs) {
13545 + /* Another issue with supporting "immediate" retirement
13546 + * is that we're forced to drop FQRNIs, because by the
13547 + * time they're seen it may already be "too late" (the
13548 + * fq may have been OOS'd and free()'d already). But if
13549 + * the upper layer wants a callback whether it's
13550 + * immediate or not, we have to fake a "MR" entry to
13551 + * look like an FQRNI... */
13552 + struct qm_mr_entry msg;
13553 + msg.verb = QM_MR_VERB_FQRNI;
13554 + msg.fq.fqs = mcr->alterfq.fqs;
13555 + msg.fq.fqid = fq->fqid;
13556 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
13557 + msg.fq.contextB = fq->key;
13558 +#else
13559 + msg.fq.contextB = (u32)(uintptr_t)fq;
13560 +#endif
13561 + fq->cb.fqs(p, fq, &msg);
13562 + }
13563 + } else if (res == QM_MCR_RESULT_PENDING) {
13564 + rval = 1;
13565 + fq_set(fq, QMAN_FQ_STATE_CHANGING);
13566 + } else {
13567 + rval = -EIO;
13568 + table_del_fq(p, fq);
13569 + }
13570 +out:
13571 + FQUNLOCK(fq);
13572 + PORTAL_IRQ_UNLOCK(p, irqflags);
13573 + put_affine_portal();
13574 + return rval;
13575 +}
13576 +EXPORT_SYMBOL(qman_retire_fq);
13577 +
13578 +int qman_oos_fq(struct qman_fq *fq)
13579 +{
13580 + struct qm_mc_command *mcc;
13581 + struct qm_mc_result *mcr;
13582 + struct qman_portal *p;
13583 + unsigned long irqflags __maybe_unused;
13584 + int ret = 0;
13585 + u8 res;
13586 +
13587 + if (fq->state != qman_fq_state_retired)
13588 + return -EINVAL;
13589 +#ifdef CONFIG_FSL_DPA_CHECKING
13590 + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
13591 + return -EINVAL;
13592 +#endif
13593 + p = get_affine_portal();
13594 + PORTAL_IRQ_LOCK(p, irqflags);
13595 + FQLOCK(fq);
13596 + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_BLOCKOOS)) ||
13597 + (fq->state != qman_fq_state_retired))) {
13598 + ret = -EBUSY;
13599 + goto out;
13600 + }
13601 + mcc = qm_mc_start(&p->p);
13602 + mcc->alterfq.fqid = cpu_to_be32(fq->fqid);
13603 + qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS);
13604 + while (!(mcr = qm_mc_result(&p->p)))
13605 + cpu_relax();
13606 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_ALTER_OOS);
13607 + res = mcr->result;
13608 + if (res != QM_MCR_RESULT_OK) {
13609 + ret = -EIO;
13610 + goto out;
13611 + }
13612 + fq->state = qman_fq_state_oos;
13613 +out:
13614 + FQUNLOCK(fq);
13615 + PORTAL_IRQ_UNLOCK(p, irqflags);
13616 + put_affine_portal();
13617 + return ret;
13618 +}
13619 +EXPORT_SYMBOL(qman_oos_fq);
13620 +
13621 +int qman_fq_flow_control(struct qman_fq *fq, int xon)
13622 +{
13623 + struct qm_mc_command *mcc;
13624 + struct qm_mc_result *mcr;
13625 + struct qman_portal *p;
13626 + unsigned long irqflags __maybe_unused;
13627 + int ret = 0;
13628 + u8 res;
13629 + u8 myverb;
13630 +
13631 + if ((fq->state == qman_fq_state_oos) ||
13632 + (fq->state == qman_fq_state_retired) ||
13633 + (fq->state == qman_fq_state_parked))
13634 + return -EINVAL;
13635 +
13636 +#ifdef CONFIG_FSL_DPA_CHECKING
13637 + if (unlikely(fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)))
13638 + return -EINVAL;
13639 +#endif
13640 + /* Issue a ALTER_FQXON or ALTER_FQXOFF management command */
13641 + p = get_affine_portal();
13642 + PORTAL_IRQ_LOCK(p, irqflags);
13643 + FQLOCK(fq);
13644 + if (unlikely((fq_isset(fq, QMAN_FQ_STATE_CHANGING)) ||
13645 + (fq->state == qman_fq_state_parked) ||
13646 + (fq->state == qman_fq_state_oos) ||
13647 + (fq->state == qman_fq_state_retired))) {
13648 + ret = -EBUSY;
13649 + goto out;
13650 + }
13651 + mcc = qm_mc_start(&p->p);
13652 + mcc->alterfq.fqid = fq->fqid;
13653 + mcc->alterfq.count = 0;
13654 + myverb = xon ? QM_MCC_VERB_ALTER_FQXON : QM_MCC_VERB_ALTER_FQXOFF;
13655 +
13656 + qm_mc_commit(&p->p, myverb);
13657 + while (!(mcr = qm_mc_result(&p->p)))
13658 + cpu_relax();
13659 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb);
13660 +
13661 + res = mcr->result;
13662 + if (res != QM_MCR_RESULT_OK) {
13663 + ret = -EIO;
13664 + goto out;
13665 + }
13666 +out:
13667 + FQUNLOCK(fq);
13668 + PORTAL_IRQ_UNLOCK(p, irqflags);
13669 + put_affine_portal();
13670 + return ret;
13671 +}
13672 +EXPORT_SYMBOL(qman_fq_flow_control);
13673 +
13674 +int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd)
13675 +{
13676 + struct qm_mc_command *mcc;
13677 + struct qm_mc_result *mcr;
13678 + struct qman_portal *p = get_affine_portal();
13679 + unsigned long irqflags __maybe_unused;
13680 + u8 res;
13681 +
13682 + PORTAL_IRQ_LOCK(p, irqflags);
13683 + mcc = qm_mc_start(&p->p);
13684 + mcc->queryfq.fqid = cpu_to_be32(fq->fqid);
13685 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ);
13686 + while (!(mcr = qm_mc_result(&p->p)))
13687 + cpu_relax();
13688 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ);
13689 + res = mcr->result;
13690 + if (res == QM_MCR_RESULT_OK)
13691 + memcpy_fromio(fqd, &mcr->queryfq.fqd, sizeof(*fqd));
13692 + hw_fqd_to_cpu(fqd);
13693 + PORTAL_IRQ_UNLOCK(p, irqflags);
13694 + put_affine_portal();
13695 + if (res != QM_MCR_RESULT_OK)
13696 + return -EIO;
13697 + return 0;
13698 +}
13699 +EXPORT_SYMBOL(qman_query_fq);
13700 +
13701 +int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np)
13702 +{
13703 + struct qm_mc_command *mcc;
13704 + struct qm_mc_result *mcr;
13705 + struct qman_portal *p = get_affine_portal();
13706 + unsigned long irqflags __maybe_unused;
13707 + u8 res;
13708 +
13709 + PORTAL_IRQ_LOCK(p, irqflags);
13710 + mcc = qm_mc_start(&p->p);
13711 + mcc->queryfq.fqid = cpu_to_be32(fq->fqid);
13712 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP);
13713 + while (!(mcr = qm_mc_result(&p->p)))
13714 + cpu_relax();
13715 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP);
13716 + res = mcr->result;
13717 + if (res == QM_MCR_RESULT_OK) {
13718 + memcpy_fromio(np, &mcr->queryfq_np, sizeof(*np));
13719 + np->fqd_link = be24_to_cpu(np->fqd_link);
13720 + np->odp_seq = be16_to_cpu(np->odp_seq);
13721 + np->orp_nesn = be16_to_cpu(np->orp_nesn);
13722 + np->orp_ea_hseq = be16_to_cpu(np->orp_ea_hseq);
13723 + np->orp_ea_tseq = be16_to_cpu(np->orp_ea_tseq);
13724 + np->orp_ea_hptr = be24_to_cpu(np->orp_ea_hptr);
13725 + np->orp_ea_tptr = be24_to_cpu(np->orp_ea_tptr);
13726 + np->pfdr_hptr = be24_to_cpu(np->pfdr_hptr);
13727 + np->pfdr_tptr = be24_to_cpu(np->pfdr_tptr);
13728 + np->ics_surp = be16_to_cpu(np->ics_surp);
13729 + np->byte_cnt = be32_to_cpu(np->byte_cnt);
13730 + np->frm_cnt = be24_to_cpu(np->frm_cnt);
13731 + np->ra1_sfdr = be16_to_cpu(np->ra1_sfdr);
13732 + np->ra2_sfdr = be16_to_cpu(np->ra2_sfdr);
13733 + np->od1_sfdr = be16_to_cpu(np->od1_sfdr);
13734 + np->od2_sfdr = be16_to_cpu(np->od2_sfdr);
13735 + np->od3_sfdr = be16_to_cpu(np->od3_sfdr);
13736 +
13737 +
13738 + }
13739 +
13740 + PORTAL_IRQ_UNLOCK(p, irqflags);
13741 + put_affine_portal();
13742 + if (res == QM_MCR_RESULT_ERR_FQID)
13743 + return -ERANGE;
13744 + else if (res != QM_MCR_RESULT_OK)
13745 + return -EIO;
13746 + return 0;
13747 +}
13748 +EXPORT_SYMBOL(qman_query_fq_np);
13749 +
13750 +int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq)
13751 +{
13752 + struct qm_mc_command *mcc;
13753 + struct qm_mc_result *mcr;
13754 + struct qman_portal *p = get_affine_portal();
13755 + unsigned long irqflags __maybe_unused;
13756 + u8 res, myverb;
13757 +
13758 + PORTAL_IRQ_LOCK(p, irqflags);
13759 + myverb = (query_dedicated) ? QM_MCR_VERB_QUERYWQ_DEDICATED :
13760 + QM_MCR_VERB_QUERYWQ;
13761 + mcc = qm_mc_start(&p->p);
13762 + mcc->querywq.channel.id = cpu_to_be16(wq->channel.id);
13763 + qm_mc_commit(&p->p, myverb);
13764 + while (!(mcr = qm_mc_result(&p->p)))
13765 + cpu_relax();
13766 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == myverb);
13767 + res = mcr->result;
13768 + if (res == QM_MCR_RESULT_OK) {
13769 + int i, array_len;
13770 + wq->channel.id = be16_to_cpu(mcr->querywq.channel.id);
13771 + array_len = ARRAY_SIZE(mcr->querywq.wq_len);
13772 + for (i = 0; i < array_len; i++)
13773 + wq->wq_len[i] = be32_to_cpu(mcr->querywq.wq_len[i]);
13774 + }
13775 + PORTAL_IRQ_UNLOCK(p, irqflags);
13776 + put_affine_portal();
13777 + if (res != QM_MCR_RESULT_OK) {
13778 + pr_err("QUERYWQ failed: %s\n", mcr_result_str(res));
13779 + return -EIO;
13780 + }
13781 + return 0;
13782 +}
13783 +EXPORT_SYMBOL(qman_query_wq);
13784 +
13785 +int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt,
13786 + struct qm_mcr_cgrtestwrite *result)
13787 +{
13788 + struct qm_mc_command *mcc;
13789 + struct qm_mc_result *mcr;
13790 + struct qman_portal *p = get_affine_portal();
13791 + unsigned long irqflags __maybe_unused;
13792 + u8 res;
13793 +
13794 + PORTAL_IRQ_LOCK(p, irqflags);
13795 + mcc = qm_mc_start(&p->p);
13796 + mcc->cgrtestwrite.cgid = cgr->cgrid;
13797 + mcc->cgrtestwrite.i_bcnt_hi = (u8)(i_bcnt >> 32);
13798 + mcc->cgrtestwrite.i_bcnt_lo = (u32)i_bcnt;
13799 + qm_mc_commit(&p->p, QM_MCC_VERB_CGRTESTWRITE);
13800 + while (!(mcr = qm_mc_result(&p->p)))
13801 + cpu_relax();
13802 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_CGRTESTWRITE);
13803 + res = mcr->result;
13804 + if (res == QM_MCR_RESULT_OK)
13805 + memcpy_fromio(result, &mcr->cgrtestwrite, sizeof(*result));
13806 + PORTAL_IRQ_UNLOCK(p, irqflags);
13807 + put_affine_portal();
13808 + if (res != QM_MCR_RESULT_OK) {
13809 + pr_err("CGR TEST WRITE failed: %s\n", mcr_result_str(res));
13810 + return -EIO;
13811 + }
13812 + return 0;
13813 +}
13814 +EXPORT_SYMBOL(qman_testwrite_cgr);
13815 +
13816 +int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *cgrd)
13817 +{
13818 + struct qm_mc_command *mcc;
13819 + struct qm_mc_result *mcr;
13820 + struct qman_portal *p = get_affine_portal();
13821 + unsigned long irqflags __maybe_unused;
13822 + u8 res;
13823 + int i;
13824 +
13825 + PORTAL_IRQ_LOCK(p, irqflags);
13826 + mcc = qm_mc_start(&p->p);
13827 + mcc->querycgr.cgid = cgr->cgrid;
13828 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR);
13829 + while (!(mcr = qm_mc_result(&p->p)))
13830 + cpu_relax();
13831 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCC_VERB_QUERYCGR);
13832 + res = mcr->result;
13833 + if (res == QM_MCR_RESULT_OK)
13834 + memcpy_fromio(cgrd, &mcr->querycgr, sizeof(*cgrd));
13835 + PORTAL_IRQ_UNLOCK(p, irqflags);
13836 + put_affine_portal();
13837 + if (res != QM_MCR_RESULT_OK) {
13838 + pr_err("QUERY_CGR failed: %s\n", mcr_result_str(res));
13839 + return -EIO;
13840 + }
13841 + cgrd->cgr.wr_parm_g.word =
13842 + be32_to_cpu(cgrd->cgr.wr_parm_g.word);
13843 + cgrd->cgr.wr_parm_y.word =
13844 + be32_to_cpu(cgrd->cgr.wr_parm_y.word);
13845 + cgrd->cgr.wr_parm_r.word =
13846 + be32_to_cpu(cgrd->cgr.wr_parm_r.word);
13847 + cgrd->cgr.cscn_targ = be32_to_cpu(cgrd->cgr.cscn_targ);
13848 + cgrd->cgr.__cs_thres = be16_to_cpu(cgrd->cgr.__cs_thres);
13849 + for (i = 0; i < ARRAY_SIZE(cgrd->cscn_targ_swp); i++)
13850 + be32_to_cpus(&cgrd->cscn_targ_swp[i]);
13851 + return 0;
13852 +}
13853 +EXPORT_SYMBOL(qman_query_cgr);
13854 +
13855 +int qman_query_congestion(struct qm_mcr_querycongestion *congestion)
13856 +{
13857 + struct qm_mc_result *mcr;
13858 + struct qman_portal *p = get_affine_portal();
13859 + unsigned long irqflags __maybe_unused;
13860 + u8 res;
13861 + int i;
13862 +
13863 + PORTAL_IRQ_LOCK(p, irqflags);
13864 + qm_mc_start(&p->p);
13865 + qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCONGESTION);
13866 + while (!(mcr = qm_mc_result(&p->p)))
13867 + cpu_relax();
13868 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
13869 + QM_MCC_VERB_QUERYCONGESTION);
13870 + res = mcr->result;
13871 + if (res == QM_MCR_RESULT_OK)
13872 + memcpy_fromio(congestion, &mcr->querycongestion,
13873 + sizeof(*congestion));
13874 + PORTAL_IRQ_UNLOCK(p, irqflags);
13875 + put_affine_portal();
13876 + if (res != QM_MCR_RESULT_OK) {
13877 + pr_err("QUERY_CONGESTION failed: %s\n", mcr_result_str(res));
13878 + return -EIO;
13879 + }
13880 +
13881 + for (i = 0; i < ARRAY_SIZE(congestion->state.__state); i++)
13882 + be32_to_cpus(&congestion->state.__state[i]);
13883 + return 0;
13884 +}
13885 +EXPORT_SYMBOL(qman_query_congestion);
13886 +
13887 +/* internal function used as a wait_event() expression */
13888 +static int set_p_vdqcr(struct qman_portal *p, struct qman_fq *fq, u32 vdqcr)
13889 +{
13890 + unsigned long irqflags __maybe_unused;
13891 + int ret = -EBUSY;
13892 + PORTAL_IRQ_LOCK(p, irqflags);
13893 + if (!p->vdqcr_owned) {
13894 + FQLOCK(fq);
13895 + if (fq_isset(fq, QMAN_FQ_STATE_VDQCR))
13896 + goto escape;
13897 + fq_set(fq, QMAN_FQ_STATE_VDQCR);
13898 + FQUNLOCK(fq);
13899 + p->vdqcr_owned = fq;
13900 + ret = 0;
13901 + }
13902 +escape:
13903 + PORTAL_IRQ_UNLOCK(p, irqflags);
13904 + if (!ret)
13905 + qm_dqrr_vdqcr_set(&p->p, vdqcr);
13906 + return ret;
13907 +}
13908 +
13909 +static int set_vdqcr(struct qman_portal **p, struct qman_fq *fq, u32 vdqcr)
13910 +{
13911 + int ret;
13912 + *p = get_affine_portal();
13913 + ret = set_p_vdqcr(*p, fq, vdqcr);
13914 + put_affine_portal();
13915 + return ret;
13916 +}
13917 +
13918 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
13919 +static int wait_p_vdqcr_start(struct qman_portal *p, struct qman_fq *fq,
13920 + u32 vdqcr, u32 flags)
13921 +{
13922 + int ret = 0;
13923 + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
13924 + ret = wait_event_interruptible(affine_queue,
13925 + !(ret = set_p_vdqcr(p, fq, vdqcr)));
13926 + else
13927 + wait_event(affine_queue, !(ret = set_p_vdqcr(p, fq, vdqcr)));
13928 + return ret;
13929 +}
13930 +
13931 +static int wait_vdqcr_start(struct qman_portal **p, struct qman_fq *fq,
13932 + u32 vdqcr, u32 flags)
13933 +{
13934 + int ret = 0;
13935 + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
13936 + ret = wait_event_interruptible(affine_queue,
13937 + !(ret = set_vdqcr(p, fq, vdqcr)));
13938 + else
13939 + wait_event(affine_queue, !(ret = set_vdqcr(p, fq, vdqcr)));
13940 + return ret;
13941 +}
13942 +#endif
13943 +
13944 +int qman_p_volatile_dequeue(struct qman_portal *p, struct qman_fq *fq,
13945 + u32 flags __maybe_unused, u32 vdqcr)
13946 +{
13947 + int ret;
13948 +
13949 + if ((fq->state != qman_fq_state_parked) &&
13950 + (fq->state != qman_fq_state_retired))
13951 + return -EINVAL;
13952 + if (vdqcr & QM_VDQCR_FQID_MASK)
13953 + return -EINVAL;
13954 + if (fq_isset(fq, QMAN_FQ_STATE_VDQCR))
13955 + return -EBUSY;
13956 + vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid;
13957 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
13958 + if (flags & QMAN_VOLATILE_FLAG_WAIT)
13959 + ret = wait_p_vdqcr_start(p, fq, vdqcr, flags);
13960 + else
13961 +#endif
13962 + ret = set_p_vdqcr(p, fq, vdqcr);
13963 + if (ret)
13964 + return ret;
13965 + /* VDQCR is set */
13966 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
13967 + if (flags & QMAN_VOLATILE_FLAG_FINISH) {
13968 + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
13969 + /* NB: don't propagate any error - the caller wouldn't
13970 + * know whether the VDQCR was issued or not. A signal
13971 + * could arrive after returning anyway, so the caller
13972 + * can check signal_pending() if that's an issue. */
13973 + wait_event_interruptible(affine_queue,
13974 + !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
13975 + else
13976 + wait_event(affine_queue,
13977 + !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
13978 + }
13979 +#endif
13980 + return 0;
13981 +}
13982 +EXPORT_SYMBOL(qman_p_volatile_dequeue);
13983 +
13984 +int qman_volatile_dequeue(struct qman_fq *fq, u32 flags __maybe_unused,
13985 + u32 vdqcr)
13986 +{
13987 + struct qman_portal *p;
13988 + int ret;
13989 +
13990 + if ((fq->state != qman_fq_state_parked) &&
13991 + (fq->state != qman_fq_state_retired))
13992 + return -EINVAL;
13993 + if (vdqcr & QM_VDQCR_FQID_MASK)
13994 + return -EINVAL;
13995 + if (fq_isset(fq, QMAN_FQ_STATE_VDQCR))
13996 + return -EBUSY;
13997 + vdqcr = (vdqcr & ~QM_VDQCR_FQID_MASK) | fq->fqid;
13998 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
13999 + if (flags & QMAN_VOLATILE_FLAG_WAIT)
14000 + ret = wait_vdqcr_start(&p, fq, vdqcr, flags);
14001 + else
14002 +#endif
14003 + ret = set_vdqcr(&p, fq, vdqcr);
14004 + if (ret)
14005 + return ret;
14006 + /* VDQCR is set */
14007 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14008 + if (flags & QMAN_VOLATILE_FLAG_FINISH) {
14009 + if (flags & QMAN_VOLATILE_FLAG_WAIT_INT)
14010 + /* NB: don't propagate any error - the caller wouldn't
14011 + * know whether the VDQCR was issued or not. A signal
14012 + * could arrive after returning anyway, so the caller
14013 + * can check signal_pending() if that's an issue. */
14014 + wait_event_interruptible(affine_queue,
14015 + !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
14016 + else
14017 + wait_event(affine_queue,
14018 + !fq_isset(fq, QMAN_FQ_STATE_VDQCR));
14019 + }
14020 +#endif
14021 + return 0;
14022 +}
14023 +EXPORT_SYMBOL(qman_volatile_dequeue);
14024 +
14025 +static noinline void update_eqcr_ci(struct qman_portal *p, u8 avail)
14026 +{
14027 + if (avail)
14028 + qm_eqcr_cce_prefetch(&p->p);
14029 + else
14030 + qm_eqcr_cce_update(&p->p);
14031 +}
14032 +
14033 +int qman_eqcr_is_empty(void)
14034 +{
14035 + unsigned long irqflags __maybe_unused;
14036 + struct qman_portal *p = get_affine_portal();
14037 + u8 avail;
14038 +
14039 + PORTAL_IRQ_LOCK(p, irqflags);
14040 + update_eqcr_ci(p, 0);
14041 + avail = qm_eqcr_get_fill(&p->p);
14042 + PORTAL_IRQ_UNLOCK(p, irqflags);
14043 + put_affine_portal();
14044 + return avail == 0;
14045 +}
14046 +EXPORT_SYMBOL(qman_eqcr_is_empty);
14047 +
14048 +void qman_set_dc_ern(qman_cb_dc_ern handler, int affine)
14049 +{
14050 + if (affine) {
14051 + unsigned long irqflags __maybe_unused;
14052 + struct qman_portal *p = get_affine_portal();
14053 + PORTAL_IRQ_LOCK(p, irqflags);
14054 + p->cb_dc_ern = handler;
14055 + PORTAL_IRQ_UNLOCK(p, irqflags);
14056 + put_affine_portal();
14057 + } else
14058 + cb_dc_ern = handler;
14059 +}
14060 +EXPORT_SYMBOL(qman_set_dc_ern);
14061 +
14062 +static inline struct qm_eqcr_entry *try_p_eq_start(struct qman_portal *p,
14063 + unsigned long *irqflags __maybe_unused,
14064 + struct qman_fq *fq,
14065 + const struct qm_fd *fd,
14066 + u32 flags)
14067 +{
14068 + struct qm_eqcr_entry *eq;
14069 + u8 avail;
14070 + PORTAL_IRQ_LOCK(p, (*irqflags));
14071 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14072 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14073 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14074 + if (p->eqci_owned) {
14075 + PORTAL_IRQ_UNLOCK(p, (*irqflags));
14076 + return NULL;
14077 + }
14078 + p->eqci_owned = fq;
14079 + }
14080 +#endif
14081 + if (p->use_eqcr_ci_stashing) {
14082 + /*
14083 + * The stashing case is easy, only update if we need to in
14084 + * order to try and liberate ring entries.
14085 + */
14086 + eq = qm_eqcr_start_stash(&p->p);
14087 + } else {
14088 + /*
14089 + * The non-stashing case is harder, need to prefetch ahead of
14090 + * time.
14091 + */
14092 + avail = qm_eqcr_get_avail(&p->p);
14093 + if (avail < 2)
14094 + update_eqcr_ci(p, avail);
14095 + eq = qm_eqcr_start_no_stash(&p->p);
14096 + }
14097 +
14098 + if (unlikely(!eq)) {
14099 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14100 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14101 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC)))
14102 + p->eqci_owned = NULL;
14103 +#endif
14104 + PORTAL_IRQ_UNLOCK(p, (*irqflags));
14105 + return NULL;
14106 + }
14107 + if (flags & QMAN_ENQUEUE_FLAG_DCA)
14108 + eq->dca = QM_EQCR_DCA_ENABLE |
14109 + ((flags & QMAN_ENQUEUE_FLAG_DCA_PARK) ?
14110 + QM_EQCR_DCA_PARK : 0) |
14111 + ((flags >> 8) & QM_EQCR_DCA_IDXMASK);
14112 + eq->fqid = cpu_to_be32(fq->fqid);
14113 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
14114 + eq->tag = cpu_to_be32(fq->key);
14115 +#else
14116 + eq->tag = cpu_to_be32((u32)(uintptr_t)fq);
14117 +#endif
14118 + eq->fd = *fd;
14119 + cpu_to_hw_fd(&eq->fd);
14120 + return eq;
14121 +}
14122 +
14123 +static inline struct qm_eqcr_entry *try_eq_start(struct qman_portal **p,
14124 + unsigned long *irqflags __maybe_unused,
14125 + struct qman_fq *fq,
14126 + const struct qm_fd *fd,
14127 + u32 flags)
14128 +{
14129 + struct qm_eqcr_entry *eq;
14130 + *p = get_affine_portal();
14131 + eq = try_p_eq_start(*p, irqflags, fq, fd, flags);
14132 + if (!eq)
14133 + put_affine_portal();
14134 + return eq;
14135 +}
14136 +
14137 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14138 +static noinline struct qm_eqcr_entry *__wait_eq_start(struct qman_portal **p,
14139 + unsigned long *irqflags __maybe_unused,
14140 + struct qman_fq *fq,
14141 + const struct qm_fd *fd,
14142 + u32 flags)
14143 +{
14144 + struct qm_eqcr_entry *eq = try_eq_start(p, irqflags, fq, fd, flags);
14145 + if (!eq)
14146 + qm_eqcr_set_ithresh(&(*p)->p, EQCR_ITHRESH);
14147 + return eq;
14148 +}
14149 +static noinline struct qm_eqcr_entry *wait_eq_start(struct qman_portal **p,
14150 + unsigned long *irqflags __maybe_unused,
14151 + struct qman_fq *fq,
14152 + const struct qm_fd *fd,
14153 + u32 flags)
14154 +{
14155 + struct qm_eqcr_entry *eq;
14156 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14157 + /* NB: return NULL if signal occurs before completion. Signal
14158 + * can occur during return. Caller must check for signal */
14159 + wait_event_interruptible(affine_queue,
14160 + (eq = __wait_eq_start(p, irqflags, fq, fd, flags)));
14161 + else
14162 + wait_event(affine_queue,
14163 + (eq = __wait_eq_start(p, irqflags, fq, fd, flags)));
14164 + return eq;
14165 +}
14166 +static noinline struct qm_eqcr_entry *__wait_p_eq_start(struct qman_portal *p,
14167 + unsigned long *irqflags __maybe_unused,
14168 + struct qman_fq *fq,
14169 + const struct qm_fd *fd,
14170 + u32 flags)
14171 +{
14172 + struct qm_eqcr_entry *eq = try_p_eq_start(p, irqflags, fq, fd, flags);
14173 + if (!eq)
14174 + qm_eqcr_set_ithresh(&p->p, EQCR_ITHRESH);
14175 + return eq;
14176 +}
14177 +static noinline struct qm_eqcr_entry *wait_p_eq_start(struct qman_portal *p,
14178 + unsigned long *irqflags __maybe_unused,
14179 + struct qman_fq *fq,
14180 + const struct qm_fd *fd,
14181 + u32 flags)
14182 +{
14183 + struct qm_eqcr_entry *eq;
14184 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14185 + /* NB: return NULL if signal occurs before completion. Signal
14186 + * can occur during return. Caller must check for signal */
14187 + wait_event_interruptible(affine_queue,
14188 + (eq = __wait_p_eq_start(p, irqflags, fq, fd, flags)));
14189 + else
14190 + wait_event(affine_queue,
14191 + (eq = __wait_p_eq_start(p, irqflags, fq, fd, flags)));
14192 + return eq;
14193 +}
14194 +#endif
14195 +
14196 +int qman_p_enqueue(struct qman_portal *p, struct qman_fq *fq,
14197 + const struct qm_fd *fd, u32 flags)
14198 +{
14199 + struct qm_eqcr_entry *eq;
14200 + unsigned long irqflags __maybe_unused;
14201 +
14202 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14203 + if (flags & QMAN_ENQUEUE_FLAG_WAIT)
14204 + eq = wait_p_eq_start(p, &irqflags, fq, fd, flags);
14205 + else
14206 +#endif
14207 + eq = try_p_eq_start(p, &irqflags, fq, fd, flags);
14208 + if (!eq)
14209 + return -EBUSY;
14210 + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
14211 + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
14212 + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
14213 + /* Factor the below out, it's used from qman_enqueue_orp() too */
14214 + PORTAL_IRQ_UNLOCK(p, irqflags);
14215 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14216 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14217 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14218 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14219 + /* NB: return success even if signal occurs before
14220 + * condition is true. pvb_commit guarantees success */
14221 + wait_event_interruptible(affine_queue,
14222 + (p->eqci_owned != fq));
14223 + else
14224 + wait_event(affine_queue, (p->eqci_owned != fq));
14225 + }
14226 +#endif
14227 + return 0;
14228 +}
14229 +EXPORT_SYMBOL(qman_p_enqueue);
14230 +
14231 +int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags)
14232 +{
14233 + struct qman_portal *p;
14234 + struct qm_eqcr_entry *eq;
14235 + unsigned long irqflags __maybe_unused;
14236 +
14237 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14238 + if (flags & QMAN_ENQUEUE_FLAG_WAIT)
14239 + eq = wait_eq_start(&p, &irqflags, fq, fd, flags);
14240 + else
14241 +#endif
14242 + eq = try_eq_start(&p, &irqflags, fq, fd, flags);
14243 + if (!eq)
14244 + return -EBUSY;
14245 + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
14246 + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
14247 + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
14248 + /* Factor the below out, it's used from qman_enqueue_orp() too */
14249 + PORTAL_IRQ_UNLOCK(p, irqflags);
14250 + put_affine_portal();
14251 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14252 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14253 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14254 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14255 + /* NB: return success even if signal occurs before
14256 + * condition is true. pvb_commit guarantees success */
14257 + wait_event_interruptible(affine_queue,
14258 + (p->eqci_owned != fq));
14259 + else
14260 + wait_event(affine_queue, (p->eqci_owned != fq));
14261 + }
14262 +#endif
14263 + return 0;
14264 +}
14265 +EXPORT_SYMBOL(qman_enqueue);
14266 +
14267 +int qman_p_enqueue_orp(struct qman_portal *p, struct qman_fq *fq,
14268 + const struct qm_fd *fd, u32 flags,
14269 + struct qman_fq *orp, u16 orp_seqnum)
14270 +{
14271 + struct qm_eqcr_entry *eq;
14272 + unsigned long irqflags __maybe_unused;
14273 +
14274 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14275 + if (flags & QMAN_ENQUEUE_FLAG_WAIT)
14276 + eq = wait_p_eq_start(p, &irqflags, fq, fd, flags);
14277 + else
14278 +#endif
14279 + eq = try_p_eq_start(p, &irqflags, fq, fd, flags);
14280 + if (!eq)
14281 + return -EBUSY;
14282 + /* Process ORP-specifics here */
14283 + if (flags & QMAN_ENQUEUE_FLAG_NLIS)
14284 + orp_seqnum |= QM_EQCR_SEQNUM_NLIS;
14285 + else {
14286 + orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS;
14287 + if (flags & QMAN_ENQUEUE_FLAG_NESN)
14288 + orp_seqnum |= QM_EQCR_SEQNUM_NESN;
14289 + else
14290 + /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */
14291 + orp_seqnum &= ~QM_EQCR_SEQNUM_NESN;
14292 + }
14293 + eq->seqnum = cpu_to_be16(orp_seqnum);
14294 + eq->orp = cpu_to_be32(orp->fqid);
14295 + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
14296 + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP |
14297 + ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ?
14298 + 0 : QM_EQCR_VERB_CMD_ENQUEUE) |
14299 + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
14300 + PORTAL_IRQ_UNLOCK(p, irqflags);
14301 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14302 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14303 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14304 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14305 + /* NB: return success even if signal occurs before
14306 + * condition is true. pvb_commit guarantees success */
14307 + wait_event_interruptible(affine_queue,
14308 + (p->eqci_owned != fq));
14309 + else
14310 + wait_event(affine_queue, (p->eqci_owned != fq));
14311 + }
14312 +#endif
14313 + return 0;
14314 +}
14315 +EXPORT_SYMBOL(qman_p_enqueue_orp);
14316 +
14317 +int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags,
14318 + struct qman_fq *orp, u16 orp_seqnum)
14319 +{
14320 + struct qman_portal *p;
14321 + struct qm_eqcr_entry *eq;
14322 + unsigned long irqflags __maybe_unused;
14323 +
14324 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14325 + if (flags & QMAN_ENQUEUE_FLAG_WAIT)
14326 + eq = wait_eq_start(&p, &irqflags, fq, fd, flags);
14327 + else
14328 +#endif
14329 + eq = try_eq_start(&p, &irqflags, fq, fd, flags);
14330 + if (!eq)
14331 + return -EBUSY;
14332 + /* Process ORP-specifics here */
14333 + if (flags & QMAN_ENQUEUE_FLAG_NLIS)
14334 + orp_seqnum |= QM_EQCR_SEQNUM_NLIS;
14335 + else {
14336 + orp_seqnum &= ~QM_EQCR_SEQNUM_NLIS;
14337 + if (flags & QMAN_ENQUEUE_FLAG_NESN)
14338 + orp_seqnum |= QM_EQCR_SEQNUM_NESN;
14339 + else
14340 + /* No need to check 4 QMAN_ENQUEUE_FLAG_HOLE */
14341 + orp_seqnum &= ~QM_EQCR_SEQNUM_NESN;
14342 + }
14343 + eq->seqnum = cpu_to_be16(orp_seqnum);
14344 + eq->orp = cpu_to_be32(orp->fqid);
14345 + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
14346 + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_ORP |
14347 + ((flags & (QMAN_ENQUEUE_FLAG_HOLE | QMAN_ENQUEUE_FLAG_NESN)) ?
14348 + 0 : QM_EQCR_VERB_CMD_ENQUEUE) |
14349 + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
14350 + PORTAL_IRQ_UNLOCK(p, irqflags);
14351 + put_affine_portal();
14352 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14353 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14354 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14355 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14356 + /* NB: return success even if signal occurs before
14357 + * condition is true. pvb_commit guarantees success */
14358 + wait_event_interruptible(affine_queue,
14359 + (p->eqci_owned != fq));
14360 + else
14361 + wait_event(affine_queue, (p->eqci_owned != fq));
14362 + }
14363 +#endif
14364 + return 0;
14365 +}
14366 +EXPORT_SYMBOL(qman_enqueue_orp);
14367 +
14368 +int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq,
14369 + const struct qm_fd *fd, u32 flags,
14370 + qman_cb_precommit cb, void *cb_arg)
14371 +{
14372 + struct qm_eqcr_entry *eq;
14373 + unsigned long irqflags __maybe_unused;
14374 +
14375 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14376 + if (flags & QMAN_ENQUEUE_FLAG_WAIT)
14377 + eq = wait_p_eq_start(p, &irqflags, fq, fd, flags);
14378 + else
14379 +#endif
14380 + eq = try_p_eq_start(p, &irqflags, fq, fd, flags);
14381 + if (!eq)
14382 + return -EBUSY;
14383 + /* invoke user supplied callback function before writing commit verb */
14384 + if (cb(cb_arg)) {
14385 + PORTAL_IRQ_UNLOCK(p, irqflags);
14386 + return -EINVAL;
14387 + }
14388 + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
14389 + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
14390 + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
14391 + /* Factor the below out, it's used from qman_enqueue_orp() too */
14392 + PORTAL_IRQ_UNLOCK(p, irqflags);
14393 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14394 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14395 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14396 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14397 + /* NB: return success even if signal occurs before
14398 + * condition is true. pvb_commit guarantees success */
14399 + wait_event_interruptible(affine_queue,
14400 + (p->eqci_owned != fq));
14401 + else
14402 + wait_event(affine_queue, (p->eqci_owned != fq));
14403 + }
14404 +#endif
14405 + return 0;
14406 +}
14407 +EXPORT_SYMBOL(qman_p_enqueue_precommit);
14408 +
14409 +int qman_enqueue_precommit(struct qman_fq *fq, const struct qm_fd *fd,
14410 + u32 flags, qman_cb_precommit cb, void *cb_arg)
14411 +{
14412 + struct qman_portal *p;
14413 + struct qm_eqcr_entry *eq;
14414 + unsigned long irqflags __maybe_unused;
14415 +
14416 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
14417 + if (flags & QMAN_ENQUEUE_FLAG_WAIT)
14418 + eq = wait_eq_start(&p, &irqflags, fq, fd, flags);
14419 + else
14420 +#endif
14421 + eq = try_eq_start(&p, &irqflags, fq, fd, flags);
14422 + if (!eq)
14423 + return -EBUSY;
14424 + /* invoke user supplied callback function before writing commit verb */
14425 + if (cb(cb_arg)) {
14426 + PORTAL_IRQ_UNLOCK(p, irqflags);
14427 + put_affine_portal();
14428 + return -EINVAL;
14429 + }
14430 + /* Note: QM_EQCR_VERB_INTERRUPT == QMAN_ENQUEUE_FLAG_WAIT_SYNC */
14431 + qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE |
14432 + (flags & (QM_EQCR_VERB_COLOUR_MASK | QM_EQCR_VERB_INTERRUPT)));
14433 + /* Factor the below out, it's used from qman_enqueue_orp() too */
14434 + PORTAL_IRQ_UNLOCK(p, irqflags);
14435 + put_affine_portal();
14436 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
14437 + if (unlikely((flags & QMAN_ENQUEUE_FLAG_WAIT) &&
14438 + (flags & QMAN_ENQUEUE_FLAG_WAIT_SYNC))) {
14439 + if (flags & QMAN_ENQUEUE_FLAG_WAIT_INT)
14440 + /* NB: return success even if signal occurs before
14441 + * condition is true. pvb_commit guarantees success */
14442 + wait_event_interruptible(affine_queue,
14443 + (p->eqci_owned != fq));
14444 + else
14445 + wait_event(affine_queue, (p->eqci_owned != fq));
14446 + }
14447 +#endif
14448 + return 0;
14449 +}
14450 +EXPORT_SYMBOL(qman_enqueue_precommit);
14451 +
14452 +int qman_modify_cgr(struct qman_cgr *cgr, u32 flags,
14453 + struct qm_mcc_initcgr *opts)
14454 +{
14455 + struct qm_mc_command *mcc;
14456 + struct qm_mc_result *mcr;
14457 + struct qman_portal *p = get_affine_portal();
14458 + unsigned long irqflags __maybe_unused;
14459 + u8 res;
14460 + u8 verb = QM_MCC_VERB_MODIFYCGR;
14461 +
14462 + PORTAL_IRQ_LOCK(p, irqflags);
14463 + mcc = qm_mc_start(&p->p);
14464 + if (opts)
14465 + mcc->initcgr = *opts;
14466 + mcc->initcgr.we_mask = cpu_to_be16(mcc->initcgr.we_mask);
14467 + mcc->initcgr.cgr.wr_parm_g.word =
14468 + cpu_to_be32(mcc->initcgr.cgr.wr_parm_g.word);
14469 + mcc->initcgr.cgr.wr_parm_y.word =
14470 + cpu_to_be32(mcc->initcgr.cgr.wr_parm_y.word);
14471 + mcc->initcgr.cgr.wr_parm_r.word =
14472 + cpu_to_be32(mcc->initcgr.cgr.wr_parm_r.word);
14473 + mcc->initcgr.cgr.cscn_targ = cpu_to_be32(mcc->initcgr.cgr.cscn_targ);
14474 + mcc->initcgr.cgr.__cs_thres = cpu_to_be16(mcc->initcgr.cgr.__cs_thres);
14475 +
14476 + mcc->initcgr.cgid = cgr->cgrid;
14477 + if (flags & QMAN_CGR_FLAG_USE_INIT)
14478 + verb = QM_MCC_VERB_INITCGR;
14479 + qm_mc_commit(&p->p, verb);
14480 + while (!(mcr = qm_mc_result(&p->p)))
14481 + cpu_relax();
14482 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == verb);
14483 + res = mcr->result;
14484 + PORTAL_IRQ_UNLOCK(p, irqflags);
14485 + put_affine_portal();
14486 + return (res == QM_MCR_RESULT_OK) ? 0 : -EIO;
14487 +}
14488 +EXPORT_SYMBOL(qman_modify_cgr);
14489 +
14490 +#define TARG_MASK(n) (0x80000000 >> (n->config->public_cfg.channel - \
14491 + QM_CHANNEL_SWPORTAL0))
14492 +#define TARG_DCP_MASK(n) (0x80000000 >> (10 + n))
14493 +#define PORTAL_IDX(n) (n->config->public_cfg.channel - QM_CHANNEL_SWPORTAL0)
14494 +
14495 +static u8 qman_cgr_cpus[__CGR_NUM];
14496 +
14497 +int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
14498 + struct qm_mcc_initcgr *opts)
14499 +{
14500 + unsigned long irqflags __maybe_unused;
14501 + struct qm_mcr_querycgr cgr_state;
14502 + struct qm_mcc_initcgr local_opts;
14503 + int ret;
14504 + struct qman_portal *p;
14505 +
14506 + /* We have to check that the provided CGRID is within the limits of the
14507 + * data-structures, for obvious reasons. However we'll let h/w take
14508 + * care of determining whether it's within the limits of what exists on
14509 + * the SoC. */
14510 + if (cgr->cgrid >= __CGR_NUM)
14511 + return -EINVAL;
14512 +
14513 + preempt_disable();
14514 + p = get_affine_portal();
14515 + qman_cgr_cpus[cgr->cgrid] = smp_processor_id();
14516 + preempt_enable();
14517 +
14518 + memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
14519 + cgr->chan = p->config->public_cfg.channel;
14520 + spin_lock_irqsave(&p->cgr_lock, irqflags);
14521 +
14522 + /* if no opts specified, just add it to the list */
14523 + if (!opts)
14524 + goto add_list;
14525 +
14526 + ret = qman_query_cgr(cgr, &cgr_state);
14527 + if (ret)
14528 + goto release_lock;
14529 + if (opts)
14530 + local_opts = *opts;
14531 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
14532 + local_opts.cgr.cscn_targ_upd_ctrl =
14533 + QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p);
14534 + else
14535 + /* Overwrite TARG */
14536 + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ |
14537 + TARG_MASK(p);
14538 + local_opts.we_mask |= QM_CGR_WE_CSCN_TARG;
14539 +
14540 + /* send init if flags indicate so */
14541 + if (opts && (flags & QMAN_CGR_FLAG_USE_INIT))
14542 + ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, &local_opts);
14543 + else
14544 + ret = qman_modify_cgr(cgr, 0, &local_opts);
14545 + if (ret)
14546 + goto release_lock;
14547 +add_list:
14548 + list_add(&cgr->node, &p->cgr_cbs);
14549 +
14550 + /* Determine if newly added object requires its callback to be called */
14551 + ret = qman_query_cgr(cgr, &cgr_state);
14552 + if (ret) {
14553 + /* we can't go back, so proceed and return success, but screen
14554 + * and wail to the log file */
14555 + pr_crit("CGR HW state partially modified\n");
14556 + ret = 0;
14557 + goto release_lock;
14558 + }
14559 + if (cgr->cb && cgr_state.cgr.cscn_en && qman_cgrs_get(&p->cgrs[1],
14560 + cgr->cgrid))
14561 + cgr->cb(p, cgr, 1);
14562 +release_lock:
14563 + spin_unlock_irqrestore(&p->cgr_lock, irqflags);
14564 + put_affine_portal();
14565 + return ret;
14566 +}
14567 +EXPORT_SYMBOL(qman_create_cgr);
14568 +
14569 +int qman_create_cgr_to_dcp(struct qman_cgr *cgr, u32 flags, u16 dcp_portal,
14570 + struct qm_mcc_initcgr *opts)
14571 +{
14572 + unsigned long irqflags __maybe_unused;
14573 + struct qm_mcc_initcgr local_opts;
14574 + struct qm_mcr_querycgr cgr_state;
14575 + int ret;
14576 +
14577 + /* We have to check that the provided CGRID is within the limits of the
14578 + * data-structures, for obvious reasons. However we'll let h/w take
14579 + * care of determining whether it's within the limits of what exists on
14580 + * the SoC.
14581 + */
14582 + if (cgr->cgrid >= __CGR_NUM)
14583 + return -EINVAL;
14584 +
14585 + ret = qman_query_cgr(cgr, &cgr_state);
14586 + if (ret)
14587 + return ret;
14588 +
14589 + memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
14590 + if (opts)
14591 + local_opts = *opts;
14592 +
14593 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
14594 + local_opts.cgr.cscn_targ_upd_ctrl =
14595 + QM_CGR_TARG_UDP_CTRL_WRITE_BIT |
14596 + QM_CGR_TARG_UDP_CTRL_DCP | dcp_portal;
14597 + else
14598 + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ |
14599 + TARG_DCP_MASK(dcp_portal);
14600 + local_opts.we_mask |= QM_CGR_WE_CSCN_TARG;
14601 +
14602 + /* send init if flags indicate so */
14603 + if (opts && (flags & QMAN_CGR_FLAG_USE_INIT))
14604 + ret = qman_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT,
14605 + &local_opts);
14606 + else
14607 + ret = qman_modify_cgr(cgr, 0, &local_opts);
14608 +
14609 + return ret;
14610 +}
14611 +EXPORT_SYMBOL(qman_create_cgr_to_dcp);
14612 +
14613 +int qman_delete_cgr(struct qman_cgr *cgr)
14614 +{
14615 + unsigned long irqflags __maybe_unused;
14616 + struct qm_mcr_querycgr cgr_state;
14617 + struct qm_mcc_initcgr local_opts;
14618 + int ret = 0;
14619 + struct qman_cgr *i;
14620 + struct qman_portal *p = get_affine_portal();
14621 +
14622 + if (cgr->chan != p->config->public_cfg.channel) {
14623 + pr_crit("Attempting to delete cgr from different portal "
14624 + "than it was create: create 0x%x, delete 0x%x\n",
14625 + cgr->chan, p->config->public_cfg.channel);
14626 + ret = -EINVAL;
14627 + goto put_portal;
14628 + }
14629 + memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
14630 + spin_lock_irqsave(&p->cgr_lock, irqflags);
14631 + list_del(&cgr->node);
14632 + /*
14633 + * If there are no other CGR objects for this CGRID in the list, update
14634 + * CSCN_TARG accordingly
14635 + */
14636 + list_for_each_entry(i, &p->cgr_cbs, node)
14637 + if ((i->cgrid == cgr->cgrid) && i->cb)
14638 + goto release_lock;
14639 + ret = qman_query_cgr(cgr, &cgr_state);
14640 + if (ret) {
14641 + /* add back to the list */
14642 + list_add(&cgr->node, &p->cgr_cbs);
14643 + goto release_lock;
14644 + }
14645 + /* Overwrite TARG */
14646 + local_opts.we_mask = QM_CGR_WE_CSCN_TARG;
14647 + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30)
14648 + local_opts.cgr.cscn_targ_upd_ctrl = PORTAL_IDX(p);
14649 + else
14650 + local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ &
14651 + ~(TARG_MASK(p));
14652 + ret = qman_modify_cgr(cgr, 0, &local_opts);
14653 + if (ret)
14654 + /* add back to the list */
14655 + list_add(&cgr->node, &p->cgr_cbs);
14656 +release_lock:
14657 + spin_unlock_irqrestore(&p->cgr_lock, irqflags);
14658 +put_portal:
14659 + put_affine_portal();
14660 + return ret;
14661 +}
14662 +EXPORT_SYMBOL(qman_delete_cgr);
14663 +
14664 +struct cgr_comp {
14665 + struct qman_cgr *cgr;
14666 + struct completion completion;
14667 +};
14668 +
14669 +static int qman_delete_cgr_thread(void *p)
14670 +{
14671 + struct cgr_comp *cgr_comp = (struct cgr_comp *)p;
14672 + int res;
14673 +
14674 + res = qman_delete_cgr((struct qman_cgr *)cgr_comp->cgr);
14675 + complete(&cgr_comp->completion);
14676 +
14677 + return res;
14678 +}
14679 +
14680 +void qman_delete_cgr_safe(struct qman_cgr *cgr)
14681 +{
14682 + struct task_struct *thread;
14683 + struct cgr_comp cgr_comp;
14684 +
14685 + preempt_disable();
14686 + if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) {
14687 + init_completion(&cgr_comp.completion);
14688 + cgr_comp.cgr = cgr;
14689 + thread = kthread_create(qman_delete_cgr_thread, &cgr_comp,
14690 + "cgr_del");
14691 +
14692 + if (likely(!IS_ERR(thread))) {
14693 + kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]);
14694 + wake_up_process(thread);
14695 + wait_for_completion(&cgr_comp.completion);
14696 + preempt_enable();
14697 + return;
14698 + }
14699 + }
14700 + qman_delete_cgr(cgr);
14701 + preempt_enable();
14702 +}
14703 +EXPORT_SYMBOL(qman_delete_cgr_safe);
14704 +
14705 +int qm_get_clock(u64 *clock_hz)
14706 +{
14707 + if (!qman_clk) {
14708 + pr_warn("Qman clock speed is unknown\n");
14709 + return -EINVAL;
14710 + }
14711 + *clock_hz = (u64)qman_clk;
14712 + return 0;
14713 +}
14714 +EXPORT_SYMBOL(qm_get_clock);
14715 +
14716 +int qm_set_clock(u64 clock_hz)
14717 +{
14718 + if (qman_clk)
14719 + return -1;
14720 + qman_clk = (u32)clock_hz;
14721 + return 0;
14722 +}
14723 +EXPORT_SYMBOL(qm_set_clock);
14724 +
14725 +/* CEETM management command */
14726 +static int qman_ceetm_configure_lfqmt(struct qm_mcc_ceetm_lfqmt_config *opts)
14727 +{
14728 + struct qm_mc_command *mcc;
14729 + struct qm_mc_result *mcr;
14730 + struct qman_portal *p;
14731 + unsigned long irqflags __maybe_unused;
14732 + u8 res;
14733 +
14734 + p = get_affine_portal();
14735 + PORTAL_IRQ_LOCK(p, irqflags);
14736 +
14737 + mcc = qm_mc_start(&p->p);
14738 + mcc->lfqmt_config = *opts;
14739 + qm_mc_commit(&p->p, QM_CEETM_VERB_LFQMT_CONFIG);
14740 + while (!(mcr = qm_mc_result(&p->p)))
14741 + cpu_relax();
14742 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
14743 + QM_CEETM_VERB_LFQMT_CONFIG);
14744 + PORTAL_IRQ_UNLOCK(p, irqflags);
14745 + put_affine_portal();
14746 +
14747 + res = mcr->result;
14748 + if (res != QM_MCR_RESULT_OK) {
14749 + pr_err("CEETM: CONFIGURE LFQMT failed\n");
14750 + return -EIO;
14751 + }
14752 + return 0;
14753 +}
14754 +
14755 +int qman_ceetm_query_lfqmt(int lfqid,
14756 + struct qm_mcr_ceetm_lfqmt_query *lfqmt_query)
14757 +{
14758 + struct qm_mc_command *mcc;
14759 + struct qm_mc_result *mcr;
14760 + struct qman_portal *p;
14761 + unsigned long irqflags __maybe_unused;
14762 + u8 res;
14763 +
14764 + p = get_affine_portal();
14765 + PORTAL_IRQ_LOCK(p, irqflags);
14766 +
14767 + mcc = qm_mc_start(&p->p);
14768 + mcc->lfqmt_query.lfqid = lfqid;
14769 + qm_mc_commit(&p->p, QM_CEETM_VERB_LFQMT_QUERY);
14770 + while (!(mcr = qm_mc_result(&p->p)))
14771 + cpu_relax();
14772 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_LFQMT_QUERY);
14773 + res = mcr->result;
14774 + if (res == QM_MCR_RESULT_OK)
14775 + *lfqmt_query = mcr->lfqmt_query;
14776 +
14777 + PORTAL_IRQ_UNLOCK(p, irqflags);
14778 + put_affine_portal();
14779 + if (res != QM_MCR_RESULT_OK) {
14780 + pr_err("CEETM: QUERY LFQMT failed\n");
14781 + return -EIO;
14782 + }
14783 + return 0;
14784 +}
14785 +EXPORT_SYMBOL(qman_ceetm_query_lfqmt);
14786 +
14787 +static int qman_ceetm_configure_cq(struct qm_mcc_ceetm_cq_config *opts)
14788 +{
14789 + struct qm_mc_command *mcc;
14790 + struct qm_mc_result *mcr;
14791 + struct qman_portal *p;
14792 + unsigned long irqflags __maybe_unused;
14793 + u8 res;
14794 +
14795 + p = get_affine_portal();
14796 + PORTAL_IRQ_LOCK(p, irqflags);
14797 +
14798 + mcc = qm_mc_start(&p->p);
14799 + mcc->cq_config = *opts;
14800 + qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_CONFIG);
14801 + while (!(mcr = qm_mc_result(&p->p)))
14802 + cpu_relax();
14803 + res = mcr->result;
14804 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CQ_CONFIG);
14805 +
14806 + PORTAL_IRQ_UNLOCK(p, irqflags);
14807 + put_affine_portal();
14808 +
14809 + if (res != QM_MCR_RESULT_OK) {
14810 + pr_err("CEETM: CONFIGURE CQ failed\n");
14811 + return -EIO;
14812 + }
14813 + return 0;
14814 +}
14815 +
14816 +int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid,
14817 + struct qm_mcr_ceetm_cq_query *cq_query)
14818 +{
14819 + struct qm_mc_command *mcc;
14820 + struct qm_mc_result *mcr;
14821 + struct qman_portal *p;
14822 + unsigned long irqflags __maybe_unused;
14823 + u8 res;
14824 +
14825 + p = get_affine_portal();
14826 + PORTAL_IRQ_LOCK(p, irqflags);
14827 +
14828 + mcc = qm_mc_start(&p->p);
14829 + mcc->cq_query.cqid = cpu_to_be16(cqid);
14830 + mcc->cq_query.dcpid = dcpid;
14831 + qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_QUERY);
14832 + while (!(mcr = qm_mc_result(&p->p)))
14833 + cpu_relax();
14834 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CQ_QUERY);
14835 + res = mcr->result;
14836 + if (res == QM_MCR_RESULT_OK) {
14837 + *cq_query = mcr->cq_query;
14838 + hw_cq_query_to_cpu(cq_query);
14839 + }
14840 +
14841 + PORTAL_IRQ_UNLOCK(p, irqflags);
14842 + put_affine_portal();
14843 +
14844 + if (res != QM_MCR_RESULT_OK) {
14845 + pr_err("CEETM: QUERY CQ failed\n");
14846 + return -EIO;
14847 + }
14848 +
14849 + return 0;
14850 +}
14851 +EXPORT_SYMBOL(qman_ceetm_query_cq);
14852 +
14853 +static int qman_ceetm_configure_dct(struct qm_mcc_ceetm_dct_config *opts)
14854 +{
14855 + struct qm_mc_command *mcc;
14856 + struct qm_mc_result *mcr;
14857 + struct qman_portal *p;
14858 + unsigned long irqflags __maybe_unused;
14859 + u8 res;
14860 +
14861 + p = get_affine_portal();
14862 + PORTAL_IRQ_LOCK(p, irqflags);
14863 +
14864 + mcc = qm_mc_start(&p->p);
14865 + mcc->dct_config = *opts;
14866 + qm_mc_commit(&p->p, QM_CEETM_VERB_DCT_CONFIG);
14867 + while (!(mcr = qm_mc_result(&p->p)))
14868 + cpu_relax();
14869 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_DCT_CONFIG);
14870 + res = mcr->result;
14871 +
14872 + PORTAL_IRQ_UNLOCK(p, irqflags);
14873 + put_affine_portal();
14874 +
14875 + if (res != QM_MCR_RESULT_OK) {
14876 + pr_err("CEETM: CONFIGURE DCT failed\n");
14877 + return -EIO;
14878 + }
14879 + return 0;
14880 +}
14881 +
14882 +static int qman_ceetm_query_dct(struct qm_mcc_ceetm_dct_query *opts,
14883 + struct qm_mcr_ceetm_dct_query *dct_query)
14884 +{
14885 + struct qm_mc_command *mcc;
14886 + struct qm_mc_result *mcr;
14887 + struct qman_portal *p = get_affine_portal();
14888 + unsigned long irqflags __maybe_unused;
14889 + u8 res;
14890 +
14891 + PORTAL_IRQ_LOCK(p, irqflags);
14892 +
14893 + mcc = qm_mc_start(&p->p);
14894 + mcc->dct_query = *opts;
14895 + qm_mc_commit(&p->p, QM_CEETM_VERB_DCT_QUERY);
14896 + while (!(mcr = qm_mc_result(&p->p)))
14897 + cpu_relax();
14898 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_DCT_QUERY);
14899 + res = mcr->result;
14900 +
14901 + PORTAL_IRQ_UNLOCK(p, irqflags);
14902 + put_affine_portal();
14903 +
14904 + if (res != QM_MCR_RESULT_OK) {
14905 + pr_err("CEETM: QUERY DCT failed\n");
14906 + return -EIO;
14907 + }
14908 +
14909 + *dct_query = mcr->dct_query;
14910 + return 0;
14911 +}
14912 +
14913 +static int qman_ceetm_configure_class_scheduler(
14914 + struct qm_mcc_ceetm_class_scheduler_config *opts)
14915 +{
14916 + struct qm_mc_command *mcc;
14917 + struct qm_mc_result *mcr;
14918 + struct qman_portal *p;
14919 + unsigned long irqflags __maybe_unused;
14920 + u8 res;
14921 +
14922 + p = get_affine_portal();
14923 + PORTAL_IRQ_LOCK(p, irqflags);
14924 +
14925 + mcc = qm_mc_start(&p->p);
14926 + mcc->csch_config = *opts;
14927 + qm_mc_commit(&p->p, QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG);
14928 + while (!(mcr = qm_mc_result(&p->p)))
14929 + cpu_relax();
14930 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
14931 + QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG);
14932 + res = mcr->result;
14933 +
14934 + PORTAL_IRQ_UNLOCK(p, irqflags);
14935 + put_affine_portal();
14936 +
14937 + if (res != QM_MCR_RESULT_OK) {
14938 + pr_err("CEETM: CONFIGURE CLASS SCHEDULER failed\n");
14939 + return -EIO;
14940 + }
14941 + return 0;
14942 +}
14943 +
14944 +static int qman_ceetm_query_class_scheduler(struct qm_ceetm_channel *channel,
14945 + struct qm_mcr_ceetm_class_scheduler_query *query)
14946 +{
14947 + struct qm_mc_command *mcc;
14948 + struct qm_mc_result *mcr;
14949 + struct qman_portal *p;
14950 + unsigned long irqflags __maybe_unused;
14951 + u8 res;
14952 +
14953 + p = get_affine_portal();
14954 + PORTAL_IRQ_LOCK(p, irqflags);
14955 +
14956 + mcc = qm_mc_start(&p->p);
14957 + mcc->csch_query.cqcid = channel->idx;
14958 + mcc->csch_query.dcpid = channel->dcp_idx;
14959 + qm_mc_commit(&p->p, QM_CEETM_VERB_CLASS_SCHEDULER_QUERY);
14960 + while (!(mcr = qm_mc_result(&p->p)))
14961 + cpu_relax();
14962 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
14963 + QM_CEETM_VERB_CLASS_SCHEDULER_QUERY);
14964 + res = mcr->result;
14965 +
14966 + PORTAL_IRQ_UNLOCK(p, irqflags);
14967 + put_affine_portal();
14968 +
14969 + if (res != QM_MCR_RESULT_OK) {
14970 + pr_err("CEETM: QUERY CLASS SCHEDULER failed\n");
14971 + return -EIO;
14972 + }
14973 + *query = mcr->csch_query;
14974 + return 0;
14975 +}
14976 +
14977 +static int qman_ceetm_configure_mapping_shaper_tcfc(
14978 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config *opts)
14979 +{
14980 + struct qm_mc_command *mcc;
14981 + struct qm_mc_result *mcr;
14982 + struct qman_portal *p;
14983 + unsigned long irqflags __maybe_unused;
14984 + u8 res;
14985 +
14986 + p = get_affine_portal();
14987 + PORTAL_IRQ_LOCK(p, irqflags);
14988 +
14989 + mcc = qm_mc_start(&p->p);
14990 + mcc->mst_config = *opts;
14991 + qm_mc_commit(&p->p, QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG);
14992 + while (!(mcr = qm_mc_result(&p->p)))
14993 + cpu_relax();
14994 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
14995 + QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG);
14996 + res = mcr->result;
14997 +
14998 + PORTAL_IRQ_UNLOCK(p, irqflags);
14999 + put_affine_portal();
15000 +
15001 + if (res != QM_MCR_RESULT_OK) {
15002 + pr_err("CEETM: CONFIGURE CHANNEL MAPPING failed\n");
15003 + return -EIO;
15004 + }
15005 + return 0;
15006 +}
15007 +
15008 +static int qman_ceetm_query_mapping_shaper_tcfc(
15009 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query *opts,
15010 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query *response)
15011 +{
15012 + struct qm_mc_command *mcc;
15013 + struct qm_mc_result *mcr;
15014 + struct qman_portal *p;
15015 + unsigned long irqflags __maybe_unused;
15016 + u8 res;
15017 +
15018 + p = get_affine_portal();
15019 + PORTAL_IRQ_LOCK(p, irqflags);
15020 +
15021 + mcc = qm_mc_start(&p->p);
15022 + mcc->mst_query = *opts;
15023 + qm_mc_commit(&p->p, QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY);
15024 + while (!(mcr = qm_mc_result(&p->p)))
15025 + cpu_relax();
15026 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
15027 + QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY);
15028 + res = mcr->result;
15029 +
15030 + PORTAL_IRQ_UNLOCK(p, irqflags);
15031 + put_affine_portal();
15032 +
15033 + if (res != QM_MCR_RESULT_OK) {
15034 + pr_err("CEETM: QUERY CHANNEL MAPPING failed\n");
15035 + return -EIO;
15036 + }
15037 +
15038 + *response = mcr->mst_query;
15039 + return 0;
15040 +}
15041 +
15042 +static int qman_ceetm_configure_ccgr(struct qm_mcc_ceetm_ccgr_config *opts)
15043 +{
15044 + struct qm_mc_command *mcc;
15045 + struct qm_mc_result *mcr;
15046 + struct qman_portal *p;
15047 + unsigned long irqflags __maybe_unused;
15048 + u8 res;
15049 +
15050 + p = get_affine_portal();
15051 + PORTAL_IRQ_LOCK(p, irqflags);
15052 +
15053 + mcc = qm_mc_start(&p->p);
15054 + mcc->ccgr_config = *opts;
15055 +
15056 + qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_CONFIG);
15057 + while (!(mcr = qm_mc_result(&p->p)))
15058 + cpu_relax();
15059 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CCGR_CONFIG);
15060 +
15061 + PORTAL_IRQ_UNLOCK(p, irqflags);
15062 + put_affine_portal();
15063 +
15064 + res = mcr->result;
15065 + if (res != QM_MCR_RESULT_OK) {
15066 + pr_err("CEETM: CONFIGURE CCGR failed\n");
15067 + return -EIO;
15068 + }
15069 + return 0;
15070 +}
15071 +
15072 +int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query,
15073 + struct qm_mcr_ceetm_ccgr_query *response)
15074 +{
15075 + struct qm_mc_command *mcc;
15076 + struct qm_mc_result *mcr;
15077 + struct qman_portal *p;
15078 + unsigned long irqflags __maybe_unused;
15079 + u8 res;
15080 +
15081 + p = get_affine_portal();
15082 + PORTAL_IRQ_LOCK(p, irqflags);
15083 +
15084 + mcc = qm_mc_start(&p->p);
15085 + mcc->ccgr_query.ccgrid = cpu_to_be16(ccgr_query->ccgrid);
15086 + mcc->ccgr_query.dcpid = ccgr_query->dcpid;
15087 + qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY);
15088 +
15089 + while (!(mcr = qm_mc_result(&p->p)))
15090 + cpu_relax();
15091 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_CEETM_VERB_CCGR_QUERY);
15092 + res = mcr->result;
15093 + if (res == QM_MCR_RESULT_OK) {
15094 + *response = mcr->ccgr_query;
15095 + hw_ccgr_query_to_cpu(response);
15096 + }
15097 +
15098 + PORTAL_IRQ_UNLOCK(p, irqflags);
15099 + put_affine_portal();
15100 + if (res != QM_MCR_RESULT_OK) {
15101 + pr_err("CEETM: QUERY CCGR failed\n");
15102 + return -EIO;
15103 + }
15104 + return 0;
15105 +}
15106 +EXPORT_SYMBOL(qman_ceetm_query_ccgr);
15107 +
15108 +static int qman_ceetm_cq_peek_pop_xsfdrread(struct qm_ceetm_cq *cq,
15109 + u8 command_type, u16 xsfdr,
15110 + struct qm_mcr_ceetm_cq_peek_pop_xsfdrread *cq_ppxr)
15111 +{
15112 + struct qm_mc_command *mcc;
15113 + struct qm_mc_result *mcr;
15114 + struct qman_portal *p;
15115 + unsigned long irqflags __maybe_unused;
15116 + u8 res;
15117 +
15118 + p = get_affine_portal();
15119 + PORTAL_IRQ_LOCK(p, irqflags);
15120 +
15121 + mcc = qm_mc_start(&p->p);
15122 + switch (command_type) {
15123 + case 0:
15124 + case 1:
15125 + mcc->cq_ppxr.cqid = (cq->parent->idx << 4) | cq->idx;
15126 + break;
15127 + case 2:
15128 + mcc->cq_ppxr.xsfdr = xsfdr;
15129 + break;
15130 + default:
15131 + break;
15132 + }
15133 + mcc->cq_ppxr.ct = command_type;
15134 + mcc->cq_ppxr.dcpid = cq->parent->dcp_idx;
15135 + qm_mc_commit(&p->p, QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD);
15136 + while (!(mcr = qm_mc_result(&p->p)))
15137 + cpu_relax();
15138 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
15139 + QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD);
15140 +
15141 + PORTAL_IRQ_UNLOCK(p, irqflags);
15142 + put_affine_portal();
15143 +
15144 + res = mcr->result;
15145 + if (res != QM_MCR_RESULT_OK) {
15146 + pr_err("CEETM: CQ PEEK/POP/XSFDR READ failed\n");
15147 + return -EIO;
15148 + }
15149 + *cq_ppxr = mcr->cq_ppxr;
15150 + return 0;
15151 +}
15152 +
15153 +static int qman_ceetm_query_statistics(u16 cid,
15154 + enum qm_dc_portal dcp_idx,
15155 + u16 command_type,
15156 + struct qm_mcr_ceetm_statistics_query *query_result)
15157 +{
15158 + struct qm_mc_command *mcc;
15159 + struct qm_mc_result *mcr;
15160 + struct qman_portal *p;
15161 + unsigned long irqflags __maybe_unused;
15162 + u8 res;
15163 +
15164 + p = get_affine_portal();
15165 + PORTAL_IRQ_LOCK(p, irqflags);
15166 +
15167 + mcc = qm_mc_start(&p->p);
15168 + mcc->stats_query_write.cid = cid;
15169 + mcc->stats_query_write.dcpid = dcp_idx;
15170 + mcc->stats_query_write.ct = command_type;
15171 + qm_mc_commit(&p->p, QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
15172 +
15173 + while (!(mcr = qm_mc_result(&p->p)))
15174 + cpu_relax();
15175 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
15176 + QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
15177 +
15178 + PORTAL_IRQ_UNLOCK(p, irqflags);
15179 + put_affine_portal();
15180 +
15181 + res = mcr->result;
15182 + if (res != QM_MCR_RESULT_OK) {
15183 + pr_err("CEETM: STATISTICS QUERY failed\n");
15184 + return -EIO;
15185 + }
15186 + *query_result = mcr->stats_query;
15187 + return 0;
15188 +}
15189 +
15190 +int qman_ceetm_query_write_statistics(u16 cid, enum qm_dc_portal dcp_idx,
15191 + u16 command_type, u64 frame_count,
15192 + u64 byte_count)
15193 +{
15194 + struct qm_mc_command *mcc;
15195 + struct qm_mc_result *mcr;
15196 + struct qman_portal *p;
15197 + unsigned long irqflags __maybe_unused;
15198 + u8 res;
15199 +
15200 + p = get_affine_portal();
15201 + PORTAL_IRQ_LOCK(p, irqflags);
15202 +
15203 + mcc = qm_mc_start(&p->p);
15204 + mcc->stats_query_write.cid = cid;
15205 + mcc->stats_query_write.dcpid = dcp_idx;
15206 + mcc->stats_query_write.ct = command_type;
15207 + mcc->stats_query_write.frm_cnt = frame_count;
15208 + mcc->stats_query_write.byte_cnt = byte_count;
15209 + qm_mc_commit(&p->p, QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
15210 +
15211 + while (!(mcr = qm_mc_result(&p->p)))
15212 + cpu_relax();
15213 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
15214 + QM_CEETM_VERB_STATISTICS_QUERY_WRITE);
15215 +
15216 + PORTAL_IRQ_UNLOCK(p, irqflags);
15217 + put_affine_portal();
15218 +
15219 + res = mcr->result;
15220 + if (res != QM_MCR_RESULT_OK) {
15221 + pr_err("CEETM: STATISTICS WRITE failed\n");
15222 + return -EIO;
15223 + }
15224 + return 0;
15225 +}
15226 +EXPORT_SYMBOL(qman_ceetm_query_write_statistics);
15227 +
15228 +int qman_ceetm_bps2tokenrate(u64 bps, struct qm_ceetm_rate *token_rate,
15229 + int rounding)
15230 +{
15231 + u16 pres;
15232 + u64 temp;
15233 + u64 qman_freq;
15234 + int ret;
15235 +
15236 + /* Read PRES from CEET_CFG_PRES register */
15237 + ret = qman_ceetm_get_prescaler(&pres);
15238 + if (ret)
15239 + return -EINVAL;
15240 +
15241 + ret = qm_get_clock(&qman_freq);
15242 + if (ret)
15243 + return -EINVAL;
15244 +
15245 + /* token-rate = bytes-per-second * update-reference-period
15246 + *
15247 + * Where token-rate is N/8192 for a integer N, and
15248 + * update-reference-period is (2^22)/(PRES*QHz), where PRES
15249 + * is the prescalar value and QHz is the QMan clock frequency.
15250 + * So:
15251 + *
15252 + * token-rate = (byte-per-second*2^22)/PRES*QHZ)
15253 + *
15254 + * Converting to bits-per-second gives;
15255 + *
15256 + * token-rate = (bps*2^19) / (PRES*QHZ)
15257 + * N = (bps*2^32) / (PRES*QHz)
15258 + *
15259 + * And to avoid 64-bit overflow if 'bps' is larger than 4Gbps
15260 + * (yet minimise rounding error if 'bps' is small), we reorganise
15261 + * the formula to use two 16-bit shifts rather than 1 32-bit shift.
15262 + * N = (((bps*2^16)/PRES)*2^16)/QHz
15263 + */
15264 + temp = ROUNDING((bps << 16), pres, rounding);
15265 + temp = ROUNDING((temp << 16), qman_freq, rounding);
15266 + token_rate->whole = temp >> 13;
15267 + token_rate->fraction = temp & (((u64)1 << 13) - 1);
15268 + return 0;
15269 +}
15270 +EXPORT_SYMBOL(qman_ceetm_bps2tokenrate);
15271 +
15272 +int qman_ceetm_tokenrate2bps(const struct qm_ceetm_rate *token_rate, u64 *bps,
15273 + int rounding)
15274 +{
15275 + u16 pres;
15276 + u64 temp;
15277 + u64 qman_freq;
15278 + int ret;
15279 +
15280 + /* Read PRES from CEET_CFG_PRES register */
15281 + ret = qman_ceetm_get_prescaler(&pres);
15282 + if (ret)
15283 + return -EINVAL;
15284 +
15285 + ret = qm_get_clock(&qman_freq);
15286 + if (ret)
15287 + return -EINVAL;
15288 +
15289 + /* bytes-per-second = token-rate / update-reference-period
15290 + *
15291 + * where "token-rate" is N/8192 for an integer N, and
15292 + * "update-reference-period" is (2^22)/(PRES*QHz), where PRES is
15293 + * the prescalar value and QHz is the QMan clock frequency. So;
15294 + *
15295 + * bytes-per-second = (N/8192) / (4194304/PRES*QHz)
15296 + * = N*PRES*QHz / (4194304*8192)
15297 + * = N*PRES*QHz / (2^35)
15298 + *
15299 + * Converting to bits-per-second gives;
15300 + *
15301 + * bps = N*PRES*QHZ / (2^32)
15302 + *
15303 + * Note, the numerator has a maximum width of 72 bits! So to
15304 + * avoid 64-bit overflow errors, we calculate PRES*QHZ (maximum
15305 + * width 48 bits) divided by 2^9 (reducing to maximum 39 bits), before
15306 + * multiplying by N (goes to maximum of 63 bits).
15307 + *
15308 + * temp = PRES*QHZ / (2^16)
15309 + * kbps = temp*N / (2^16)
15310 + */
15311 + temp = ROUNDING(qman_freq * pres, (u64)1 << 16 , rounding);
15312 + temp *= ((token_rate->whole << 13) + token_rate->fraction);
15313 + *bps = ROUNDING(temp, (u64)(1) << 16, rounding);
15314 + return 0;
15315 +}
15316 +EXPORT_SYMBOL(qman_ceetm_tokenrate2bps);
15317 +
15318 +int qman_ceetm_sp_claim(struct qm_ceetm_sp **sp, enum qm_dc_portal dcp_idx,
15319 + unsigned int sp_idx)
15320 +{
15321 + struct qm_ceetm_sp *p;
15322 +
15323 + DPA_ASSERT((dcp_idx == qm_dc_portal_fman0) ||
15324 + (dcp_idx == qm_dc_portal_fman1));
15325 +
15326 + if ((sp_idx < qman_ceetms[dcp_idx].sp_range[0]) ||
15327 + (sp_idx > (qman_ceetms[dcp_idx].sp_range[0] +
15328 + qman_ceetms[dcp_idx].sp_range[1]))) {
15329 + pr_err("Sub-portal index doesn't exist\n");
15330 + return -EINVAL;
15331 + }
15332 +
15333 + list_for_each_entry(p, &qman_ceetms[dcp_idx].sub_portals, node) {
15334 + if ((p->idx == sp_idx) && (p->is_claimed == 0)) {
15335 + p->is_claimed = 1;
15336 + *sp = p;
15337 + return 0;
15338 + }
15339 + }
15340 + pr_err("The sub-portal#%d is not available!\n", sp_idx);
15341 + return -ENODEV;
15342 +}
15343 +EXPORT_SYMBOL(qman_ceetm_sp_claim);
15344 +
15345 +int qman_ceetm_sp_release(struct qm_ceetm_sp *sp)
15346 +{
15347 + struct qm_ceetm_sp *p;
15348 +
15349 + if (sp->lni && sp->lni->is_claimed == 1) {
15350 + pr_err("The dependency of sub-portal has not been released!\n");
15351 + return -EBUSY;
15352 + }
15353 +
15354 + list_for_each_entry(p, &qman_ceetms[sp->dcp_idx].sub_portals, node) {
15355 + if (p->idx == sp->idx) {
15356 + p->is_claimed = 0;
15357 + p->lni = NULL;
15358 + }
15359 + }
15360 + /* Disable CEETM mode of this sub-portal */
15361 + qman_sp_disable_ceetm_mode(sp->dcp_idx, sp->idx);
15362 +
15363 + return 0;
15364 +}
15365 +EXPORT_SYMBOL(qman_ceetm_sp_release);
15366 +
15367 +int qman_ceetm_lni_claim(struct qm_ceetm_lni **lni, enum qm_dc_portal dcp_idx,
15368 + unsigned int lni_idx)
15369 +{
15370 + struct qm_ceetm_lni *p;
15371 +
15372 + if ((lni_idx < qman_ceetms[dcp_idx].lni_range[0]) ||
15373 + (lni_idx > (qman_ceetms[dcp_idx].lni_range[0] +
15374 + qman_ceetms[dcp_idx].lni_range[1]))) {
15375 + pr_err("The lni index is out of range\n");
15376 + return -EINVAL;
15377 + }
15378 +
15379 + list_for_each_entry(p, &qman_ceetms[dcp_idx].lnis, node) {
15380 + if ((p->idx == lni_idx) && (p->is_claimed == 0)) {
15381 + *lni = p;
15382 + p->is_claimed = 1;
15383 + return 0;
15384 + }
15385 + }
15386 +
15387 + pr_err("The LNI#%d is not available!\n", lni_idx);
15388 + return -EINVAL;
15389 +}
15390 +EXPORT_SYMBOL(qman_ceetm_lni_claim);
15391 +
15392 +int qman_ceetm_lni_release(struct qm_ceetm_lni *lni)
15393 +{
15394 + struct qm_ceetm_lni *p;
15395 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15396 +
15397 + if (!list_empty(&lni->channels)) {
15398 + pr_err("The LNI dependencies are not released!\n");
15399 + return -EBUSY;
15400 + }
15401 +
15402 + list_for_each_entry(p, &qman_ceetms[lni->dcp_idx].lnis, node) {
15403 + if (p->idx == lni->idx) {
15404 + p->shaper_enable = 0;
15405 + p->shaper_couple = 0;
15406 + p->cr_token_rate.whole = 0;
15407 + p->cr_token_rate.fraction = 0;
15408 + p->er_token_rate.whole = 0;
15409 + p->er_token_rate.fraction = 0;
15410 + p->cr_token_bucket_limit = 0;
15411 + p->er_token_bucket_limit = 0;
15412 + p->is_claimed = 0;
15413 + }
15414 + }
15415 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15416 + config_opts.dcpid = lni->dcp_idx;
15417 + memset(&config_opts.shaper_config, 0,
15418 + sizeof(config_opts.shaper_config));
15419 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15420 +}
15421 +EXPORT_SYMBOL(qman_ceetm_lni_release);
15422 +
15423 +int qman_ceetm_sp_set_lni(struct qm_ceetm_sp *sp, struct qm_ceetm_lni *lni)
15424 +{
15425 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15426 +
15427 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_SP_MAPPING | sp->idx);
15428 + config_opts.dcpid = sp->dcp_idx;
15429 + config_opts.sp_mapping.map_lni_id = lni->idx;
15430 + sp->lni = lni;
15431 +
15432 + if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts))
15433 + return -EINVAL;
15434 +
15435 + /* Enable CEETM mode for this sub-portal */
15436 + return qman_sp_enable_ceetm_mode(sp->dcp_idx, sp->idx);
15437 +}
15438 +EXPORT_SYMBOL(qman_ceetm_sp_set_lni);
15439 +
15440 +int qman_ceetm_sp_get_lni(struct qm_ceetm_sp *sp, unsigned int *lni_idx)
15441 +{
15442 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15443 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15444 +
15445 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_SP_MAPPING | sp->idx);
15446 + query_opts.dcpid = sp->dcp_idx;
15447 + if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
15448 + pr_err("Can't get SP <-> LNI mapping\n");
15449 + return -EINVAL;
15450 + }
15451 + *lni_idx = query_result.sp_mapping_query.map_lni_id;
15452 + sp->lni->idx = query_result.sp_mapping_query.map_lni_id;
15453 + return 0;
15454 +}
15455 +EXPORT_SYMBOL(qman_ceetm_sp_get_lni);
15456 +
15457 +int qman_ceetm_lni_enable_shaper(struct qm_ceetm_lni *lni, int coupled,
15458 + int oal)
15459 +{
15460 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15461 +
15462 + lni->shaper_enable = 1;
15463 + lni->shaper_couple = coupled;
15464 + lni->oal = oal;
15465 +
15466 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15467 + config_opts.dcpid = lni->dcp_idx;
15468 + config_opts.shaper_config.cpl = coupled;
15469 + config_opts.shaper_config.oal = oal;
15470 + config_opts.shaper_config.crtcr = cpu_to_be24((lni->cr_token_rate.whole
15471 + << 13) | lni->cr_token_rate.fraction);
15472 + config_opts.shaper_config.ertcr = cpu_to_be24((lni->er_token_rate.whole
15473 + << 13) | lni->er_token_rate.fraction);
15474 + config_opts.shaper_config.crtbl =
15475 + cpu_to_be16(lni->cr_token_bucket_limit);
15476 + config_opts.shaper_config.ertbl =
15477 + cpu_to_be16(lni->er_token_bucket_limit);
15478 + config_opts.shaper_config.mps = 60;
15479 +
15480 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15481 +}
15482 +EXPORT_SYMBOL(qman_ceetm_lni_enable_shaper);
15483 +
15484 +int qman_ceetm_lni_disable_shaper(struct qm_ceetm_lni *lni)
15485 +{
15486 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15487 +
15488 + if (!lni->shaper_enable) {
15489 + pr_err("The shaper has been disabled\n");
15490 + return -EINVAL;
15491 + }
15492 +
15493 + config_opts.cid = CEETM_COMMAND_LNI_SHAPER | lni->idx;
15494 + config_opts.dcpid = lni->dcp_idx;
15495 + config_opts.shaper_config.cpl = (lni->shaper_couple << 7) | lni->oal;
15496 + config_opts.shaper_config.crtbl = lni->cr_token_bucket_limit;
15497 + config_opts.shaper_config.ertbl = lni->er_token_bucket_limit;
15498 + /* Set CR/ER rate with all 1's to configure an infinite rate, thus
15499 + * disable the shaping.
15500 + */
15501 + config_opts.shaper_config.crtcr = 0xFFFFFF;
15502 + config_opts.shaper_config.ertcr = 0xFFFFFF;
15503 + config_opts.shaper_config.mps = 60;
15504 + lni->shaper_enable = 0;
15505 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15506 +}
15507 +EXPORT_SYMBOL(qman_ceetm_lni_disable_shaper);
15508 +
15509 +int qman_ceetm_lni_is_shaper_enabled(struct qm_ceetm_lni *lni)
15510 +{
15511 + return lni->shaper_enable;
15512 +}
15513 +EXPORT_SYMBOL(qman_ceetm_lni_is_shaper_enabled);
15514 +
15515 +int qman_ceetm_lni_set_commit_rate(struct qm_ceetm_lni *lni,
15516 + const struct qm_ceetm_rate *token_rate,
15517 + u16 token_limit)
15518 +{
15519 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15520 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15521 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15522 + int ret;
15523 +
15524 + lni->cr_token_rate.whole = token_rate->whole;
15525 + lni->cr_token_rate.fraction = token_rate->fraction;
15526 + lni->cr_token_bucket_limit = token_limit;
15527 + if (!lni->shaper_enable)
15528 + return 0;
15529 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15530 + query_opts.dcpid = lni->dcp_idx;
15531 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts,
15532 + &query_result);
15533 + if (ret) {
15534 + pr_err("Fail to get current LNI shaper setting\n");
15535 + return -EINVAL;
15536 + }
15537 +
15538 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15539 + config_opts.dcpid = lni->dcp_idx;
15540 + config_opts.shaper_config.crtcr = cpu_to_be24((token_rate->whole << 13)
15541 + | (token_rate->fraction));
15542 + config_opts.shaper_config.crtbl = cpu_to_be16(token_limit);
15543 + config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
15544 + config_opts.shaper_config.oal = query_result.shaper_query.oal;
15545 + config_opts.shaper_config.ertcr = query_result.shaper_query.ertcr;
15546 + config_opts.shaper_config.ertbl = query_result.shaper_query.ertbl;
15547 + config_opts.shaper_config.mps = query_result.shaper_query.mps;
15548 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15549 +}
15550 +EXPORT_SYMBOL(qman_ceetm_lni_set_commit_rate);
15551 +
15552 +int qman_ceetm_lni_set_commit_rate_bps(struct qm_ceetm_lni *lni,
15553 + u64 bps,
15554 + u16 token_limit)
15555 +{
15556 + struct qm_ceetm_rate token_rate;
15557 + int ret;
15558 +
15559 + ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
15560 + if (ret) {
15561 + pr_err("Can not convert bps to token rate\n");
15562 + return -EINVAL;
15563 + }
15564 +
15565 + return qman_ceetm_lni_set_commit_rate(lni, &token_rate, token_limit);
15566 +}
15567 +EXPORT_SYMBOL(qman_ceetm_lni_set_commit_rate_bps);
15568 +
15569 +int qman_ceetm_lni_get_commit_rate(struct qm_ceetm_lni *lni,
15570 + struct qm_ceetm_rate *token_rate,
15571 + u16 *token_limit)
15572 +{
15573 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15574 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15575 + int ret;
15576 +
15577 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15578 + query_opts.dcpid = lni->dcp_idx;
15579 +
15580 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
15581 + if (ret) {
15582 + pr_err("The LNI CR rate or limit is not set\n");
15583 + return -EINVAL;
15584 + }
15585 + token_rate->whole = be24_to_cpu(query_result.shaper_query.crtcr) >> 13;
15586 + token_rate->fraction = be24_to_cpu(query_result.shaper_query.crtcr) &
15587 + 0x1FFF;
15588 + *token_limit = be16_to_cpu(query_result.shaper_query.crtbl);
15589 + return 0;
15590 +}
15591 +EXPORT_SYMBOL(qman_ceetm_lni_get_commit_rate);
15592 +
15593 +int qman_ceetm_lni_get_commit_rate_bps(struct qm_ceetm_lni *lni,
15594 + u64 *bps, u16 *token_limit)
15595 +{
15596 + struct qm_ceetm_rate token_rate;
15597 + int ret;
15598 +
15599 + ret = qman_ceetm_lni_get_commit_rate(lni, &token_rate, token_limit);
15600 + if (ret) {
15601 + pr_err("The LNI CR rate or limit is not available\n");
15602 + return -EINVAL;
15603 + }
15604 +
15605 + return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
15606 +}
15607 +EXPORT_SYMBOL(qman_ceetm_lni_get_commit_rate_bps);
15608 +
15609 +int qman_ceetm_lni_set_excess_rate(struct qm_ceetm_lni *lni,
15610 + const struct qm_ceetm_rate *token_rate,
15611 + u16 token_limit)
15612 +{
15613 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15614 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15615 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15616 + int ret;
15617 +
15618 + lni->er_token_rate.whole = token_rate->whole;
15619 + lni->er_token_rate.fraction = token_rate->fraction;
15620 + lni->er_token_bucket_limit = token_limit;
15621 + if (!lni->shaper_enable)
15622 + return 0;
15623 +
15624 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15625 + query_opts.dcpid = lni->dcp_idx;
15626 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts,
15627 + &query_result);
15628 + if (ret) {
15629 + pr_err("Fail to get current LNI shaper setting\n");
15630 + return -EINVAL;
15631 + }
15632 +
15633 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15634 + config_opts.dcpid = lni->dcp_idx;
15635 + config_opts.shaper_config.ertcr = cpu_to_be24(
15636 + (token_rate->whole << 13) | (token_rate->fraction));
15637 + config_opts.shaper_config.ertbl = cpu_to_be16(token_limit);
15638 + config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
15639 + config_opts.shaper_config.oal = query_result.shaper_query.oal;
15640 + config_opts.shaper_config.crtcr = query_result.shaper_query.crtcr;
15641 + config_opts.shaper_config.crtbl = query_result.shaper_query.crtbl;
15642 + config_opts.shaper_config.mps = query_result.shaper_query.mps;
15643 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15644 +}
15645 +EXPORT_SYMBOL(qman_ceetm_lni_set_excess_rate);
15646 +
15647 +int qman_ceetm_lni_set_excess_rate_bps(struct qm_ceetm_lni *lni,
15648 + u64 bps,
15649 + u16 token_limit)
15650 +{
15651 + struct qm_ceetm_rate token_rate;
15652 + int ret;
15653 +
15654 + ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
15655 + if (ret) {
15656 + pr_err("Can not convert bps to token rate\n");
15657 + return -EINVAL;
15658 + }
15659 + return qman_ceetm_lni_set_excess_rate(lni, &token_rate, token_limit);
15660 +}
15661 +EXPORT_SYMBOL(qman_ceetm_lni_set_excess_rate_bps);
15662 +
15663 +int qman_ceetm_lni_get_excess_rate(struct qm_ceetm_lni *lni,
15664 + struct qm_ceetm_rate *token_rate,
15665 + u16 *token_limit)
15666 +{
15667 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15668 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15669 + int ret;
15670 +
15671 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_LNI_SHAPER | lni->idx);
15672 + query_opts.dcpid = lni->dcp_idx;
15673 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
15674 + if (ret) {
15675 + pr_err("The LNI ER rate or limit is not set\n");
15676 + return -EINVAL;
15677 + }
15678 + token_rate->whole = be24_to_cpu(query_result.shaper_query.ertcr) >> 13;
15679 + token_rate->fraction = be24_to_cpu(query_result.shaper_query.ertcr) &
15680 + 0x1FFF;
15681 + *token_limit = be16_to_cpu(query_result.shaper_query.ertbl);
15682 + return 0;
15683 +}
15684 +EXPORT_SYMBOL(qman_ceetm_lni_get_excess_rate);
15685 +
15686 +int qman_ceetm_lni_get_excess_rate_bps(struct qm_ceetm_lni *lni,
15687 + u64 *bps, u16 *token_limit)
15688 +{
15689 + struct qm_ceetm_rate token_rate;
15690 + int ret;
15691 +
15692 + ret = qman_ceetm_lni_get_excess_rate(lni, &token_rate, token_limit);
15693 + if (ret) {
15694 + pr_err("The LNI ER rate or limit is not available\n");
15695 + return -EINVAL;
15696 + }
15697 +
15698 + return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
15699 +}
15700 +EXPORT_SYMBOL(qman_ceetm_lni_get_excess_rate_bps);
15701 +
15702 +#define QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(n) ((15 - n) * 4)
15703 +#define QMAN_CEETM_LNITCFCC_ENABLE 0x8
15704 +int qman_ceetm_lni_set_tcfcc(struct qm_ceetm_lni *lni,
15705 + unsigned int cq_level,
15706 + int traffic_class)
15707 +{
15708 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15709 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15710 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15711 + u64 lnitcfcc;
15712 +
15713 + if ((cq_level > 15) | (traffic_class > 7)) {
15714 + pr_err("The CQ or traffic class id is out of range\n");
15715 + return -EINVAL;
15716 + }
15717 +
15718 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx);
15719 + query_opts.dcpid = lni->dcp_idx;
15720 + if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
15721 + pr_err("Fail to query tcfcc\n");
15722 + return -EINVAL;
15723 + }
15724 +
15725 + lnitcfcc = be64_to_cpu(query_result.tcfc_query.lnitcfcc);
15726 + if (traffic_class == -1) {
15727 + /* disable tcfc for this CQ */
15728 + lnitcfcc &= ~((u64)QMAN_CEETM_LNITCFCC_ENABLE <<
15729 + QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level));
15730 + } else {
15731 + lnitcfcc &= ~((u64)0xF <<
15732 + QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level));
15733 + lnitcfcc |= ((u64)(QMAN_CEETM_LNITCFCC_ENABLE |
15734 + traffic_class)) <<
15735 + QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level);
15736 + }
15737 + config_opts.tcfc_config.lnitcfcc = cpu_to_be64(lnitcfcc);
15738 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx);
15739 + config_opts.dcpid = lni->dcp_idx;
15740 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15741 +}
15742 +EXPORT_SYMBOL(qman_ceetm_lni_set_tcfcc);
15743 +
15744 +#define QMAN_CEETM_LNITCFCC_TC_MASK 0x7
15745 +int qman_ceetm_lni_get_tcfcc(struct qm_ceetm_lni *lni, unsigned int cq_level,
15746 + int *traffic_class)
15747 +{
15748 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15749 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15750 + int ret;
15751 + u8 lnitcfcc;
15752 +
15753 + if (cq_level > 15) {
15754 + pr_err("the CQ level is out of range\n");
15755 + return -EINVAL;
15756 + }
15757 +
15758 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_TCFC | lni->idx);
15759 + query_opts.dcpid = lni->dcp_idx;
15760 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
15761 + if (ret)
15762 + return ret;
15763 + lnitcfcc = (u8)be64_to_cpu((query_result.tcfc_query.lnitcfcc) >>
15764 + QMAN_CEETM_LNITCFCC_CQ_LEVEL_SHIFT(cq_level));
15765 + if (lnitcfcc & QMAN_CEETM_LNITCFCC_ENABLE)
15766 + *traffic_class = lnitcfcc & QMAN_CEETM_LNITCFCC_TC_MASK;
15767 + else
15768 + *traffic_class = -1;
15769 + return 0;
15770 +}
15771 +EXPORT_SYMBOL(qman_ceetm_lni_get_tcfcc);
15772 +
15773 +int qman_ceetm_channel_claim(struct qm_ceetm_channel **channel,
15774 + struct qm_ceetm_lni *lni)
15775 +{
15776 + struct qm_ceetm_channel *p;
15777 + u32 channel_idx;
15778 + int ret = 0;
15779 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15780 +
15781 + if (lni->dcp_idx == qm_dc_portal_fman0) {
15782 + ret = qman_alloc_ceetm0_channel(&channel_idx);
15783 + } else if (lni->dcp_idx == qm_dc_portal_fman1) {
15784 + ret = qman_alloc_ceetm1_channel(&channel_idx);
15785 + } else {
15786 + pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
15787 + lni->dcp_idx);
15788 + return -EINVAL;
15789 + }
15790 +
15791 + if (ret) {
15792 + pr_err("The is no channel available for LNI#%d\n", lni->idx);
15793 + return -ENODEV;
15794 + }
15795 +
15796 + p = kzalloc(sizeof(*p), GFP_KERNEL);
15797 + if (!p)
15798 + return -ENOMEM;
15799 + p->idx = channel_idx;
15800 + p->dcp_idx = lni->dcp_idx;
15801 + list_add_tail(&p->node, &lni->channels);
15802 + INIT_LIST_HEAD(&p->class_queues);
15803 + INIT_LIST_HEAD(&p->ccgs);
15804 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
15805 + channel_idx);
15806 + config_opts.dcpid = lni->dcp_idx;
15807 + config_opts.channel_mapping.map_lni_id = lni->idx;
15808 + config_opts.channel_mapping.map_shaped = 0;
15809 + if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) {
15810 + pr_err("Can't map channel#%d for LNI#%d\n",
15811 + channel_idx, lni->idx);
15812 + return -EINVAL;
15813 + }
15814 + *channel = p;
15815 + return 0;
15816 +}
15817 +EXPORT_SYMBOL(qman_ceetm_channel_claim);
15818 +
15819 +int qman_ceetm_channel_release(struct qm_ceetm_channel *channel)
15820 +{
15821 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15822 + if (!list_empty(&channel->class_queues)) {
15823 + pr_err("CEETM channel#%d has class queue unreleased!\n",
15824 + channel->idx);
15825 + return -EBUSY;
15826 + }
15827 + if (!list_empty(&channel->ccgs)) {
15828 + pr_err("CEETM channel#%d has ccg unreleased!\n",
15829 + channel->idx);
15830 + return -EBUSY;
15831 + }
15832 +
15833 + /* channel->dcp_idx corresponds to known fman validation */
15834 + if ((channel->dcp_idx != qm_dc_portal_fman0) &&
15835 + (channel->dcp_idx != qm_dc_portal_fman1)) {
15836 + pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
15837 + channel->dcp_idx);
15838 + return -EINVAL;
15839 + }
15840 +
15841 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
15842 + channel->idx);
15843 + config_opts.dcpid = channel->dcp_idx;
15844 + memset(&config_opts.shaper_config, 0,
15845 + sizeof(config_opts.shaper_config));
15846 + if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) {
15847 + pr_err("Can't reset channel shapping parameters\n");
15848 + return -EINVAL;
15849 + }
15850 +
15851 + if (channel->dcp_idx == qm_dc_portal_fman0) {
15852 + qman_release_ceetm0_channelid(channel->idx);
15853 + } else if (channel->dcp_idx == qm_dc_portal_fman1) {
15854 + qman_release_ceetm1_channelid(channel->idx);
15855 + } else {
15856 + pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
15857 + channel->dcp_idx);
15858 + return -EINVAL;
15859 + }
15860 + list_del(&channel->node);
15861 + kfree(channel);
15862 +
15863 + return 0;
15864 +}
15865 +EXPORT_SYMBOL(qman_ceetm_channel_release);
15866 +
15867 +int qman_ceetm_channel_enable_shaper(struct qm_ceetm_channel *channel,
15868 + int coupled)
15869 +{
15870 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15871 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15872 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15873 +
15874 + if (channel->shaper_enable == 1) {
15875 + pr_err("This channel shaper has been enabled!\n");
15876 + return -EINVAL;
15877 + }
15878 +
15879 + channel->shaper_enable = 1;
15880 + channel->shaper_couple = coupled;
15881 +
15882 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
15883 + channel->idx);
15884 + query_opts.dcpid = (u8)channel->dcp_idx;
15885 +
15886 + if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
15887 + pr_err("Can't query channel mapping\n");
15888 + return -EINVAL;
15889 + }
15890 +
15891 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
15892 + channel->idx);
15893 + config_opts.dcpid = channel->dcp_idx;
15894 + config_opts.channel_mapping.map_lni_id =
15895 + query_result.channel_mapping_query.map_lni_id;
15896 + config_opts.channel_mapping.map_shaped = 1;
15897 + if (qman_ceetm_configure_mapping_shaper_tcfc(&config_opts)) {
15898 + pr_err("Can't enable shaper for channel #%d\n", channel->idx);
15899 + return -EINVAL;
15900 + }
15901 +
15902 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
15903 + channel->idx);
15904 + config_opts.shaper_config.cpl = coupled;
15905 + config_opts.shaper_config.crtcr = cpu_to_be24((channel->cr_token_rate.
15906 + whole << 13) |
15907 + channel->cr_token_rate.fraction);
15908 + config_opts.shaper_config.ertcr = cpu_to_be24((channel->er_token_rate.
15909 + whole << 13) |
15910 + channel->er_token_rate.fraction);
15911 + config_opts.shaper_config.crtbl =
15912 + cpu_to_be16(channel->cr_token_bucket_limit);
15913 + config_opts.shaper_config.ertbl =
15914 + cpu_to_be16(channel->er_token_bucket_limit);
15915 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15916 +}
15917 +EXPORT_SYMBOL(qman_ceetm_channel_enable_shaper);
15918 +
15919 +int qman_ceetm_channel_disable_shaper(struct qm_ceetm_channel *channel)
15920 +{
15921 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15922 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15923 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15924 +
15925 +
15926 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
15927 + channel->idx);
15928 + query_opts.dcpid = channel->dcp_idx;
15929 +
15930 + if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
15931 + pr_err("Can't query channel mapping\n");
15932 + return -EINVAL;
15933 + }
15934 +
15935 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_MAPPING |
15936 + channel->idx);
15937 + config_opts.dcpid = channel->dcp_idx;
15938 + config_opts.channel_mapping.map_shaped = 0;
15939 + config_opts.channel_mapping.map_lni_id =
15940 + query_result.channel_mapping_query.map_lni_id;
15941 +
15942 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15943 +}
15944 +EXPORT_SYMBOL(qman_ceetm_channel_disable_shaper);
15945 +
15946 +int qman_ceetm_channel_is_shaper_enabled(struct qm_ceetm_channel *channel)
15947 +{
15948 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15949 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15950 +
15951 + query_opts.cid = CEETM_COMMAND_CHANNEL_MAPPING | channel->idx;
15952 + query_opts.dcpid = channel->dcp_idx;
15953 +
15954 + if (qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result)) {
15955 + pr_err("Can't query channel mapping\n");
15956 + return -EINVAL;
15957 + }
15958 +
15959 + return query_result.channel_mapping_query.map_shaped;
15960 +}
15961 +EXPORT_SYMBOL(qman_ceetm_channel_is_shaper_enabled);
15962 +
15963 +int qman_ceetm_channel_set_commit_rate(struct qm_ceetm_channel *channel,
15964 + const struct qm_ceetm_rate *token_rate,
15965 + u16 token_limit)
15966 +{
15967 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
15968 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
15969 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
15970 + int ret;
15971 +
15972 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
15973 + channel->idx);
15974 + query_opts.dcpid = channel->dcp_idx;
15975 +
15976 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
15977 + if (ret) {
15978 + pr_err("Fail to get the current channel shaper setting\n");
15979 + return -EINVAL;
15980 + }
15981 +
15982 + channel->cr_token_rate.whole = token_rate->whole;
15983 + channel->cr_token_rate.fraction = token_rate->fraction;
15984 + channel->cr_token_bucket_limit = token_limit;
15985 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
15986 + channel->idx);
15987 + config_opts.dcpid = channel->dcp_idx;
15988 + config_opts.shaper_config.crtcr = cpu_to_be24((token_rate->whole
15989 + << 13) | (token_rate->fraction));
15990 + config_opts.shaper_config.crtbl = cpu_to_be16(token_limit);
15991 + config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
15992 + config_opts.shaper_config.ertcr = query_result.shaper_query.ertcr;
15993 + config_opts.shaper_config.ertbl = query_result.shaper_query.ertbl;
15994 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
15995 +}
15996 +EXPORT_SYMBOL(qman_ceetm_channel_set_commit_rate);
15997 +
15998 +int qman_ceetm_channel_set_commit_rate_bps(struct qm_ceetm_channel *channel,
15999 + u64 bps, u16 token_limit)
16000 +{
16001 + struct qm_ceetm_rate token_rate;
16002 + int ret;
16003 +
16004 + ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
16005 + if (ret) {
16006 + pr_err("Can not convert bps to token rate\n");
16007 + return -EINVAL;
16008 + }
16009 + return qman_ceetm_channel_set_commit_rate(channel, &token_rate,
16010 + token_limit);
16011 +}
16012 +EXPORT_SYMBOL(qman_ceetm_channel_set_commit_rate_bps);
16013 +
16014 +int qman_ceetm_channel_get_commit_rate(struct qm_ceetm_channel *channel,
16015 + struct qm_ceetm_rate *token_rate,
16016 + u16 *token_limit)
16017 +{
16018 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
16019 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
16020 + int ret;
16021 +
16022 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
16023 + channel->idx);
16024 + query_opts.dcpid = channel->dcp_idx;
16025 +
16026 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
16027 + if (ret | !query_result.shaper_query.crtcr |
16028 + !query_result.shaper_query.crtbl) {
16029 + pr_err("The channel commit rate or limit is not set\n");
16030 + return -EINVAL;
16031 + }
16032 + token_rate->whole = be24_to_cpu(query_result.shaper_query.crtcr) >> 13;
16033 + token_rate->fraction = be24_to_cpu(query_result.shaper_query.crtcr) &
16034 + 0x1FFF;
16035 + *token_limit = be16_to_cpu(query_result.shaper_query.crtbl);
16036 + return 0;
16037 +}
16038 +EXPORT_SYMBOL(qman_ceetm_channel_get_commit_rate);
16039 +
16040 +int qman_ceetm_channel_get_commit_rate_bps(struct qm_ceetm_channel *channel,
16041 + u64 *bps, u16 *token_limit)
16042 +{
16043 + struct qm_ceetm_rate token_rate;
16044 + int ret;
16045 +
16046 + ret = qman_ceetm_channel_get_commit_rate(channel, &token_rate,
16047 + token_limit);
16048 + if (ret) {
16049 + pr_err("The channel CR rate or limit is not available\n");
16050 + return -EINVAL;
16051 + }
16052 +
16053 + return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
16054 +}
16055 +EXPORT_SYMBOL(qman_ceetm_channel_get_commit_rate_bps);
16056 +
16057 +int qman_ceetm_channel_set_excess_rate(struct qm_ceetm_channel *channel,
16058 + const struct qm_ceetm_rate *token_rate,
16059 + u16 token_limit)
16060 +{
16061 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
16062 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
16063 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
16064 + int ret;
16065 +
16066 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
16067 + channel->idx);
16068 + query_opts.dcpid = channel->dcp_idx;
16069 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
16070 + if (ret) {
16071 + pr_err("Fail to get the current channel shaper setting\n");
16072 + return -EINVAL;
16073 + }
16074 +
16075 + channel->er_token_rate.whole = token_rate->whole;
16076 + channel->er_token_rate.fraction = token_rate->fraction;
16077 + channel->er_token_bucket_limit = token_limit;
16078 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
16079 + channel->idx);
16080 + config_opts.dcpid = channel->dcp_idx;
16081 + config_opts.shaper_config.ertcr = cpu_to_be24(
16082 + (token_rate->whole << 13) | (token_rate->fraction));
16083 + config_opts.shaper_config.ertbl = cpu_to_be16(token_limit);
16084 + config_opts.shaper_config.cpl = query_result.shaper_query.cpl;
16085 + config_opts.shaper_config.crtcr = query_result.shaper_query.crtcr;
16086 + config_opts.shaper_config.crtbl = query_result.shaper_query.crtbl;
16087 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
16088 +}
16089 +EXPORT_SYMBOL(qman_ceetm_channel_set_excess_rate);
16090 +
16091 +int qman_ceetm_channel_set_excess_rate_bps(struct qm_ceetm_channel *channel,
16092 + u64 bps, u16 token_limit)
16093 +{
16094 + struct qm_ceetm_rate token_rate;
16095 + int ret;
16096 +
16097 + ret = qman_ceetm_bps2tokenrate(bps, &token_rate, 0);
16098 + if (ret) {
16099 + pr_err("Can not convert bps to token rate\n");
16100 + return -EINVAL;
16101 + }
16102 + return qman_ceetm_channel_set_excess_rate(channel, &token_rate,
16103 + token_limit);
16104 +}
16105 +EXPORT_SYMBOL(qman_ceetm_channel_set_excess_rate_bps);
16106 +
16107 +int qman_ceetm_channel_get_excess_rate(struct qm_ceetm_channel *channel,
16108 + struct qm_ceetm_rate *token_rate,
16109 + u16 *token_limit)
16110 +{
16111 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
16112 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
16113 + int ret;
16114 +
16115 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
16116 + channel->idx);
16117 + query_opts.dcpid = channel->dcp_idx;
16118 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
16119 + if (ret | !query_result.shaper_query.ertcr |
16120 + !query_result.shaper_query.ertbl) {
16121 + pr_err("The channel excess rate or limit is not set\n");
16122 + return -EINVAL;
16123 + }
16124 + token_rate->whole = be24_to_cpu(query_result.shaper_query.ertcr) >> 13;
16125 + token_rate->fraction = be24_to_cpu(query_result.shaper_query.ertcr) &
16126 + 0x1FFF;
16127 + *token_limit = be16_to_cpu(query_result.shaper_query.ertbl);
16128 + return 0;
16129 +}
16130 +EXPORT_SYMBOL(qman_ceetm_channel_get_excess_rate);
16131 +
16132 +int qman_ceetm_channel_get_excess_rate_bps(struct qm_ceetm_channel *channel,
16133 + u64 *bps, u16 *token_limit)
16134 +{
16135 + struct qm_ceetm_rate token_rate;
16136 + int ret;
16137 +
16138 + ret = qman_ceetm_channel_get_excess_rate(channel, &token_rate,
16139 + token_limit);
16140 + if (ret) {
16141 + pr_err("The channel ER rate or limit is not available\n");
16142 + return -EINVAL;
16143 + }
16144 +
16145 + return qman_ceetm_tokenrate2bps(&token_rate, bps, 0);
16146 +}
16147 +EXPORT_SYMBOL(qman_ceetm_channel_get_excess_rate_bps);
16148 +
16149 +int qman_ceetm_channel_set_weight(struct qm_ceetm_channel *channel,
16150 + u16 token_limit)
16151 +{
16152 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config config_opts;
16153 +
16154 + if (channel->shaper_enable) {
16155 + pr_err("This channel is a shaped one\n");
16156 + return -EINVAL;
16157 + }
16158 +
16159 + channel->cr_token_bucket_limit = token_limit;
16160 + config_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
16161 + channel->idx);
16162 + config_opts.dcpid = channel->dcp_idx;
16163 + config_opts.shaper_config.crtbl = cpu_to_be16(token_limit);
16164 + return qman_ceetm_configure_mapping_shaper_tcfc(&config_opts);
16165 +}
16166 +EXPORT_SYMBOL(qman_ceetm_channel_set_weight);
16167 +
16168 +int qman_ceetm_channel_get_weight(struct qm_ceetm_channel *channel,
16169 + u16 *token_limit)
16170 +{
16171 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query query_opts;
16172 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query query_result;
16173 + int ret;
16174 +
16175 + query_opts.cid = cpu_to_be16(CEETM_COMMAND_CHANNEL_SHAPER |
16176 + channel->idx);
16177 + query_opts.dcpid = channel->dcp_idx;
16178 + ret = qman_ceetm_query_mapping_shaper_tcfc(&query_opts, &query_result);
16179 + if (ret | !query_result.shaper_query.crtbl) {
16180 + pr_err("This unshaped channel's uFQ wight is unavailable\n");
16181 + return -EINVAL;
16182 + }
16183 + *token_limit = be16_to_cpu(query_result.shaper_query.crtbl);
16184 + return 0;
16185 +}
16186 +EXPORT_SYMBOL(qman_ceetm_channel_get_weight);
16187 +
16188 +int qman_ceetm_channel_set_group(struct qm_ceetm_channel *channel, int group_b,
16189 + unsigned int prio_a, unsigned int prio_b)
16190 +{
16191 + struct qm_mcc_ceetm_class_scheduler_config config_opts;
16192 + struct qm_mcr_ceetm_class_scheduler_query query_result;
16193 + int i;
16194 +
16195 + if (prio_a > 7) {
16196 + pr_err("The priority of group A is out of range\n");
16197 + return -EINVAL;
16198 + }
16199 + if (group_b && (prio_b > 7)) {
16200 + pr_err("The priority of group B is out of range\n");
16201 + return -EINVAL;
16202 + }
16203 +
16204 + if (qman_ceetm_query_class_scheduler(channel, &query_result)) {
16205 + pr_err("Can't query channel#%d's scheduler!\n", channel->idx);
16206 + return -EINVAL;
16207 + }
16208 +
16209 + config_opts.cqcid = cpu_to_be16(channel->idx);
16210 + config_opts.dcpid = channel->dcp_idx;
16211 + config_opts.gpc_combine_flag = !group_b;
16212 + config_opts.gpc_prio_a = prio_a;
16213 + config_opts.gpc_prio_b = prio_b;
16214 +
16215 + for (i = 0; i < 8; i++)
16216 + config_opts.w[i] = query_result.w[i];
16217 + config_opts.crem = query_result.crem;
16218 + config_opts.erem = query_result.erem;
16219 +
16220 + return qman_ceetm_configure_class_scheduler(&config_opts);
16221 +}
16222 +EXPORT_SYMBOL(qman_ceetm_channel_set_group);
16223 +
16224 +int qman_ceetm_channel_get_group(struct qm_ceetm_channel *channel, int *group_b,
16225 + unsigned int *prio_a, unsigned int *prio_b)
16226 +{
16227 + struct qm_mcr_ceetm_class_scheduler_query query_result;
16228 +
16229 + if (qman_ceetm_query_class_scheduler(channel, &query_result)) {
16230 + pr_err("Can't query channel#%d's scheduler!\n", channel->idx);
16231 + return -EINVAL;
16232 + }
16233 + *group_b = !query_result.gpc_combine_flag;
16234 + *prio_a = query_result.gpc_prio_a;
16235 + *prio_b = query_result.gpc_prio_b;
16236 +
16237 + return 0;
16238 +}
16239 +EXPORT_SYMBOL(qman_ceetm_channel_get_group);
16240 +
16241 +#define GROUP_A_ELIGIBILITY_SET (1 << 8)
16242 +#define GROUP_B_ELIGIBILITY_SET (1 << 9)
16243 +#define CQ_ELIGIBILITY_SET(n) (1 << (7 - n))
16244 +int qman_ceetm_channel_set_group_cr_eligibility(struct qm_ceetm_channel
16245 + *channel, int group_b, int cre)
16246 +{
16247 + struct qm_mcc_ceetm_class_scheduler_config csch_config;
16248 + struct qm_mcr_ceetm_class_scheduler_query csch_query;
16249 + int i;
16250 +
16251 + if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
16252 + pr_err("Cannot get the channel %d scheduler setting.\n",
16253 + channel->idx);
16254 + return -EINVAL;
16255 + }
16256 + csch_config.cqcid = cpu_to_be16(channel->idx);
16257 + csch_config.dcpid = channel->dcp_idx;
16258 + csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
16259 + csch_config.gpc_prio_a = csch_query.gpc_prio_a;
16260 + csch_config.gpc_prio_b = csch_query.gpc_prio_b;
16261 +
16262 + for (i = 0; i < 8; i++)
16263 + csch_config.w[i] = csch_query.w[i];
16264 + csch_config.erem = csch_query.erem;
16265 + if (group_b)
16266 + csch_config.crem = (be16_to_cpu(csch_query.crem)
16267 + & ~GROUP_B_ELIGIBILITY_SET)
16268 + | (cre ? GROUP_B_ELIGIBILITY_SET : 0);
16269 + else
16270 + csch_config.crem = (be16_to_cpu(csch_query.crem)
16271 + & ~GROUP_A_ELIGIBILITY_SET)
16272 + | (cre ? GROUP_A_ELIGIBILITY_SET : 0);
16273 +
16274 + csch_config.crem = cpu_to_be16(csch_config.crem);
16275 +
16276 + if (qman_ceetm_configure_class_scheduler(&csch_config)) {
16277 + pr_err("Cannot config channel %d's scheduler with "
16278 + "group_%c's cr eligibility\n", channel->idx,
16279 + group_b ? 'b' : 'a');
16280 + return -EINVAL;
16281 + }
16282 +
16283 + return 0;
16284 +}
16285 +EXPORT_SYMBOL(qman_ceetm_channel_set_group_cr_eligibility);
16286 +
16287 +int qman_ceetm_channel_set_group_er_eligibility(struct qm_ceetm_channel
16288 + *channel, int group_b, int ere)
16289 +{
16290 + struct qm_mcc_ceetm_class_scheduler_config csch_config;
16291 + struct qm_mcr_ceetm_class_scheduler_query csch_query;
16292 + int i;
16293 +
16294 + if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
16295 + pr_err("Cannot get the channel %d scheduler setting.\n",
16296 + channel->idx);
16297 + return -EINVAL;
16298 + }
16299 + csch_config.cqcid = cpu_to_be16(channel->idx);
16300 + csch_config.dcpid = channel->dcp_idx;
16301 + csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
16302 + csch_config.gpc_prio_a = csch_query.gpc_prio_a;
16303 + csch_config.gpc_prio_b = csch_query.gpc_prio_b;
16304 +
16305 + for (i = 0; i < 8; i++)
16306 + csch_config.w[i] = csch_query.w[i];
16307 + csch_config.crem = csch_query.crem;
16308 + if (group_b)
16309 + csch_config.erem = (be16_to_cpu(csch_query.erem)
16310 + & ~GROUP_B_ELIGIBILITY_SET)
16311 + | (ere ? GROUP_B_ELIGIBILITY_SET : 0);
16312 + else
16313 + csch_config.erem = (be16_to_cpu(csch_query.erem)
16314 + & ~GROUP_A_ELIGIBILITY_SET)
16315 + | (ere ? GROUP_A_ELIGIBILITY_SET : 0);
16316 +
16317 + csch_config.erem = cpu_to_be16(csch_config.erem);
16318 +
16319 + if (qman_ceetm_configure_class_scheduler(&csch_config)) {
16320 + pr_err("Cannot config channel %d's scheduler with "
16321 + "group_%c's er eligibility\n", channel->idx,
16322 + group_b ? 'b' : 'a');
16323 + return -EINVAL;
16324 + }
16325 +
16326 + return 0;
16327 +}
16328 +EXPORT_SYMBOL(qman_ceetm_channel_set_group_er_eligibility);
16329 +
16330 +int qman_ceetm_channel_set_cq_cr_eligibility(struct qm_ceetm_channel *channel,
16331 + unsigned int idx, int cre)
16332 +{
16333 + struct qm_mcc_ceetm_class_scheduler_config csch_config;
16334 + struct qm_mcr_ceetm_class_scheduler_query csch_query;
16335 + int i;
16336 +
16337 + if (idx > 7) {
16338 + pr_err("CQ index is out of range\n");
16339 + return -EINVAL;
16340 + }
16341 + if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
16342 + pr_err("Cannot get the channel %d scheduler setting.\n",
16343 + channel->idx);
16344 + return -EINVAL;
16345 + }
16346 + csch_config.cqcid = cpu_to_be16(channel->idx);
16347 + csch_config.dcpid = channel->dcp_idx;
16348 + csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
16349 + csch_config.gpc_prio_a = csch_query.gpc_prio_a;
16350 + csch_config.gpc_prio_b = csch_query.gpc_prio_b;
16351 + for (i = 0; i < 8; i++)
16352 + csch_config.w[i] = csch_query.w[i];
16353 + csch_config.erem = csch_query.erem;
16354 + csch_config.crem = (be16_to_cpu(csch_query.crem)
16355 + & ~CQ_ELIGIBILITY_SET(idx)) |
16356 + (cre ? CQ_ELIGIBILITY_SET(idx) : 0);
16357 + csch_config.crem = cpu_to_be16(csch_config.crem);
16358 + if (qman_ceetm_configure_class_scheduler(&csch_config)) {
16359 + pr_err("Cannot config channel scheduler to set "
16360 + "cr eligibility mask for CQ#%d\n", idx);
16361 + return -EINVAL;
16362 + }
16363 +
16364 + return 0;
16365 +}
16366 +EXPORT_SYMBOL(qman_ceetm_channel_set_cq_cr_eligibility);
16367 +
16368 +int qman_ceetm_channel_set_cq_er_eligibility(struct qm_ceetm_channel *channel,
16369 + unsigned int idx, int ere)
16370 +{
16371 + struct qm_mcc_ceetm_class_scheduler_config csch_config;
16372 + struct qm_mcr_ceetm_class_scheduler_query csch_query;
16373 + int i;
16374 +
16375 + if (idx > 7) {
16376 + pr_err("CQ index is out of range\n");
16377 + return -EINVAL;
16378 + }
16379 + if (qman_ceetm_query_class_scheduler(channel, &csch_query)) {
16380 + pr_err("Cannot get the channel %d scheduler setting.\n",
16381 + channel->idx);
16382 + return -EINVAL;
16383 + }
16384 + csch_config.cqcid = cpu_to_be16(channel->idx);
16385 + csch_config.dcpid = channel->dcp_idx;
16386 + csch_config.gpc_combine_flag = csch_query.gpc_combine_flag;
16387 + csch_config.gpc_prio_a = csch_query.gpc_prio_a;
16388 + csch_config.gpc_prio_b = csch_query.gpc_prio_b;
16389 + for (i = 0; i < 8; i++)
16390 + csch_config.w[i] = csch_query.w[i];
16391 + csch_config.crem = csch_query.crem;
16392 + csch_config.erem = (be16_to_cpu(csch_query.erem)
16393 + & ~CQ_ELIGIBILITY_SET(idx)) |
16394 + (ere ? CQ_ELIGIBILITY_SET(idx) : 0);
16395 + csch_config.erem = cpu_to_be16(csch_config.erem);
16396 + if (qman_ceetm_configure_class_scheduler(&csch_config)) {
16397 + pr_err("Cannot config channel scheduler to set "
16398 + "er eligibility mask for CQ#%d\n", idx);
16399 + return -EINVAL;
16400 + }
16401 + return 0;
16402 +}
16403 +EXPORT_SYMBOL(qman_ceetm_channel_set_cq_er_eligibility);
16404 +
16405 +int qman_ceetm_cq_claim(struct qm_ceetm_cq **cq,
16406 + struct qm_ceetm_channel *channel, unsigned int idx,
16407 + struct qm_ceetm_ccg *ccg)
16408 +{
16409 + struct qm_ceetm_cq *p;
16410 + struct qm_mcc_ceetm_cq_config cq_config;
16411 +
16412 + if (idx > 7) {
16413 + pr_err("The independent class queue id is out of range\n");
16414 + return -EINVAL;
16415 + }
16416 +
16417 + list_for_each_entry(p, &channel->class_queues, node) {
16418 + if (p->idx == idx) {
16419 + pr_err("The CQ#%d has been claimed!\n", idx);
16420 + return -EINVAL;
16421 + }
16422 + }
16423 +
16424 + p = kmalloc(sizeof(*p), GFP_KERNEL);
16425 + if (!p) {
16426 + pr_err("Can't allocate memory for CQ#%d!\n", idx);
16427 + return -ENOMEM;
16428 + }
16429 +
16430 + list_add_tail(&p->node, &channel->class_queues);
16431 + p->idx = idx;
16432 + p->is_claimed = 1;
16433 + p->parent = channel;
16434 + INIT_LIST_HEAD(&p->bound_lfqids);
16435 +
16436 + if (ccg) {
16437 + cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx);
16438 + cq_config.dcpid = channel->dcp_idx;
16439 + cq_config.ccgid = cpu_to_be16(ccg->idx);
16440 + if (qman_ceetm_configure_cq(&cq_config)) {
16441 + pr_err("Can't configure the CQ#%d with CCGRID#%d\n",
16442 + idx, ccg->idx);
16443 + list_del(&p->node);
16444 + kfree(p);
16445 + return -EINVAL;
16446 + }
16447 + }
16448 +
16449 + *cq = p;
16450 + return 0;
16451 +}
16452 +EXPORT_SYMBOL(qman_ceetm_cq_claim);
16453 +
16454 +int qman_ceetm_cq_claim_A(struct qm_ceetm_cq **cq,
16455 + struct qm_ceetm_channel *channel, unsigned int idx,
16456 + struct qm_ceetm_ccg *ccg)
16457 +{
16458 + struct qm_ceetm_cq *p;
16459 + struct qm_mcc_ceetm_cq_config cq_config;
16460 +
16461 + if ((idx < 8) || (idx > 15)) {
16462 + pr_err("This grouped class queue id is out of range\n");
16463 + return -EINVAL;
16464 + }
16465 +
16466 + list_for_each_entry(p, &channel->class_queues, node) {
16467 + if (p->idx == idx) {
16468 + pr_err("The CQ#%d has been claimed!\n", idx);
16469 + return -EINVAL;
16470 + }
16471 + }
16472 +
16473 + p = kmalloc(sizeof(*p), GFP_KERNEL);
16474 + if (!p) {
16475 + pr_err("Can't allocate memory for CQ#%d!\n", idx);
16476 + return -ENOMEM;
16477 + }
16478 +
16479 + list_add_tail(&p->node, &channel->class_queues);
16480 + p->idx = idx;
16481 + p->is_claimed = 1;
16482 + p->parent = channel;
16483 + INIT_LIST_HEAD(&p->bound_lfqids);
16484 +
16485 + if (ccg) {
16486 + cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx);
16487 + cq_config.dcpid = channel->dcp_idx;
16488 + cq_config.ccgid = cpu_to_be16(ccg->idx);
16489 + if (qman_ceetm_configure_cq(&cq_config)) {
16490 + pr_err("Can't configure the CQ#%d with CCGRID#%d\n",
16491 + idx, ccg->idx);
16492 + list_del(&p->node);
16493 + kfree(p);
16494 + return -EINVAL;
16495 + }
16496 + }
16497 + *cq = p;
16498 + return 0;
16499 +}
16500 +EXPORT_SYMBOL(qman_ceetm_cq_claim_A);
16501 +
16502 +int qman_ceetm_cq_claim_B(struct qm_ceetm_cq **cq,
16503 + struct qm_ceetm_channel *channel, unsigned int idx,
16504 + struct qm_ceetm_ccg *ccg)
16505 +{
16506 + struct qm_ceetm_cq *p;
16507 + struct qm_mcc_ceetm_cq_config cq_config;
16508 +
16509 + if ((idx < 12) || (idx > 15)) {
16510 + pr_err("This grouped class queue id is out of range\n");
16511 + return -EINVAL;
16512 + }
16513 +
16514 + list_for_each_entry(p, &channel->class_queues, node) {
16515 + if (p->idx == idx) {
16516 + pr_err("The CQ#%d has been claimed!\n", idx);
16517 + return -EINVAL;
16518 + }
16519 + }
16520 +
16521 + p = kmalloc(sizeof(*p), GFP_KERNEL);
16522 + if (!p) {
16523 + pr_err("Can't allocate memory for CQ#%d!\n", idx);
16524 + return -ENOMEM;
16525 + }
16526 +
16527 + list_add_tail(&p->node, &channel->class_queues);
16528 + p->idx = idx;
16529 + p->is_claimed = 1;
16530 + p->parent = channel;
16531 + INIT_LIST_HEAD(&p->bound_lfqids);
16532 +
16533 + if (ccg) {
16534 + cq_config.cqid = cpu_to_be16((channel->idx << 4) | idx);
16535 + cq_config.dcpid = channel->dcp_idx;
16536 + cq_config.ccgid = cpu_to_be16(ccg->idx);
16537 + if (qman_ceetm_configure_cq(&cq_config)) {
16538 + pr_err("Can't configure the CQ#%d with CCGRID#%d\n",
16539 + idx, ccg->idx);
16540 + list_del(&p->node);
16541 + kfree(p);
16542 + return -EINVAL;
16543 + }
16544 + }
16545 + *cq = p;
16546 + return 0;
16547 +}
16548 +EXPORT_SYMBOL(qman_ceetm_cq_claim_B);
16549 +
16550 +int qman_ceetm_cq_release(struct qm_ceetm_cq *cq)
16551 +{
16552 + if (!list_empty(&cq->bound_lfqids)) {
16553 + pr_err("The CQ#%d has unreleased LFQID\n", cq->idx);
16554 + return -EBUSY;
16555 + }
16556 + list_del(&cq->node);
16557 + qman_ceetm_drain_cq(cq);
16558 + kfree(cq);
16559 + return 0;
16560 +}
16561 +EXPORT_SYMBOL(qman_ceetm_cq_release);
16562 +
16563 +int qman_ceetm_set_queue_weight(struct qm_ceetm_cq *cq,
16564 + struct qm_ceetm_weight_code *weight_code)
16565 +{
16566 + struct qm_mcc_ceetm_class_scheduler_config config_opts;
16567 + struct qm_mcr_ceetm_class_scheduler_query query_result;
16568 + int i;
16569 +
16570 + if (cq->idx < 8) {
16571 + pr_err("Can not set weight for ungrouped class queue\n");
16572 + return -EINVAL;
16573 + }
16574 +
16575 + if (qman_ceetm_query_class_scheduler(cq->parent, &query_result)) {
16576 + pr_err("Can't query channel#%d's scheduler!\n",
16577 + cq->parent->idx);
16578 + return -EINVAL;
16579 + }
16580 +
16581 + config_opts.cqcid = cpu_to_be16(cq->parent->idx);
16582 + config_opts.dcpid = cq->parent->dcp_idx;
16583 + config_opts.crem = query_result.crem;
16584 + config_opts.erem = query_result.erem;
16585 + config_opts.gpc_combine_flag = query_result.gpc_combine_flag;
16586 + config_opts.gpc_prio_a = query_result.gpc_prio_a;
16587 + config_opts.gpc_prio_b = query_result.gpc_prio_b;
16588 +
16589 + for (i = 0; i < 8; i++)
16590 + config_opts.w[i] = query_result.w[i];
16591 + config_opts.w[cq->idx - 8] = ((weight_code->y << 3) |
16592 + (weight_code->x & 0x7));
16593 + return qman_ceetm_configure_class_scheduler(&config_opts);
16594 +}
16595 +EXPORT_SYMBOL(qman_ceetm_set_queue_weight);
16596 +
16597 +int qman_ceetm_get_queue_weight(struct qm_ceetm_cq *cq,
16598 + struct qm_ceetm_weight_code *weight_code)
16599 +{
16600 + struct qm_mcr_ceetm_class_scheduler_query query_result;
16601 +
16602 + if (cq->idx < 8) {
16603 + pr_err("Can not get weight for ungrouped class queue\n");
16604 + return -EINVAL;
16605 + }
16606 +
16607 + if (qman_ceetm_query_class_scheduler(cq->parent,
16608 + &query_result)) {
16609 + pr_err("Can't get the weight code for CQ#%d!\n", cq->idx);
16610 + return -EINVAL;
16611 + }
16612 + weight_code->y = query_result.w[cq->idx - 8] >> 3;
16613 + weight_code->x = query_result.w[cq->idx - 8] & 0x7;
16614 +
16615 + return 0;
16616 +}
16617 +EXPORT_SYMBOL(qman_ceetm_get_queue_weight);
16618 +
16619 +/* The WBFS code is represent as {x,y}, the effect wieght can be calculated as:
16620 + * effective weight = 2^x / (1 - (y/64))
16621 + * = 2^(x+6) / (64 - y)
16622 + */
16623 +static void reduce_fraction(u32 *n, u32 *d)
16624 +{
16625 + u32 factor = 2;
16626 + u32 lesser = (*n < *d) ? *n : *d;
16627 + /* If factor exceeds the square-root of the lesser of *n and *d,
16628 + * then there's no point continuing. Proof: if there was a factor
16629 + * bigger than the square root, that would imply there exists
16630 + * another factor smaller than the square-root with which it
16631 + * multiplies to give 'lesser' - but that's a contradiction
16632 + * because the other factor would have already been found and
16633 + * divided out.
16634 + */
16635 + while ((factor * factor) <= lesser) {
16636 + /* If 'factor' is a factor of *n and *d, divide them both
16637 + * by 'factor' as many times as possible.
16638 + */
16639 + while (!(*n % factor) && !(*d % factor)) {
16640 + *n /= factor;
16641 + *d /= factor;
16642 + lesser /= factor;
16643 + }
16644 + if (factor == 2)
16645 + factor = 3;
16646 + else
16647 + factor += 2;
16648 + }
16649 +}
16650 +
16651 +int qman_ceetm_wbfs2ratio(struct qm_ceetm_weight_code *weight_code,
16652 + u32 *numerator,
16653 + u32 *denominator)
16654 +{
16655 + *numerator = (u32) 1 << (weight_code->x + 6);
16656 + *denominator = 64 - weight_code->y;
16657 + reduce_fraction(numerator, denominator);
16658 + return 0;
16659 +}
16660 +EXPORT_SYMBOL(qman_ceetm_wbfs2ratio);
16661 +
16662 +/* For a given x, the weight is between 2^x (inclusive) and 2^(x+1) (exclusive).
16663 + * So find 'x' by range, and then estimate 'y' using:
16664 + * 64 - y = 2^(x + 6) / weight
16665 + * = 2^(x + 6) / (n/d)
16666 + * = d * 2^(x+6) / n
16667 + * y = 64 - (d * 2^(x+6) / n)
16668 + */
16669 +int qman_ceetm_ratio2wbfs(u32 numerator,
16670 + u32 denominator,
16671 + struct qm_ceetm_weight_code *weight_code,
16672 + int rounding)
16673 +{
16674 + unsigned int y, x = 0;
16675 + /* search incrementing 'x' until:
16676 + * weight < 2^(x+1)
16677 + * n/d < 2^(x+1)
16678 + * n < d * 2^(x+1)
16679 + */
16680 + while ((x < 8) && (numerator >= (denominator << (x + 1))))
16681 + x++;
16682 + if (x >= 8)
16683 + return -ERANGE;
16684 + /* because of the subtraction, use '-rounding' */
16685 + y = 64 - ROUNDING(denominator << (x + 6), numerator, -rounding);
16686 + if (y >= 32)
16687 + return -ERANGE;
16688 + weight_code->x = x;
16689 + weight_code->y = y;
16690 + return 0;
16691 +}
16692 +EXPORT_SYMBOL(qman_ceetm_ratio2wbfs);
16693 +
16694 +int qman_ceetm_set_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 ratio)
16695 +{
16696 + struct qm_ceetm_weight_code weight_code;
16697 +
16698 + if (qman_ceetm_ratio2wbfs(ratio, 100, &weight_code, 0)) {
16699 + pr_err("Cannot get wbfs code for cq %x\n", cq->idx);
16700 + return -EINVAL;
16701 + }
16702 + return qman_ceetm_set_queue_weight(cq, &weight_code);
16703 +}
16704 +EXPORT_SYMBOL(qman_ceetm_set_queue_weight_in_ratio);
16705 +
16706 +int qman_ceetm_get_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 *ratio)
16707 +{
16708 + struct qm_ceetm_weight_code weight_code;
16709 + u32 n, d;
16710 +
16711 + if (qman_ceetm_get_queue_weight(cq, &weight_code)) {
16712 + pr_err("Cannot query the weight code for cq%x\n", cq->idx);
16713 + return -EINVAL;
16714 + }
16715 +
16716 + if (qman_ceetm_wbfs2ratio(&weight_code, &n, &d)) {
16717 + pr_err("Cannot get the ratio with wbfs code\n");
16718 + return -EINVAL;
16719 + }
16720 +
16721 + *ratio = (n * (u32)100) / d;
16722 + return 0;
16723 +}
16724 +EXPORT_SYMBOL(qman_ceetm_get_queue_weight_in_ratio);
16725 +
16726 +int qman_ceetm_cq_get_dequeue_statistics(struct qm_ceetm_cq *cq, u32 flags,
16727 + u64 *frame_count, u64 *byte_count)
16728 +{
16729 + struct qm_mcr_ceetm_statistics_query result;
16730 + u16 cid, command_type;
16731 + enum qm_dc_portal dcp_idx;
16732 + int ret;
16733 +
16734 + cid = cpu_to_be16((cq->parent->idx << 4) | cq->idx);
16735 + dcp_idx = cq->parent->dcp_idx;
16736 + if (flags == QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER)
16737 + command_type = CEETM_QUERY_DEQUEUE_CLEAR_STATISTICS;
16738 + else
16739 + command_type = CEETM_QUERY_DEQUEUE_STATISTICS;
16740 +
16741 + ret = qman_ceetm_query_statistics(cid, dcp_idx, command_type, &result);
16742 + if (ret) {
16743 + pr_err("Can't query the statistics of CQ#%d!\n", cq->idx);
16744 + return -EINVAL;
16745 + }
16746 +
16747 + *frame_count = be40_to_cpu(result.frm_cnt);
16748 + *byte_count = be48_to_cpu(result.byte_cnt);
16749 + return 0;
16750 +}
16751 +EXPORT_SYMBOL(qman_ceetm_cq_get_dequeue_statistics);
16752 +
16753 +int qman_ceetm_drain_cq(struct qm_ceetm_cq *cq)
16754 +{
16755 + struct qm_mcr_ceetm_cq_peek_pop_xsfdrread ppxr;
16756 + int ret;
16757 +
16758 + do {
16759 + ret = qman_ceetm_cq_peek_pop_xsfdrread(cq, 1, 0, &ppxr);
16760 + if (ret) {
16761 + pr_err("Failed to pop frame from CQ\n");
16762 + return -EINVAL;
16763 + }
16764 + } while (!(ppxr.stat & 0x2));
16765 +
16766 + return 0;
16767 +}
16768 +EXPORT_SYMBOL(qman_ceetm_drain_cq);
16769 +
16770 +#define CEETM_LFQMT_LFQID_MSB 0xF00000
16771 +#define CEETM_LFQMT_LFQID_LSB 0x000FFF
16772 +int qman_ceetm_lfq_claim(struct qm_ceetm_lfq **lfq,
16773 + struct qm_ceetm_cq *cq)
16774 +{
16775 + struct qm_ceetm_lfq *p;
16776 + u32 lfqid;
16777 + int ret = 0;
16778 + struct qm_mcc_ceetm_lfqmt_config lfqmt_config;
16779 +
16780 + if (cq->parent->dcp_idx == qm_dc_portal_fman0) {
16781 + ret = qman_alloc_ceetm0_lfqid(&lfqid);
16782 + } else if (cq->parent->dcp_idx == qm_dc_portal_fman1) {
16783 + ret = qman_alloc_ceetm1_lfqid(&lfqid);
16784 + } else {
16785 + pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
16786 + cq->parent->dcp_idx);
16787 + return -EINVAL;
16788 + }
16789 +
16790 + if (ret) {
16791 + pr_err("There is no lfqid avalaible for CQ#%d!\n", cq->idx);
16792 + return -ENODEV;
16793 + }
16794 + p = kmalloc(sizeof(*p), GFP_KERNEL);
16795 + if (!p)
16796 + return -ENOMEM;
16797 + p->idx = lfqid;
16798 + p->dctidx = (u16)(lfqid & CEETM_LFQMT_LFQID_LSB);
16799 + p->parent = cq->parent;
16800 + list_add_tail(&p->node, &cq->bound_lfqids);
16801 +
16802 + lfqmt_config.lfqid = cpu_to_be24(CEETM_LFQMT_LFQID_MSB |
16803 + (cq->parent->dcp_idx << 16) |
16804 + (lfqid & CEETM_LFQMT_LFQID_LSB));
16805 + lfqmt_config.cqid = cpu_to_be16((cq->parent->idx << 4) | (cq->idx));
16806 + lfqmt_config.dctidx = cpu_to_be16(p->dctidx);
16807 + if (qman_ceetm_configure_lfqmt(&lfqmt_config)) {
16808 + pr_err("Can't configure LFQMT for LFQID#%d @ CQ#%d\n",
16809 + lfqid, cq->idx);
16810 + list_del(&p->node);
16811 + kfree(p);
16812 + return -EINVAL;
16813 + }
16814 + *lfq = p;
16815 + return 0;
16816 +}
16817 +EXPORT_SYMBOL(qman_ceetm_lfq_claim);
16818 +
16819 +int qman_ceetm_lfq_release(struct qm_ceetm_lfq *lfq)
16820 +{
16821 + if (lfq->parent->dcp_idx == qm_dc_portal_fman0) {
16822 + qman_release_ceetm0_lfqid(lfq->idx);
16823 + } else if (lfq->parent->dcp_idx == qm_dc_portal_fman1) {
16824 + qman_release_ceetm1_lfqid(lfq->idx);
16825 + } else {
16826 + pr_err("dcp_idx %u does not correspond to a known fman in this driver\n",
16827 + lfq->parent->dcp_idx);
16828 + return -EINVAL;
16829 + }
16830 + list_del(&lfq->node);
16831 + kfree(lfq);
16832 + return 0;
16833 +}
16834 +EXPORT_SYMBOL(qman_ceetm_lfq_release);
16835 +
16836 +int qman_ceetm_lfq_set_context(struct qm_ceetm_lfq *lfq, u64 context_a,
16837 + u32 context_b)
16838 +{
16839 + struct qm_mcc_ceetm_dct_config dct_config;
16840 + lfq->context_a = context_a;
16841 + lfq->context_b = context_b;
16842 + dct_config.dctidx = cpu_to_be16(lfq->dctidx);
16843 + dct_config.dcpid = lfq->parent->dcp_idx;
16844 + dct_config.context_b = cpu_to_be32(context_b);
16845 + dct_config.context_a = cpu_to_be64(context_a);
16846 + return qman_ceetm_configure_dct(&dct_config);
16847 +}
16848 +EXPORT_SYMBOL(qman_ceetm_lfq_set_context);
16849 +
16850 +int qman_ceetm_lfq_get_context(struct qm_ceetm_lfq *lfq, u64 *context_a,
16851 + u32 *context_b)
16852 +{
16853 + struct qm_mcc_ceetm_dct_query dct_query;
16854 + struct qm_mcr_ceetm_dct_query query_result;
16855 +
16856 + dct_query.dctidx = cpu_to_be16(lfq->dctidx);
16857 + dct_query.dcpid = lfq->parent->dcp_idx;
16858 + if (qman_ceetm_query_dct(&dct_query, &query_result)) {
16859 + pr_err("Can't query LFQID#%d's context!\n", lfq->idx);
16860 + return -EINVAL;
16861 + }
16862 + *context_a = be64_to_cpu(query_result.context_a);
16863 + *context_b = be32_to_cpu(query_result.context_b);
16864 + return 0;
16865 +}
16866 +EXPORT_SYMBOL(qman_ceetm_lfq_get_context);
16867 +
16868 +int qman_ceetm_create_fq(struct qm_ceetm_lfq *lfq, struct qman_fq *fq)
16869 +{
16870 + spin_lock_init(&fq->fqlock);
16871 + fq->fqid = lfq->idx;
16872 + fq->flags = QMAN_FQ_FLAG_NO_MODIFY;
16873 + if (lfq->ern)
16874 + fq->cb.ern = lfq->ern;
16875 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
16876 + if (unlikely(find_empty_fq_table_entry(&fq->key, fq)))
16877 + return -ENOMEM;
16878 +#endif
16879 + return 0;
16880 +}
16881 +EXPORT_SYMBOL(qman_ceetm_create_fq);
16882 +
16883 +int qman_ceetm_ccg_claim(struct qm_ceetm_ccg **ccg,
16884 + struct qm_ceetm_channel *channel,
16885 + unsigned int idx,
16886 + void (*cscn)(struct qm_ceetm_ccg *,
16887 + void *cb_ctx,
16888 + int congested),
16889 + void *cb_ctx)
16890 +{
16891 + struct qm_ceetm_ccg *p;
16892 +
16893 + if (idx > 15) {
16894 + pr_err("The given ccg index is out of range\n");
16895 + return -EINVAL;
16896 + }
16897 +
16898 + list_for_each_entry(p, &channel->ccgs, node) {
16899 + if (p->idx == idx) {
16900 + pr_err("The CCG#%d has been claimed\n", idx);
16901 + return -EINVAL;
16902 + }
16903 + }
16904 +
16905 + p = kmalloc(sizeof(*p), GFP_KERNEL);
16906 + if (!p) {
16907 + pr_err("Can't allocate memory for CCG#%d!\n", idx);
16908 + return -ENOMEM;
16909 + }
16910 +
16911 + list_add_tail(&p->node, &channel->ccgs);
16912 +
16913 + p->idx = idx;
16914 + p->parent = channel;
16915 + p->cb = cscn;
16916 + p->cb_ctx = cb_ctx;
16917 + INIT_LIST_HEAD(&p->cb_node);
16918 +
16919 + *ccg = p;
16920 + return 0;
16921 +}
16922 +EXPORT_SYMBOL(qman_ceetm_ccg_claim);
16923 +
16924 +int qman_ceetm_ccg_release(struct qm_ceetm_ccg *ccg)
16925 +{
16926 + unsigned long irqflags __maybe_unused;
16927 + struct qm_mcc_ceetm_ccgr_config config_opts;
16928 + int ret = 0;
16929 + struct qman_portal *p = get_affine_portal();
16930 +
16931 + memset(&config_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_config));
16932 + spin_lock_irqsave(&p->ccgr_lock, irqflags);
16933 + if (!list_empty(&ccg->cb_node))
16934 + list_del(&ccg->cb_node);
16935 + config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE |
16936 + (ccg->parent->idx << 4) | ccg->idx);
16937 + config_opts.dcpid = ccg->parent->dcp_idx;
16938 + config_opts.we_mask = cpu_to_be16(QM_CCGR_WE_CSCN_TUPD);
16939 + config_opts.cm_config.cscn_tupd = cpu_to_be16(PORTAL_IDX(p));
16940 + ret = qman_ceetm_configure_ccgr(&config_opts);
16941 + spin_unlock_irqrestore(&p->ccgr_lock, irqflags);
16942 + put_affine_portal();
16943 +
16944 + list_del(&ccg->node);
16945 + kfree(ccg);
16946 + return ret;
16947 +}
16948 +EXPORT_SYMBOL(qman_ceetm_ccg_release);
16949 +
16950 +int qman_ceetm_ccg_set(struct qm_ceetm_ccg *ccg, u16 we_mask,
16951 + const struct qm_ceetm_ccg_params *params)
16952 +{
16953 + struct qm_mcc_ceetm_ccgr_config config_opts;
16954 + unsigned long irqflags __maybe_unused;
16955 + int ret;
16956 + struct qman_portal *p;
16957 +
16958 + if (((ccg->parent->idx << 4) | ccg->idx) >= (2 * __CGR_NUM))
16959 + return -EINVAL;
16960 +
16961 + p = get_affine_portal();
16962 +
16963 + memset(&config_opts, 0, sizeof(struct qm_mcc_ceetm_ccgr_config));
16964 + spin_lock_irqsave(&p->ccgr_lock, irqflags);
16965 +
16966 + config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE |
16967 + (ccg->parent->idx << 4) | ccg->idx);
16968 + config_opts.dcpid = ccg->parent->dcp_idx;
16969 + config_opts.we_mask = we_mask;
16970 + if (we_mask & QM_CCGR_WE_CSCN_EN) {
16971 + config_opts.we_mask |= QM_CCGR_WE_CSCN_TUPD;
16972 + config_opts.cm_config.cscn_tupd = cpu_to_be16(
16973 + QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p));
16974 + }
16975 + config_opts.we_mask = cpu_to_be16(config_opts.we_mask);
16976 + config_opts.cm_config.ctl_wr_en_g = params->wr_en_g;
16977 + config_opts.cm_config.ctl_wr_en_y = params->wr_en_y;
16978 + config_opts.cm_config.ctl_wr_en_r = params->wr_en_r;
16979 + config_opts.cm_config.ctl_td_en = params->td_en;
16980 + config_opts.cm_config.ctl_td_mode = params->td_mode;
16981 + config_opts.cm_config.ctl_cscn_en = params->cscn_en;
16982 + config_opts.cm_config.ctl_mode = params->mode;
16983 + config_opts.cm_config.oal = params->oal;
16984 + config_opts.cm_config.cs_thres.hword =
16985 + cpu_to_be16(params->cs_thres_in.hword);
16986 + config_opts.cm_config.cs_thres_x.hword =
16987 + cpu_to_be16(params->cs_thres_out.hword);
16988 + config_opts.cm_config.td_thres.hword =
16989 + cpu_to_be16(params->td_thres.hword);
16990 + config_opts.cm_config.wr_parm_g.word =
16991 + cpu_to_be32(params->wr_parm_g.word);
16992 + config_opts.cm_config.wr_parm_y.word =
16993 + cpu_to_be32(params->wr_parm_y.word);
16994 + config_opts.cm_config.wr_parm_r.word =
16995 + cpu_to_be32(params->wr_parm_r.word);
16996 + ret = qman_ceetm_configure_ccgr(&config_opts);
16997 + if (ret) {
16998 + pr_err("Configure CCGR CM failed!\n");
16999 + goto release_lock;
17000 + }
17001 +
17002 + if (we_mask & QM_CCGR_WE_CSCN_EN)
17003 + if (list_empty(&ccg->cb_node))
17004 + list_add(&ccg->cb_node,
17005 + &p->ccgr_cbs[ccg->parent->dcp_idx]);
17006 +release_lock:
17007 + spin_unlock_irqrestore(&p->ccgr_lock, irqflags);
17008 + put_affine_portal();
17009 + return ret;
17010 +}
17011 +EXPORT_SYMBOL(qman_ceetm_ccg_set);
17012 +
17013 +#define CEETM_CCGR_CTL_MASK 0x01
17014 +int qman_ceetm_ccg_get(struct qm_ceetm_ccg *ccg,
17015 + struct qm_ceetm_ccg_params *params)
17016 +{
17017 + struct qm_mcc_ceetm_ccgr_query query_opts;
17018 + struct qm_mcr_ceetm_ccgr_query query_result;
17019 +
17020 + query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY |
17021 + (ccg->parent->idx << 4) | ccg->idx);
17022 + query_opts.dcpid = ccg->parent->dcp_idx;
17023 +
17024 + if (qman_ceetm_query_ccgr(&query_opts, &query_result)) {
17025 + pr_err("Can't query CCGR#%d\n", ccg->idx);
17026 + return -EINVAL;
17027 + }
17028 +
17029 + params->wr_parm_r.word =
17030 + be32_to_cpu(query_result.cm_query.wr_parm_r.word);
17031 + params->wr_parm_y.word =
17032 + be32_to_cpu(query_result.cm_query.wr_parm_y.word);
17033 + params->wr_parm_g.word =
17034 + be32_to_cpu(query_result.cm_query.wr_parm_g.word);
17035 + params->td_thres.hword =
17036 + be16_to_cpu(query_result.cm_query.td_thres.hword);
17037 + params->cs_thres_out.hword =
17038 + be16_to_cpu(query_result.cm_query.cs_thres_x.hword);
17039 + params->cs_thres_in.hword =
17040 + be16_to_cpu(query_result.cm_query.cs_thres.hword);
17041 + params->oal = query_result.cm_query.oal;
17042 + params->wr_en_g = query_result.cm_query.ctl_wr_en_g;
17043 + params->wr_en_y = query_result.cm_query.ctl_wr_en_y;
17044 + params->wr_en_r = query_result.cm_query.ctl_wr_en_r;
17045 + params->td_en = query_result.cm_query.ctl_td_en;
17046 + params->td_mode = query_result.cm_query.ctl_td_mode;
17047 + params->cscn_en = query_result.cm_query.ctl_cscn_en;
17048 + params->mode = query_result.cm_query.ctl_mode;
17049 +
17050 + return 0;
17051 +}
17052 +EXPORT_SYMBOL(qman_ceetm_ccg_get);
17053 +
17054 +int qman_ceetm_ccg_get_reject_statistics(struct qm_ceetm_ccg *ccg, u32 flags,
17055 + u64 *frame_count, u64 *byte_count)
17056 +{
17057 + struct qm_mcr_ceetm_statistics_query result;
17058 + u16 cid, command_type;
17059 + enum qm_dc_portal dcp_idx;
17060 + int ret;
17061 +
17062 + cid = cpu_to_be16((ccg->parent->idx << 4) | ccg->idx);
17063 + dcp_idx = ccg->parent->dcp_idx;
17064 + if (flags == QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER)
17065 + command_type = CEETM_QUERY_REJECT_CLEAR_STATISTICS;
17066 + else
17067 + command_type = CEETM_QUERY_REJECT_STATISTICS;
17068 +
17069 + ret = qman_ceetm_query_statistics(cid, dcp_idx, command_type, &result);
17070 + if (ret) {
17071 + pr_err("Can't query the statistics of CCG#%d!\n", ccg->idx);
17072 + return -EINVAL;
17073 + }
17074 +
17075 + *frame_count = be40_to_cpu(result.frm_cnt);
17076 + *byte_count = be48_to_cpu(result.byte_cnt);
17077 + return 0;
17078 +}
17079 +EXPORT_SYMBOL(qman_ceetm_ccg_get_reject_statistics);
17080 +
17081 +int qman_ceetm_cscn_swp_get(struct qm_ceetm_ccg *ccg,
17082 + u16 swp_idx,
17083 + unsigned int *cscn_enabled)
17084 +{
17085 + struct qm_mcc_ceetm_ccgr_query query_opts;
17086 + struct qm_mcr_ceetm_ccgr_query query_result;
17087 + int i;
17088 +
17089 + DPA_ASSERT(swp_idx < 127);
17090 + query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY |
17091 + (ccg->parent->idx << 4) | ccg->idx);
17092 + query_opts.dcpid = ccg->parent->dcp_idx;
17093 +
17094 + if (qman_ceetm_query_ccgr(&query_opts, &query_result)) {
17095 + pr_err("Can't query CCGR#%d\n", ccg->idx);
17096 + return -EINVAL;
17097 + }
17098 +
17099 + i = swp_idx / 32;
17100 + i = 3 - i;
17101 + *cscn_enabled = be32_to_cpu(query_result.cm_query.cscn_targ_swp[i]) >>
17102 + (31 - swp_idx % 32);
17103 +
17104 + return 0;
17105 +}
17106 +EXPORT_SYMBOL(qman_ceetm_cscn_swp_get);
17107 +
17108 +int qman_ceetm_cscn_dcp_set(struct qm_ceetm_ccg *ccg,
17109 + u16 dcp_idx,
17110 + u8 vcgid,
17111 + unsigned int cscn_enabled,
17112 + u16 we_mask,
17113 + const struct qm_ceetm_ccg_params *params)
17114 +{
17115 + struct qm_mcc_ceetm_ccgr_config config_opts;
17116 + int ret;
17117 +
17118 + config_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_CONFIGURE |
17119 + (ccg->parent->idx << 4) | ccg->idx);
17120 + config_opts.dcpid = ccg->parent->dcp_idx;
17121 + config_opts.we_mask = cpu_to_be16(we_mask | QM_CCGR_WE_CSCN_TUPD |
17122 + QM_CCGR_WE_CDV);
17123 + config_opts.cm_config.cdv = vcgid;
17124 + config_opts.cm_config.cscn_tupd = cpu_to_be16((cscn_enabled << 15) |
17125 + QM_CGR_TARG_UDP_CTRL_DCP | dcp_idx);
17126 + config_opts.cm_config.ctl_wr_en_g = params->wr_en_g;
17127 + config_opts.cm_config.ctl_wr_en_y = params->wr_en_y;
17128 + config_opts.cm_config.ctl_wr_en_r = params->wr_en_r;
17129 + config_opts.cm_config.ctl_td_en = params->td_en;
17130 + config_opts.cm_config.ctl_td_mode = params->td_mode;
17131 + config_opts.cm_config.ctl_cscn_en = params->cscn_en;
17132 + config_opts.cm_config.ctl_mode = params->mode;
17133 + config_opts.cm_config.cs_thres.hword =
17134 + cpu_to_be16(params->cs_thres_in.hword);
17135 + config_opts.cm_config.cs_thres_x.hword =
17136 + cpu_to_be16(params->cs_thres_out.hword);
17137 + config_opts.cm_config.td_thres.hword =
17138 + cpu_to_be16(params->td_thres.hword);
17139 + config_opts.cm_config.wr_parm_g.word =
17140 + cpu_to_be32(params->wr_parm_g.word);
17141 + config_opts.cm_config.wr_parm_y.word =
17142 + cpu_to_be32(params->wr_parm_y.word);
17143 + config_opts.cm_config.wr_parm_r.word =
17144 + cpu_to_be32(params->wr_parm_r.word);
17145 +
17146 + ret = qman_ceetm_configure_ccgr(&config_opts);
17147 + if (ret) {
17148 + pr_err("Configure CSCN_TARG_DCP failed!\n");
17149 + return -EINVAL;
17150 + }
17151 + return 0;
17152 +}
17153 +EXPORT_SYMBOL(qman_ceetm_cscn_dcp_set);
17154 +
17155 +int qman_ceetm_cscn_dcp_get(struct qm_ceetm_ccg *ccg,
17156 + u16 dcp_idx,
17157 + u8 *vcgid,
17158 + unsigned int *cscn_enabled)
17159 +{
17160 + struct qm_mcc_ceetm_ccgr_query query_opts;
17161 + struct qm_mcr_ceetm_ccgr_query query_result;
17162 +
17163 + query_opts.ccgrid = cpu_to_be16(CEETM_CCGR_CM_QUERY |
17164 + (ccg->parent->idx << 4) | ccg->idx);
17165 + query_opts.dcpid = ccg->parent->dcp_idx;
17166 +
17167 + if (qman_ceetm_query_ccgr(&query_opts, &query_result)) {
17168 + pr_err("Can't query CCGR#%d\n", ccg->idx);
17169 + return -EINVAL;
17170 + }
17171 +
17172 + *vcgid = query_result.cm_query.cdv;
17173 + *cscn_enabled = (be16_to_cpu(query_result.cm_query.cscn_targ_dcp >>
17174 + dcp_idx)) & 0x1;
17175 + return 0;
17176 +}
17177 +EXPORT_SYMBOL(qman_ceetm_cscn_dcp_get);
17178 +
17179 +int qman_ceetm_querycongestion(struct __qm_mcr_querycongestion *ccg_state,
17180 + unsigned int dcp_idx)
17181 +{
17182 + struct qm_mc_command *mcc;
17183 + struct qm_mc_result *mcr;
17184 + struct qman_portal *p;
17185 + unsigned long irqflags __maybe_unused;
17186 + u8 res;
17187 + int i, j;
17188 +
17189 + p = get_affine_portal();
17190 + PORTAL_IRQ_LOCK(p, irqflags);
17191 +
17192 + mcc = qm_mc_start(&p->p);
17193 + for (i = 0; i < 2; i++) {
17194 + mcc->ccgr_query.ccgrid =
17195 + cpu_to_be16(CEETM_QUERY_CONGESTION_STATE | i);
17196 + mcc->ccgr_query.dcpid = dcp_idx;
17197 + qm_mc_commit(&p->p, QM_CEETM_VERB_CCGR_QUERY);
17198 +
17199 + while (!(mcr = qm_mc_result(&p->p)))
17200 + cpu_relax();
17201 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
17202 + QM_CEETM_VERB_CCGR_QUERY);
17203 + res = mcr->result;
17204 + if (res == QM_MCR_RESULT_OK) {
17205 + for (j = 0; j < 8; j++)
17206 + mcr->ccgr_query.congestion_state.state.
17207 + __state[j] =
17208 + be32_to_cpu(mcr->ccgr_query.
17209 + congestion_state.state.__state[j]);
17210 +
17211 + *(ccg_state + i) =
17212 + mcr->ccgr_query.congestion_state.state;
17213 + } else {
17214 + pr_err("QUERY CEETM CONGESTION STATE failed\n");
17215 + return -EIO;
17216 + }
17217 + }
17218 + PORTAL_IRQ_UNLOCK(p, irqflags);
17219 + put_affine_portal();
17220 + return 0;
17221 +}
17222 +
17223 +int qman_set_wpm(int wpm_enable)
17224 +{
17225 + return qm_set_wpm(wpm_enable);
17226 +}
17227 +EXPORT_SYMBOL(qman_set_wpm);
17228 +
17229 +int qman_get_wpm(int *wpm_enable)
17230 +{
17231 + return qm_get_wpm(wpm_enable);
17232 +}
17233 +EXPORT_SYMBOL(qman_get_wpm);
17234 +
17235 +int qman_shutdown_fq(u32 fqid)
17236 +{
17237 + struct qman_portal *p;
17238 + unsigned long irqflags __maybe_unused;
17239 + int ret;
17240 + struct qm_portal *low_p;
17241 + p = get_affine_portal();
17242 + PORTAL_IRQ_LOCK(p, irqflags);
17243 + low_p = &p->p;
17244 + ret = qm_shutdown_fq(&low_p, 1, fqid);
17245 + PORTAL_IRQ_UNLOCK(p, irqflags);
17246 + put_affine_portal();
17247 + return ret;
17248 +}
17249 +
17250 +const struct qm_portal_config *qman_get_qm_portal_config(
17251 + struct qman_portal *portal)
17252 +{
17253 + return portal->sharing_redirect ? NULL : portal->config;
17254 +}
17255 --- /dev/null
17256 +++ b/drivers/staging/fsl_qbman/qman_low.h
17257 @@ -0,0 +1,1407 @@
17258 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
17259 + *
17260 + * Redistribution and use in source and binary forms, with or without
17261 + * modification, are permitted provided that the following conditions are met:
17262 + * * Redistributions of source code must retain the above copyright
17263 + * notice, this list of conditions and the following disclaimer.
17264 + * * Redistributions in binary form must reproduce the above copyright
17265 + * notice, this list of conditions and the following disclaimer in the
17266 + * documentation and/or other materials provided with the distribution.
17267 + * * Neither the name of Freescale Semiconductor nor the
17268 + * names of its contributors may be used to endorse or promote products
17269 + * derived from this software without specific prior written permission.
17270 + *
17271 + *
17272 + * ALTERNATIVELY, this software may be distributed under the terms of the
17273 + * GNU General Public License ("GPL") as published by the Free Software
17274 + * Foundation, either version 2 of that License or (at your option) any
17275 + * later version.
17276 + *
17277 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
17278 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17279 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17280 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
17281 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17282 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
17283 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
17284 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
17285 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
17286 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17287 + */
17288 +
17289 +#include "qman_private.h"
17290 +
17291 +/***************************/
17292 +/* Portal register assists */
17293 +/***************************/
17294 +
17295 +/* Cache-inhibited register offsets */
17296 +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64)
17297 +
17298 +#define QM_REG_EQCR_PI_CINH 0x0000
17299 +#define QM_REG_EQCR_CI_CINH 0x0004
17300 +#define QM_REG_EQCR_ITR 0x0008
17301 +#define QM_REG_DQRR_PI_CINH 0x0040
17302 +#define QM_REG_DQRR_CI_CINH 0x0044
17303 +#define QM_REG_DQRR_ITR 0x0048
17304 +#define QM_REG_DQRR_DCAP 0x0050
17305 +#define QM_REG_DQRR_SDQCR 0x0054
17306 +#define QM_REG_DQRR_VDQCR 0x0058
17307 +#define QM_REG_DQRR_PDQCR 0x005c
17308 +#define QM_REG_MR_PI_CINH 0x0080
17309 +#define QM_REG_MR_CI_CINH 0x0084
17310 +#define QM_REG_MR_ITR 0x0088
17311 +#define QM_REG_CFG 0x0100
17312 +#define QM_REG_ISR 0x0e00
17313 +#define QM_REG_IIR 0x0e0c
17314 +#define QM_REG_ITPR 0x0e14
17315 +
17316 +/* Cache-enabled register offsets */
17317 +#define QM_CL_EQCR 0x0000
17318 +#define QM_CL_DQRR 0x1000
17319 +#define QM_CL_MR 0x2000
17320 +#define QM_CL_EQCR_PI_CENA 0x3000
17321 +#define QM_CL_EQCR_CI_CENA 0x3100
17322 +#define QM_CL_DQRR_PI_CENA 0x3200
17323 +#define QM_CL_DQRR_CI_CENA 0x3300
17324 +#define QM_CL_MR_PI_CENA 0x3400
17325 +#define QM_CL_MR_CI_CENA 0x3500
17326 +#define QM_CL_CR 0x3800
17327 +#define QM_CL_RR0 0x3900
17328 +#define QM_CL_RR1 0x3940
17329 +
17330 +#endif
17331 +
17332 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
17333 +
17334 +#define QM_REG_EQCR_PI_CINH 0x3000
17335 +#define QM_REG_EQCR_CI_CINH 0x3040
17336 +#define QM_REG_EQCR_ITR 0x3080
17337 +#define QM_REG_DQRR_PI_CINH 0x3100
17338 +#define QM_REG_DQRR_CI_CINH 0x3140
17339 +#define QM_REG_DQRR_ITR 0x3180
17340 +#define QM_REG_DQRR_DCAP 0x31C0
17341 +#define QM_REG_DQRR_SDQCR 0x3200
17342 +#define QM_REG_DQRR_VDQCR 0x3240
17343 +#define QM_REG_DQRR_PDQCR 0x3280
17344 +#define QM_REG_MR_PI_CINH 0x3300
17345 +#define QM_REG_MR_CI_CINH 0x3340
17346 +#define QM_REG_MR_ITR 0x3380
17347 +#define QM_REG_CFG 0x3500
17348 +#define QM_REG_ISR 0x3600
17349 +#define QM_REG_IIR 0x36C0
17350 +#define QM_REG_ITPR 0x3740
17351 +
17352 +/* Cache-enabled register offsets */
17353 +#define QM_CL_EQCR 0x0000
17354 +#define QM_CL_DQRR 0x1000
17355 +#define QM_CL_MR 0x2000
17356 +#define QM_CL_EQCR_PI_CENA 0x3000
17357 +#define QM_CL_EQCR_CI_CENA 0x3040
17358 +#define QM_CL_DQRR_PI_CENA 0x3100
17359 +#define QM_CL_DQRR_CI_CENA 0x3140
17360 +#define QM_CL_MR_PI_CENA 0x3300
17361 +#define QM_CL_MR_CI_CENA 0x3340
17362 +#define QM_CL_CR 0x3800
17363 +#define QM_CL_RR0 0x3900
17364 +#define QM_CL_RR1 0x3940
17365 +
17366 +#endif
17367 +
17368 +
17369 +/* BTW, the drivers (and h/w programming model) already obtain the required
17370 + * synchronisation for portal accesses via lwsync(), hwsync(), and
17371 + * data-dependencies. Use of barrier()s or other order-preserving primitives
17372 + * simply degrade performance. Hence the use of the __raw_*() interfaces, which
17373 + * simply ensure that the compiler treats the portal registers as volatile (ie.
17374 + * non-coherent). */
17375 +
17376 +/* Cache-inhibited register access. */
17377 +#define __qm_in(qm, o) be32_to_cpu(__raw_readl((qm)->addr_ci + (o)))
17378 +#define __qm_out(qm, o, val) __raw_writel((cpu_to_be32(val)), \
17379 + (qm)->addr_ci + (o));
17380 +#define qm_in(reg) __qm_in(&portal->addr, QM_REG_##reg)
17381 +#define qm_out(reg, val) __qm_out(&portal->addr, QM_REG_##reg, val)
17382 +
17383 +/* Cache-enabled (index) register access */
17384 +#define __qm_cl_touch_ro(qm, o) dcbt_ro((qm)->addr_ce + (o))
17385 +#define __qm_cl_touch_rw(qm, o) dcbt_rw((qm)->addr_ce + (o))
17386 +#define __qm_cl_in(qm, o) be32_to_cpu(__raw_readl((qm)->addr_ce + (o)))
17387 +#define __qm_cl_out(qm, o, val) \
17388 + do { \
17389 + u32 *__tmpclout = (qm)->addr_ce + (o); \
17390 + __raw_writel(cpu_to_be32(val), __tmpclout); \
17391 + dcbf(__tmpclout); \
17392 + } while (0)
17393 +#define __qm_cl_invalidate(qm, o) dcbi((qm)->addr_ce + (o))
17394 +#define qm_cl_touch_ro(reg) __qm_cl_touch_ro(&portal->addr, QM_CL_##reg##_CENA)
17395 +#define qm_cl_touch_rw(reg) __qm_cl_touch_rw(&portal->addr, QM_CL_##reg##_CENA)
17396 +#define qm_cl_in(reg) __qm_cl_in(&portal->addr, QM_CL_##reg##_CENA)
17397 +#define qm_cl_out(reg, val) __qm_cl_out(&portal->addr, QM_CL_##reg##_CENA, val)
17398 +#define qm_cl_invalidate(reg)\
17399 + __qm_cl_invalidate(&portal->addr, QM_CL_##reg##_CENA)
17400 +
17401 +/* Cache-enabled ring access */
17402 +#define qm_cl(base, idx) ((void *)base + ((idx) << 6))
17403 +
17404 +/* Cyclic helper for rings. FIXME: once we are able to do fine-grain perf
17405 + * analysis, look at using the "extra" bit in the ring index registers to avoid
17406 + * cyclic issues. */
17407 +static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last)
17408 +{
17409 + /* 'first' is included, 'last' is excluded */
17410 + if (first <= last)
17411 + return last - first;
17412 + return ringsize + last - first;
17413 +}
17414 +
17415 +/* Portal modes.
17416 + * Enum types;
17417 + * pmode == production mode
17418 + * cmode == consumption mode,
17419 + * dmode == h/w dequeue mode.
17420 + * Enum values use 3 letter codes. First letter matches the portal mode,
17421 + * remaining two letters indicate;
17422 + * ci == cache-inhibited portal register
17423 + * ce == cache-enabled portal register
17424 + * vb == in-band valid-bit (cache-enabled)
17425 + * dc == DCA (Discrete Consumption Acknowledgement), DQRR-only
17426 + * As for "enum qm_dqrr_dmode", it should be self-explanatory.
17427 + */
17428 +enum qm_eqcr_pmode { /* matches QCSP_CFG::EPM */
17429 + qm_eqcr_pci = 0, /* PI index, cache-inhibited */
17430 + qm_eqcr_pce = 1, /* PI index, cache-enabled */
17431 + qm_eqcr_pvb = 2 /* valid-bit */
17432 +};
17433 +enum qm_dqrr_dmode { /* matches QCSP_CFG::DP */
17434 + qm_dqrr_dpush = 0, /* SDQCR + VDQCR */
17435 + qm_dqrr_dpull = 1 /* PDQCR */
17436 +};
17437 +enum qm_dqrr_pmode { /* s/w-only */
17438 + qm_dqrr_pci, /* reads DQRR_PI_CINH */
17439 + qm_dqrr_pce, /* reads DQRR_PI_CENA */
17440 + qm_dqrr_pvb /* reads valid-bit */
17441 +};
17442 +enum qm_dqrr_cmode { /* matches QCSP_CFG::DCM */
17443 + qm_dqrr_cci = 0, /* CI index, cache-inhibited */
17444 + qm_dqrr_cce = 1, /* CI index, cache-enabled */
17445 + qm_dqrr_cdc = 2 /* Discrete Consumption Acknowledgement */
17446 +};
17447 +enum qm_mr_pmode { /* s/w-only */
17448 + qm_mr_pci, /* reads MR_PI_CINH */
17449 + qm_mr_pce, /* reads MR_PI_CENA */
17450 + qm_mr_pvb /* reads valid-bit */
17451 +};
17452 +enum qm_mr_cmode { /* matches QCSP_CFG::MM */
17453 + qm_mr_cci = 0, /* CI index, cache-inhibited */
17454 + qm_mr_cce = 1 /* CI index, cache-enabled */
17455 +};
17456 +
17457 +
17458 +/* ------------------------- */
17459 +/* --- Portal structures --- */
17460 +
17461 +#define QM_EQCR_SIZE 8
17462 +#define QM_DQRR_SIZE 16
17463 +#define QM_MR_SIZE 8
17464 +
17465 +struct qm_eqcr {
17466 + struct qm_eqcr_entry *ring, *cursor;
17467 + u8 ci, available, ithresh, vbit;
17468 +#ifdef CONFIG_FSL_DPA_CHECKING
17469 + u32 busy;
17470 + enum qm_eqcr_pmode pmode;
17471 +#endif
17472 +};
17473 +
17474 +struct qm_dqrr {
17475 + const struct qm_dqrr_entry *ring, *cursor;
17476 + u8 pi, ci, fill, ithresh, vbit;
17477 +#ifdef CONFIG_FSL_DPA_CHECKING
17478 + enum qm_dqrr_dmode dmode;
17479 + enum qm_dqrr_pmode pmode;
17480 + enum qm_dqrr_cmode cmode;
17481 +#endif
17482 +};
17483 +
17484 +struct qm_mr {
17485 + const struct qm_mr_entry *ring, *cursor;
17486 + u8 pi, ci, fill, ithresh, vbit;
17487 +#ifdef CONFIG_FSL_DPA_CHECKING
17488 + enum qm_mr_pmode pmode;
17489 + enum qm_mr_cmode cmode;
17490 +#endif
17491 +};
17492 +
17493 +struct qm_mc {
17494 + struct qm_mc_command *cr;
17495 + struct qm_mc_result *rr;
17496 + u8 rridx, vbit;
17497 +#ifdef CONFIG_FSL_DPA_CHECKING
17498 + enum {
17499 + /* Can be _mc_start()ed */
17500 + qman_mc_idle,
17501 + /* Can be _mc_commit()ed or _mc_abort()ed */
17502 + qman_mc_user,
17503 + /* Can only be _mc_retry()ed */
17504 + qman_mc_hw
17505 + } state;
17506 +#endif
17507 +};
17508 +
17509 +#define QM_PORTAL_ALIGNMENT ____cacheline_aligned
17510 +
17511 +struct qm_addr {
17512 + void __iomem *addr_ce; /* cache-enabled */
17513 + void __iomem *addr_ci; /* cache-inhibited */
17514 +};
17515 +
17516 +struct qm_portal {
17517 + /* In the non-CONFIG_FSL_DPA_CHECKING case, the following stuff up to
17518 + * and including 'mc' fits within a cacheline (yay!). The 'config' part
17519 + * is setup-only, so isn't a cause for a concern. In other words, don't
17520 + * rearrange this structure on a whim, there be dragons ... */
17521 + struct qm_addr addr;
17522 + struct qm_eqcr eqcr;
17523 + struct qm_dqrr dqrr;
17524 + struct qm_mr mr;
17525 + struct qm_mc mc;
17526 +} QM_PORTAL_ALIGNMENT;
17527 +
17528 +
17529 +/* ---------------- */
17530 +/* --- EQCR API --- */
17531 +
17532 +/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */
17533 +#define EQCR_CARRYCLEAR(p) \
17534 + (void *)((unsigned long)(p) & (~(unsigned long)(QM_EQCR_SIZE << 6)))
17535 +
17536 +/* Bit-wise logic to convert a ring pointer to a ring index */
17537 +static inline u8 EQCR_PTR2IDX(struct qm_eqcr_entry *e)
17538 +{
17539 + return ((uintptr_t)e >> 6) & (QM_EQCR_SIZE - 1);
17540 +}
17541 +
17542 +/* Increment the 'cursor' ring pointer, taking 'vbit' into account */
17543 +static inline void EQCR_INC(struct qm_eqcr *eqcr)
17544 +{
17545 + /* NB: this is odd-looking, but experiments show that it generates fast
17546 + * code with essentially no branching overheads. We increment to the
17547 + * next EQCR pointer and handle overflow and 'vbit'. */
17548 + struct qm_eqcr_entry *partial = eqcr->cursor + 1;
17549 + eqcr->cursor = EQCR_CARRYCLEAR(partial);
17550 + if (partial != eqcr->cursor)
17551 + eqcr->vbit ^= QM_EQCR_VERB_VBIT;
17552 +}
17553 +
17554 +static inline int qm_eqcr_init(struct qm_portal *portal,
17555 + enum qm_eqcr_pmode pmode,
17556 + unsigned int eq_stash_thresh,
17557 + int eq_stash_prio)
17558 +{
17559 + /* This use of 'register', as well as all other occurrences, is because
17560 + * it has been observed to generate much faster code with gcc than is
17561 + * otherwise the case. */
17562 + register struct qm_eqcr *eqcr = &portal->eqcr;
17563 + u32 cfg;
17564 + u8 pi;
17565 +
17566 + eqcr->ring = portal->addr.addr_ce + QM_CL_EQCR;
17567 + eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1);
17568 + qm_cl_invalidate(EQCR_CI);
17569 + pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1);
17570 + eqcr->cursor = eqcr->ring + pi;
17571 + eqcr->vbit = (qm_in(EQCR_PI_CINH) & QM_EQCR_SIZE) ?
17572 + QM_EQCR_VERB_VBIT : 0;
17573 + eqcr->available = QM_EQCR_SIZE - 1 -
17574 + qm_cyc_diff(QM_EQCR_SIZE, eqcr->ci, pi);
17575 + eqcr->ithresh = qm_in(EQCR_ITR);
17576 +#ifdef CONFIG_FSL_DPA_CHECKING
17577 + eqcr->busy = 0;
17578 + eqcr->pmode = pmode;
17579 +#endif
17580 + cfg = (qm_in(CFG) & 0x00ffffff) |
17581 + (eq_stash_thresh << 28) | /* QCSP_CFG: EST */
17582 + (eq_stash_prio << 26) | /* QCSP_CFG: EP */
17583 + ((pmode & 0x3) << 24); /* QCSP_CFG::EPM */
17584 + qm_out(CFG, cfg);
17585 + return 0;
17586 +}
17587 +
17588 +static inline unsigned int qm_eqcr_get_ci_stashing(struct qm_portal *portal)
17589 +{
17590 + return (qm_in(CFG) >> 28) & 0x7;
17591 +}
17592 +
17593 +static inline void qm_eqcr_finish(struct qm_portal *portal)
17594 +{
17595 + register struct qm_eqcr *eqcr = &portal->eqcr;
17596 + u8 pi, ci;
17597 + u32 cfg;
17598 +
17599 + /*
17600 + * Disable EQCI stashing because the QMan only
17601 + * presents the value it previously stashed to
17602 + * maintain coherency. Setting the stash threshold
17603 + * to 1 then 0 ensures that QMan has resyncronized
17604 + * its internal copy so that the portal is clean
17605 + * when it is reinitialized in the future
17606 + */
17607 + cfg = (qm_in(CFG) & 0x0fffffff) |
17608 + (1 << 28); /* QCSP_CFG: EST */
17609 + qm_out(CFG, cfg);
17610 + cfg &= 0x0fffffff; /* stash threshold = 0 */
17611 + qm_out(CFG, cfg);
17612 +
17613 + pi = qm_in(EQCR_PI_CINH) & (QM_EQCR_SIZE - 1);
17614 + ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1);
17615 +
17616 + /* Refresh EQCR CI cache value */
17617 + qm_cl_invalidate(EQCR_CI);
17618 + eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1);
17619 +
17620 + DPA_ASSERT(!eqcr->busy);
17621 + if (pi != EQCR_PTR2IDX(eqcr->cursor))
17622 + pr_crit("losing uncommited EQCR entries\n");
17623 + if (ci != eqcr->ci)
17624 + pr_crit("missing existing EQCR completions\n");
17625 + if (eqcr->ci != EQCR_PTR2IDX(eqcr->cursor))
17626 + pr_crit("EQCR destroyed unquiesced\n");
17627 +}
17628 +
17629 +static inline struct qm_eqcr_entry *qm_eqcr_start_no_stash(struct qm_portal
17630 + *portal)
17631 +{
17632 + register struct qm_eqcr *eqcr = &portal->eqcr;
17633 + DPA_ASSERT(!eqcr->busy);
17634 + if (!eqcr->available)
17635 + return NULL;
17636 +
17637 +
17638 +#ifdef CONFIG_FSL_DPA_CHECKING
17639 + eqcr->busy = 1;
17640 +#endif
17641 + dcbz_64(eqcr->cursor);
17642 + return eqcr->cursor;
17643 +}
17644 +
17645 +static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal
17646 + *portal)
17647 +{
17648 + register struct qm_eqcr *eqcr = &portal->eqcr;
17649 + u8 diff, old_ci;
17650 +
17651 + DPA_ASSERT(!eqcr->busy);
17652 + if (!eqcr->available) {
17653 + old_ci = eqcr->ci;
17654 + eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1);
17655 + diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);
17656 + eqcr->available += diff;
17657 + if (!diff)
17658 + return NULL;
17659 + }
17660 +#ifdef CONFIG_FSL_DPA_CHECKING
17661 + eqcr->busy = 1;
17662 +#endif
17663 + dcbz_64(eqcr->cursor);
17664 + return eqcr->cursor;
17665 +}
17666 +
17667 +static inline void qm_eqcr_abort(struct qm_portal *portal)
17668 +{
17669 + __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr;
17670 + DPA_ASSERT(eqcr->busy);
17671 +#ifdef CONFIG_FSL_DPA_CHECKING
17672 + eqcr->busy = 0;
17673 +#endif
17674 +}
17675 +
17676 +static inline struct qm_eqcr_entry *qm_eqcr_pend_and_next(
17677 + struct qm_portal *portal, u8 myverb)
17678 +{
17679 + register struct qm_eqcr *eqcr = &portal->eqcr;
17680 + DPA_ASSERT(eqcr->busy);
17681 + DPA_ASSERT(eqcr->pmode != qm_eqcr_pvb);
17682 + if (eqcr->available == 1)
17683 + return NULL;
17684 + eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit;
17685 + dcbf(eqcr->cursor);
17686 + EQCR_INC(eqcr);
17687 + eqcr->available--;
17688 + dcbz_64(eqcr->cursor);
17689 + return eqcr->cursor;
17690 +}
17691 +
17692 +#define EQCR_COMMIT_CHECKS(eqcr) \
17693 +do { \
17694 + DPA_ASSERT(eqcr->busy); \
17695 + DPA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); \
17696 + DPA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); \
17697 +} while (0)
17698 +
17699 +static inline void qm_eqcr_pci_commit(struct qm_portal *portal, u8 myverb)
17700 +{
17701 + register struct qm_eqcr *eqcr = &portal->eqcr;
17702 + EQCR_COMMIT_CHECKS(eqcr);
17703 + DPA_ASSERT(eqcr->pmode == qm_eqcr_pci);
17704 + eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit;
17705 + EQCR_INC(eqcr);
17706 + eqcr->available--;
17707 + dcbf(eqcr->cursor);
17708 + hwsync();
17709 + qm_out(EQCR_PI_CINH, EQCR_PTR2IDX(eqcr->cursor));
17710 +#ifdef CONFIG_FSL_DPA_CHECKING
17711 + eqcr->busy = 0;
17712 +#endif
17713 +}
17714 +
17715 +static inline void qm_eqcr_pce_prefetch(struct qm_portal *portal)
17716 +{
17717 + __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr;
17718 + DPA_ASSERT(eqcr->pmode == qm_eqcr_pce);
17719 + qm_cl_invalidate(EQCR_PI);
17720 + qm_cl_touch_rw(EQCR_PI);
17721 +}
17722 +
17723 +static inline void qm_eqcr_pce_commit(struct qm_portal *portal, u8 myverb)
17724 +{
17725 + register struct qm_eqcr *eqcr = &portal->eqcr;
17726 + EQCR_COMMIT_CHECKS(eqcr);
17727 + DPA_ASSERT(eqcr->pmode == qm_eqcr_pce);
17728 + eqcr->cursor->__dont_write_directly__verb = myverb | eqcr->vbit;
17729 + EQCR_INC(eqcr);
17730 + eqcr->available--;
17731 + dcbf(eqcr->cursor);
17732 + lwsync();
17733 + qm_cl_out(EQCR_PI, EQCR_PTR2IDX(eqcr->cursor));
17734 +#ifdef CONFIG_FSL_DPA_CHECKING
17735 + eqcr->busy = 0;
17736 +#endif
17737 +}
17738 +
17739 +static inline void qm_eqcr_pvb_commit(struct qm_portal *portal, u8 myverb)
17740 +{
17741 + register struct qm_eqcr *eqcr = &portal->eqcr;
17742 + struct qm_eqcr_entry *eqcursor;
17743 + EQCR_COMMIT_CHECKS(eqcr);
17744 + DPA_ASSERT(eqcr->pmode == qm_eqcr_pvb);
17745 + lwsync();
17746 + eqcursor = eqcr->cursor;
17747 + eqcursor->__dont_write_directly__verb = myverb | eqcr->vbit;
17748 + dcbf(eqcursor);
17749 + EQCR_INC(eqcr);
17750 + eqcr->available--;
17751 +#ifdef CONFIG_FSL_DPA_CHECKING
17752 + eqcr->busy = 0;
17753 +#endif
17754 +}
17755 +
17756 +static inline u8 qm_eqcr_cci_update(struct qm_portal *portal)
17757 +{
17758 + register struct qm_eqcr *eqcr = &portal->eqcr;
17759 + u8 diff, old_ci = eqcr->ci;
17760 + eqcr->ci = qm_in(EQCR_CI_CINH) & (QM_EQCR_SIZE - 1);
17761 + diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);
17762 + eqcr->available += diff;
17763 + return diff;
17764 +}
17765 +
17766 +static inline void qm_eqcr_cce_prefetch(struct qm_portal *portal)
17767 +{
17768 + __maybe_unused register struct qm_eqcr *eqcr = &portal->eqcr;
17769 + qm_cl_touch_ro(EQCR_CI);
17770 +}
17771 +
17772 +static inline u8 qm_eqcr_cce_update(struct qm_portal *portal)
17773 +{
17774 + register struct qm_eqcr *eqcr = &portal->eqcr;
17775 + u8 diff, old_ci = eqcr->ci;
17776 + eqcr->ci = qm_cl_in(EQCR_CI) & (QM_EQCR_SIZE - 1);
17777 + qm_cl_invalidate(EQCR_CI);
17778 + diff = qm_cyc_diff(QM_EQCR_SIZE, old_ci, eqcr->ci);
17779 + eqcr->available += diff;
17780 + return diff;
17781 +}
17782 +
17783 +static inline u8 qm_eqcr_get_ithresh(struct qm_portal *portal)
17784 +{
17785 + register struct qm_eqcr *eqcr = &portal->eqcr;
17786 + return eqcr->ithresh;
17787 +}
17788 +
17789 +static inline void qm_eqcr_set_ithresh(struct qm_portal *portal, u8 ithresh)
17790 +{
17791 + register struct qm_eqcr *eqcr = &portal->eqcr;
17792 + eqcr->ithresh = ithresh;
17793 + qm_out(EQCR_ITR, ithresh);
17794 +}
17795 +
17796 +static inline u8 qm_eqcr_get_avail(struct qm_portal *portal)
17797 +{
17798 + register struct qm_eqcr *eqcr = &portal->eqcr;
17799 + return eqcr->available;
17800 +}
17801 +
17802 +static inline u8 qm_eqcr_get_fill(struct qm_portal *portal)
17803 +{
17804 + register struct qm_eqcr *eqcr = &portal->eqcr;
17805 + return QM_EQCR_SIZE - 1 - eqcr->available;
17806 +}
17807 +
17808 +
17809 +/* ---------------- */
17810 +/* --- DQRR API --- */
17811 +
17812 +/* FIXME: many possible improvements;
17813 + * - look at changing the API to use pointer rather than index parameters now
17814 + * that 'cursor' is a pointer,
17815 + * - consider moving other parameters to pointer if it could help (ci)
17816 + */
17817 +
17818 +#define DQRR_CARRYCLEAR(p) \
17819 + (void *)((unsigned long)(p) & (~(unsigned long)(QM_DQRR_SIZE << 6)))
17820 +
17821 +static inline u8 DQRR_PTR2IDX(const struct qm_dqrr_entry *e)
17822 +{
17823 + return ((uintptr_t)e >> 6) & (QM_DQRR_SIZE - 1);
17824 +}
17825 +
17826 +static inline const struct qm_dqrr_entry *DQRR_INC(
17827 + const struct qm_dqrr_entry *e)
17828 +{
17829 + return DQRR_CARRYCLEAR(e + 1);
17830 +}
17831 +
17832 +static inline void qm_dqrr_set_maxfill(struct qm_portal *portal, u8 mf)
17833 +{
17834 + qm_out(CFG, (qm_in(CFG) & 0xff0fffff) |
17835 + ((mf & (QM_DQRR_SIZE - 1)) << 20));
17836 +}
17837 +
17838 +static inline void qm_dqrr_cci_consume(struct qm_portal *portal, u8 num)
17839 +{
17840 + register struct qm_dqrr *dqrr = &portal->dqrr;
17841 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cci);
17842 + dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1);
17843 + qm_out(DQRR_CI_CINH, dqrr->ci);
17844 +}
17845 +
17846 +static inline void qm_dqrr_cce_consume(struct qm_portal *portal, u8 num)
17847 +{
17848 + register struct qm_dqrr *dqrr = &portal->dqrr;
17849 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cce);
17850 + dqrr->ci = (dqrr->ci + num) & (QM_DQRR_SIZE - 1);
17851 + qm_cl_out(DQRR_CI, dqrr->ci);
17852 +}
17853 +
17854 +static inline void qm_dqrr_cdc_consume_n(struct qm_portal *portal, u16 bitmask)
17855 +{
17856 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
17857 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
17858 + qm_out(DQRR_DCAP, (1 << 8) | /* DQRR_DCAP::S */
17859 + ((u32)bitmask << 16)); /* DQRR_DCAP::DCAP_CI */
17860 + dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1);
17861 + dqrr->fill = qm_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi);
17862 +}
17863 +
17864 +static inline int qm_dqrr_init(struct qm_portal *portal,
17865 + const struct qm_portal_config *config,
17866 + enum qm_dqrr_dmode dmode,
17867 + __maybe_unused enum qm_dqrr_pmode pmode,
17868 + enum qm_dqrr_cmode cmode, u8 max_fill)
17869 +{
17870 + register struct qm_dqrr *dqrr = &portal->dqrr;
17871 + u32 cfg;
17872 +
17873 + /* Make sure the DQRR will be idle when we enable */
17874 + qm_out(DQRR_SDQCR, 0);
17875 + qm_out(DQRR_VDQCR, 0);
17876 + qm_out(DQRR_PDQCR, 0);
17877 + dqrr->ring = portal->addr.addr_ce + QM_CL_DQRR;
17878 + dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1);
17879 + dqrr->ci = qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1);
17880 + dqrr->cursor = dqrr->ring + dqrr->ci;
17881 + dqrr->fill = qm_cyc_diff(QM_DQRR_SIZE, dqrr->ci, dqrr->pi);
17882 + dqrr->vbit = (qm_in(DQRR_PI_CINH) & QM_DQRR_SIZE) ?
17883 + QM_DQRR_VERB_VBIT : 0;
17884 + dqrr->ithresh = qm_in(DQRR_ITR);
17885 +
17886 + /* Free up pending DQRR entries if any as per current DCM */
17887 + if (dqrr->fill) {
17888 + enum qm_dqrr_cmode dcm = (qm_in(CFG) >> 16) & 3;
17889 +
17890 +#ifdef CONFIG_FSL_DPA_CHECKING
17891 + dqrr->cmode = dcm;
17892 +#endif
17893 + switch (dcm) {
17894 + case qm_dqrr_cci:
17895 + qm_dqrr_cci_consume(portal, dqrr->fill);
17896 + break;
17897 + case qm_dqrr_cce:
17898 + qm_dqrr_cce_consume(portal, dqrr->fill);
17899 + break;
17900 + case qm_dqrr_cdc:
17901 + qm_dqrr_cdc_consume_n(portal, (QM_DQRR_SIZE - 1));
17902 + break;
17903 + default:
17904 + DPA_ASSERT(0);
17905 + }
17906 + }
17907 +
17908 +#ifdef CONFIG_FSL_DPA_CHECKING
17909 + dqrr->dmode = dmode;
17910 + dqrr->pmode = pmode;
17911 + dqrr->cmode = cmode;
17912 +#endif
17913 + /* Invalidate every ring entry before beginning */
17914 + for (cfg = 0; cfg < QM_DQRR_SIZE; cfg++)
17915 + dcbi(qm_cl(dqrr->ring, cfg));
17916 + cfg = (qm_in(CFG) & 0xff000f00) |
17917 + ((max_fill & (QM_DQRR_SIZE - 1)) << 20) | /* DQRR_MF */
17918 + ((dmode & 1) << 18) | /* DP */
17919 + ((cmode & 3) << 16) | /* DCM */
17920 + 0xa0 | /* RE+SE */
17921 + (0 ? 0x40 : 0) | /* Ignore RP */
17922 + (0 ? 0x10 : 0); /* Ignore SP */
17923 + qm_out(CFG, cfg);
17924 + qm_dqrr_set_maxfill(portal, max_fill);
17925 + return 0;
17926 +}
17927 +
17928 +static inline void qm_dqrr_finish(struct qm_portal *portal)
17929 +{
17930 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
17931 +#ifdef CONFIG_FSL_DPA_CHECKING
17932 + if ((dqrr->cmode != qm_dqrr_cdc) &&
17933 + (dqrr->ci != DQRR_PTR2IDX(dqrr->cursor)))
17934 + pr_crit("Ignoring completed DQRR entries\n");
17935 +#endif
17936 +}
17937 +
17938 +static inline const struct qm_dqrr_entry *qm_dqrr_current(
17939 + struct qm_portal *portal)
17940 +{
17941 + register struct qm_dqrr *dqrr = &portal->dqrr;
17942 + if (!dqrr->fill)
17943 + return NULL;
17944 + return dqrr->cursor;
17945 +}
17946 +
17947 +static inline u8 qm_dqrr_cursor(struct qm_portal *portal)
17948 +{
17949 + register struct qm_dqrr *dqrr = &portal->dqrr;
17950 + return DQRR_PTR2IDX(dqrr->cursor);
17951 +}
17952 +
17953 +static inline u8 qm_dqrr_next(struct qm_portal *portal)
17954 +{
17955 + register struct qm_dqrr *dqrr = &portal->dqrr;
17956 + DPA_ASSERT(dqrr->fill);
17957 + dqrr->cursor = DQRR_INC(dqrr->cursor);
17958 + return --dqrr->fill;
17959 +}
17960 +
17961 +static inline u8 qm_dqrr_pci_update(struct qm_portal *portal)
17962 +{
17963 + register struct qm_dqrr *dqrr = &portal->dqrr;
17964 + u8 diff, old_pi = dqrr->pi;
17965 + DPA_ASSERT(dqrr->pmode == qm_dqrr_pci);
17966 + dqrr->pi = qm_in(DQRR_PI_CINH) & (QM_DQRR_SIZE - 1);
17967 + diff = qm_cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi);
17968 + dqrr->fill += diff;
17969 + return diff;
17970 +}
17971 +
17972 +static inline void qm_dqrr_pce_prefetch(struct qm_portal *portal)
17973 +{
17974 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
17975 + DPA_ASSERT(dqrr->pmode == qm_dqrr_pce);
17976 + qm_cl_invalidate(DQRR_PI);
17977 + qm_cl_touch_ro(DQRR_PI);
17978 +}
17979 +
17980 +static inline u8 qm_dqrr_pce_update(struct qm_portal *portal)
17981 +{
17982 + register struct qm_dqrr *dqrr = &portal->dqrr;
17983 + u8 diff, old_pi = dqrr->pi;
17984 + DPA_ASSERT(dqrr->pmode == qm_dqrr_pce);
17985 + dqrr->pi = qm_cl_in(DQRR_PI) & (QM_DQRR_SIZE - 1);
17986 + diff = qm_cyc_diff(QM_DQRR_SIZE, old_pi, dqrr->pi);
17987 + dqrr->fill += diff;
17988 + return diff;
17989 +}
17990 +
17991 +static inline void qm_dqrr_pvb_update(struct qm_portal *portal)
17992 +{
17993 + register struct qm_dqrr *dqrr = &portal->dqrr;
17994 + const struct qm_dqrr_entry *res = qm_cl(dqrr->ring, dqrr->pi);
17995 + DPA_ASSERT(dqrr->pmode == qm_dqrr_pvb);
17996 +#ifndef CONFIG_FSL_PAMU
17997 + /*
17998 + * If PAMU is not available we need to invalidate the cache.
17999 + * When PAMU is available the cache is updated by stash
18000 + */
18001 + dcbi(res);
18002 + dcbt_ro(res);
18003 +#endif
18004 +
18005 + /* when accessing 'verb', use __raw_readb() to ensure that compiler
18006 + * inlining doesn't try to optimise out "excess reads". */
18007 + if ((__raw_readb(&res->verb) & QM_DQRR_VERB_VBIT) == dqrr->vbit) {
18008 + dqrr->pi = (dqrr->pi + 1) & (QM_DQRR_SIZE - 1);
18009 + if (!dqrr->pi)
18010 + dqrr->vbit ^= QM_DQRR_VERB_VBIT;
18011 + dqrr->fill++;
18012 + }
18013 +}
18014 +
18015 +
18016 +static inline void qm_dqrr_cci_consume_to_current(struct qm_portal *portal)
18017 +{
18018 + register struct qm_dqrr *dqrr = &portal->dqrr;
18019 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cci);
18020 + dqrr->ci = DQRR_PTR2IDX(dqrr->cursor);
18021 + qm_out(DQRR_CI_CINH, dqrr->ci);
18022 +}
18023 +
18024 +static inline void qm_dqrr_cce_prefetch(struct qm_portal *portal)
18025 +{
18026 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18027 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cce);
18028 + qm_cl_invalidate(DQRR_CI);
18029 + qm_cl_touch_rw(DQRR_CI);
18030 +}
18031 +
18032 +static inline void qm_dqrr_cce_consume_to_current(struct qm_portal *portal)
18033 +{
18034 + register struct qm_dqrr *dqrr = &portal->dqrr;
18035 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cce);
18036 + dqrr->ci = DQRR_PTR2IDX(dqrr->cursor);
18037 + qm_cl_out(DQRR_CI, dqrr->ci);
18038 +}
18039 +
18040 +static inline void qm_dqrr_cdc_consume_1(struct qm_portal *portal, u8 idx,
18041 + int park)
18042 +{
18043 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18044 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
18045 + DPA_ASSERT(idx < QM_DQRR_SIZE);
18046 + qm_out(DQRR_DCAP, (0 << 8) | /* S */
18047 + ((park ? 1 : 0) << 6) | /* PK */
18048 + idx); /* DCAP_CI */
18049 +}
18050 +
18051 +static inline void qm_dqrr_cdc_consume_1ptr(struct qm_portal *portal,
18052 + const struct qm_dqrr_entry *dq,
18053 + int park)
18054 +{
18055 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18056 + u8 idx = DQRR_PTR2IDX(dq);
18057 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
18058 + DPA_ASSERT((dqrr->ring + idx) == dq);
18059 + DPA_ASSERT(idx < QM_DQRR_SIZE);
18060 + qm_out(DQRR_DCAP, (0 << 8) | /* DQRR_DCAP::S */
18061 + ((park ? 1 : 0) << 6) | /* DQRR_DCAP::PK */
18062 + idx); /* DQRR_DCAP::DCAP_CI */
18063 +}
18064 +
18065 +static inline u8 qm_dqrr_cdc_cci(struct qm_portal *portal)
18066 +{
18067 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18068 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
18069 + return qm_in(DQRR_CI_CINH) & (QM_DQRR_SIZE - 1);
18070 +}
18071 +
18072 +static inline void qm_dqrr_cdc_cce_prefetch(struct qm_portal *portal)
18073 +{
18074 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18075 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
18076 + qm_cl_invalidate(DQRR_CI);
18077 + qm_cl_touch_ro(DQRR_CI);
18078 +}
18079 +
18080 +static inline u8 qm_dqrr_cdc_cce(struct qm_portal *portal)
18081 +{
18082 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18083 + DPA_ASSERT(dqrr->cmode == qm_dqrr_cdc);
18084 + return qm_cl_in(DQRR_CI) & (QM_DQRR_SIZE - 1);
18085 +}
18086 +
18087 +static inline u8 qm_dqrr_get_ci(struct qm_portal *portal)
18088 +{
18089 + register struct qm_dqrr *dqrr = &portal->dqrr;
18090 + DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc);
18091 + return dqrr->ci;
18092 +}
18093 +
18094 +static inline void qm_dqrr_park(struct qm_portal *portal, u8 idx)
18095 +{
18096 + __maybe_unused register struct qm_dqrr *dqrr = &portal->dqrr;
18097 + DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc);
18098 + qm_out(DQRR_DCAP, (0 << 8) | /* S */
18099 + (1 << 6) | /* PK */
18100 + (idx & (QM_DQRR_SIZE - 1))); /* DCAP_CI */
18101 +}
18102 +
18103 +static inline void qm_dqrr_park_current(struct qm_portal *portal)
18104 +{
18105 + register struct qm_dqrr *dqrr = &portal->dqrr;
18106 + DPA_ASSERT(dqrr->cmode != qm_dqrr_cdc);
18107 + qm_out(DQRR_DCAP, (0 << 8) | /* S */
18108 + (1 << 6) | /* PK */
18109 + DQRR_PTR2IDX(dqrr->cursor)); /* DCAP_CI */
18110 +}
18111 +
18112 +static inline void qm_dqrr_sdqcr_set(struct qm_portal *portal, u32 sdqcr)
18113 +{
18114 + qm_out(DQRR_SDQCR, sdqcr);
18115 +}
18116 +
18117 +static inline u32 qm_dqrr_sdqcr_get(struct qm_portal *portal)
18118 +{
18119 + return qm_in(DQRR_SDQCR);
18120 +}
18121 +
18122 +static inline void qm_dqrr_vdqcr_set(struct qm_portal *portal, u32 vdqcr)
18123 +{
18124 + qm_out(DQRR_VDQCR, vdqcr);
18125 +}
18126 +
18127 +static inline u32 qm_dqrr_vdqcr_get(struct qm_portal *portal)
18128 +{
18129 + return qm_in(DQRR_VDQCR);
18130 +}
18131 +
18132 +static inline void qm_dqrr_pdqcr_set(struct qm_portal *portal, u32 pdqcr)
18133 +{
18134 + qm_out(DQRR_PDQCR, pdqcr);
18135 +}
18136 +
18137 +static inline u32 qm_dqrr_pdqcr_get(struct qm_portal *portal)
18138 +{
18139 + return qm_in(DQRR_PDQCR);
18140 +}
18141 +
18142 +static inline u8 qm_dqrr_get_ithresh(struct qm_portal *portal)
18143 +{
18144 + register struct qm_dqrr *dqrr = &portal->dqrr;
18145 + return dqrr->ithresh;
18146 +}
18147 +
18148 +static inline void qm_dqrr_set_ithresh(struct qm_portal *portal, u8 ithresh)
18149 +{
18150 + qm_out(DQRR_ITR, ithresh);
18151 +}
18152 +
18153 +static inline u8 qm_dqrr_get_maxfill(struct qm_portal *portal)
18154 +{
18155 + return (qm_in(CFG) & 0x00f00000) >> 20;
18156 +}
18157 +
18158 +
18159 +/* -------------- */
18160 +/* --- MR API --- */
18161 +
18162 +#define MR_CARRYCLEAR(p) \
18163 + (void *)((unsigned long)(p) & (~(unsigned long)(QM_MR_SIZE << 6)))
18164 +
18165 +static inline u8 MR_PTR2IDX(const struct qm_mr_entry *e)
18166 +{
18167 + return ((uintptr_t)e >> 6) & (QM_MR_SIZE - 1);
18168 +}
18169 +
18170 +static inline const struct qm_mr_entry *MR_INC(const struct qm_mr_entry *e)
18171 +{
18172 + return MR_CARRYCLEAR(e + 1);
18173 +}
18174 +
18175 +static inline int qm_mr_init(struct qm_portal *portal, enum qm_mr_pmode pmode,
18176 + enum qm_mr_cmode cmode)
18177 +{
18178 + register struct qm_mr *mr = &portal->mr;
18179 + u32 cfg;
18180 +
18181 + mr->ring = portal->addr.addr_ce + QM_CL_MR;
18182 + mr->pi = qm_in(MR_PI_CINH) & (QM_MR_SIZE - 1);
18183 + mr->ci = qm_in(MR_CI_CINH) & (QM_MR_SIZE - 1);
18184 + mr->cursor = mr->ring + mr->ci;
18185 + mr->fill = qm_cyc_diff(QM_MR_SIZE, mr->ci, mr->pi);
18186 + mr->vbit = (qm_in(MR_PI_CINH) & QM_MR_SIZE) ? QM_MR_VERB_VBIT : 0;
18187 + mr->ithresh = qm_in(MR_ITR);
18188 +#ifdef CONFIG_FSL_DPA_CHECKING
18189 + mr->pmode = pmode;
18190 + mr->cmode = cmode;
18191 +#endif
18192 + cfg = (qm_in(CFG) & 0xfffff0ff) |
18193 + ((cmode & 1) << 8); /* QCSP_CFG:MM */
18194 + qm_out(CFG, cfg);
18195 + return 0;
18196 +}
18197 +
18198 +static inline void qm_mr_finish(struct qm_portal *portal)
18199 +{
18200 + register struct qm_mr *mr = &portal->mr;
18201 + if (mr->ci != MR_PTR2IDX(mr->cursor))
18202 + pr_crit("Ignoring completed MR entries\n");
18203 +}
18204 +
18205 +static inline const struct qm_mr_entry *qm_mr_current(struct qm_portal *portal)
18206 +{
18207 + register struct qm_mr *mr = &portal->mr;
18208 + if (!mr->fill)
18209 + return NULL;
18210 + return mr->cursor;
18211 +}
18212 +
18213 +static inline u8 qm_mr_cursor(struct qm_portal *portal)
18214 +{
18215 + register struct qm_mr *mr = &portal->mr;
18216 + return MR_PTR2IDX(mr->cursor);
18217 +}
18218 +
18219 +static inline u8 qm_mr_next(struct qm_portal *portal)
18220 +{
18221 + register struct qm_mr *mr = &portal->mr;
18222 + DPA_ASSERT(mr->fill);
18223 + mr->cursor = MR_INC(mr->cursor);
18224 + return --mr->fill;
18225 +}
18226 +
18227 +static inline u8 qm_mr_pci_update(struct qm_portal *portal)
18228 +{
18229 + register struct qm_mr *mr = &portal->mr;
18230 + u8 diff, old_pi = mr->pi;
18231 + DPA_ASSERT(mr->pmode == qm_mr_pci);
18232 + mr->pi = qm_in(MR_PI_CINH);
18233 + diff = qm_cyc_diff(QM_MR_SIZE, old_pi, mr->pi);
18234 + mr->fill += diff;
18235 + return diff;
18236 +}
18237 +
18238 +static inline void qm_mr_pce_prefetch(struct qm_portal *portal)
18239 +{
18240 + __maybe_unused register struct qm_mr *mr = &portal->mr;
18241 + DPA_ASSERT(mr->pmode == qm_mr_pce);
18242 + qm_cl_invalidate(MR_PI);
18243 + qm_cl_touch_ro(MR_PI);
18244 +}
18245 +
18246 +static inline u8 qm_mr_pce_update(struct qm_portal *portal)
18247 +{
18248 + register struct qm_mr *mr = &portal->mr;
18249 + u8 diff, old_pi = mr->pi;
18250 + DPA_ASSERT(mr->pmode == qm_mr_pce);
18251 + mr->pi = qm_cl_in(MR_PI) & (QM_MR_SIZE - 1);
18252 + diff = qm_cyc_diff(QM_MR_SIZE, old_pi, mr->pi);
18253 + mr->fill += diff;
18254 + return diff;
18255 +}
18256 +
18257 +static inline void qm_mr_pvb_update(struct qm_portal *portal)
18258 +{
18259 + register struct qm_mr *mr = &portal->mr;
18260 + const struct qm_mr_entry *res = qm_cl(mr->ring, mr->pi);
18261 + DPA_ASSERT(mr->pmode == qm_mr_pvb);
18262 + /* when accessing 'verb', use __raw_readb() to ensure that compiler
18263 + * inlining doesn't try to optimise out "excess reads". */
18264 + if ((__raw_readb(&res->verb) & QM_MR_VERB_VBIT) == mr->vbit) {
18265 + mr->pi = (mr->pi + 1) & (QM_MR_SIZE - 1);
18266 + if (!mr->pi)
18267 + mr->vbit ^= QM_MR_VERB_VBIT;
18268 + mr->fill++;
18269 + res = MR_INC(res);
18270 + }
18271 + dcbit_ro(res);
18272 +}
18273 +
18274 +static inline void qm_mr_cci_consume(struct qm_portal *portal, u8 num)
18275 +{
18276 + register struct qm_mr *mr = &portal->mr;
18277 + DPA_ASSERT(mr->cmode == qm_mr_cci);
18278 + mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1);
18279 + qm_out(MR_CI_CINH, mr->ci);
18280 +}
18281 +
18282 +static inline void qm_mr_cci_consume_to_current(struct qm_portal *portal)
18283 +{
18284 + register struct qm_mr *mr = &portal->mr;
18285 + DPA_ASSERT(mr->cmode == qm_mr_cci);
18286 + mr->ci = MR_PTR2IDX(mr->cursor);
18287 + qm_out(MR_CI_CINH, mr->ci);
18288 +}
18289 +
18290 +static inline void qm_mr_cce_prefetch(struct qm_portal *portal)
18291 +{
18292 + __maybe_unused register struct qm_mr *mr = &portal->mr;
18293 + DPA_ASSERT(mr->cmode == qm_mr_cce);
18294 + qm_cl_invalidate(MR_CI);
18295 + qm_cl_touch_rw(MR_CI);
18296 +}
18297 +
18298 +static inline void qm_mr_cce_consume(struct qm_portal *portal, u8 num)
18299 +{
18300 + register struct qm_mr *mr = &portal->mr;
18301 + DPA_ASSERT(mr->cmode == qm_mr_cce);
18302 + mr->ci = (mr->ci + num) & (QM_MR_SIZE - 1);
18303 + qm_cl_out(MR_CI, mr->ci);
18304 +}
18305 +
18306 +static inline void qm_mr_cce_consume_to_current(struct qm_portal *portal)
18307 +{
18308 + register struct qm_mr *mr = &portal->mr;
18309 + DPA_ASSERT(mr->cmode == qm_mr_cce);
18310 + mr->ci = MR_PTR2IDX(mr->cursor);
18311 + qm_cl_out(MR_CI, mr->ci);
18312 +}
18313 +
18314 +static inline u8 qm_mr_get_ci(struct qm_portal *portal)
18315 +{
18316 + register struct qm_mr *mr = &portal->mr;
18317 + return mr->ci;
18318 +}
18319 +
18320 +static inline u8 qm_mr_get_ithresh(struct qm_portal *portal)
18321 +{
18322 + register struct qm_mr *mr = &portal->mr;
18323 + return mr->ithresh;
18324 +}
18325 +
18326 +static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh)
18327 +{
18328 + qm_out(MR_ITR, ithresh);
18329 +}
18330 +
18331 +
18332 +/* ------------------------------ */
18333 +/* --- Management command API --- */
18334 +
18335 +static inline int qm_mc_init(struct qm_portal *portal)
18336 +{
18337 + register struct qm_mc *mc = &portal->mc;
18338 + mc->cr = portal->addr.addr_ce + QM_CL_CR;
18339 + mc->rr = portal->addr.addr_ce + QM_CL_RR0;
18340 + mc->rridx = (__raw_readb(&mc->cr->__dont_write_directly__verb) &
18341 + QM_MCC_VERB_VBIT) ? 0 : 1;
18342 + mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0;
18343 +#ifdef CONFIG_FSL_DPA_CHECKING
18344 + mc->state = qman_mc_idle;
18345 +#endif
18346 + return 0;
18347 +}
18348 +
18349 +static inline void qm_mc_finish(struct qm_portal *portal)
18350 +{
18351 + __maybe_unused register struct qm_mc *mc = &portal->mc;
18352 + DPA_ASSERT(mc->state == qman_mc_idle);
18353 +#ifdef CONFIG_FSL_DPA_CHECKING
18354 + if (mc->state != qman_mc_idle)
18355 + pr_crit("Losing incomplete MC command\n");
18356 +#endif
18357 +}
18358 +
18359 +static inline struct qm_mc_command *qm_mc_start(struct qm_portal *portal)
18360 +{
18361 + register struct qm_mc *mc = &portal->mc;
18362 + DPA_ASSERT(mc->state == qman_mc_idle);
18363 +#ifdef CONFIG_FSL_DPA_CHECKING
18364 + mc->state = qman_mc_user;
18365 +#endif
18366 + dcbz_64(mc->cr);
18367 + return mc->cr;
18368 +}
18369 +
18370 +static inline void qm_mc_abort(struct qm_portal *portal)
18371 +{
18372 + __maybe_unused register struct qm_mc *mc = &portal->mc;
18373 + DPA_ASSERT(mc->state == qman_mc_user);
18374 +#ifdef CONFIG_FSL_DPA_CHECKING
18375 + mc->state = qman_mc_idle;
18376 +#endif
18377 +}
18378 +
18379 +static inline void qm_mc_commit(struct qm_portal *portal, u8 myverb)
18380 +{
18381 + register struct qm_mc *mc = &portal->mc;
18382 + struct qm_mc_result *rr = mc->rr + mc->rridx;
18383 + DPA_ASSERT(mc->state == qman_mc_user);
18384 + lwsync();
18385 + mc->cr->__dont_write_directly__verb = myverb | mc->vbit;
18386 + dcbf(mc->cr);
18387 + dcbit_ro(rr);
18388 +#ifdef CONFIG_FSL_DPA_CHECKING
18389 + mc->state = qman_mc_hw;
18390 +#endif
18391 +}
18392 +
18393 +static inline struct qm_mc_result *qm_mc_result(struct qm_portal *portal)
18394 +{
18395 + register struct qm_mc *mc = &portal->mc;
18396 + struct qm_mc_result *rr = mc->rr + mc->rridx;
18397 + DPA_ASSERT(mc->state == qman_mc_hw);
18398 + /* The inactive response register's verb byte always returns zero until
18399 + * its command is submitted and completed. This includes the valid-bit,
18400 + * in case you were wondering... */
18401 + if (!__raw_readb(&rr->verb)) {
18402 + dcbit_ro(rr);
18403 + return NULL;
18404 + }
18405 + mc->rridx ^= 1;
18406 + mc->vbit ^= QM_MCC_VERB_VBIT;
18407 +#ifdef CONFIG_FSL_DPA_CHECKING
18408 + mc->state = qman_mc_idle;
18409 +#endif
18410 + return rr;
18411 +}
18412 +
18413 +
18414 +/* ------------------------------------- */
18415 +/* --- Portal interrupt register API --- */
18416 +
18417 +static inline int qm_isr_init(__always_unused struct qm_portal *portal)
18418 +{
18419 + return 0;
18420 +}
18421 +
18422 +static inline void qm_isr_finish(__always_unused struct qm_portal *portal)
18423 +{
18424 +}
18425 +
18426 +static inline void qm_isr_set_iperiod(struct qm_portal *portal, u16 iperiod)
18427 +{
18428 + qm_out(ITPR, iperiod);
18429 +}
18430 +
18431 +static inline u32 __qm_isr_read(struct qm_portal *portal, enum qm_isr_reg n)
18432 +{
18433 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
18434 + return __qm_in(&portal->addr, QM_REG_ISR + (n << 6));
18435 +#else
18436 + return __qm_in(&portal->addr, QM_REG_ISR + (n << 2));
18437 +#endif
18438 +}
18439 +
18440 +static inline void __qm_isr_write(struct qm_portal *portal, enum qm_isr_reg n,
18441 + u32 val)
18442 +{
18443 +#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
18444 + __qm_out(&portal->addr, QM_REG_ISR + (n << 6), val);
18445 +#else
18446 + __qm_out(&portal->addr, QM_REG_ISR + (n << 2), val);
18447 +#endif
18448 +}
18449 +
18450 +/* Cleanup FQs */
18451 +static inline int qm_shutdown_fq(struct qm_portal **portal, int portal_count,
18452 + u32 fqid)
18453 +{
18454 +
18455 + struct qm_mc_command *mcc;
18456 + struct qm_mc_result *mcr;
18457 + u8 state;
18458 + int orl_empty, fq_empty, i, drain = 0;
18459 + u32 result;
18460 + u32 channel, wq;
18461 + u16 dest_wq;
18462 +
18463 + /* Determine the state of the FQID */
18464 + mcc = qm_mc_start(portal[0]);
18465 + mcc->queryfq_np.fqid = cpu_to_be32(fqid);
18466 + qm_mc_commit(portal[0], QM_MCC_VERB_QUERYFQ_NP);
18467 + while (!(mcr = qm_mc_result(portal[0])))
18468 + cpu_relax();
18469 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ_NP);
18470 + state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK;
18471 + if (state == QM_MCR_NP_STATE_OOS)
18472 + return 0; /* Already OOS, no need to do anymore checks */
18473 +
18474 + /* Query which channel the FQ is using */
18475 + mcc = qm_mc_start(portal[0]);
18476 + mcc->queryfq.fqid = cpu_to_be32(fqid);
18477 + qm_mc_commit(portal[0], QM_MCC_VERB_QUERYFQ);
18478 + while (!(mcr = qm_mc_result(portal[0])))
18479 + cpu_relax();
18480 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == QM_MCR_VERB_QUERYFQ);
18481 +
18482 + /* Need to store these since the MCR gets reused */
18483 + dest_wq = be16_to_cpu(mcr->queryfq.fqd.dest_wq);
18484 + wq = dest_wq & 0x7;
18485 + channel = dest_wq>>3;
18486 +
18487 + switch (state) {
18488 + case QM_MCR_NP_STATE_TEN_SCHED:
18489 + case QM_MCR_NP_STATE_TRU_SCHED:
18490 + case QM_MCR_NP_STATE_ACTIVE:
18491 + case QM_MCR_NP_STATE_PARKED:
18492 + orl_empty = 0;
18493 + mcc = qm_mc_start(portal[0]);
18494 + mcc->alterfq.fqid = cpu_to_be32(fqid);
18495 + qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_RETIRE);
18496 + while (!(mcr = qm_mc_result(portal[0])))
18497 + cpu_relax();
18498 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
18499 + QM_MCR_VERB_ALTER_RETIRE);
18500 + result = mcr->result; /* Make a copy as we reuse MCR below */
18501 +
18502 + if (result == QM_MCR_RESULT_PENDING) {
18503 + /* Need to wait for the FQRN in the message ring, which
18504 + will only occur once the FQ has been drained. In
18505 + order for the FQ to drain the portal needs to be set
18506 + to dequeue from the channel the FQ is scheduled on */
18507 + const struct qm_mr_entry *msg;
18508 + const struct qm_dqrr_entry *dqrr = NULL;
18509 + int found_fqrn = 0;
18510 + u16 dequeue_wq = 0;
18511 +
18512 + /* Flag that we need to drain FQ */
18513 + drain = 1;
18514 +
18515 + if (channel >= qm_channel_pool1 &&
18516 + channel < (qm_channel_pool1 + 15)) {
18517 + /* Pool channel, enable the bit in the portal */
18518 + dequeue_wq = (channel -
18519 + qm_channel_pool1 + 1)<<4 | wq;
18520 + } else if (channel < qm_channel_pool1) {
18521 + /* Dedicated channel */
18522 + dequeue_wq = wq;
18523 + } else {
18524 + pr_info("Cannot recover FQ 0x%x, it is "
18525 + "scheduled on channel 0x%x",
18526 + fqid, channel);
18527 + return -EBUSY;
18528 + }
18529 + /* Set the sdqcr to drain this channel */
18530 + if (channel < qm_channel_pool1)
18531 + for (i = 0; i < portal_count; i++)
18532 + qm_dqrr_sdqcr_set(portal[i],
18533 + QM_SDQCR_TYPE_ACTIVE |
18534 + QM_SDQCR_CHANNELS_DEDICATED);
18535 + else
18536 + for (i = 0; i < portal_count; i++)
18537 + qm_dqrr_sdqcr_set(
18538 + portal[i],
18539 + QM_SDQCR_TYPE_ACTIVE |
18540 + QM_SDQCR_CHANNELS_POOL_CONV
18541 + (channel));
18542 + while (!found_fqrn) {
18543 + /* Keep draining DQRR while checking the MR*/
18544 + for (i = 0; i < portal_count; i++) {
18545 + qm_dqrr_pvb_update(portal[i]);
18546 + dqrr = qm_dqrr_current(portal[i]);
18547 + while (dqrr) {
18548 + qm_dqrr_cdc_consume_1ptr(
18549 + portal[i], dqrr, 0);
18550 + qm_dqrr_pvb_update(portal[i]);
18551 + qm_dqrr_next(portal[i]);
18552 + dqrr = qm_dqrr_current(
18553 + portal[i]);
18554 + }
18555 + /* Process message ring too */
18556 + qm_mr_pvb_update(portal[i]);
18557 + msg = qm_mr_current(portal[i]);
18558 + while (msg) {
18559 + if ((msg->verb &
18560 + QM_MR_VERB_TYPE_MASK)
18561 + == QM_MR_VERB_FQRN)
18562 + found_fqrn = 1;
18563 + qm_mr_next(portal[i]);
18564 + qm_mr_cci_consume_to_current(
18565 + portal[i]);
18566 + qm_mr_pvb_update(portal[i]);
18567 + msg = qm_mr_current(portal[i]);
18568 + }
18569 + cpu_relax();
18570 + }
18571 + }
18572 + }
18573 + if (result != QM_MCR_RESULT_OK &&
18574 + result != QM_MCR_RESULT_PENDING) {
18575 + /* error */
18576 + pr_err("qman_retire_fq failed on FQ 0x%x, result=0x%x\n",
18577 + fqid, result);
18578 + return -1;
18579 + }
18580 + if (!(mcr->alterfq.fqs & QM_MCR_FQS_ORLPRESENT)) {
18581 + /* ORL had no entries, no need to wait until the
18582 + ERNs come in */
18583 + orl_empty = 1;
18584 + }
18585 + /* Retirement succeeded, check to see if FQ needs
18586 + to be drained */
18587 + if (drain || mcr->alterfq.fqs & QM_MCR_FQS_NOTEMPTY) {
18588 + /* FQ is Not Empty, drain using volatile DQ commands */
18589 + fq_empty = 0;
18590 + do {
18591 + const struct qm_dqrr_entry *dqrr = NULL;
18592 + u32 vdqcr = fqid | QM_VDQCR_NUMFRAMES_SET(3);
18593 + qm_dqrr_vdqcr_set(portal[0], vdqcr);
18594 +
18595 + /* Wait for a dequeue to occur */
18596 + while (dqrr == NULL) {
18597 + qm_dqrr_pvb_update(portal[0]);
18598 + dqrr = qm_dqrr_current(portal[0]);
18599 + if (!dqrr)
18600 + cpu_relax();
18601 + }
18602 + /* Process the dequeues, making sure to
18603 + empty the ring completely */
18604 + while (dqrr) {
18605 + if (be32_to_cpu(dqrr->fqid) == fqid &&
18606 + dqrr->stat & QM_DQRR_STAT_FQ_EMPTY)
18607 + fq_empty = 1;
18608 + qm_dqrr_cdc_consume_1ptr(portal[0],
18609 + dqrr, 0);
18610 + qm_dqrr_pvb_update(portal[0]);
18611 + qm_dqrr_next(portal[0]);
18612 + dqrr = qm_dqrr_current(portal[0]);
18613 + }
18614 + } while (fq_empty == 0);
18615 + }
18616 + for (i = 0; i < portal_count; i++)
18617 + qm_dqrr_sdqcr_set(portal[i], 0);
18618 +
18619 + /* Wait for the ORL to have been completely drained */
18620 + while (orl_empty == 0) {
18621 + const struct qm_mr_entry *msg;
18622 + qm_mr_pvb_update(portal[0]);
18623 + msg = qm_mr_current(portal[0]);
18624 + while (msg) {
18625 + if ((msg->verb & QM_MR_VERB_TYPE_MASK) ==
18626 + QM_MR_VERB_FQRL)
18627 + orl_empty = 1;
18628 + qm_mr_next(portal[0]);
18629 + qm_mr_cci_consume_to_current(portal[0]);
18630 + qm_mr_pvb_update(portal[0]);
18631 + msg = qm_mr_current(portal[0]);
18632 + }
18633 + cpu_relax();
18634 + }
18635 + mcc = qm_mc_start(portal[0]);
18636 + mcc->alterfq.fqid = cpu_to_be32(fqid);
18637 + qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_OOS);
18638 + while (!(mcr = qm_mc_result(portal[0])))
18639 + cpu_relax();
18640 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
18641 + QM_MCR_VERB_ALTER_OOS);
18642 + if (mcr->result != QM_MCR_RESULT_OK) {
18643 + pr_err("OOS after drain Failed on FQID 0x%x, result 0x%x\n",
18644 + fqid, mcr->result);
18645 + return -1;
18646 + }
18647 + return 0;
18648 + case QM_MCR_NP_STATE_RETIRED:
18649 + /* Send OOS Command */
18650 + mcc = qm_mc_start(portal[0]);
18651 + mcc->alterfq.fqid = cpu_to_be32(fqid);
18652 + qm_mc_commit(portal[0], QM_MCC_VERB_ALTER_OOS);
18653 + while (!(mcr = qm_mc_result(portal[0])))
18654 + cpu_relax();
18655 + DPA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
18656 + QM_MCR_VERB_ALTER_OOS);
18657 + if (mcr->result) {
18658 + pr_err("OOS Failed on FQID 0x%x\n", fqid);
18659 + return -1;
18660 + }
18661 + return 0;
18662 + }
18663 + return -1;
18664 +}
18665 --- /dev/null
18666 +++ b/drivers/staging/fsl_qbman/qman_private.h
18667 @@ -0,0 +1,398 @@
18668 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
18669 + *
18670 + * Redistribution and use in source and binary forms, with or without
18671 + * modification, are permitted provided that the following conditions are met:
18672 + * * Redistributions of source code must retain the above copyright
18673 + * notice, this list of conditions and the following disclaimer.
18674 + * * Redistributions in binary form must reproduce the above copyright
18675 + * notice, this list of conditions and the following disclaimer in the
18676 + * documentation and/or other materials provided with the distribution.
18677 + * * Neither the name of Freescale Semiconductor nor the
18678 + * names of its contributors may be used to endorse or promote products
18679 + * derived from this software without specific prior written permission.
18680 + *
18681 + *
18682 + * ALTERNATIVELY, this software may be distributed under the terms of the
18683 + * GNU General Public License ("GPL") as published by the Free Software
18684 + * Foundation, either version 2 of that License or (at your option) any
18685 + * later version.
18686 + *
18687 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
18688 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18689 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18690 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
18691 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18692 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18693 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
18694 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
18695 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
18696 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
18697 + */
18698 +
18699 +#include "dpa_sys.h"
18700 +#include <linux/fsl_qman.h>
18701 +#include <linux/iommu.h>
18702 +
18703 +#if defined(CONFIG_FSL_PAMU)
18704 +#include <asm/fsl_pamu_stash.h>
18705 +#endif
18706 +
18707 +#if !defined(CONFIG_FSL_QMAN_FQ_LOOKUP) && defined(CONFIG_PPC64)
18708 +#error "_PPC64 requires _FSL_QMAN_FQ_LOOKUP"
18709 +#endif
18710 +
18711 +#define QBMAN_ANY_PORTAL_IDX 0xffffffff
18712 + /* ----------------- */
18713 + /* Congestion Groups */
18714 + /* ----------------- */
18715 +/* This wrapper represents a bit-array for the state of the 256 Qman congestion
18716 + * groups. Is also used as a *mask* for congestion groups, eg. so we ignore
18717 + * those that don't concern us. We harness the structure and accessor details
18718 + * already used in the management command to query congestion groups. */
18719 +struct qman_cgrs {
18720 + struct __qm_mcr_querycongestion q;
18721 +};
18722 +static inline void qman_cgrs_init(struct qman_cgrs *c)
18723 +{
18724 + memset(c, 0, sizeof(*c));
18725 +}
18726 +static inline void qman_cgrs_fill(struct qman_cgrs *c)
18727 +{
18728 + memset(c, 0xff, sizeof(*c));
18729 +}
18730 +static inline int qman_cgrs_get(struct qman_cgrs *c, int num)
18731 +{
18732 + return QM_MCR_QUERYCONGESTION(&c->q, num);
18733 +}
18734 +static inline void qman_cgrs_set(struct qman_cgrs *c, int num)
18735 +{
18736 + c->q.__state[__CGR_WORD(num)] |= (0x80000000 >> __CGR_SHIFT(num));
18737 +}
18738 +static inline void qman_cgrs_unset(struct qman_cgrs *c, int num)
18739 +{
18740 + c->q.__state[__CGR_WORD(num)] &= ~(0x80000000 >> __CGR_SHIFT(num));
18741 +}
18742 +static inline int qman_cgrs_next(struct qman_cgrs *c, int num)
18743 +{
18744 + while ((++num < __CGR_NUM) && !qman_cgrs_get(c, num))
18745 + ;
18746 + return num;
18747 +}
18748 +static inline void qman_cgrs_cp(struct qman_cgrs *dest,
18749 + const struct qman_cgrs *src)
18750 +{
18751 + *dest = *src;
18752 +}
18753 +static inline void qman_cgrs_and(struct qman_cgrs *dest,
18754 + const struct qman_cgrs *a, const struct qman_cgrs *b)
18755 +{
18756 + int ret;
18757 + u32 *_d = dest->q.__state;
18758 + const u32 *_a = a->q.__state;
18759 + const u32 *_b = b->q.__state;
18760 + for (ret = 0; ret < 8; ret++)
18761 + *(_d++) = *(_a++) & *(_b++);
18762 +}
18763 +static inline void qman_cgrs_xor(struct qman_cgrs *dest,
18764 + const struct qman_cgrs *a, const struct qman_cgrs *b)
18765 +{
18766 + int ret;
18767 + u32 *_d = dest->q.__state;
18768 + const u32 *_a = a->q.__state;
18769 + const u32 *_b = b->q.__state;
18770 + for (ret = 0; ret < 8; ret++)
18771 + *(_d++) = *(_a++) ^ *(_b++);
18772 +}
18773 +
18774 + /* ----------------------- */
18775 + /* CEETM Congestion Groups */
18776 + /* ----------------------- */
18777 +/* This wrapper represents a bit-array for the state of the 512 Qman CEETM
18778 + * congestion groups.
18779 + */
18780 +struct qman_ccgrs {
18781 + struct __qm_mcr_querycongestion q[2];
18782 +};
18783 +static inline void qman_ccgrs_init(struct qman_ccgrs *c)
18784 +{
18785 + memset(c, 0, sizeof(*c));
18786 +}
18787 +static inline void qman_ccgrs_fill(struct qman_ccgrs *c)
18788 +{
18789 + memset(c, 0xff, sizeof(*c));
18790 +}
18791 +static inline int qman_ccgrs_get(struct qman_ccgrs *c, int num)
18792 +{
18793 + if (num < __CGR_NUM)
18794 + return QM_MCR_QUERYCONGESTION(&c->q[0], num);
18795 + else
18796 + return QM_MCR_QUERYCONGESTION(&c->q[1], (num - __CGR_NUM));
18797 +}
18798 +static inline int qman_ccgrs_next(struct qman_ccgrs *c, int num)
18799 +{
18800 + while ((++num < __CGR_NUM) && !qman_ccgrs_get(c, num))
18801 + ;
18802 + return num;
18803 +}
18804 +static inline void qman_ccgrs_cp(struct qman_ccgrs *dest,
18805 + const struct qman_ccgrs *src)
18806 +{
18807 + *dest = *src;
18808 +}
18809 +static inline void qman_ccgrs_and(struct qman_ccgrs *dest,
18810 + const struct qman_ccgrs *a, const struct qman_ccgrs *b)
18811 +{
18812 + int ret, i;
18813 + u32 *_d;
18814 + const u32 *_a, *_b;
18815 + for (i = 0; i < 2; i++) {
18816 + _d = dest->q[i].__state;
18817 + _a = a->q[i].__state;
18818 + _b = b->q[i].__state;
18819 + for (ret = 0; ret < 8; ret++)
18820 + *(_d++) = *(_a++) & *(_b++);
18821 + }
18822 +}
18823 +static inline void qman_ccgrs_xor(struct qman_ccgrs *dest,
18824 + const struct qman_ccgrs *a, const struct qman_ccgrs *b)
18825 +{
18826 + int ret, i;
18827 + u32 *_d;
18828 + const u32 *_a, *_b;
18829 + for (i = 0; i < 2; i++) {
18830 + _d = dest->q[i].__state;
18831 + _a = a->q[i].__state;
18832 + _b = b->q[i].__state;
18833 + for (ret = 0; ret < 8; ret++)
18834 + *(_d++) = *(_a++) ^ *(_b++);
18835 + }
18836 +}
18837 +
18838 +/* used by CCSR and portal interrupt code */
18839 +enum qm_isr_reg {
18840 + qm_isr_status = 0,
18841 + qm_isr_enable = 1,
18842 + qm_isr_disable = 2,
18843 + qm_isr_inhibit = 3
18844 +};
18845 +
18846 +struct qm_portal_config {
18847 + /* Corenet portal addresses;
18848 + * [0]==cache-enabled, [1]==cache-inhibited. */
18849 + __iomem void *addr_virt[2];
18850 + struct resource addr_phys[2];
18851 + struct device dev;
18852 + struct iommu_domain *iommu_domain;
18853 + /* Allow these to be joined in lists */
18854 + struct list_head list;
18855 + /* User-visible portal configuration settings */
18856 + struct qman_portal_config public_cfg;
18857 + /* power management saved data */
18858 + u32 saved_isdr;
18859 +};
18860 +
18861 +/* Revision info (for errata and feature handling) */
18862 +#define QMAN_REV11 0x0101
18863 +#define QMAN_REV12 0x0102
18864 +#define QMAN_REV20 0x0200
18865 +#define QMAN_REV30 0x0300
18866 +#define QMAN_REV31 0x0301
18867 +#define QMAN_REV32 0x0302
18868 +
18869 +/* QMan REV_2 register contains the Cfg option */
18870 +#define QMAN_REV_CFG_0 0x0
18871 +#define QMAN_REV_CFG_1 0x1
18872 +#define QMAN_REV_CFG_2 0x2
18873 +#define QMAN_REV_CFG_3 0x3
18874 +
18875 +extern u16 qman_ip_rev; /* 0 if uninitialised, otherwise QMAN_REVx */
18876 +extern u8 qman_ip_cfg;
18877 +extern u32 qman_clk;
18878 +extern u16 qman_portal_max;
18879 +
18880 +#ifdef CONFIG_FSL_QMAN_CONFIG
18881 +/* Hooks from qman_driver.c to qman_config.c */
18882 +int qman_init_ccsr(struct device_node *node);
18883 +void qman_liodn_fixup(u16 channel);
18884 +int qman_set_sdest(u16 channel, unsigned int cpu_idx);
18885 +size_t get_qman_fqd_size(void);
18886 +#else
18887 +static inline size_t get_qman_fqd_size(void)
18888 +{
18889 + return (PAGE_SIZE << CONFIG_FSL_QMAN_FQD_SZ);
18890 +}
18891 +#endif
18892 +
18893 +int qm_set_wpm(int wpm);
18894 +int qm_get_wpm(int *wpm);
18895 +
18896 +/* Hooks from qman_driver.c in to qman_high.c */
18897 +struct qman_portal *qman_create_portal(
18898 + struct qman_portal *portal,
18899 + const struct qm_portal_config *config,
18900 + const struct qman_cgrs *cgrs);
18901 +
18902 +struct qman_portal *qman_create_affine_portal(
18903 + const struct qm_portal_config *config,
18904 + const struct qman_cgrs *cgrs);
18905 +struct qman_portal *qman_create_affine_slave(struct qman_portal *redirect,
18906 + int cpu);
18907 +const struct qm_portal_config *qman_destroy_affine_portal(void);
18908 +void qman_destroy_portal(struct qman_portal *qm);
18909 +
18910 +/* Hooks from fsl_usdpaa.c to qman_driver.c */
18911 +struct qm_portal_config *qm_get_unused_portal(void);
18912 +struct qm_portal_config *qm_get_unused_portal_idx(uint32_t idx);
18913 +
18914 +void qm_put_unused_portal(struct qm_portal_config *pcfg);
18915 +void qm_set_liodns(struct qm_portal_config *pcfg);
18916 +
18917 +/* This CGR feature is supported by h/w and required by unit-tests and the
18918 + * debugfs hooks, so is implemented in the driver. However it allows an explicit
18919 + * corruption of h/w fields by s/w that are usually incorruptible (because the
18920 + * counters are usually maintained entirely within h/w). As such, we declare
18921 + * this API internally. */
18922 +int qman_testwrite_cgr(struct qman_cgr *cgr, u64 i_bcnt,
18923 + struct qm_mcr_cgrtestwrite *result);
18924 +
18925 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
18926 +/* If the fq object pointer is greater than the size of context_b field,
18927 + * than a lookup table is required. */
18928 +int qman_setup_fq_lookup_table(size_t num_entries);
18929 +#endif
18930 +
18931 +
18932 +/*************************************************/
18933 +/* QMan s/w corenet portal, low-level i/face */
18934 +/*************************************************/
18935 +
18936 +/* Note: most functions are only used by the high-level interface, so are
18937 + * inlined from qman_low.h. The stuff below is for use by other parts of the
18938 + * driver. */
18939 +
18940 +/* For qm_dqrr_sdqcr_set(); Choose one SOURCE. Choose one COUNT. Choose one
18941 + * dequeue TYPE. Choose TOKEN (8-bit).
18942 + * If SOURCE == CHANNELS,
18943 + * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL(n).
18944 + * You can choose DEDICATED_PRECEDENCE if the portal channel should have
18945 + * priority.
18946 + * If SOURCE == SPECIFICWQ,
18947 + * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the
18948 + * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the
18949 + * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the
18950 + * same value.
18951 + */
18952 +#define QM_SDQCR_SOURCE_CHANNELS 0x0
18953 +#define QM_SDQCR_SOURCE_SPECIFICWQ 0x40000000
18954 +#define QM_SDQCR_COUNT_EXACT1 0x0
18955 +#define QM_SDQCR_COUNT_UPTO3 0x20000000
18956 +#define QM_SDQCR_DEDICATED_PRECEDENCE 0x10000000
18957 +#define QM_SDQCR_TYPE_MASK 0x03000000
18958 +#define QM_SDQCR_TYPE_NULL 0x0
18959 +#define QM_SDQCR_TYPE_PRIO_QOS 0x01000000
18960 +#define QM_SDQCR_TYPE_ACTIVE_QOS 0x02000000
18961 +#define QM_SDQCR_TYPE_ACTIVE 0x03000000
18962 +#define QM_SDQCR_TOKEN_MASK 0x00ff0000
18963 +#define QM_SDQCR_TOKEN_SET(v) (((v) & 0xff) << 16)
18964 +#define QM_SDQCR_TOKEN_GET(v) (((v) >> 16) & 0xff)
18965 +#define QM_SDQCR_CHANNELS_DEDICATED 0x00008000
18966 +#define QM_SDQCR_SPECIFICWQ_MASK 0x000000f7
18967 +#define QM_SDQCR_SPECIFICWQ_DEDICATED 0x00000000
18968 +#define QM_SDQCR_SPECIFICWQ_POOL(n) ((n) << 4)
18969 +#define QM_SDQCR_SPECIFICWQ_WQ(n) (n)
18970 +
18971 +/* For qm_dqrr_vdqcr_set(): use FQID(n) to fill in the frame queue ID */
18972 +#define QM_VDQCR_FQID_MASK 0x00ffffff
18973 +#define QM_VDQCR_FQID(n) ((n) & QM_VDQCR_FQID_MASK)
18974 +
18975 +/* For qm_dqrr_pdqcr_set(); Choose one MODE. Choose one COUNT.
18976 + * If MODE==SCHEDULED
18977 + * Choose SCHEDULED_CHANNELS or SCHEDULED_SPECIFICWQ. Choose one dequeue TYPE.
18978 + * If CHANNELS,
18979 + * Choose CHANNELS_DEDICATED and/or CHANNELS_POOL() channels.
18980 + * You can choose DEDICATED_PRECEDENCE if the portal channel should have
18981 + * priority.
18982 + * If SPECIFICWQ,
18983 + * Either select the work-queue ID with SPECIFICWQ_WQ(), or select the
18984 + * channel (SPECIFICWQ_DEDICATED or SPECIFICWQ_POOL()) and specify the
18985 + * work-queue priority (0-7) with SPECIFICWQ_WQ() - either way, you get the
18986 + * same value.
18987 + * If MODE==UNSCHEDULED
18988 + * Choose FQID().
18989 + */
18990 +#define QM_PDQCR_MODE_SCHEDULED 0x0
18991 +#define QM_PDQCR_MODE_UNSCHEDULED 0x80000000
18992 +#define QM_PDQCR_SCHEDULED_CHANNELS 0x0
18993 +#define QM_PDQCR_SCHEDULED_SPECIFICWQ 0x40000000
18994 +#define QM_PDQCR_COUNT_EXACT1 0x0
18995 +#define QM_PDQCR_COUNT_UPTO3 0x20000000
18996 +#define QM_PDQCR_DEDICATED_PRECEDENCE 0x10000000
18997 +#define QM_PDQCR_TYPE_MASK 0x03000000
18998 +#define QM_PDQCR_TYPE_NULL 0x0
18999 +#define QM_PDQCR_TYPE_PRIO_QOS 0x01000000
19000 +#define QM_PDQCR_TYPE_ACTIVE_QOS 0x02000000
19001 +#define QM_PDQCR_TYPE_ACTIVE 0x03000000
19002 +#define QM_PDQCR_CHANNELS_DEDICATED 0x00008000
19003 +#define QM_PDQCR_CHANNELS_POOL(n) (0x00008000 >> (n))
19004 +#define QM_PDQCR_SPECIFICWQ_MASK 0x000000f7
19005 +#define QM_PDQCR_SPECIFICWQ_DEDICATED 0x00000000
19006 +#define QM_PDQCR_SPECIFICWQ_POOL(n) ((n) << 4)
19007 +#define QM_PDQCR_SPECIFICWQ_WQ(n) (n)
19008 +#define QM_PDQCR_FQID(n) ((n) & 0xffffff)
19009 +
19010 +/* Used by all portal interrupt registers except 'inhibit'
19011 + * Channels with frame availability
19012 + */
19013 +#define QM_PIRQ_DQAVAIL 0x0000ffff
19014 +
19015 +/* The DQAVAIL interrupt fields break down into these bits; */
19016 +#define QM_DQAVAIL_PORTAL 0x8000 /* Portal channel */
19017 +#define QM_DQAVAIL_POOL(n) (0x8000 >> (n)) /* Pool channel, n==[1..15] */
19018 +#define QM_DQAVAIL_MASK 0xffff
19019 +/* This mask contains all the "irqsource" bits visible to API users */
19020 +#define QM_PIRQ_VISIBLE (QM_PIRQ_SLOW | QM_PIRQ_DQRI)
19021 +
19022 +/* These are qm_<reg>_<verb>(). So for example, qm_disable_write() means "write
19023 + * the disable register" rather than "disable the ability to write". */
19024 +#define qm_isr_status_read(qm) __qm_isr_read(qm, qm_isr_status)
19025 +#define qm_isr_status_clear(qm, m) __qm_isr_write(qm, qm_isr_status, m)
19026 +#define qm_isr_enable_read(qm) __qm_isr_read(qm, qm_isr_enable)
19027 +#define qm_isr_enable_write(qm, v) __qm_isr_write(qm, qm_isr_enable, v)
19028 +#define qm_isr_disable_read(qm) __qm_isr_read(qm, qm_isr_disable)
19029 +#define qm_isr_disable_write(qm, v) __qm_isr_write(qm, qm_isr_disable, v)
19030 +/* TODO: unfortunate name-clash here, reword? */
19031 +#define qm_isr_inhibit(qm) __qm_isr_write(qm, qm_isr_inhibit, 1)
19032 +#define qm_isr_uninhibit(qm) __qm_isr_write(qm, qm_isr_inhibit, 0)
19033 +
19034 +#ifdef CONFIG_FSL_QMAN_CONFIG
19035 +int qman_have_ccsr(void);
19036 +#else
19037 +#define qman_have_ccsr 0
19038 +#endif
19039 +
19040 +__init int qman_init(void);
19041 +__init int qman_resource_init(void);
19042 +
19043 +/* CEETM related */
19044 +#define QMAN_CEETM_MAX 2
19045 +extern u8 num_ceetms;
19046 +extern struct qm_ceetm qman_ceetms[QMAN_CEETM_MAX];
19047 +int qman_sp_enable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal);
19048 +int qman_sp_disable_ceetm_mode(enum qm_dc_portal portal, u16 sub_portal);
19049 +int qman_ceetm_set_prescaler(enum qm_dc_portal portal);
19050 +int qman_ceetm_get_prescaler(u16 *pres);
19051 +int qman_ceetm_query_cq(unsigned int cqid, unsigned int dcpid,
19052 + struct qm_mcr_ceetm_cq_query *cq_query);
19053 +int qman_ceetm_query_ccgr(struct qm_mcc_ceetm_ccgr_query *ccgr_query,
19054 + struct qm_mcr_ceetm_ccgr_query *response);
19055 +int qman_ceetm_get_xsfdr(enum qm_dc_portal portal, unsigned int *num);
19056 +
19057 +extern void *affine_portals[NR_CPUS];
19058 +const struct qm_portal_config *qman_get_qm_portal_config(
19059 + struct qman_portal *portal);
19060 +
19061 +/* power management */
19062 +#ifdef CONFIG_SUSPEND
19063 +void suspend_unused_qportal(void);
19064 +void resume_unused_qportal(void);
19065 +#endif
19066 --- /dev/null
19067 +++ b/drivers/staging/fsl_qbman/qman_test.c
19068 @@ -0,0 +1,57 @@
19069 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
19070 + *
19071 + * Redistribution and use in source and binary forms, with or without
19072 + * modification, are permitted provided that the following conditions are met:
19073 + * * Redistributions of source code must retain the above copyright
19074 + * notice, this list of conditions and the following disclaimer.
19075 + * * Redistributions in binary form must reproduce the above copyright
19076 + * notice, this list of conditions and the following disclaimer in the
19077 + * documentation and/or other materials provided with the distribution.
19078 + * * Neither the name of Freescale Semiconductor nor the
19079 + * names of its contributors may be used to endorse or promote products
19080 + * derived from this software without specific prior written permission.
19081 + *
19082 + *
19083 + * ALTERNATIVELY, this software may be distributed under the terms of the
19084 + * GNU General Public License ("GPL") as published by the Free Software
19085 + * Foundation, either version 2 of that License or (at your option) any
19086 + * later version.
19087 + *
19088 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
19089 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19090 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19091 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
19092 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19093 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19094 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19095 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19096 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19097 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19098 + */
19099 +
19100 +#include "qman_test.h"
19101 +
19102 +MODULE_AUTHOR("Geoff Thorpe");
19103 +MODULE_LICENSE("Dual BSD/GPL");
19104 +MODULE_DESCRIPTION("Qman testing");
19105 +
19106 +static int test_init(void)
19107 +{
19108 + int loop = 1;
19109 + while (loop--) {
19110 +#ifdef CONFIG_FSL_QMAN_TEST_STASH_POTATO
19111 + qman_test_hotpotato();
19112 +#endif
19113 +#ifdef CONFIG_FSL_QMAN_TEST_HIGH
19114 + qman_test_high();
19115 +#endif
19116 + }
19117 + return 0;
19118 +}
19119 +
19120 +static void test_exit(void)
19121 +{
19122 +}
19123 +
19124 +module_init(test_init);
19125 +module_exit(test_exit);
19126 --- /dev/null
19127 +++ b/drivers/staging/fsl_qbman/qman_test.h
19128 @@ -0,0 +1,45 @@
19129 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
19130 + *
19131 + * Redistribution and use in source and binary forms, with or without
19132 + * modification, are permitted provided that the following conditions are met:
19133 + * * Redistributions of source code must retain the above copyright
19134 + * notice, this list of conditions and the following disclaimer.
19135 + * * Redistributions in binary form must reproduce the above copyright
19136 + * notice, this list of conditions and the following disclaimer in the
19137 + * documentation and/or other materials provided with the distribution.
19138 + * * Neither the name of Freescale Semiconductor nor the
19139 + * names of its contributors may be used to endorse or promote products
19140 + * derived from this software without specific prior written permission.
19141 + *
19142 + *
19143 + * ALTERNATIVELY, this software may be distributed under the terms of the
19144 + * GNU General Public License ("GPL") as published by the Free Software
19145 + * Foundation, either version 2 of that License or (at your option) any
19146 + * later version.
19147 + *
19148 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
19149 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19150 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19151 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
19152 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19153 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19154 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19155 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19156 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19157 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19158 + */
19159 +
19160 +#include <linux/kernel.h>
19161 +#include <linux/errno.h>
19162 +#include <linux/io.h>
19163 +#include <linux/slab.h>
19164 +#include <linux/module.h>
19165 +#include <linux/interrupt.h>
19166 +#include <linux/delay.h>
19167 +#include <linux/sched.h>
19168 +
19169 +#include <linux/fsl_qman.h>
19170 +
19171 +void qman_test_hotpotato(void);
19172 +void qman_test_high(void);
19173 +
19174 --- /dev/null
19175 +++ b/drivers/staging/fsl_qbman/qman_test_high.c
19176 @@ -0,0 +1,216 @@
19177 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
19178 + *
19179 + * Redistribution and use in source and binary forms, with or without
19180 + * modification, are permitted provided that the following conditions are met:
19181 + * * Redistributions of source code must retain the above copyright
19182 + * notice, this list of conditions and the following disclaimer.
19183 + * * Redistributions in binary form must reproduce the above copyright
19184 + * notice, this list of conditions and the following disclaimer in the
19185 + * documentation and/or other materials provided with the distribution.
19186 + * * Neither the name of Freescale Semiconductor nor the
19187 + * names of its contributors may be used to endorse or promote products
19188 + * derived from this software without specific prior written permission.
19189 + *
19190 + *
19191 + * ALTERNATIVELY, this software may be distributed under the terms of the
19192 + * GNU General Public License ("GPL") as published by the Free Software
19193 + * Foundation, either version 2 of that License or (at your option) any
19194 + * later version.
19195 + *
19196 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
19197 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19198 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19199 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
19200 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19201 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19202 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19203 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19204 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19205 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19206 + */
19207 +
19208 +#include "qman_test.h"
19209 +
19210 +/*************/
19211 +/* constants */
19212 +/*************/
19213 +
19214 +#define CGR_ID 27
19215 +#define POOL_ID 2
19216 +#define FQ_FLAGS QMAN_FQ_FLAG_DYNAMIC_FQID
19217 +#define NUM_ENQUEUES 10
19218 +#define NUM_PARTIAL 4
19219 +#define PORTAL_SDQCR (QM_SDQCR_SOURCE_CHANNELS | \
19220 + QM_SDQCR_TYPE_PRIO_QOS | \
19221 + QM_SDQCR_TOKEN_SET(0x98) | \
19222 + QM_SDQCR_CHANNELS_DEDICATED | \
19223 + QM_SDQCR_CHANNELS_POOL(POOL_ID))
19224 +#define PORTAL_OPAQUE ((void *)0xf00dbeef)
19225 +#define VDQCR_FLAGS (QMAN_VOLATILE_FLAG_WAIT | QMAN_VOLATILE_FLAG_FINISH)
19226 +
19227 +/*************************************/
19228 +/* Predeclarations (eg. for fq_base) */
19229 +/*************************************/
19230 +
19231 +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *,
19232 + struct qman_fq *,
19233 + const struct qm_dqrr_entry *);
19234 +static void cb_ern(struct qman_portal *, struct qman_fq *,
19235 + const struct qm_mr_entry *);
19236 +static void cb_fqs(struct qman_portal *, struct qman_fq *,
19237 + const struct qm_mr_entry *);
19238 +
19239 +/***************/
19240 +/* global vars */
19241 +/***************/
19242 +
19243 +static struct qm_fd fd, fd_dq;
19244 +static struct qman_fq fq_base = {
19245 + .cb.dqrr = cb_dqrr,
19246 + .cb.ern = cb_ern,
19247 + .cb.fqs = cb_fqs
19248 +};
19249 +static DECLARE_WAIT_QUEUE_HEAD(waitqueue);
19250 +static int retire_complete, sdqcr_complete;
19251 +
19252 +/**********************/
19253 +/* internal functions */
19254 +/**********************/
19255 +
19256 +/* Helpers for initialising and "incrementing" a frame descriptor */
19257 +static void fd_init(struct qm_fd *__fd)
19258 +{
19259 + qm_fd_addr_set64(__fd, 0xabdeadbeefLLU);
19260 + __fd->format = qm_fd_contig_big;
19261 + __fd->length29 = 0x0000ffff;
19262 + __fd->cmd = 0xfeedf00d;
19263 +}
19264 +
19265 +static void fd_inc(struct qm_fd *__fd)
19266 +{
19267 + u64 t = qm_fd_addr_get64(__fd);
19268 + int z = t >> 40;
19269 + t <<= 1;
19270 + if (z)
19271 + t |= 1;
19272 + qm_fd_addr_set64(__fd, t);
19273 + __fd->length29--;
19274 + __fd->cmd++;
19275 +}
19276 +
19277 +/* The only part of the 'fd' we can't memcmp() is the ppid */
19278 +static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b)
19279 +{
19280 + int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1;
19281 + if (!r)
19282 + r = a->format - b->format;
19283 + if (!r)
19284 + r = a->opaque - b->opaque;
19285 + if (!r)
19286 + r = a->cmd - b->cmd;
19287 + return r;
19288 +}
19289 +
19290 +/********/
19291 +/* test */
19292 +/********/
19293 +
19294 +static void do_enqueues(struct qman_fq *fq)
19295 +{
19296 + unsigned int loop;
19297 + for (loop = 0; loop < NUM_ENQUEUES; loop++) {
19298 + if (qman_enqueue(fq, &fd, QMAN_ENQUEUE_FLAG_WAIT |
19299 + (((loop + 1) == NUM_ENQUEUES) ?
19300 + QMAN_ENQUEUE_FLAG_WAIT_SYNC : 0)))
19301 + panic("qman_enqueue() failed\n");
19302 + fd_inc(&fd);
19303 + }
19304 +}
19305 +
19306 +void qman_test_high(void)
19307 +{
19308 + unsigned int flags;
19309 + int res;
19310 + struct qman_fq *fq = &fq_base;
19311 +
19312 + pr_info("qman_test_high starting\n");
19313 + fd_init(&fd);
19314 + fd_init(&fd_dq);
19315 +
19316 + /* Initialise (parked) FQ */
19317 + if (qman_create_fq(0, FQ_FLAGS, fq))
19318 + panic("qman_create_fq() failed\n");
19319 + if (qman_init_fq(fq, QMAN_INITFQ_FLAG_LOCAL, NULL))
19320 + panic("qman_init_fq() failed\n");
19321 +
19322 + /* Do enqueues + VDQCR, twice. (Parked FQ) */
19323 + do_enqueues(fq);
19324 + pr_info("VDQCR (till-empty);\n");
19325 + if (qman_volatile_dequeue(fq, VDQCR_FLAGS,
19326 + QM_VDQCR_NUMFRAMES_TILLEMPTY))
19327 + panic("qman_volatile_dequeue() failed\n");
19328 + do_enqueues(fq);
19329 + pr_info("VDQCR (%d of %d);\n", NUM_PARTIAL, NUM_ENQUEUES);
19330 + if (qman_volatile_dequeue(fq, VDQCR_FLAGS,
19331 + QM_VDQCR_NUMFRAMES_SET(NUM_PARTIAL)))
19332 + panic("qman_volatile_dequeue() failed\n");
19333 + pr_info("VDQCR (%d of %d);\n", NUM_ENQUEUES - NUM_PARTIAL,
19334 + NUM_ENQUEUES);
19335 + if (qman_volatile_dequeue(fq, VDQCR_FLAGS,
19336 + QM_VDQCR_NUMFRAMES_SET(NUM_ENQUEUES - NUM_PARTIAL)))
19337 + panic("qman_volatile_dequeue() failed\n");
19338 +
19339 + do_enqueues(fq);
19340 + pr_info("scheduled dequeue (till-empty)\n");
19341 + if (qman_schedule_fq(fq))
19342 + panic("qman_schedule_fq() failed\n");
19343 + wait_event(waitqueue, sdqcr_complete);
19344 +
19345 + /* Retire and OOS the FQ */
19346 + res = qman_retire_fq(fq, &flags);
19347 + if (res < 0)
19348 + panic("qman_retire_fq() failed\n");
19349 + wait_event(waitqueue, retire_complete);
19350 + if (flags & QMAN_FQ_STATE_BLOCKOOS)
19351 + panic("leaking frames\n");
19352 + if (qman_oos_fq(fq))
19353 + panic("qman_oos_fq() failed\n");
19354 + qman_destroy_fq(fq, 0);
19355 + pr_info("qman_test_high finished\n");
19356 +}
19357 +
19358 +static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p,
19359 + struct qman_fq *fq,
19360 + const struct qm_dqrr_entry *dq)
19361 +{
19362 + if (fd_cmp(&fd_dq, &dq->fd)) {
19363 + pr_err("BADNESS: dequeued frame doesn't match;\n");
19364 + pr_err("Expected 0x%llx, got 0x%llx\n",
19365 + (unsigned long long)fd_dq.length29,
19366 + (unsigned long long)dq->fd.length29);
19367 + BUG();
19368 + }
19369 + fd_inc(&fd_dq);
19370 + if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) {
19371 + sdqcr_complete = 1;
19372 + wake_up(&waitqueue);
19373 + }
19374 + return qman_cb_dqrr_consume;
19375 +}
19376 +
19377 +static void cb_ern(struct qman_portal *p, struct qman_fq *fq,
19378 + const struct qm_mr_entry *msg)
19379 +{
19380 + panic("cb_ern() unimplemented");
19381 +}
19382 +
19383 +static void cb_fqs(struct qman_portal *p, struct qman_fq *fq,
19384 + const struct qm_mr_entry *msg)
19385 +{
19386 + u8 verb = (msg->verb & QM_MR_VERB_TYPE_MASK);
19387 + if ((verb != QM_MR_VERB_FQRN) && (verb != QM_MR_VERB_FQRNI))
19388 + panic("unexpected FQS message");
19389 + pr_info("Retirement message received\n");
19390 + retire_complete = 1;
19391 + wake_up(&waitqueue);
19392 +}
19393 --- /dev/null
19394 +++ b/drivers/staging/fsl_qbman/qman_test_hotpotato.c
19395 @@ -0,0 +1,499 @@
19396 +/* Copyright 2009-2012 Freescale Semiconductor, Inc.
19397 + *
19398 + * Redistribution and use in source and binary forms, with or without
19399 + * modification, are permitted provided that the following conditions are met:
19400 + * * Redistributions of source code must retain the above copyright
19401 + * notice, this list of conditions and the following disclaimer.
19402 + * * Redistributions in binary form must reproduce the above copyright
19403 + * notice, this list of conditions and the following disclaimer in the
19404 + * documentation and/or other materials provided with the distribution.
19405 + * * Neither the name of Freescale Semiconductor nor the
19406 + * names of its contributors may be used to endorse or promote products
19407 + * derived from this software without specific prior written permission.
19408 + *
19409 + *
19410 + * ALTERNATIVELY, this software may be distributed under the terms of the
19411 + * GNU General Public License ("GPL") as published by the Free Software
19412 + * Foundation, either version 2 of that License or (at your option) any
19413 + * later version.
19414 + *
19415 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
19416 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19417 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19418 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
19419 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19420 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19421 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19422 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19423 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19424 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19425 + */
19426 +
19427 +#include <linux/kthread.h>
19428 +#include <linux/platform_device.h>
19429 +#include <linux/dma-mapping.h>
19430 +#include "qman_test.h"
19431 +
19432 +/* Algorithm:
19433 + *
19434 + * Each cpu will have HP_PER_CPU "handlers" set up, each of which incorporates
19435 + * an rx/tx pair of FQ objects (both of which are stashed on dequeue). The
19436 + * organisation of FQIDs is such that the HP_PER_CPU*NUM_CPUS handlers will
19437 + * shuttle a "hot potato" frame around them such that every forwarding action
19438 + * moves it from one cpu to another. (The use of more than one handler per cpu
19439 + * is to allow enough handlers/FQs to truly test the significance of caching -
19440 + * ie. when cache-expiries are occurring.)
19441 + *
19442 + * The "hot potato" frame content will be HP_NUM_WORDS*4 bytes in size, and the
19443 + * first and last words of the frame data will undergo a transformation step on
19444 + * each forwarding action. To achieve this, each handler will be assigned a
19445 + * 32-bit "mixer", that is produced using a 32-bit LFSR. When a frame is
19446 + * received by a handler, the mixer of the expected sender is XOR'd into all
19447 + * words of the entire frame, which is then validated against the original
19448 + * values. Then, before forwarding, the entire frame is XOR'd with the mixer of
19449 + * the current handler. Apart from validating that the frame is taking the
19450 + * expected path, this also provides some quasi-realistic overheads to each
19451 + * forwarding action - dereferencing *all* the frame data, computation, and
19452 + * conditional branching. There is a "special" handler designated to act as the
19453 + * instigator of the test by creating an enqueuing the "hot potato" frame, and
19454 + * to determine when the test has completed by counting HP_LOOPS iterations.
19455 + *
19456 + * Init phases:
19457 + *
19458 + * 1. prepare each cpu's 'hp_cpu' struct using on_each_cpu(,,1) and link them
19459 + * into 'hp_cpu_list'. Specifically, set processor_id, allocate HP_PER_CPU
19460 + * handlers and link-list them (but do no other handler setup).
19461 + *
19462 + * 2. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each
19463 + * hp_cpu's 'iterator' to point to its first handler. With each loop,
19464 + * allocate rx/tx FQIDs and mixer values to the hp_cpu's iterator handler
19465 + * and advance the iterator for the next loop. This includes a final fixup,
19466 + * which connects the last handler to the first (and which is why phase 2
19467 + * and 3 are separate).
19468 + *
19469 + * 3. scan over 'hp_cpu_list' HP_PER_CPU times, the first time sets each
19470 + * hp_cpu's 'iterator' to point to its first handler. With each loop,
19471 + * initialise FQ objects and advance the iterator for the next loop.
19472 + * Moreover, do this initialisation on the cpu it applies to so that Rx FQ
19473 + * initialisation targets the correct cpu.
19474 + */
19475 +
19476 +/* helper to run something on all cpus (can't use on_each_cpu(), as that invokes
19477 + * the fn from irq context, which is too restrictive). */
19478 +struct bstrap {
19479 + void (*fn)(void);
19480 + atomic_t started;
19481 +};
19482 +static int bstrap_fn(void *__bstrap)
19483 +{
19484 + struct bstrap *bstrap = __bstrap;
19485 + atomic_inc(&bstrap->started);
19486 + bstrap->fn();
19487 + while (!kthread_should_stop())
19488 + msleep(1);
19489 + return 0;
19490 +}
19491 +static int on_all_cpus(void (*fn)(void))
19492 +{
19493 + int cpu;
19494 + for_each_cpu(cpu, cpu_online_mask) {
19495 + struct bstrap bstrap = {
19496 + .fn = fn,
19497 + .started = ATOMIC_INIT(0)
19498 + };
19499 + struct task_struct *k = kthread_create(bstrap_fn, &bstrap,
19500 + "hotpotato%d", cpu);
19501 + int ret;
19502 + if (IS_ERR(k))
19503 + return -ENOMEM;
19504 + kthread_bind(k, cpu);
19505 + wake_up_process(k);
19506 + /* If we call kthread_stop() before the "wake up" has had an
19507 + * effect, then the thread may exit with -EINTR without ever
19508 + * running the function. So poll until it's started before
19509 + * requesting it to stop. */
19510 + while (!atomic_read(&bstrap.started))
19511 + msleep(10);
19512 + ret = kthread_stop(k);
19513 + if (ret)
19514 + return ret;
19515 + }
19516 + return 0;
19517 +}
19518 +
19519 +struct hp_handler {
19520 +
19521 + /* The following data is stashed when 'rx' is dequeued; */
19522 + /* -------------- */
19523 + /* The Rx FQ, dequeues of which will stash the entire hp_handler */
19524 + struct qman_fq rx;
19525 + /* The Tx FQ we should forward to */
19526 + struct qman_fq tx;
19527 + /* The value we XOR post-dequeue, prior to validating */
19528 + u32 rx_mixer;
19529 + /* The value we XOR pre-enqueue, after validating */
19530 + u32 tx_mixer;
19531 + /* what the hotpotato address should be on dequeue */
19532 + dma_addr_t addr;
19533 + u32 *frame_ptr;
19534 +
19535 + /* The following data isn't (necessarily) stashed on dequeue; */
19536 + /* -------------- */
19537 + u32 fqid_rx, fqid_tx;
19538 + /* list node for linking us into 'hp_cpu' */
19539 + struct list_head node;
19540 + /* Just to check ... */
19541 + unsigned int processor_id;
19542 +} ____cacheline_aligned;
19543 +
19544 +struct hp_cpu {
19545 + /* identify the cpu we run on; */
19546 + unsigned int processor_id;
19547 + /* root node for the per-cpu list of handlers */
19548 + struct list_head handlers;
19549 + /* list node for linking us into 'hp_cpu_list' */
19550 + struct list_head node;
19551 + /* when repeatedly scanning 'hp_list', each time linking the n'th
19552 + * handlers together, this is used as per-cpu iterator state */
19553 + struct hp_handler *iterator;
19554 +};
19555 +
19556 +/* Each cpu has one of these */
19557 +static DEFINE_PER_CPU(struct hp_cpu, hp_cpus);
19558 +
19559 +/* links together the hp_cpu structs, in first-come first-serve order. */
19560 +static LIST_HEAD(hp_cpu_list);
19561 +static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock);
19562 +
19563 +static unsigned int hp_cpu_list_length;
19564 +
19565 +/* the "special" handler, that starts and terminates the test. */
19566 +static struct hp_handler *special_handler;
19567 +static int loop_counter;
19568 +
19569 +/* handlers are allocated out of this, so they're properly aligned. */
19570 +static struct kmem_cache *hp_handler_slab;
19571 +
19572 +/* this is the frame data */
19573 +static void *__frame_ptr;
19574 +static u32 *frame_ptr;
19575 +static dma_addr_t frame_dma;
19576 +
19577 +/* the main function waits on this */
19578 +static DECLARE_WAIT_QUEUE_HEAD(queue);
19579 +
19580 +#define HP_PER_CPU 2
19581 +#define HP_LOOPS 8
19582 +/* 80 bytes, like a small ethernet frame, and bleeds into a second cacheline */
19583 +#define HP_NUM_WORDS 80
19584 +/* First word of the LFSR-based frame data */
19585 +#define HP_FIRST_WORD 0xabbaf00d
19586 +
19587 +static inline u32 do_lfsr(u32 prev)
19588 +{
19589 + return (prev >> 1) ^ (-(prev & 1u) & 0xd0000001u);
19590 +}
19591 +
19592 +static void allocate_frame_data(void)
19593 +{
19594 + u32 lfsr = HP_FIRST_WORD;
19595 + int loop;
19596 + struct platform_device *pdev = platform_device_alloc("foobar", -1);
19597 + if (!pdev)
19598 + panic("platform_device_alloc() failed");
19599 + if (platform_device_add(pdev))
19600 + panic("platform_device_add() failed");
19601 + __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL);
19602 + if (!__frame_ptr)
19603 + panic("kmalloc() failed");
19604 + frame_ptr = (void *)(((unsigned long)__frame_ptr + 63) &
19605 + ~(unsigned long)63);
19606 + for (loop = 0; loop < HP_NUM_WORDS; loop++) {
19607 + frame_ptr[loop] = lfsr;
19608 + lfsr = do_lfsr(lfsr);
19609 + }
19610 + frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS,
19611 + DMA_BIDIRECTIONAL);
19612 + platform_device_del(pdev);
19613 + platform_device_put(pdev);
19614 +}
19615 +
19616 +static void deallocate_frame_data(void)
19617 +{
19618 + kfree(__frame_ptr);
19619 +}
19620 +
19621 +static inline void process_frame_data(struct hp_handler *handler,
19622 + const struct qm_fd *fd)
19623 +{
19624 + u32 *p = handler->frame_ptr;
19625 + u32 lfsr = HP_FIRST_WORD;
19626 + int loop;
19627 + if (qm_fd_addr_get64(fd) != handler->addr)
19628 + panic("bad frame address");
19629 + for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) {
19630 + *p ^= handler->rx_mixer;
19631 + if (*p != lfsr)
19632 + panic("corrupt frame data");
19633 + *p ^= handler->tx_mixer;
19634 + lfsr = do_lfsr(lfsr);
19635 + }
19636 +}
19637 +
19638 +static enum qman_cb_dqrr_result normal_dqrr(struct qman_portal *portal,
19639 + struct qman_fq *fq,
19640 + const struct qm_dqrr_entry *dqrr)
19641 +{
19642 + struct hp_handler *handler = (struct hp_handler *)fq;
19643 +
19644 + process_frame_data(handler, &dqrr->fd);
19645 + if (qman_enqueue(&handler->tx, &dqrr->fd, 0))
19646 + panic("qman_enqueue() failed");
19647 + return qman_cb_dqrr_consume;
19648 +}
19649 +
19650 +static enum qman_cb_dqrr_result special_dqrr(struct qman_portal *portal,
19651 + struct qman_fq *fq,
19652 + const struct qm_dqrr_entry *dqrr)
19653 +{
19654 + struct hp_handler *handler = (struct hp_handler *)fq;
19655 +
19656 + process_frame_data(handler, &dqrr->fd);
19657 + if (++loop_counter < HP_LOOPS) {
19658 + if (qman_enqueue(&handler->tx, &dqrr->fd, 0))
19659 + panic("qman_enqueue() failed");
19660 + } else {
19661 + pr_info("Received final (%dth) frame\n", loop_counter);
19662 + wake_up(&queue);
19663 + }
19664 + return qman_cb_dqrr_consume;
19665 +}
19666 +
19667 +static void create_per_cpu_handlers(void)
19668 +{
19669 + struct hp_handler *handler;
19670 + int loop;
19671 + struct hp_cpu *hp_cpu = &get_cpu_var(hp_cpus);
19672 +
19673 + hp_cpu->processor_id = smp_processor_id();
19674 + spin_lock(&hp_lock);
19675 + list_add_tail(&hp_cpu->node, &hp_cpu_list);
19676 + hp_cpu_list_length++;
19677 + spin_unlock(&hp_lock);
19678 + INIT_LIST_HEAD(&hp_cpu->handlers);
19679 + for (loop = 0; loop < HP_PER_CPU; loop++) {
19680 + handler = kmem_cache_alloc(hp_handler_slab, GFP_KERNEL);
19681 + if (!handler)
19682 + panic("kmem_cache_alloc() failed");
19683 + handler->processor_id = hp_cpu->processor_id;
19684 + handler->addr = frame_dma;
19685 + handler->frame_ptr = frame_ptr;
19686 + list_add_tail(&handler->node, &hp_cpu->handlers);
19687 + }
19688 + put_cpu_var(hp_cpus);
19689 +}
19690 +
19691 +static void destroy_per_cpu_handlers(void)
19692 +{
19693 + struct list_head *loop, *tmp;
19694 + struct hp_cpu *hp_cpu = &get_cpu_var(hp_cpus);
19695 +
19696 + spin_lock(&hp_lock);
19697 + list_del(&hp_cpu->node);
19698 + spin_unlock(&hp_lock);
19699 + list_for_each_safe(loop, tmp, &hp_cpu->handlers) {
19700 + u32 flags;
19701 + struct hp_handler *handler = list_entry(loop, struct hp_handler,
19702 + node);
19703 + if (qman_retire_fq(&handler->rx, &flags))
19704 + panic("qman_retire_fq(rx) failed");
19705 + BUG_ON(flags & QMAN_FQ_STATE_BLOCKOOS);
19706 + if (qman_oos_fq(&handler->rx))
19707 + panic("qman_oos_fq(rx) failed");
19708 + qman_destroy_fq(&handler->rx, 0);
19709 + qman_destroy_fq(&handler->tx, 0);
19710 + qman_release_fqid(handler->fqid_rx);
19711 + list_del(&handler->node);
19712 + kmem_cache_free(hp_handler_slab, handler);
19713 + }
19714 + put_cpu_var(hp_cpus);
19715 +}
19716 +
19717 +static inline u8 num_cachelines(u32 offset)
19718 +{
19719 + u8 res = (offset + (L1_CACHE_BYTES - 1))
19720 + / (L1_CACHE_BYTES);
19721 + if (res > 3)
19722 + return 3;
19723 + return res;
19724 +}
19725 +#define STASH_DATA_CL \
19726 + num_cachelines(HP_NUM_WORDS * 4)
19727 +#define STASH_CTX_CL \
19728 + num_cachelines(offsetof(struct hp_handler, fqid_rx))
19729 +
19730 +static void init_handler(void *__handler)
19731 +{
19732 + struct qm_mcc_initfq opts;
19733 + struct hp_handler *handler = __handler;
19734 + BUG_ON(handler->processor_id != smp_processor_id());
19735 + /* Set up rx */
19736 + memset(&handler->rx, 0, sizeof(handler->rx));
19737 + if (handler == special_handler)
19738 + handler->rx.cb.dqrr = special_dqrr;
19739 + else
19740 + handler->rx.cb.dqrr = normal_dqrr;
19741 + if (qman_create_fq(handler->fqid_rx, 0, &handler->rx))
19742 + panic("qman_create_fq(rx) failed");
19743 + memset(&opts, 0, sizeof(opts));
19744 + opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA;
19745 + opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING;
19746 + opts.fqd.context_a.stashing.data_cl = STASH_DATA_CL;
19747 + opts.fqd.context_a.stashing.context_cl = STASH_CTX_CL;
19748 + if (qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED |
19749 + QMAN_INITFQ_FLAG_LOCAL, &opts))
19750 + panic("qman_init_fq(rx) failed");
19751 + /* Set up tx */
19752 + memset(&handler->tx, 0, sizeof(handler->tx));
19753 + if (qman_create_fq(handler->fqid_tx, QMAN_FQ_FLAG_NO_MODIFY,
19754 + &handler->tx))
19755 + panic("qman_create_fq(tx) failed");
19756 +}
19757 +
19758 +static void init_phase2(void)
19759 +{
19760 + int loop;
19761 + u32 fqid = 0;
19762 + u32 lfsr = 0xdeadbeef;
19763 + struct hp_cpu *hp_cpu;
19764 + struct hp_handler *handler;
19765 +
19766 + for (loop = 0; loop < HP_PER_CPU; loop++) {
19767 + list_for_each_entry(hp_cpu, &hp_cpu_list, node) {
19768 + int ret;
19769 + if (!loop)
19770 + hp_cpu->iterator = list_first_entry(
19771 + &hp_cpu->handlers,
19772 + struct hp_handler, node);
19773 + else
19774 + hp_cpu->iterator = list_entry(
19775 + hp_cpu->iterator->node.next,
19776 + struct hp_handler, node);
19777 + /* Rx FQID is the previous handler's Tx FQID */
19778 + hp_cpu->iterator->fqid_rx = fqid;
19779 + /* Allocate new FQID for Tx */
19780 + ret = qman_alloc_fqid(&fqid);
19781 + if (ret)
19782 + panic("qman_alloc_fqid() failed");
19783 + hp_cpu->iterator->fqid_tx = fqid;
19784 + /* Rx mixer is the previous handler's Tx mixer */
19785 + hp_cpu->iterator->rx_mixer = lfsr;
19786 + /* Get new mixer for Tx */
19787 + lfsr = do_lfsr(lfsr);
19788 + hp_cpu->iterator->tx_mixer = lfsr;
19789 + }
19790 + }
19791 + /* Fix up the first handler (fqid_rx==0, rx_mixer=0xdeadbeef) */
19792 + hp_cpu = list_first_entry(&hp_cpu_list, struct hp_cpu, node);
19793 + handler = list_first_entry(&hp_cpu->handlers, struct hp_handler, node);
19794 + BUG_ON((handler->fqid_rx != 0) || (handler->rx_mixer != 0xdeadbeef));
19795 + handler->fqid_rx = fqid;
19796 + handler->rx_mixer = lfsr;
19797 + /* and tag it as our "special" handler */
19798 + special_handler = handler;
19799 +}
19800 +
19801 +static void init_phase3(void)
19802 +{
19803 + int loop;
19804 + struct hp_cpu *hp_cpu;
19805 +
19806 + for (loop = 0; loop < HP_PER_CPU; loop++) {
19807 + list_for_each_entry(hp_cpu, &hp_cpu_list, node) {
19808 + if (!loop)
19809 + hp_cpu->iterator = list_first_entry(
19810 + &hp_cpu->handlers,
19811 + struct hp_handler, node);
19812 + else
19813 + hp_cpu->iterator = list_entry(
19814 + hp_cpu->iterator->node.next,
19815 + struct hp_handler, node);
19816 + preempt_disable();
19817 + if (hp_cpu->processor_id == smp_processor_id())
19818 + init_handler(hp_cpu->iterator);
19819 + else
19820 + smp_call_function_single(hp_cpu->processor_id,
19821 + init_handler, hp_cpu->iterator, 1);
19822 + preempt_enable();
19823 + }
19824 + }
19825 +}
19826 +
19827 +static void send_first_frame(void *ignore)
19828 +{
19829 + u32 *p = special_handler->frame_ptr;
19830 + u32 lfsr = HP_FIRST_WORD;
19831 + int loop;
19832 + struct qm_fd fd;
19833 +
19834 + BUG_ON(special_handler->processor_id != smp_processor_id());
19835 + memset(&fd, 0, sizeof(fd));
19836 + qm_fd_addr_set64(&fd, special_handler->addr);
19837 + fd.format = qm_fd_contig_big;
19838 + fd.length29 = HP_NUM_WORDS * 4;
19839 + for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) {
19840 + if (*p != lfsr)
19841 + panic("corrupt frame data");
19842 + *p ^= special_handler->tx_mixer;
19843 + lfsr = do_lfsr(lfsr);
19844 + }
19845 + pr_info("Sending first frame\n");
19846 + if (qman_enqueue(&special_handler->tx, &fd, 0))
19847 + panic("qman_enqueue() failed");
19848 +}
19849 +
19850 +void qman_test_hotpotato(void)
19851 +{
19852 + if (cpumask_weight(cpu_online_mask) < 2) {
19853 + pr_info("qman_test_hotpotato, skip - only 1 CPU\n");
19854 + return;
19855 + }
19856 +
19857 + pr_info("qman_test_hotpotato starting\n");
19858 +
19859 + hp_cpu_list_length = 0;
19860 + loop_counter = 0;
19861 + hp_handler_slab = kmem_cache_create("hp_handler_slab",
19862 + sizeof(struct hp_handler), L1_CACHE_BYTES,
19863 + SLAB_HWCACHE_ALIGN, NULL);
19864 + if (!hp_handler_slab)
19865 + panic("kmem_cache_create() failed");
19866 +
19867 + allocate_frame_data();
19868 +
19869 + /* Init phase 1 */
19870 + pr_info("Creating %d handlers per cpu...\n", HP_PER_CPU);
19871 + if (on_all_cpus(create_per_cpu_handlers))
19872 + panic("on_each_cpu() failed");
19873 + pr_info("Number of cpus: %d, total of %d handlers\n",
19874 + hp_cpu_list_length, hp_cpu_list_length * HP_PER_CPU);
19875 +
19876 + init_phase2();
19877 +
19878 + init_phase3();
19879 +
19880 + preempt_disable();
19881 + if (special_handler->processor_id == smp_processor_id())
19882 + send_first_frame(NULL);
19883 + else
19884 + smp_call_function_single(special_handler->processor_id,
19885 + send_first_frame, NULL, 1);
19886 + preempt_enable();
19887 +
19888 + wait_event(queue, loop_counter == HP_LOOPS);
19889 + deallocate_frame_data();
19890 + if (on_all_cpus(destroy_per_cpu_handlers))
19891 + panic("on_each_cpu() failed");
19892 + kmem_cache_destroy(hp_handler_slab);
19893 + pr_info("qman_test_hotpotato finished\n");
19894 +}
19895 --- /dev/null
19896 +++ b/drivers/staging/fsl_qbman/qman_utility.c
19897 @@ -0,0 +1,129 @@
19898 +/* Copyright 2008-2011 Freescale Semiconductor, Inc.
19899 + *
19900 + * Redistribution and use in source and binary forms, with or without
19901 + * modification, are permitted provided that the following conditions are met:
19902 + * * Redistributions of source code must retain the above copyright
19903 + * notice, this list of conditions and the following disclaimer.
19904 + * * Redistributions in binary form must reproduce the above copyright
19905 + * notice, this list of conditions and the following disclaimer in the
19906 + * documentation and/or other materials provided with the distribution.
19907 + * * Neither the name of Freescale Semiconductor nor the
19908 + * names of its contributors may be used to endorse or promote products
19909 + * derived from this software without specific prior written permission.
19910 + *
19911 + *
19912 + * ALTERNATIVELY, this software may be distributed under the terms of the
19913 + * GNU General Public License ("GPL") as published by the Free Software
19914 + * Foundation, either version 2 of that License or (at your option) any
19915 + * later version.
19916 + *
19917 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
19918 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19919 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19920 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
19921 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19922 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19923 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19924 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
19925 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
19926 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19927 + */
19928 +
19929 +#include "qman_private.h"
19930 +
19931 +/* ----------------- */
19932 +/* --- FQID Pool --- */
19933 +
19934 +struct qman_fqid_pool {
19935 + /* Base and size of the FQID range */
19936 + u32 fqid_base;
19937 + u32 total;
19938 + /* Number of FQIDs currently "allocated" */
19939 + u32 used;
19940 + /* Allocation optimisation. When 'used<total', it is the index of an
19941 + * available FQID. Otherwise there are no available FQIDs, and this
19942 + * will be set when the next deallocation occurs. */
19943 + u32 next;
19944 + /* A bit-field representation of the FQID range. */
19945 + unsigned long *bits;
19946 +};
19947 +
19948 +#define QLONG_BYTES sizeof(unsigned long)
19949 +#define QLONG_BITS (QLONG_BYTES * 8)
19950 +/* Number of 'longs' required for the given number of bits */
19951 +#define QNUM_LONGS(b) (((b) + QLONG_BITS - 1) / QLONG_BITS)
19952 +/* Shorthand for the number of bytes of same (kmalloc, memset, etc) */
19953 +#define QNUM_BYTES(b) (QNUM_LONGS(b) * QLONG_BYTES)
19954 +/* And in bits */
19955 +#define QNUM_BITS(b) (QNUM_LONGS(b) * QLONG_BITS)
19956 +
19957 +struct qman_fqid_pool *qman_fqid_pool_create(u32 fqid_start, u32 num)
19958 +{
19959 + struct qman_fqid_pool *pool = kmalloc(sizeof(*pool), GFP_KERNEL);
19960 + unsigned int i;
19961 +
19962 + BUG_ON(!num);
19963 + if (!pool)
19964 + return NULL;
19965 + pool->fqid_base = fqid_start;
19966 + pool->total = num;
19967 + pool->used = 0;
19968 + pool->next = 0;
19969 + pool->bits = kzalloc(QNUM_BYTES(num), GFP_KERNEL);
19970 + if (!pool->bits) {
19971 + kfree(pool);
19972 + return NULL;
19973 + }
19974 + /* If num is not an even multiple of QLONG_BITS (or even 8, for
19975 + * byte-oriented searching) then we fill the trailing bits with 1, to
19976 + * make them look allocated (permanently). */
19977 + for (i = num + 1; i < QNUM_BITS(num); i++)
19978 + set_bit(i, pool->bits);
19979 + return pool;
19980 +}
19981 +EXPORT_SYMBOL(qman_fqid_pool_create);
19982 +
19983 +int qman_fqid_pool_destroy(struct qman_fqid_pool *pool)
19984 +{
19985 + int ret = pool->used;
19986 + kfree(pool->bits);
19987 + kfree(pool);
19988 + return ret;
19989 +}
19990 +EXPORT_SYMBOL(qman_fqid_pool_destroy);
19991 +
19992 +int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid)
19993 +{
19994 + int ret;
19995 + if (pool->used == pool->total)
19996 + return -ENOMEM;
19997 + *fqid = pool->fqid_base + pool->next;
19998 + ret = test_and_set_bit(pool->next, pool->bits);
19999 + BUG_ON(ret);
20000 + if (++pool->used == pool->total)
20001 + return 0;
20002 + pool->next = find_next_zero_bit(pool->bits, pool->total, pool->next);
20003 + if (pool->next >= pool->total)
20004 + pool->next = find_first_zero_bit(pool->bits, pool->total);
20005 + BUG_ON(pool->next >= pool->total);
20006 + return 0;
20007 +}
20008 +EXPORT_SYMBOL(qman_fqid_pool_alloc);
20009 +
20010 +void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid)
20011 +{
20012 + int ret;
20013 +
20014 + fqid -= pool->fqid_base;
20015 + ret = test_and_clear_bit(fqid, pool->bits);
20016 + BUG_ON(!ret);
20017 + if (pool->used-- == pool->total)
20018 + pool->next = fqid;
20019 +}
20020 +EXPORT_SYMBOL(qman_fqid_pool_free);
20021 +
20022 +u32 qman_fqid_pool_used(struct qman_fqid_pool *pool)
20023 +{
20024 + return pool->used;
20025 +}
20026 +EXPORT_SYMBOL(qman_fqid_pool_used);
20027 --- /dev/null
20028 +++ b/include/linux/fsl_bman.h
20029 @@ -0,0 +1,532 @@
20030 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
20031 + *
20032 + * Redistribution and use in source and binary forms, with or without
20033 + * modification, are permitted provided that the following conditions are met:
20034 + * * Redistributions of source code must retain the above copyright
20035 + * notice, this list of conditions and the following disclaimer.
20036 + * * Redistributions in binary form must reproduce the above copyright
20037 + * notice, this list of conditions and the following disclaimer in the
20038 + * documentation and/or other materials provided with the distribution.
20039 + * * Neither the name of Freescale Semiconductor nor the
20040 + * names of its contributors may be used to endorse or promote products
20041 + * derived from this software without specific prior written permission.
20042 + *
20043 + *
20044 + * ALTERNATIVELY, this software may be distributed under the terms of the
20045 + * GNU General Public License ("GPL") as published by the Free Software
20046 + * Foundation, either version 2 of that License or (at your option) any
20047 + * later version.
20048 + *
20049 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
20050 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20051 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20052 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
20053 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20054 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20055 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20056 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20057 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20058 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20059 + */
20060 +
20061 +#ifndef FSL_BMAN_H
20062 +#define FSL_BMAN_H
20063 +
20064 +#ifdef __cplusplus
20065 +extern "C" {
20066 +#endif
20067 +
20068 +/* Last updated for v00.79 of the BG */
20069 +
20070 +/* Portal processing (interrupt) sources */
20071 +#define BM_PIRQ_RCRI 0x00000002 /* RCR Ring (below threshold) */
20072 +#define BM_PIRQ_BSCN 0x00000001 /* Buffer depletion State Change */
20073 +
20074 +/* This wrapper represents a bit-array for the depletion state of the 64 Bman
20075 + * buffer pools. */
20076 +struct bman_depletion {
20077 + u32 __state[2];
20078 +};
20079 +#define BMAN_DEPLETION_EMPTY { { 0x00000000, 0x00000000 } }
20080 +#define BMAN_DEPLETION_FULL { { 0xffffffff, 0xffffffff } }
20081 +#define __bmdep_word(x) ((x) >> 5)
20082 +#define __bmdep_shift(x) ((x) & 0x1f)
20083 +#define __bmdep_bit(x) (0x80000000 >> __bmdep_shift(x))
20084 +static inline void bman_depletion_init(struct bman_depletion *c)
20085 +{
20086 + c->__state[0] = c->__state[1] = 0;
20087 +}
20088 +static inline void bman_depletion_fill(struct bman_depletion *c)
20089 +{
20090 + c->__state[0] = c->__state[1] = ~0;
20091 +}
20092 +static inline int bman_depletion_get(const struct bman_depletion *c, u8 bpid)
20093 +{
20094 + return c->__state[__bmdep_word(bpid)] & __bmdep_bit(bpid);
20095 +}
20096 +static inline void bman_depletion_set(struct bman_depletion *c, u8 bpid)
20097 +{
20098 + c->__state[__bmdep_word(bpid)] |= __bmdep_bit(bpid);
20099 +}
20100 +static inline void bman_depletion_unset(struct bman_depletion *c, u8 bpid)
20101 +{
20102 + c->__state[__bmdep_word(bpid)] &= ~__bmdep_bit(bpid);
20103 +}
20104 +
20105 +/* ------------------------------------------------------- */
20106 +/* --- Bman data structures (and associated constants) --- */
20107 +
20108 +/* Represents s/w corenet portal mapped data structures */
20109 +struct bm_rcr_entry; /* RCR (Release Command Ring) entries */
20110 +struct bm_mc_command; /* MC (Management Command) command */
20111 +struct bm_mc_result; /* MC result */
20112 +
20113 +/* Code-reduction, define a wrapper for 48-bit buffers. In cases where a buffer
20114 + * pool id specific to this buffer is needed (BM_RCR_VERB_CMD_BPID_MULTI,
20115 + * BM_MCC_VERB_ACQUIRE), the 'bpid' field is used. */
20116 +struct bm_buffer {
20117 + union {
20118 + struct {
20119 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20120 + u8 __reserved1;
20121 + u8 bpid;
20122 + u16 hi; /* High 16-bits of 48-bit address */
20123 + u32 lo; /* Low 32-bits of 48-bit address */
20124 +#else
20125 + u32 lo;
20126 + u16 hi;
20127 + u8 bpid;
20128 + u8 __reserved;
20129 +#endif
20130 + };
20131 + struct {
20132 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20133 + u64 __notaddress:16;
20134 + u64 addr:48;
20135 +#else
20136 + u64 addr:48;
20137 + u64 __notaddress:16;
20138 +#endif
20139 + };
20140 + u64 opaque;
20141 + };
20142 +} __aligned(8);
20143 +static inline u64 bm_buffer_get64(const struct bm_buffer *buf)
20144 +{
20145 + return buf->addr;
20146 +}
20147 +static inline dma_addr_t bm_buf_addr(const struct bm_buffer *buf)
20148 +{
20149 + return (dma_addr_t)buf->addr;
20150 +}
20151 +/* Macro, so we compile better if 'v' isn't always 64-bit */
20152 +#define bm_buffer_set64(buf, v) \
20153 + do { \
20154 + struct bm_buffer *__buf931 = (buf); \
20155 + __buf931->hi = upper_32_bits(v); \
20156 + __buf931->lo = lower_32_bits(v); \
20157 + } while (0)
20158 +
20159 +/* See 1.5.3.5.4: "Release Command" */
20160 +struct bm_rcr_entry {
20161 + union {
20162 + struct {
20163 + u8 __dont_write_directly__verb;
20164 + u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */
20165 + u8 __reserved1[62];
20166 + };
20167 + struct bm_buffer bufs[8];
20168 + };
20169 +} __packed;
20170 +#define BM_RCR_VERB_VBIT 0x80
20171 +#define BM_RCR_VERB_CMD_MASK 0x70 /* one of two values; */
20172 +#define BM_RCR_VERB_CMD_BPID_SINGLE 0x20
20173 +#define BM_RCR_VERB_CMD_BPID_MULTI 0x30
20174 +#define BM_RCR_VERB_BUFCOUNT_MASK 0x0f /* values 1..8 */
20175 +
20176 +/* See 1.5.3.1: "Acquire Command" */
20177 +/* See 1.5.3.2: "Query Command" */
20178 +struct bm_mcc_acquire {
20179 + u8 bpid;
20180 + u8 __reserved1[62];
20181 +} __packed;
20182 +struct bm_mcc_query {
20183 + u8 __reserved2[63];
20184 +} __packed;
20185 +struct bm_mc_command {
20186 + u8 __dont_write_directly__verb;
20187 + union {
20188 + struct bm_mcc_acquire acquire;
20189 + struct bm_mcc_query query;
20190 + };
20191 +} __packed;
20192 +#define BM_MCC_VERB_VBIT 0x80
20193 +#define BM_MCC_VERB_CMD_MASK 0x70 /* where the verb contains; */
20194 +#define BM_MCC_VERB_CMD_ACQUIRE 0x10
20195 +#define BM_MCC_VERB_CMD_QUERY 0x40
20196 +#define BM_MCC_VERB_ACQUIRE_BUFCOUNT 0x0f /* values 1..8 go here */
20197 +
20198 +/* See 1.5.3.3: "Acquire Response" */
20199 +/* See 1.5.3.4: "Query Response" */
20200 +struct bm_pool_state {
20201 + u8 __reserved1[32];
20202 + /* "availability state" and "depletion state" */
20203 + struct {
20204 + u8 __reserved1[8];
20205 + /* Access using bman_depletion_***() */
20206 + struct bman_depletion state;
20207 + } as, ds;
20208 +};
20209 +struct bm_mc_result {
20210 + union {
20211 + struct {
20212 + u8 verb;
20213 + u8 __reserved1[63];
20214 + };
20215 + union {
20216 + struct {
20217 + u8 __reserved1;
20218 + u8 bpid;
20219 + u8 __reserved2[62];
20220 + };
20221 + struct bm_buffer bufs[8];
20222 + } acquire;
20223 + struct bm_pool_state query;
20224 + };
20225 +} __packed;
20226 +#define BM_MCR_VERB_VBIT 0x80
20227 +#define BM_MCR_VERB_CMD_MASK BM_MCC_VERB_CMD_MASK
20228 +#define BM_MCR_VERB_CMD_ACQUIRE BM_MCC_VERB_CMD_ACQUIRE
20229 +#define BM_MCR_VERB_CMD_QUERY BM_MCC_VERB_CMD_QUERY
20230 +#define BM_MCR_VERB_CMD_ERR_INVALID 0x60
20231 +#define BM_MCR_VERB_CMD_ERR_ECC 0x70
20232 +#define BM_MCR_VERB_ACQUIRE_BUFCOUNT BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */
20233 +/* Determine the "availability state" of pool 'p' from a query result 'r' */
20234 +#define BM_MCR_QUERY_AVAILABILITY(r, p) \
20235 + bman_depletion_get(&r->query.as.state, p)
20236 +/* Determine the "depletion state" of pool 'p' from a query result 'r' */
20237 +#define BM_MCR_QUERY_DEPLETION(r, p) \
20238 + bman_depletion_get(&r->query.ds.state, p)
20239 +
20240 +/*******************************************************************/
20241 +/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */
20242 +/*******************************************************************/
20243 +
20244 + /* Portal and Buffer Pools */
20245 + /* ----------------------- */
20246 +/* Represents a managed portal */
20247 +struct bman_portal;
20248 +
20249 +/* This object type represents Bman buffer pools. */
20250 +struct bman_pool;
20251 +
20252 +struct bman_portal_config {
20253 + /* This is used for any "core-affine" portals, ie. default portals
20254 + * associated to the corresponding cpu. -1 implies that there is no core
20255 + * affinity configured. */
20256 + int cpu;
20257 + /* portal interrupt line */
20258 + int irq;
20259 + /* the unique index of this portal */
20260 + u32 index;
20261 + /* Is this portal shared? (If so, it has coarser locking and demuxes
20262 + * processing on behalf of other CPUs.) */
20263 + int is_shared;
20264 + /* These are the buffer pool IDs that may be used via this portal. */
20265 + struct bman_depletion mask;
20266 +};
20267 +
20268 +/* This callback type is used when handling pool depletion entry/exit. The
20269 + * 'cb_ctx' value is the opaque value associated with the pool object in
20270 + * bman_new_pool(). 'depleted' is non-zero on depletion-entry, and zero on
20271 + * depletion-exit. */
20272 +typedef void (*bman_cb_depletion)(struct bman_portal *bm,
20273 + struct bman_pool *pool, void *cb_ctx, int depleted);
20274 +
20275 +/* This struct specifies parameters for a bman_pool object. */
20276 +struct bman_pool_params {
20277 + /* index of the buffer pool to encapsulate (0-63), ignored if
20278 + * BMAN_POOL_FLAG_DYNAMIC_BPID is set. */
20279 + u32 bpid;
20280 + /* bit-mask of BMAN_POOL_FLAG_*** options */
20281 + u32 flags;
20282 + /* depletion-entry/exit callback, if BMAN_POOL_FLAG_DEPLETION is set */
20283 + bman_cb_depletion cb;
20284 + /* opaque user value passed as a parameter to 'cb' */
20285 + void *cb_ctx;
20286 + /* depletion-entry/exit thresholds, if BMAN_POOL_FLAG_THRESH is set. NB:
20287 + * this is only allowed if BMAN_POOL_FLAG_DYNAMIC_BPID is used *and*
20288 + * when run in the control plane (which controls Bman CCSR). This array
20289 + * matches the definition of bm_pool_set(). */
20290 + u32 thresholds[4];
20291 +};
20292 +
20293 +/* Flags to bman_new_pool() */
20294 +#define BMAN_POOL_FLAG_NO_RELEASE 0x00000001 /* can't release to pool */
20295 +#define BMAN_POOL_FLAG_ONLY_RELEASE 0x00000002 /* can only release to pool */
20296 +#define BMAN_POOL_FLAG_DEPLETION 0x00000004 /* track depletion entry/exit */
20297 +#define BMAN_POOL_FLAG_DYNAMIC_BPID 0x00000008 /* (de)allocate bpid */
20298 +#define BMAN_POOL_FLAG_THRESH 0x00000010 /* set depletion thresholds */
20299 +#define BMAN_POOL_FLAG_STOCKPILE 0x00000020 /* stockpile to reduce hw ops */
20300 +
20301 +/* Flags to bman_release() */
20302 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
20303 +#define BMAN_RELEASE_FLAG_WAIT 0x00000001 /* wait if RCR is full */
20304 +#define BMAN_RELEASE_FLAG_WAIT_INT 0x00000002 /* if we wait, interruptible? */
20305 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
20306 +#define BMAN_RELEASE_FLAG_WAIT_SYNC 0x00000004 /* if wait, until consumed? */
20307 +#endif
20308 +#endif
20309 +#define BMAN_RELEASE_FLAG_NOW 0x00000008 /* issue immediate release */
20310 +
20311 +/* Flags to bman_acquire() */
20312 +#define BMAN_ACQUIRE_FLAG_STOCKPILE 0x00000001 /* no hw op, stockpile only */
20313 +
20314 + /* Portal Management */
20315 + /* ----------------- */
20316 +/**
20317 + * bman_get_portal_config - get portal configuration settings
20318 + *
20319 + * This returns a read-only view of the current cpu's affine portal settings.
20320 + */
20321 +const struct bman_portal_config *bman_get_portal_config(void);
20322 +
20323 +/**
20324 + * bman_irqsource_get - return the portal work that is interrupt-driven
20325 + *
20326 + * Returns a bitmask of BM_PIRQ_**I processing sources that are currently
20327 + * enabled for interrupt handling on the current cpu's affine portal. These
20328 + * sources will trigger the portal interrupt and the interrupt handler (or a
20329 + * tasklet/bottom-half it defers to) will perform the corresponding processing
20330 + * work. The bman_poll_***() functions will only process sources that are not in
20331 + * this bitmask. If the current CPU is sharing a portal hosted on another CPU,
20332 + * this always returns zero.
20333 + */
20334 +u32 bman_irqsource_get(void);
20335 +
20336 +/**
20337 + * bman_irqsource_add - add processing sources to be interrupt-driven
20338 + * @bits: bitmask of BM_PIRQ_**I processing sources
20339 + *
20340 + * Adds processing sources that should be interrupt-driven (rather than
20341 + * processed via bman_poll_***() functions). Returns zero for success, or
20342 + * -EINVAL if the current CPU is sharing a portal hosted on another CPU. */
20343 +int bman_irqsource_add(u32 bits);
20344 +
20345 +/**
20346 + * bman_irqsource_remove - remove processing sources from being interrupt-driven
20347 + * @bits: bitmask of BM_PIRQ_**I processing sources
20348 + *
20349 + * Removes processing sources from being interrupt-driven, so that they will
20350 + * instead be processed via bman_poll_***() functions. Returns zero for success,
20351 + * or -EINVAL if the current CPU is sharing a portal hosted on another CPU. */
20352 +int bman_irqsource_remove(u32 bits);
20353 +
20354 +/**
20355 + * bman_affine_cpus - return a mask of cpus that have affine portals
20356 + */
20357 +const cpumask_t *bman_affine_cpus(void);
20358 +
20359 +/**
20360 + * bman_poll_slow - process anything that isn't interrupt-driven.
20361 + *
20362 + * This function does any portal processing that isn't interrupt-driven. If the
20363 + * current CPU is sharing a portal hosted on another CPU, this function will
20364 + * return -EINVAL, otherwise the return value is a bitmask of BM_PIRQ_* sources
20365 + * indicating what interrupt sources were actually processed by the call.
20366 + *
20367 + * NB, unlike the legacy wrapper bman_poll(), this function will
20368 + * deterministically check for the presence of portal processing work and do it,
20369 + * which implies some latency even if there's nothing to do. The bman_poll()
20370 + * wrapper on the other hand (like the qman_poll() wrapper) attenuates this by
20371 + * checking for (and doing) portal processing infrequently. Ie. such that
20372 + * qman_poll() and bman_poll() can be called from core-processing loops. Use
20373 + * bman_poll_slow() when you yourself are deciding when to incur the overhead of
20374 + * processing.
20375 + */
20376 +u32 bman_poll_slow(void);
20377 +
20378 +/**
20379 + * bman_poll - process anything that isn't interrupt-driven.
20380 + *
20381 + * Dispatcher logic on a cpu can use this to trigger any maintenance of the
20382 + * affine portal. This function does whatever processing is not triggered by
20383 + * interrupts. This is a legacy wrapper that can be used in core-processing
20384 + * loops but mitigates the performance overhead of portal processing by
20385 + * adaptively bypassing true portal processing most of the time. (Processing is
20386 + * done once every 10 calls if the previous processing revealed that work needed
20387 + * to be done, or once very 1000 calls if the previous processing revealed no
20388 + * work needed doing.) If you wish to control this yourself, call
20389 + * bman_poll_slow() instead, which always checks for portal processing work.
20390 + */
20391 +void bman_poll(void);
20392 +
20393 +/**
20394 + * bman_rcr_is_empty - Determine if portal's RCR is empty
20395 + *
20396 + * For use in situations where a cpu-affine caller needs to determine when all
20397 + * releases for the local portal have been processed by Bman but can't use the
20398 + * BMAN_RELEASE_FLAG_WAIT_SYNC flag to do this from the final bman_release().
20399 + * The function forces tracking of RCR consumption (which normally doesn't
20400 + * happen until release processing needs to find space to put new release
20401 + * commands), and returns zero if the ring still has unprocessed entries,
20402 + * non-zero if it is empty.
20403 + */
20404 +int bman_rcr_is_empty(void);
20405 +
20406 +/**
20407 + * bman_alloc_bpid_range - Allocate a contiguous range of BPIDs
20408 + * @result: is set by the API to the base BPID of the allocated range
20409 + * @count: the number of BPIDs required
20410 + * @align: required alignment of the allocated range
20411 + * @partial: non-zero if the API can return fewer than @count BPIDs
20412 + *
20413 + * Returns the number of buffer pools allocated, or a negative error code. If
20414 + * @partial is non zero, the allocation request may return a smaller range of
20415 + * BPs than requested (though alignment will be as requested). If @partial is
20416 + * zero, the return value will either be 'count' or negative.
20417 + */
20418 +int bman_alloc_bpid_range(u32 *result, u32 count, u32 align, int partial);
20419 +static inline int bman_alloc_bpid(u32 *result)
20420 +{
20421 + int ret = bman_alloc_bpid_range(result, 1, 0, 0);
20422 + return (ret > 0) ? 0 : ret;
20423 +}
20424 +
20425 +/**
20426 + * bman_release_bpid_range - Release the specified range of buffer pool IDs
20427 + * @bpid: the base BPID of the range to deallocate
20428 + * @count: the number of BPIDs in the range
20429 + *
20430 + * This function can also be used to seed the allocator with ranges of BPIDs
20431 + * that it can subsequently allocate from.
20432 + */
20433 +void bman_release_bpid_range(u32 bpid, unsigned int count);
20434 +static inline void bman_release_bpid(u32 bpid)
20435 +{
20436 + bman_release_bpid_range(bpid, 1);
20437 +}
20438 +
20439 +int bman_reserve_bpid_range(u32 bpid, unsigned int count);
20440 +static inline int bman_reserve_bpid(u32 bpid)
20441 +{
20442 + return bman_reserve_bpid_range(bpid, 1);
20443 +}
20444 +
20445 +void bman_seed_bpid_range(u32 bpid, unsigned int count);
20446 +
20447 +
20448 +int bman_shutdown_pool(u32 bpid);
20449 +
20450 + /* Pool management */
20451 + /* --------------- */
20452 +/**
20453 + * bman_new_pool - Allocates a Buffer Pool object
20454 + * @params: parameters specifying the buffer pool ID and behaviour
20455 + *
20456 + * Creates a pool object for the given @params. A portal and the depletion
20457 + * callback field of @params are only used if the BMAN_POOL_FLAG_DEPLETION flag
20458 + * is set. NB, the fields from @params are copied into the new pool object, so
20459 + * the structure provided by the caller can be released or reused after the
20460 + * function returns.
20461 + */
20462 +struct bman_pool *bman_new_pool(const struct bman_pool_params *params);
20463 +
20464 +/**
20465 + * bman_free_pool - Deallocates a Buffer Pool object
20466 + * @pool: the pool object to release
20467 + *
20468 + */
20469 +void bman_free_pool(struct bman_pool *pool);
20470 +
20471 +/**
20472 + * bman_get_params - Returns a pool object's parameters.
20473 + * @pool: the pool object
20474 + *
20475 + * The returned pointer refers to state within the pool object so must not be
20476 + * modified and can no longer be read once the pool object is destroyed.
20477 + */
20478 +const struct bman_pool_params *bman_get_params(const struct bman_pool *pool);
20479 +
20480 +/**
20481 + * bman_release - Release buffer(s) to the buffer pool
20482 + * @pool: the buffer pool object to release to
20483 + * @bufs: an array of buffers to release
20484 + * @num: the number of buffers in @bufs (1-8)
20485 + * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options
20486 + *
20487 + * Adds the given buffers to RCR entries. If the portal @p was created with the
20488 + * "COMPACT" flag, then it will be using a compaction algorithm to improve
20489 + * utilisation of RCR. As such, these buffers may join an existing ring entry
20490 + * and/or it may not be issued right away so as to allow future releases to join
20491 + * the same ring entry. Use the BMAN_RELEASE_FLAG_NOW flag to override this
20492 + * behaviour by committing the RCR entry (or entries) right away. If the RCR
20493 + * ring is full, the function will return -EBUSY unless BMAN_RELEASE_FLAG_WAIT
20494 + * is selected, in which case it will sleep waiting for space to become
20495 + * available in RCR. If the function receives a signal before such time (and
20496 + * BMAN_RELEASE_FLAG_WAIT_INT is set), the function returns -EINTR. Otherwise,
20497 + * it returns zero.
20498 + */
20499 +int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num,
20500 + u32 flags);
20501 +
20502 +/**
20503 + * bman_acquire - Acquire buffer(s) from a buffer pool
20504 + * @pool: the buffer pool object to acquire from
20505 + * @bufs: array for storing the acquired buffers
20506 + * @num: the number of buffers desired (@bufs is at least this big)
20507 + *
20508 + * Issues an "Acquire" command via the portal's management command interface.
20509 + * The return value will be the number of buffers obtained from the pool, or a
20510 + * negative error code if a h/w error or pool starvation was encountered. In
20511 + * the latter case, the content of @bufs is undefined.
20512 + */
20513 +int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num,
20514 + u32 flags);
20515 +
20516 +/**
20517 + * bman_flush_stockpile - Flush stockpile buffer(s) to the buffer pool
20518 + * @pool: the buffer pool object the stockpile belongs
20519 + * @flags: bit-mask of BMAN_RELEASE_FLAG_*** options
20520 + *
20521 + * Adds stockpile buffers to RCR entries until the stockpile is empty.
20522 + * The return value will be a negative error code if a h/w error occurred.
20523 + * If BMAN_RELEASE_FLAG_NOW flag is passed and RCR ring is full,
20524 + * -EAGAIN will be returned.
20525 + */
20526 +int bman_flush_stockpile(struct bman_pool *pool, u32 flags);
20527 +
20528 +/**
20529 + * bman_query_pools - Query all buffer pool states
20530 + * @state: storage for the queried availability and depletion states
20531 + */
20532 +int bman_query_pools(struct bm_pool_state *state);
20533 +
20534 +#ifdef CONFIG_FSL_BMAN_CONFIG
20535 +/**
20536 + * bman_query_free_buffers - Query how many free buffers are in buffer pool
20537 + * @pool: the buffer pool object to query
20538 + *
20539 + * Return the number of the free buffers
20540 + */
20541 +u32 bman_query_free_buffers(struct bman_pool *pool);
20542 +
20543 +/**
20544 + * bman_update_pool_thresholds - Change the buffer pool's depletion thresholds
20545 + * @pool: the buffer pool object to which the thresholds will be set
20546 + * @thresholds: the new thresholds
20547 + */
20548 +int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds);
20549 +#endif
20550 +
20551 +/**
20552 + * The below bman_p_***() variant might be called in a situation that the cpu
20553 + * which the portal affine to is not online yet.
20554 + * @bman_portal specifies which portal the API will use.
20555 +*/
20556 +int bman_p_irqsource_add(struct bman_portal *p, __maybe_unused u32 bits);
20557 +#ifdef __cplusplus
20558 +}
20559 +#endif
20560 +
20561 +#endif /* FSL_BMAN_H */
20562 --- /dev/null
20563 +++ b/include/linux/fsl_qman.h
20564 @@ -0,0 +1,3889 @@
20565 +/* Copyright 2008-2012 Freescale Semiconductor, Inc.
20566 + *
20567 + * Redistribution and use in source and binary forms, with or without
20568 + * modification, are permitted provided that the following conditions are met:
20569 + * * Redistributions of source code must retain the above copyright
20570 + * notice, this list of conditions and the following disclaimer.
20571 + * * Redistributions in binary form must reproduce the above copyright
20572 + * notice, this list of conditions and the following disclaimer in the
20573 + * documentation and/or other materials provided with the distribution.
20574 + * * Neither the name of Freescale Semiconductor nor the
20575 + * names of its contributors may be used to endorse or promote products
20576 + * derived from this software without specific prior written permission.
20577 + *
20578 + *
20579 + * ALTERNATIVELY, this software may be distributed under the terms of the
20580 + * GNU General Public License ("GPL") as published by the Free Software
20581 + * Foundation, either version 2 of that License or (at your option) any
20582 + * later version.
20583 + *
20584 + * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
20585 + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20586 + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20587 + * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
20588 + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20589 + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20590 + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20591 + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20592 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20593 + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
20594 + */
20595 +
20596 +#ifndef FSL_QMAN_H
20597 +#define FSL_QMAN_H
20598 +
20599 +#ifdef __cplusplus
20600 +extern "C" {
20601 +#endif
20602 +
20603 +/* Last updated for v00.800 of the BG */
20604 +
20605 +/* Hardware constants */
20606 +#define QM_CHANNEL_SWPORTAL0 0
20607 +#define QMAN_CHANNEL_POOL1 0x21
20608 +#define QMAN_CHANNEL_CAAM 0x80
20609 +#define QMAN_CHANNEL_PME 0xa0
20610 +#define QMAN_CHANNEL_POOL1_REV3 0x401
20611 +#define QMAN_CHANNEL_CAAM_REV3 0x840
20612 +#define QMAN_CHANNEL_PME_REV3 0x860
20613 +#define QMAN_CHANNEL_DCE 0x8a0
20614 +#define QMAN_CHANNEL_DCE_QMANREV312 0x880
20615 +extern u16 qm_channel_pool1;
20616 +extern u16 qm_channel_caam;
20617 +extern u16 qm_channel_pme;
20618 +extern u16 qm_channel_dce;
20619 +enum qm_dc_portal {
20620 + qm_dc_portal_fman0 = 0,
20621 + qm_dc_portal_fman1 = 1,
20622 + qm_dc_portal_caam = 2,
20623 + qm_dc_portal_pme = 3,
20624 + qm_dc_portal_rman = 4,
20625 + qm_dc_portal_dce = 5
20626 +};
20627 +
20628 +/* Portal processing (interrupt) sources */
20629 +#define QM_PIRQ_CCSCI 0x00200000 /* CEETM Congestion State Change */
20630 +#define QM_PIRQ_CSCI 0x00100000 /* Congestion State Change */
20631 +#define QM_PIRQ_EQCI 0x00080000 /* Enqueue Command Committed */
20632 +#define QM_PIRQ_EQRI 0x00040000 /* EQCR Ring (below threshold) */
20633 +#define QM_PIRQ_DQRI 0x00020000 /* DQRR Ring (non-empty) */
20634 +#define QM_PIRQ_MRI 0x00010000 /* MR Ring (non-empty) */
20635 +/* This mask contains all the interrupt sources that need handling except DQRI,
20636 + * ie. that if present should trigger slow-path processing. */
20637 +#define QM_PIRQ_SLOW (QM_PIRQ_CSCI | QM_PIRQ_EQCI | QM_PIRQ_EQRI | \
20638 + QM_PIRQ_MRI | QM_PIRQ_CCSCI)
20639 +
20640 +/* --- Clock speed --- */
20641 +/* A qman driver instance may or may not know the current qman clock speed.
20642 + * However, certain CEETM calculations may not be possible if this is not known.
20643 + * The 'set' function will only succeed (return zero) if the driver did not
20644 + * already know the clock speed. Likewise, the 'get' function will only succeed
20645 + * if the driver does know the clock speed (either because it knew when booting,
20646 + * or was told via 'set'). In cases where software is running on a driver
20647 + * instance that does not know the clock speed (eg. on a hypervised data-plane),
20648 + * and the user can obtain the current qman clock speed by other means (eg. from
20649 + * a message sent from the control-plane), then the 'set' function can be used
20650 + * to enable rate-calculations in a driver where it would otherwise not be
20651 + * possible. */
20652 +int qm_get_clock(u64 *clock_hz);
20653 +int qm_set_clock(u64 clock_hz);
20654 +
20655 +/* For qman_static_dequeue_*** APIs */
20656 +#define QM_SDQCR_CHANNELS_POOL_MASK 0x00007fff
20657 +/* for n in [1,15] */
20658 +#define QM_SDQCR_CHANNELS_POOL(n) (0x00008000 >> (n))
20659 +/* for conversion from n of qm_channel */
20660 +static inline u32 QM_SDQCR_CHANNELS_POOL_CONV(u16 channel)
20661 +{
20662 + return QM_SDQCR_CHANNELS_POOL(channel + 1 - qm_channel_pool1);
20663 +}
20664 +
20665 +/* For qman_volatile_dequeue(); Choose one PRECEDENCE. EXACT is optional. Use
20666 + * NUMFRAMES(n) (6-bit) or NUMFRAMES_TILLEMPTY to fill in the frame-count. Use
20667 + * FQID(n) to fill in the frame queue ID. */
20668 +#define QM_VDQCR_PRECEDENCE_VDQCR 0x0
20669 +#define QM_VDQCR_PRECEDENCE_SDQCR 0x80000000
20670 +#define QM_VDQCR_EXACT 0x40000000
20671 +#define QM_VDQCR_NUMFRAMES_MASK 0x3f000000
20672 +#define QM_VDQCR_NUMFRAMES_SET(n) (((n) & 0x3f) << 24)
20673 +#define QM_VDQCR_NUMFRAMES_GET(n) (((n) >> 24) & 0x3f)
20674 +#define QM_VDQCR_NUMFRAMES_TILLEMPTY QM_VDQCR_NUMFRAMES_SET(0)
20675 +
20676 +
20677 +/* ------------------------------------------------------- */
20678 +/* --- Qman data structures (and associated constants) --- */
20679 +
20680 +/* Represents s/w corenet portal mapped data structures */
20681 +struct qm_eqcr_entry; /* EQCR (EnQueue Command Ring) entries */
20682 +struct qm_dqrr_entry; /* DQRR (DeQueue Response Ring) entries */
20683 +struct qm_mr_entry; /* MR (Message Ring) entries */
20684 +struct qm_mc_command; /* MC (Management Command) command */
20685 +struct qm_mc_result; /* MC result */
20686 +
20687 +/* See David Lapp's "Frame formats" document, "dpateam", Jan 07, 2008 */
20688 +#define QM_FD_FORMAT_SG 0x4
20689 +#define QM_FD_FORMAT_LONG 0x2
20690 +#define QM_FD_FORMAT_COMPOUND 0x1
20691 +enum qm_fd_format {
20692 + /* 'contig' implies a contiguous buffer, whereas 'sg' implies a
20693 + * scatter-gather table. 'big' implies a 29-bit length with no offset
20694 + * field, otherwise length is 20-bit and offset is 9-bit. 'compound'
20695 + * implies a s/g-like table, where each entry itself represents a frame
20696 + * (contiguous or scatter-gather) and the 29-bit "length" is
20697 + * interpreted purely for congestion calculations, ie. a "congestion
20698 + * weight". */
20699 + qm_fd_contig = 0,
20700 + qm_fd_contig_big = QM_FD_FORMAT_LONG,
20701 + qm_fd_sg = QM_FD_FORMAT_SG,
20702 + qm_fd_sg_big = QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG,
20703 + qm_fd_compound = QM_FD_FORMAT_COMPOUND
20704 +};
20705 +
20706 +/* Capitalised versions are un-typed but can be used in static expressions */
20707 +#define QM_FD_CONTIG 0
20708 +#define QM_FD_CONTIG_BIG QM_FD_FORMAT_LONG
20709 +#define QM_FD_SG QM_FD_FORMAT_SG
20710 +#define QM_FD_SG_BIG (QM_FD_FORMAT_SG | QM_FD_FORMAT_LONG)
20711 +#define QM_FD_COMPOUND QM_FD_FORMAT_COMPOUND
20712 +
20713 +/* See 1.5.1.1: "Frame Descriptor (FD)" */
20714 +struct qm_fd {
20715 + union {
20716 + struct {
20717 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20718 + u8 dd:2; /* dynamic debug */
20719 + u8 liodn_offset:6;
20720 + u8 bpid:8; /* Buffer Pool ID */
20721 + u8 eliodn_offset:4;
20722 + u8 __reserved:4;
20723 + u8 addr_hi; /* high 8-bits of 40-bit address */
20724 + u32 addr_lo; /* low 32-bits of 40-bit address */
20725 +#else
20726 + u8 liodn_offset:6;
20727 + u8 dd:2; /* dynamic debug */
20728 + u8 bpid:8; /* Buffer Pool ID */
20729 + u8 __reserved:4;
20730 + u8 eliodn_offset:4;
20731 + u8 addr_hi; /* high 8-bits of 40-bit address */
20732 + u32 addr_lo; /* low 32-bits of 40-bit address */
20733 +#endif
20734 + };
20735 + struct {
20736 + u64 __notaddress:24;
20737 + /* More efficient address accessor */
20738 + u64 addr:40;
20739 + };
20740 + u64 opaque_addr;
20741 + };
20742 + /* The 'format' field indicates the interpretation of the remaining 29
20743 + * bits of the 32-bit word. For packing reasons, it is duplicated in the
20744 + * other union elements. Note, union'd structs are difficult to use with
20745 + * static initialisation under gcc, in which case use the "opaque" form
20746 + * with one of the macros. */
20747 + union {
20748 + /* For easier/faster copying of this part of the fd (eg. from a
20749 + * DQRR entry to an EQCR entry) copy 'opaque' */
20750 + u32 opaque;
20751 + /* If 'format' is _contig or _sg, 20b length and 9b offset */
20752 + struct {
20753 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20754 + enum qm_fd_format format:3;
20755 + u16 offset:9;
20756 + u32 length20:20;
20757 +#else
20758 + u32 length20:20;
20759 + u16 offset:9;
20760 + enum qm_fd_format format:3;
20761 +#endif
20762 + };
20763 + /* If 'format' is _contig_big or _sg_big, 29b length */
20764 + struct {
20765 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20766 + enum qm_fd_format _format1:3;
20767 + u32 length29:29;
20768 +#else
20769 + u32 length29:29;
20770 + enum qm_fd_format _format1:3;
20771 +#endif
20772 + };
20773 + /* If 'format' is _compound, 29b "congestion weight" */
20774 + struct {
20775 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20776 + enum qm_fd_format _format2:3;
20777 + u32 cong_weight:29;
20778 +#else
20779 + u32 cong_weight:29;
20780 + enum qm_fd_format _format2:3;
20781 +#endif
20782 + };
20783 + };
20784 + union {
20785 + u32 cmd;
20786 + u32 status;
20787 + };
20788 +} __aligned(8);
20789 +#define QM_FD_DD_NULL 0x00
20790 +#define QM_FD_PID_MASK 0x3f
20791 +static inline u64 qm_fd_addr_get64(const struct qm_fd *fd)
20792 +{
20793 + return fd->addr;
20794 +}
20795 +
20796 +static inline dma_addr_t qm_fd_addr(const struct qm_fd *fd)
20797 +{
20798 + return (dma_addr_t)fd->addr;
20799 +}
20800 +/* Macro, so we compile better if 'v' isn't always 64-bit */
20801 +#define qm_fd_addr_set64(fd, v) \
20802 + do { \
20803 + struct qm_fd *__fd931 = (fd); \
20804 + __fd931->addr = v; \
20805 + } while (0)
20806 +
20807 +/* For static initialisation of FDs (which is complicated by the use of unions
20808 + * in "struct qm_fd"), use the following macros. Note that;
20809 + * - 'dd', 'pid' and 'bpid' are ignored because there's no static initialisation
20810 + * use-case),
20811 + * - use capitalised QM_FD_*** formats for static initialisation.
20812 + */
20813 +#define QM_FD_FMT_20(cmd, addr_hi, addr_lo, fmt, off, len) \
20814 + { 0, 0, 0, 0, 0, addr_hi, addr_lo, \
20815 + { (((fmt)&0x7) << 29) | (((off)&0x1ff) << 20) | ((len)&0xfffff) }, \
20816 + { cmd } }
20817 +#define QM_FD_FMT_29(cmd, addr_hi, addr_lo, fmt, len) \
20818 + { 0, 0, 0, 0, 0, addr_hi, addr_lo, \
20819 + { (((fmt)&0x7) << 29) | ((len)&0x1fffffff) }, \
20820 + { cmd } }
20821 +
20822 +/* See 2.2.1.3 Multi-Core Datapath Acceleration Architecture */
20823 +#define QM_SG_OFFSET_MASK 0x1FFF
20824 +struct qm_sg_entry {
20825 + union {
20826 + struct {
20827 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20828 + u8 __reserved1[3];
20829 + u8 addr_hi; /* high 8-bits of 40-bit address */
20830 + u32 addr_lo; /* low 32-bits of 40-bit address */
20831 +#else
20832 + u32 addr_lo; /* low 32-bits of 40-bit address */
20833 + u8 addr_hi; /* high 8-bits of 40-bit address */
20834 + u8 __reserved1[3];
20835 +#endif
20836 + };
20837 + struct {
20838 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20839 + u64 __notaddress:24;
20840 + u64 addr:40;
20841 +#else
20842 + u64 addr:40;
20843 + u64 __notaddress:24;
20844 +#endif
20845 + };
20846 + u64 opaque;
20847 + };
20848 + union {
20849 + struct {
20850 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20851 + u32 extension:1; /* Extension bit */
20852 + u32 final:1; /* Final bit */
20853 + u32 length:30;
20854 +#else
20855 + u32 length:30;
20856 + u32 final:1; /* Final bit */
20857 + u32 extension:1; /* Extension bit */
20858 +#endif
20859 + };
20860 + u32 sgt_efl;
20861 + };
20862 + u8 __reserved2;
20863 + u8 bpid;
20864 + union {
20865 + struct {
20866 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20867 + u16 __reserved3:3;
20868 + u16 offset:13;
20869 +#else
20870 + u16 offset:13;
20871 + u16 __reserved3:3;
20872 +#endif
20873 + };
20874 + u16 opaque_offset;
20875 + };
20876 +} __packed;
20877 +union qm_sg_efl {
20878 + struct {
20879 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
20880 + u32 extension:1; /* Extension bit */
20881 + u32 final:1; /* Final bit */
20882 + u32 length:30;
20883 +#else
20884 + u32 length:30;
20885 + u32 final:1; /* Final bit */
20886 + u32 extension:1; /* Extension bit */
20887 +#endif
20888 + };
20889 + u32 efl;
20890 +};
20891 +static inline u64 qm_sg_entry_get64(const struct qm_sg_entry *sg)
20892 +{
20893 + return be64_to_cpu(sg->opaque);
20894 +}
20895 +static inline dma_addr_t qm_sg_addr(const struct qm_sg_entry *sg)
20896 +{
20897 + return (dma_addr_t)be64_to_cpu(sg->opaque);
20898 +}
20899 +static inline u8 qm_sg_entry_get_ext(const struct qm_sg_entry *sg)
20900 +{
20901 + union qm_sg_efl u;
20902 +
20903 + u.efl = be32_to_cpu(sg->sgt_efl);
20904 + return u.extension;
20905 +}
20906 +static inline u8 qm_sg_entry_get_final(const struct qm_sg_entry *sg)
20907 +{
20908 + union qm_sg_efl u;
20909 +
20910 + u.efl = be32_to_cpu(sg->sgt_efl);
20911 + return u.final;
20912 +}
20913 +static inline u32 qm_sg_entry_get_len(const struct qm_sg_entry *sg)
20914 +{
20915 + union qm_sg_efl u;
20916 +
20917 + u.efl = be32_to_cpu(sg->sgt_efl);
20918 + return u.length;
20919 +}
20920 +static inline u8 qm_sg_entry_get_bpid(const struct qm_sg_entry *sg)
20921 +{
20922 + return sg->bpid;
20923 +}
20924 +static inline u16 qm_sg_entry_get_offset(const struct qm_sg_entry *sg)
20925 +{
20926 + u32 opaque_offset = be16_to_cpu(sg->opaque_offset);
20927 +
20928 + return opaque_offset & 0x1fff;
20929 +}
20930 +
20931 +/* Macro, so we compile better if 'v' isn't always 64-bit */
20932 +#define qm_sg_entry_set64(sg, v) \
20933 + do { \
20934 + struct qm_sg_entry *__sg931 = (sg); \
20935 + __sg931->opaque = cpu_to_be64(v); \
20936 + } while (0)
20937 +#define qm_sg_entry_set_ext(sg, v) \
20938 + do { \
20939 + union qm_sg_efl __u932; \
20940 + __u932.efl = be32_to_cpu((sg)->sgt_efl); \
20941 + __u932.extension = v; \
20942 + (sg)->sgt_efl = cpu_to_be32(__u932.efl); \
20943 + } while (0)
20944 +#define qm_sg_entry_set_final(sg, v) \
20945 + do { \
20946 + union qm_sg_efl __u933; \
20947 + __u933.efl = be32_to_cpu((sg)->sgt_efl); \
20948 + __u933.final = v; \
20949 + (sg)->sgt_efl = cpu_to_be32(__u933.efl); \
20950 + } while (0)
20951 +#define qm_sg_entry_set_len(sg, v) \
20952 + do { \
20953 + union qm_sg_efl __u934; \
20954 + __u934.efl = be32_to_cpu((sg)->sgt_efl); \
20955 + __u934.length = v; \
20956 + (sg)->sgt_efl = cpu_to_be32(__u934.efl); \
20957 + } while (0)
20958 +#define qm_sg_entry_set_bpid(sg, v) \
20959 + do { \
20960 + struct qm_sg_entry *__u935 = (sg); \
20961 + __u935->bpid = v; \
20962 + } while (0)
20963 +#define qm_sg_entry_set_offset(sg, v) \
20964 + do { \
20965 + struct qm_sg_entry *__u936 = (sg); \
20966 + __u936->opaque_offset = cpu_to_be16(v); \
20967 + } while (0)
20968 +
20969 +/* See 1.5.8.1: "Enqueue Command" */
20970 +struct qm_eqcr_entry {
20971 + u8 __dont_write_directly__verb;
20972 + u8 dca;
20973 + u16 seqnum;
20974 + u32 orp; /* 24-bit */
20975 + u32 fqid; /* 24-bit */
20976 + u32 tag;
20977 + struct qm_fd fd;
20978 + u8 __reserved3[32];
20979 +} __packed;
20980 +#define QM_EQCR_VERB_VBIT 0x80
20981 +#define QM_EQCR_VERB_CMD_MASK 0x61 /* but only one value; */
20982 +#define QM_EQCR_VERB_CMD_ENQUEUE 0x01
20983 +#define QM_EQCR_VERB_COLOUR_MASK 0x18 /* 4 possible values; */
20984 +#define QM_EQCR_VERB_COLOUR_GREEN 0x00
20985 +#define QM_EQCR_VERB_COLOUR_YELLOW 0x08
20986 +#define QM_EQCR_VERB_COLOUR_RED 0x10
20987 +#define QM_EQCR_VERB_COLOUR_OVERRIDE 0x18
20988 +#define QM_EQCR_VERB_INTERRUPT 0x04 /* on command consumption */
20989 +#define QM_EQCR_VERB_ORP 0x02 /* enable order restoration */
20990 +#define QM_EQCR_DCA_ENABLE 0x80
20991 +#define QM_EQCR_DCA_PARK 0x40
20992 +#define QM_EQCR_DCA_IDXMASK 0x0f /* "DQRR::idx" goes here */
20993 +#define QM_EQCR_SEQNUM_NESN 0x8000 /* Advance NESN */
20994 +#define QM_EQCR_SEQNUM_NLIS 0x4000 /* More fragments to come */
20995 +#define QM_EQCR_SEQNUM_SEQMASK 0x3fff /* sequence number goes here */
20996 +#define QM_EQCR_FQID_NULL 0 /* eg. for an ORP seqnum hole */
20997 +
20998 +/* See 1.5.8.2: "Frame Dequeue Response" */
20999 +struct qm_dqrr_entry {
21000 + u8 verb;
21001 + u8 stat;
21002 + u16 seqnum; /* 15-bit */
21003 + u8 tok;
21004 + u8 __reserved2[3];
21005 + u32 fqid; /* 24-bit */
21006 + u32 contextB;
21007 + struct qm_fd fd;
21008 + u8 __reserved4[32];
21009 +};
21010 +#define QM_DQRR_VERB_VBIT 0x80
21011 +#define QM_DQRR_VERB_MASK 0x7f /* where the verb contains; */
21012 +#define QM_DQRR_VERB_FRAME_DEQUEUE 0x60 /* "this format" */
21013 +#define QM_DQRR_STAT_FQ_EMPTY 0x80 /* FQ empty */
21014 +#define QM_DQRR_STAT_FQ_HELDACTIVE 0x40 /* FQ held active */
21015 +#define QM_DQRR_STAT_FQ_FORCEELIGIBLE 0x20 /* FQ was force-eligible'd */
21016 +#define QM_DQRR_STAT_FD_VALID 0x10 /* has a non-NULL FD */
21017 +#define QM_DQRR_STAT_UNSCHEDULED 0x02 /* Unscheduled dequeue */
21018 +#define QM_DQRR_STAT_DQCR_EXPIRED 0x01 /* VDQCR or PDQCR expired*/
21019 +
21020 +/* See 1.5.8.3: "ERN Message Response" */
21021 +/* See 1.5.8.4: "FQ State Change Notification" */
21022 +struct qm_mr_entry {
21023 + u8 verb;
21024 + union {
21025 + struct {
21026 + u8 dca;
21027 + u16 seqnum;
21028 + u8 rc; /* Rejection Code */
21029 + u32 orp:24;
21030 + u32 fqid; /* 24-bit */
21031 + u32 tag;
21032 + struct qm_fd fd;
21033 + } __packed ern;
21034 + struct {
21035 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21036 + u8 colour:2; /* See QM_MR_DCERN_COLOUR_* */
21037 + u8 __reserved1:3;
21038 + enum qm_dc_portal portal:3;
21039 +#else
21040 + enum qm_dc_portal portal:3;
21041 + u8 __reserved1:3;
21042 + u8 colour:2; /* See QM_MR_DCERN_COLOUR_* */
21043 +#endif
21044 + u16 __reserved2;
21045 + u8 rc; /* Rejection Code */
21046 + u32 __reserved3:24;
21047 + u32 fqid; /* 24-bit */
21048 + u32 tag;
21049 + struct qm_fd fd;
21050 + } __packed dcern;
21051 + struct {
21052 + u8 fqs; /* Frame Queue Status */
21053 + u8 __reserved1[6];
21054 + u32 fqid; /* 24-bit */
21055 + u32 contextB;
21056 + u8 __reserved2[16];
21057 + } __packed fq; /* FQRN/FQRNI/FQRL/FQPN */
21058 + };
21059 + u8 __reserved2[32];
21060 +} __packed;
21061 +#define QM_MR_VERB_VBIT 0x80
21062 +/* The "ern" VERB bits match QM_EQCR_VERB_*** so aren't reproduced here. ERNs
21063 + * originating from direct-connect portals ("dcern") use 0x20 as a verb which
21064 + * would be invalid as a s/w enqueue verb. A s/w ERN can be distinguished from
21065 + * the other MR types by noting if the 0x20 bit is unset. */
21066 +#define QM_MR_VERB_TYPE_MASK 0x27
21067 +#define QM_MR_VERB_DC_ERN 0x20
21068 +#define QM_MR_VERB_FQRN 0x21
21069 +#define QM_MR_VERB_FQRNI 0x22
21070 +#define QM_MR_VERB_FQRL 0x23
21071 +#define QM_MR_VERB_FQPN 0x24
21072 +#define QM_MR_RC_MASK 0xf0 /* contains one of; */
21073 +#define QM_MR_RC_CGR_TAILDROP 0x00
21074 +#define QM_MR_RC_WRED 0x10
21075 +#define QM_MR_RC_ERROR 0x20
21076 +#define QM_MR_RC_ORPWINDOW_EARLY 0x30
21077 +#define QM_MR_RC_ORPWINDOW_LATE 0x40
21078 +#define QM_MR_RC_FQ_TAILDROP 0x50
21079 +#define QM_MR_RC_ORPWINDOW_RETIRED 0x60
21080 +#define QM_MR_RC_ORP_ZERO 0x70
21081 +#define QM_MR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */
21082 +#define QM_MR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */
21083 +#define QM_MR_DCERN_COLOUR_GREEN 0x00
21084 +#define QM_MR_DCERN_COLOUR_YELLOW 0x01
21085 +#define QM_MR_DCERN_COLOUR_RED 0x02
21086 +#define QM_MR_DCERN_COLOUR_OVERRIDE 0x03
21087 +
21088 +/* An identical structure of FQD fields is present in the "Init FQ" command and
21089 + * the "Query FQ" result, it's suctioned out into the "struct qm_fqd" type.
21090 + * Within that, the 'stashing' and 'taildrop' pieces are also factored out, the
21091 + * latter has two inlines to assist with converting to/from the mant+exp
21092 + * representation. */
21093 +struct qm_fqd_stashing {
21094 + /* See QM_STASHING_EXCL_<...> */
21095 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21096 + u8 exclusive;
21097 + u8 __reserved1:2;
21098 + /* Numbers of cachelines */
21099 + u8 annotation_cl:2;
21100 + u8 data_cl:2;
21101 + u8 context_cl:2;
21102 +#else
21103 + u8 context_cl:2;
21104 + u8 data_cl:2;
21105 + u8 annotation_cl:2;
21106 + u8 __reserved1:2;
21107 + u8 exclusive;
21108 +#endif
21109 +} __packed;
21110 +struct qm_fqd_taildrop {
21111 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21112 + u16 __reserved1:3;
21113 + u16 mant:8;
21114 + u16 exp:5;
21115 +#else
21116 + u16 exp:5;
21117 + u16 mant:8;
21118 + u16 __reserved1:3;
21119 +#endif
21120 +} __packed;
21121 +struct qm_fqd_oac {
21122 + /* See QM_OAC_<...> */
21123 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21124 + u8 oac:2; /* "Overhead Accounting Control" */
21125 + u8 __reserved1:6;
21126 +#else
21127 + u8 __reserved1:6;
21128 + u8 oac:2; /* "Overhead Accounting Control" */
21129 +#endif
21130 + /* Two's-complement value (-128 to +127) */
21131 + signed char oal; /* "Overhead Accounting Length" */
21132 +} __packed;
21133 +struct qm_fqd {
21134 + union {
21135 + u8 orpc;
21136 + struct {
21137 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21138 + u8 __reserved1:2;
21139 + u8 orprws:3;
21140 + u8 oa:1;
21141 + u8 olws:2;
21142 +#else
21143 + u8 olws:2;
21144 + u8 oa:1;
21145 + u8 orprws:3;
21146 + u8 __reserved1:2;
21147 +#endif
21148 + } __packed;
21149 + };
21150 + u8 cgid;
21151 + u16 fq_ctrl; /* See QM_FQCTRL_<...> */
21152 + union {
21153 + u16 dest_wq;
21154 + struct {
21155 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21156 + u16 channel:13; /* qm_channel */
21157 + u16 wq:3;
21158 +#else
21159 + u16 wq:3;
21160 + u16 channel:13; /* qm_channel */
21161 +#endif
21162 + } __packed dest;
21163 + };
21164 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21165 + u16 __reserved2:1;
21166 + u16 ics_cred:15;
21167 +#else
21168 + u16 __reserved2:1;
21169 + u16 ics_cred:15;
21170 +#endif
21171 + /* For "Initialize Frame Queue" commands, the write-enable mask
21172 + * determines whether 'td' or 'oac_init' is observed. For query
21173 + * commands, this field is always 'td', and 'oac_query' (below) reflects
21174 + * the Overhead ACcounting values. */
21175 + union {
21176 + struct qm_fqd_taildrop td;
21177 + struct qm_fqd_oac oac_init;
21178 + };
21179 + u32 context_b;
21180 + union {
21181 + /* Treat it as 64-bit opaque */
21182 + u64 opaque;
21183 + struct {
21184 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21185 + u32 hi;
21186 + u32 lo;
21187 +#else
21188 + u32 lo;
21189 + u32 hi;
21190 +#endif
21191 + };
21192 + /* Treat it as s/w portal stashing config */
21193 + /* See 1.5.6.7.1: "FQD Context_A field used for [...] */
21194 + struct {
21195 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21196 + struct qm_fqd_stashing stashing;
21197 + /* 48-bit address of FQ context to
21198 + * stash, must be cacheline-aligned */
21199 + u16 context_hi;
21200 + u32 context_lo;
21201 +#else
21202 + u32 context_lo;
21203 + u16 context_hi;
21204 + struct qm_fqd_stashing stashing;
21205 +#endif
21206 + } __packed;
21207 + } context_a;
21208 + struct qm_fqd_oac oac_query;
21209 +} __packed;
21210 +/* 64-bit converters for context_hi/lo */
21211 +static inline u64 qm_fqd_stashing_get64(const struct qm_fqd *fqd)
21212 +{
21213 + return ((u64)fqd->context_a.context_hi << 32) |
21214 + (u64)fqd->context_a.context_lo;
21215 +}
21216 +static inline dma_addr_t qm_fqd_stashing_addr(const struct qm_fqd *fqd)
21217 +{
21218 + return (dma_addr_t)qm_fqd_stashing_get64(fqd);
21219 +}
21220 +static inline u64 qm_fqd_context_a_get64(const struct qm_fqd *fqd)
21221 +{
21222 + return ((u64)fqd->context_a.hi << 32) |
21223 + (u64)fqd->context_a.lo;
21224 +}
21225 +/* Macro, so we compile better when 'v' isn't necessarily 64-bit */
21226 +#define qm_fqd_stashing_set64(fqd, v) \
21227 + do { \
21228 + struct qm_fqd *__fqd931 = (fqd); \
21229 + __fqd931->context_a.context_hi = upper_32_bits(v); \
21230 + __fqd931->context_a.context_lo = lower_32_bits(v); \
21231 + } while (0)
21232 +#define qm_fqd_context_a_set64(fqd, v) \
21233 + do { \
21234 + struct qm_fqd *__fqd931 = (fqd); \
21235 + __fqd931->context_a.hi = upper_32_bits(v); \
21236 + __fqd931->context_a.lo = lower_32_bits(v); \
21237 + } while (0)
21238 +/* convert a threshold value into mant+exp representation */
21239 +static inline int qm_fqd_taildrop_set(struct qm_fqd_taildrop *td, u32 val,
21240 + int roundup)
21241 +{
21242 + u32 e = 0;
21243 + int oddbit = 0;
21244 + if (val > 0xe0000000)
21245 + return -ERANGE;
21246 + while (val > 0xff) {
21247 + oddbit = val & 1;
21248 + val >>= 1;
21249 + e++;
21250 + if (roundup && oddbit)
21251 + val++;
21252 + }
21253 + td->exp = e;
21254 + td->mant = val;
21255 + return 0;
21256 +}
21257 +/* and the other direction */
21258 +static inline u32 qm_fqd_taildrop_get(const struct qm_fqd_taildrop *td)
21259 +{
21260 + return (u32)td->mant << td->exp;
21261 +}
21262 +
21263 +/* See 1.5.2.2: "Frame Queue Descriptor (FQD)" */
21264 +/* Frame Queue Descriptor (FQD) field 'fq_ctrl' uses these constants */
21265 +#define QM_FQCTRL_MASK 0x07ff /* 'fq_ctrl' flags; */
21266 +#define QM_FQCTRL_CGE 0x0400 /* Congestion Group Enable */
21267 +#define QM_FQCTRL_TDE 0x0200 /* Tail-Drop Enable */
21268 +#define QM_FQCTRL_ORP 0x0100 /* ORP Enable */
21269 +#define QM_FQCTRL_CTXASTASHING 0x0080 /* Context-A stashing */
21270 +#define QM_FQCTRL_CPCSTASH 0x0040 /* CPC Stash Enable */
21271 +#define QM_FQCTRL_FORCESFDR 0x0008 /* High-priority SFDRs */
21272 +#define QM_FQCTRL_AVOIDBLOCK 0x0004 /* Don't block active */
21273 +#define QM_FQCTRL_HOLDACTIVE 0x0002 /* Hold active in portal */
21274 +#define QM_FQCTRL_PREFERINCACHE 0x0001 /* Aggressively cache FQD */
21275 +#define QM_FQCTRL_LOCKINCACHE QM_FQCTRL_PREFERINCACHE /* older naming */
21276 +
21277 +/* See 1.5.6.7.1: "FQD Context_A field used for [...] */
21278 +/* Frame Queue Descriptor (FQD) field 'CONTEXT_A' uses these constants */
21279 +#define QM_STASHING_EXCL_ANNOTATION 0x04
21280 +#define QM_STASHING_EXCL_DATA 0x02
21281 +#define QM_STASHING_EXCL_CTX 0x01
21282 +
21283 +/* See 1.5.5.3: "Intra Class Scheduling" */
21284 +/* FQD field 'OAC' (Overhead ACcounting) uses these constants */
21285 +#define QM_OAC_ICS 0x2 /* Accounting for Intra-Class Scheduling */
21286 +#define QM_OAC_CG 0x1 /* Accounting for Congestion Groups */
21287 +
21288 +/* See 1.5.8.4: "FQ State Change Notification" */
21289 +/* This struct represents the 32-bit "WR_PARM_[GYR]" parameters in CGR fields
21290 + * and associated commands/responses. The WRED parameters are calculated from
21291 + * these fields as follows;
21292 + * MaxTH = MA * (2 ^ Mn)
21293 + * Slope = SA / (2 ^ Sn)
21294 + * MaxP = 4 * (Pn + 1)
21295 + */
21296 +struct qm_cgr_wr_parm {
21297 + union {
21298 + u32 word;
21299 + struct {
21300 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21301 + u32 MA:8;
21302 + u32 Mn:5;
21303 + u32 SA:7; /* must be between 64-127 */
21304 + u32 Sn:6;
21305 + u32 Pn:6;
21306 +#else
21307 + u32 Pn:6;
21308 + u32 Sn:6;
21309 + u32 SA:7; /* must be between 64-127 */
21310 + u32 Mn:5;
21311 + u32 MA:8;
21312 +#endif
21313 + } __packed;
21314 + };
21315 +} __packed;
21316 +/* This struct represents the 13-bit "CS_THRES" CGR field. In the corresponding
21317 + * management commands, this is padded to a 16-bit structure field, so that's
21318 + * how we represent it here. The congestion state threshold is calculated from
21319 + * these fields as follows;
21320 + * CS threshold = TA * (2 ^ Tn)
21321 + */
21322 +struct qm_cgr_cs_thres {
21323 + union {
21324 + u16 hword;
21325 + struct {
21326 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21327 + u16 __reserved:3;
21328 + u16 TA:8;
21329 + u16 Tn:5;
21330 +#else
21331 + u16 Tn:5;
21332 + u16 TA:8;
21333 + u16 __reserved:3;
21334 +#endif
21335 + } __packed;
21336 + };
21337 +} __packed;
21338 +/* This identical structure of CGR fields is present in the "Init/Modify CGR"
21339 + * commands and the "Query CGR" result. It's suctioned out here into its own
21340 + * struct. */
21341 +struct __qm_mc_cgr {
21342 + struct qm_cgr_wr_parm wr_parm_g;
21343 + struct qm_cgr_wr_parm wr_parm_y;
21344 + struct qm_cgr_wr_parm wr_parm_r;
21345 + u8 wr_en_g; /* boolean, use QM_CGR_EN */
21346 + u8 wr_en_y; /* boolean, use QM_CGR_EN */
21347 + u8 wr_en_r; /* boolean, use QM_CGR_EN */
21348 + u8 cscn_en; /* boolean, use QM_CGR_EN */
21349 + union {
21350 + struct {
21351 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21352 + u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */
21353 + u16 cscn_targ_dcp_low; /* CSCN_TARG_DCP low-16bits */
21354 +#else
21355 + u16 cscn_targ_dcp_low; /* CSCN_TARG_DCP low-16bits */
21356 + u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */
21357 +#endif
21358 + };
21359 + u32 cscn_targ; /* use QM_CGR_TARG_* */
21360 + };
21361 + u8 cstd_en; /* boolean, use QM_CGR_EN */
21362 + u8 cs; /* boolean, only used in query response */
21363 + union {
21364 + /* use qm_cgr_cs_thres_set64() */
21365 + struct qm_cgr_cs_thres cs_thres;
21366 + u16 __cs_thres;
21367 + };
21368 + u8 mode; /* QMAN_CGR_MODE_FRAME not supported in rev1.0 */
21369 +} __packed;
21370 +#define QM_CGR_EN 0x01 /* For wr_en_*, cscn_en, cstd_en */
21371 +#define QM_CGR_TARG_UDP_CTRL_WRITE_BIT 0x8000 /* value written to portal bit*/
21372 +#define QM_CGR_TARG_UDP_CTRL_DCP 0x4000 /* 0: SWP, 1: DCP */
21373 +#define QM_CGR_TARG_PORTAL(n) (0x80000000 >> (n)) /* s/w portal, 0-9 */
21374 +#define QM_CGR_TARG_FMAN0 0x00200000 /* direct-connect portal: fman0 */
21375 +#define QM_CGR_TARG_FMAN1 0x00100000 /* : fman1 */
21376 +/* Convert CGR thresholds to/from "cs_thres" format */
21377 +static inline u64 qm_cgr_cs_thres_get64(const struct qm_cgr_cs_thres *th)
21378 +{
21379 + return (u64)th->TA << th->Tn;
21380 +}
21381 +static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val,
21382 + int roundup)
21383 +{
21384 + u32 e = 0;
21385 + int oddbit = 0;
21386 + while (val > 0xff) {
21387 + oddbit = val & 1;
21388 + val >>= 1;
21389 + e++;
21390 + if (roundup && oddbit)
21391 + val++;
21392 + }
21393 + th->Tn = e;
21394 + th->TA = val;
21395 + return 0;
21396 +}
21397 +
21398 +/* See 1.5.8.5.1: "Initialize FQ" */
21399 +/* See 1.5.8.5.2: "Query FQ" */
21400 +/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */
21401 +/* See 1.5.8.5.4: "Alter FQ State Commands " */
21402 +/* See 1.5.8.6.1: "Initialize/Modify CGR" */
21403 +/* See 1.5.8.6.2: "CGR Test Write" */
21404 +/* See 1.5.8.6.3: "Query CGR" */
21405 +/* See 1.5.8.6.4: "Query Congestion Group State" */
21406 +struct qm_mcc_initfq {
21407 + u8 __reserved1;
21408 + u16 we_mask; /* Write Enable Mask */
21409 + u32 fqid; /* 24-bit */
21410 + u16 count; /* Initialises 'count+1' FQDs */
21411 + struct qm_fqd fqd; /* the FQD fields go here */
21412 + u8 __reserved3[30];
21413 +} __packed;
21414 +struct qm_mcc_queryfq {
21415 + u8 __reserved1[3];
21416 + u32 fqid; /* 24-bit */
21417 + u8 __reserved2[56];
21418 +} __packed;
21419 +struct qm_mcc_queryfq_np {
21420 + u8 __reserved1[3];
21421 + u32 fqid; /* 24-bit */
21422 + u8 __reserved2[56];
21423 +} __packed;
21424 +struct qm_mcc_alterfq {
21425 + u8 __reserved1[3];
21426 + u32 fqid; /* 24-bit */
21427 + u8 __reserved2;
21428 + u8 count; /* number of consecutive FQID */
21429 + u8 __reserved3[10];
21430 + u32 context_b; /* frame queue context b */
21431 + u8 __reserved4[40];
21432 +} __packed;
21433 +struct qm_mcc_initcgr {
21434 + u8 __reserved1;
21435 + u16 we_mask; /* Write Enable Mask */
21436 + struct __qm_mc_cgr cgr; /* CGR fields */
21437 + u8 __reserved2[2];
21438 + u8 cgid;
21439 + u8 __reserved4[32];
21440 +} __packed;
21441 +struct qm_mcc_cgrtestwrite {
21442 + u8 __reserved1[2];
21443 + u8 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
21444 + u32 i_bcnt_lo; /* low 32-bits of 40-bit */
21445 + u8 __reserved2[23];
21446 + u8 cgid;
21447 + u8 __reserved3[32];
21448 +} __packed;
21449 +struct qm_mcc_querycgr {
21450 + u8 __reserved1[30];
21451 + u8 cgid;
21452 + u8 __reserved2[32];
21453 +} __packed;
21454 +struct qm_mcc_querycongestion {
21455 + u8 __reserved[63];
21456 +} __packed;
21457 +struct qm_mcc_querywq {
21458 + u8 __reserved;
21459 + /* select channel if verb != QUERYWQ_DEDICATED */
21460 + union {
21461 + u16 channel_wq; /* ignores wq (3 lsbits) */
21462 + struct {
21463 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21464 + u16 id:13; /* qm_channel */
21465 + u16 __reserved1:3;
21466 +#else
21467 + u16 __reserved1:3;
21468 + u16 id:13; /* qm_channel */
21469 +#endif
21470 + } __packed channel;
21471 + };
21472 + u8 __reserved2[60];
21473 +} __packed;
21474 +
21475 +struct qm_mcc_ceetm_lfqmt_config {
21476 + u8 __reserved1[4];
21477 + u32 lfqid:24;
21478 + u8 __reserved2[2];
21479 + u16 cqid;
21480 + u8 __reserved3[2];
21481 + u16 dctidx;
21482 + u8 __reserved4[48];
21483 +} __packed;
21484 +
21485 +struct qm_mcc_ceetm_lfqmt_query {
21486 + u8 __reserved1[4];
21487 + u32 lfqid:24;
21488 + u8 __reserved2[56];
21489 +} __packed;
21490 +
21491 +struct qm_mcc_ceetm_cq_config {
21492 + u8 __reserved1;
21493 + u16 cqid;
21494 + u8 dcpid;
21495 + u8 __reserved2;
21496 + u16 ccgid;
21497 + u8 __reserved3[56];
21498 +} __packed;
21499 +
21500 +struct qm_mcc_ceetm_cq_query {
21501 + u8 __reserved1;
21502 + u16 cqid;
21503 + u8 dcpid;
21504 + u8 __reserved2[59];
21505 +} __packed;
21506 +
21507 +struct qm_mcc_ceetm_dct_config {
21508 + u8 __reserved1;
21509 + u16 dctidx;
21510 + u8 dcpid;
21511 + u8 __reserved2[15];
21512 + u32 context_b;
21513 + u64 context_a;
21514 + u8 __reserved3[32];
21515 +} __packed;
21516 +
21517 +struct qm_mcc_ceetm_dct_query {
21518 + u8 __reserved1;
21519 + u16 dctidx;
21520 + u8 dcpid;
21521 + u8 __reserved2[59];
21522 +} __packed;
21523 +
21524 +struct qm_mcc_ceetm_class_scheduler_config {
21525 + u8 __reserved1;
21526 + u16 cqcid;
21527 + u8 dcpid;
21528 + u8 __reserved2[6];
21529 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21530 + u8 gpc_reserved:1;
21531 + u8 gpc_combine_flag:1;
21532 + u8 gpc_prio_b:3;
21533 + u8 gpc_prio_a:3;
21534 +#else
21535 + u8 gpc_prio_a:3;
21536 + u8 gpc_prio_b:3;
21537 + u8 gpc_combine_flag:1;
21538 + u8 gpc_reserved:1;
21539 +#endif
21540 + u16 crem;
21541 + u16 erem;
21542 + u8 w[8];
21543 + u8 __reserved3[40];
21544 +} __packed;
21545 +
21546 +struct qm_mcc_ceetm_class_scheduler_query {
21547 + u8 __reserved1;
21548 + u16 cqcid;
21549 + u8 dcpid;
21550 + u8 __reserved2[59];
21551 +} __packed;
21552 +
21553 +#define CEETM_COMMAND_CHANNEL_MAPPING (0 << 12)
21554 +#define CEETM_COMMAND_SP_MAPPING (1 << 12)
21555 +#define CEETM_COMMAND_CHANNEL_SHAPER (2 << 12)
21556 +#define CEETM_COMMAND_LNI_SHAPER (3 << 12)
21557 +#define CEETM_COMMAND_TCFC (4 << 12)
21558 +
21559 +#define CEETM_CCGRID_MASK 0x01FF
21560 +#define CEETM_CCGR_CM_CONFIGURE (0 << 14)
21561 +#define CEETM_CCGR_DN_CONFIGURE (1 << 14)
21562 +#define CEETM_CCGR_TEST_WRITE (2 << 14)
21563 +#define CEETM_CCGR_CM_QUERY (0 << 14)
21564 +#define CEETM_CCGR_DN_QUERY (1 << 14)
21565 +#define CEETM_CCGR_DN_QUERY_FLUSH (2 << 14)
21566 +#define CEETM_QUERY_CONGESTION_STATE (3 << 14)
21567 +
21568 +struct qm_mcc_ceetm_mapping_shaper_tcfc_config {
21569 + u8 __reserved1;
21570 + u16 cid;
21571 + u8 dcpid;
21572 + union {
21573 + struct {
21574 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21575 + u8 map_shaped:1;
21576 + u8 map_reserved:4;
21577 + u8 map_lni_id:3;
21578 +#else
21579 + u8 map_lni_id:3;
21580 + u8 map_reserved:4;
21581 + u8 map_shaped:1;
21582 +#endif
21583 + u8 __reserved2[58];
21584 + } __packed channel_mapping;
21585 + struct {
21586 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21587 + u8 map_reserved:5;
21588 + u8 map_lni_id:3;
21589 +#else
21590 + u8 map_lni_id:3;
21591 + u8 map_reserved:5;
21592 +#endif
21593 + u8 __reserved2[58];
21594 + } __packed sp_mapping;
21595 + struct {
21596 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21597 + u8 cpl:1;
21598 + u8 cpl_reserved:2;
21599 + u8 oal:5;
21600 +#else
21601 + u8 oal:5;
21602 + u8 cpl_reserved:2;
21603 + u8 cpl:1;
21604 +#endif
21605 + u32 crtcr:24;
21606 + u32 ertcr:24;
21607 + u16 crtbl;
21608 + u16 ertbl;
21609 + u8 mps; /* This will be hardcoded by driver with 60 */
21610 + u8 __reserved2[47];
21611 + } __packed shaper_config;
21612 + struct {
21613 + u8 __reserved2[11];
21614 + u64 lnitcfcc;
21615 + u8 __reserved3[40];
21616 + } __packed tcfc_config;
21617 + };
21618 +} __packed;
21619 +
21620 +struct qm_mcc_ceetm_mapping_shaper_tcfc_query {
21621 + u8 __reserved1;
21622 + u16 cid;
21623 + u8 dcpid;
21624 + u8 __reserved2[59];
21625 +} __packed;
21626 +
21627 +struct qm_mcc_ceetm_ccgr_config {
21628 + u8 __reserved1;
21629 + u16 ccgrid;
21630 + u8 dcpid;
21631 + u8 __reserved2;
21632 + u16 we_mask;
21633 + union {
21634 + struct {
21635 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21636 + u8 ctl_reserved:1;
21637 + u8 ctl_wr_en_g:1;
21638 + u8 ctl_wr_en_y:1;
21639 + u8 ctl_wr_en_r:1;
21640 + u8 ctl_td_en:1;
21641 + u8 ctl_td_mode:1;
21642 + u8 ctl_cscn_en:1;
21643 + u8 ctl_mode:1;
21644 +#else
21645 + u8 ctl_mode:1;
21646 + u8 ctl_cscn_en:1;
21647 + u8 ctl_td_mode:1;
21648 + u8 ctl_td_en:1;
21649 + u8 ctl_wr_en_r:1;
21650 + u8 ctl_wr_en_y:1;
21651 + u8 ctl_wr_en_g:1;
21652 + u8 ctl_reserved:1;
21653 +#endif
21654 + u8 cdv;
21655 + u16 cscn_tupd;
21656 + u8 oal;
21657 + u8 __reserved3;
21658 + struct qm_cgr_cs_thres cs_thres;
21659 + struct qm_cgr_cs_thres cs_thres_x;
21660 + struct qm_cgr_cs_thres td_thres;
21661 + struct qm_cgr_wr_parm wr_parm_g;
21662 + struct qm_cgr_wr_parm wr_parm_y;
21663 + struct qm_cgr_wr_parm wr_parm_r;
21664 + } __packed cm_config;
21665 + struct {
21666 + u8 dnc;
21667 + u8 dn0;
21668 + u8 dn1;
21669 + u64 dnba:40;
21670 + u8 __reserved3[2];
21671 + u16 dnth_0;
21672 + u8 __reserved4[2];
21673 + u16 dnth_1;
21674 + u8 __reserved5[8];
21675 + } __packed dn_config;
21676 + struct {
21677 + u8 __reserved3[3];
21678 + u64 i_cnt:40;
21679 + u8 __reserved4[16];
21680 + } __packed test_write;
21681 + };
21682 + u8 __reserved5[32];
21683 +} __packed;
21684 +
21685 +struct qm_mcc_ceetm_ccgr_query {
21686 + u8 __reserved1;
21687 + u16 ccgrid;
21688 + u8 dcpid;
21689 + u8 __reserved2[59];
21690 +} __packed;
21691 +
21692 +struct qm_mcc_ceetm_cq_peek_pop_xsfdrread {
21693 + u8 __reserved1;
21694 + u16 cqid;
21695 + u8 dcpid;
21696 + u8 ct;
21697 + u16 xsfdr;
21698 + u8 __reserved2[56];
21699 +} __packed;
21700 +
21701 +#define CEETM_QUERY_DEQUEUE_STATISTICS 0x00
21702 +#define CEETM_QUERY_DEQUEUE_CLEAR_STATISTICS 0x01
21703 +#define CEETM_WRITE_DEQUEUE_STATISTICS 0x02
21704 +#define CEETM_QUERY_REJECT_STATISTICS 0x03
21705 +#define CEETM_QUERY_REJECT_CLEAR_STATISTICS 0x04
21706 +#define CEETM_WRITE_REJECT_STATISTICS 0x05
21707 +struct qm_mcc_ceetm_statistics_query_write {
21708 + u8 __reserved1;
21709 + u16 cid;
21710 + u8 dcpid;
21711 + u8 ct;
21712 + u8 __reserved2[13];
21713 + u64 frm_cnt:40;
21714 + u8 __reserved3[2];
21715 + u64 byte_cnt:48;
21716 + u8 __reserved[32];
21717 +} __packed;
21718 +
21719 +struct qm_mc_command {
21720 + u8 __dont_write_directly__verb;
21721 + union {
21722 + struct qm_mcc_initfq initfq;
21723 + struct qm_mcc_queryfq queryfq;
21724 + struct qm_mcc_queryfq_np queryfq_np;
21725 + struct qm_mcc_alterfq alterfq;
21726 + struct qm_mcc_initcgr initcgr;
21727 + struct qm_mcc_cgrtestwrite cgrtestwrite;
21728 + struct qm_mcc_querycgr querycgr;
21729 + struct qm_mcc_querycongestion querycongestion;
21730 + struct qm_mcc_querywq querywq;
21731 + struct qm_mcc_ceetm_lfqmt_config lfqmt_config;
21732 + struct qm_mcc_ceetm_lfqmt_query lfqmt_query;
21733 + struct qm_mcc_ceetm_cq_config cq_config;
21734 + struct qm_mcc_ceetm_cq_query cq_query;
21735 + struct qm_mcc_ceetm_dct_config dct_config;
21736 + struct qm_mcc_ceetm_dct_query dct_query;
21737 + struct qm_mcc_ceetm_class_scheduler_config csch_config;
21738 + struct qm_mcc_ceetm_class_scheduler_query csch_query;
21739 + struct qm_mcc_ceetm_mapping_shaper_tcfc_config mst_config;
21740 + struct qm_mcc_ceetm_mapping_shaper_tcfc_query mst_query;
21741 + struct qm_mcc_ceetm_ccgr_config ccgr_config;
21742 + struct qm_mcc_ceetm_ccgr_query ccgr_query;
21743 + struct qm_mcc_ceetm_cq_peek_pop_xsfdrread cq_ppxr;
21744 + struct qm_mcc_ceetm_statistics_query_write stats_query_write;
21745 + };
21746 +} __packed;
21747 +#define QM_MCC_VERB_VBIT 0x80
21748 +#define QM_MCC_VERB_MASK 0x7f /* where the verb contains; */
21749 +#define QM_MCC_VERB_INITFQ_PARKED 0x40
21750 +#define QM_MCC_VERB_INITFQ_SCHED 0x41
21751 +#define QM_MCC_VERB_QUERYFQ 0x44
21752 +#define QM_MCC_VERB_QUERYFQ_NP 0x45 /* "non-programmable" fields */
21753 +#define QM_MCC_VERB_QUERYWQ 0x46
21754 +#define QM_MCC_VERB_QUERYWQ_DEDICATED 0x47
21755 +#define QM_MCC_VERB_ALTER_SCHED 0x48 /* Schedule FQ */
21756 +#define QM_MCC_VERB_ALTER_FE 0x49 /* Force Eligible FQ */
21757 +#define QM_MCC_VERB_ALTER_RETIRE 0x4a /* Retire FQ */
21758 +#define QM_MCC_VERB_ALTER_OOS 0x4b /* Take FQ out of service */
21759 +#define QM_MCC_VERB_ALTER_FQXON 0x4d /* FQ XON */
21760 +#define QM_MCC_VERB_ALTER_FQXOFF 0x4e /* FQ XOFF */
21761 +#define QM_MCC_VERB_INITCGR 0x50
21762 +#define QM_MCC_VERB_MODIFYCGR 0x51
21763 +#define QM_MCC_VERB_CGRTESTWRITE 0x52
21764 +#define QM_MCC_VERB_QUERYCGR 0x58
21765 +#define QM_MCC_VERB_QUERYCONGESTION 0x59
21766 +/* INITFQ-specific flags */
21767 +#define QM_INITFQ_WE_MASK 0x01ff /* 'Write Enable' flags; */
21768 +#define QM_INITFQ_WE_OAC 0x0100
21769 +#define QM_INITFQ_WE_ORPC 0x0080
21770 +#define QM_INITFQ_WE_CGID 0x0040
21771 +#define QM_INITFQ_WE_FQCTRL 0x0020
21772 +#define QM_INITFQ_WE_DESTWQ 0x0010
21773 +#define QM_INITFQ_WE_ICSCRED 0x0008
21774 +#define QM_INITFQ_WE_TDTHRESH 0x0004
21775 +#define QM_INITFQ_WE_CONTEXTB 0x0002
21776 +#define QM_INITFQ_WE_CONTEXTA 0x0001
21777 +/* INITCGR/MODIFYCGR-specific flags */
21778 +#define QM_CGR_WE_MASK 0x07ff /* 'Write Enable Mask'; */
21779 +#define QM_CGR_WE_WR_PARM_G 0x0400
21780 +#define QM_CGR_WE_WR_PARM_Y 0x0200
21781 +#define QM_CGR_WE_WR_PARM_R 0x0100
21782 +#define QM_CGR_WE_WR_EN_G 0x0080
21783 +#define QM_CGR_WE_WR_EN_Y 0x0040
21784 +#define QM_CGR_WE_WR_EN_R 0x0020
21785 +#define QM_CGR_WE_CSCN_EN 0x0010
21786 +#define QM_CGR_WE_CSCN_TARG 0x0008
21787 +#define QM_CGR_WE_CSTD_EN 0x0004
21788 +#define QM_CGR_WE_CS_THRES 0x0002
21789 +#define QM_CGR_WE_MODE 0x0001
21790 +
21791 +/* See 1.5.9.7 CEETM Management Commands */
21792 +#define QM_CEETM_VERB_LFQMT_CONFIG 0x70
21793 +#define QM_CEETM_VERB_LFQMT_QUERY 0x71
21794 +#define QM_CEETM_VERB_CQ_CONFIG 0x72
21795 +#define QM_CEETM_VERB_CQ_QUERY 0x73
21796 +#define QM_CEETM_VERB_DCT_CONFIG 0x74
21797 +#define QM_CEETM_VERB_DCT_QUERY 0x75
21798 +#define QM_CEETM_VERB_CLASS_SCHEDULER_CONFIG 0x76
21799 +#define QM_CEETM_VERB_CLASS_SCHEDULER_QUERY 0x77
21800 +#define QM_CEETM_VERB_MAPPING_SHAPER_TCFC_CONFIG 0x78
21801 +#define QM_CEETM_VERB_MAPPING_SHAPER_TCFC_QUERY 0x79
21802 +#define QM_CEETM_VERB_CCGR_CONFIG 0x7A
21803 +#define QM_CEETM_VERB_CCGR_QUERY 0x7B
21804 +#define QM_CEETM_VERB_CQ_PEEK_POP_XFDRREAD 0x7C
21805 +#define QM_CEETM_VERB_STATISTICS_QUERY_WRITE 0x7D
21806 +
21807 +/* See 1.5.8.5.1: "Initialize FQ" */
21808 +/* See 1.5.8.5.2: "Query FQ" */
21809 +/* See 1.5.8.5.3: "Query FQ Non-Programmable Fields" */
21810 +/* See 1.5.8.5.4: "Alter FQ State Commands " */
21811 +/* See 1.5.8.6.1: "Initialize/Modify CGR" */
21812 +/* See 1.5.8.6.2: "CGR Test Write" */
21813 +/* See 1.5.8.6.3: "Query CGR" */
21814 +/* See 1.5.8.6.4: "Query Congestion Group State" */
21815 +struct qm_mcr_initfq {
21816 + u8 __reserved1[62];
21817 +} __packed;
21818 +struct qm_mcr_queryfq {
21819 + u8 __reserved1[8];
21820 + struct qm_fqd fqd; /* the FQD fields are here */
21821 + u8 __reserved2[30];
21822 +} __packed;
21823 +struct qm_mcr_queryfq_np {
21824 + u8 __reserved1;
21825 + u8 state; /* QM_MCR_NP_STATE_*** */
21826 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21827 + u8 __reserved2;
21828 + u32 fqd_link:24;
21829 + u16 __reserved3:2;
21830 + u16 odp_seq:14;
21831 + u16 __reserved4:2;
21832 + u16 orp_nesn:14;
21833 + u16 __reserved5:1;
21834 + u16 orp_ea_hseq:15;
21835 + u16 __reserved6:1;
21836 + u16 orp_ea_tseq:15;
21837 + u8 __reserved7;
21838 + u32 orp_ea_hptr:24;
21839 + u8 __reserved8;
21840 + u32 orp_ea_tptr:24;
21841 + u8 __reserved9;
21842 + u32 pfdr_hptr:24;
21843 + u8 __reserved10;
21844 + u32 pfdr_tptr:24;
21845 + u8 __reserved11[5];
21846 + u8 __reserved12:7;
21847 + u8 is:1;
21848 + u16 ics_surp;
21849 + u32 byte_cnt;
21850 + u8 __reserved13;
21851 + u32 frm_cnt:24;
21852 + u32 __reserved14;
21853 + u16 ra1_sfdr; /* QM_MCR_NP_RA1_*** */
21854 + u16 ra2_sfdr; /* QM_MCR_NP_RA2_*** */
21855 + u16 __reserved15;
21856 + u16 od1_sfdr; /* QM_MCR_NP_OD1_*** */
21857 + u16 od2_sfdr; /* QM_MCR_NP_OD2_*** */
21858 + u16 od3_sfdr; /* QM_MCR_NP_OD3_*** */
21859 +#else
21860 + u8 __reserved2;
21861 + u32 fqd_link:24;
21862 +
21863 + u16 odp_seq:14;
21864 + u16 __reserved3:2;
21865 +
21866 + u16 orp_nesn:14;
21867 + u16 __reserved4:2;
21868 +
21869 + u16 orp_ea_hseq:15;
21870 + u16 __reserved5:1;
21871 +
21872 + u16 orp_ea_tseq:15;
21873 + u16 __reserved6:1;
21874 +
21875 + u8 __reserved7;
21876 + u32 orp_ea_hptr:24;
21877 +
21878 + u8 __reserved8;
21879 + u32 orp_ea_tptr:24;
21880 +
21881 + u8 __reserved9;
21882 + u32 pfdr_hptr:24;
21883 +
21884 + u8 __reserved10;
21885 + u32 pfdr_tptr:24;
21886 +
21887 + u8 __reserved11[5];
21888 + u8 is:1;
21889 + u8 __reserved12:7;
21890 + u16 ics_surp;
21891 + u32 byte_cnt;
21892 + u8 __reserved13;
21893 + u32 frm_cnt:24;
21894 + u32 __reserved14;
21895 + u16 ra1_sfdr; /* QM_MCR_NP_RA1_*** */
21896 + u16 ra2_sfdr; /* QM_MCR_NP_RA2_*** */
21897 + u16 __reserved15;
21898 + u16 od1_sfdr; /* QM_MCR_NP_OD1_*** */
21899 + u16 od2_sfdr; /* QM_MCR_NP_OD2_*** */
21900 + u16 od3_sfdr; /* QM_MCR_NP_OD3_*** */
21901 +#endif
21902 +} __packed;
21903 +
21904 +
21905 +struct qm_mcr_alterfq {
21906 + u8 fqs; /* Frame Queue Status */
21907 + u8 __reserved1[61];
21908 +} __packed;
21909 +struct qm_mcr_initcgr {
21910 + u8 __reserved1[62];
21911 +} __packed;
21912 +struct qm_mcr_cgrtestwrite {
21913 + u16 __reserved1;
21914 + struct __qm_mc_cgr cgr; /* CGR fields */
21915 + u8 __reserved2[3];
21916 + u32 __reserved3:24;
21917 + u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
21918 + u32 i_bcnt_lo; /* low 32-bits of 40-bit */
21919 + u32 __reserved4:24;
21920 + u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */
21921 + u32 a_bcnt_lo; /* low 32-bits of 40-bit */
21922 + u16 lgt; /* Last Group Tick */
21923 + u16 wr_prob_g;
21924 + u16 wr_prob_y;
21925 + u16 wr_prob_r;
21926 + u8 __reserved5[8];
21927 +} __packed;
21928 +struct qm_mcr_querycgr {
21929 + u16 __reserved1;
21930 + struct __qm_mc_cgr cgr; /* CGR fields */
21931 + u8 __reserved2[3];
21932 + union {
21933 + struct {
21934 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21935 + u32 __reserved3:24;
21936 + u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
21937 + u32 i_bcnt_lo; /* low 32-bits of 40-bit */
21938 +#else
21939 + u32 i_bcnt_lo; /* low 32-bits of 40-bit */
21940 + u32 i_bcnt_hi:8;/* high 8-bits of 40-bit "Instant" */
21941 + u32 __reserved3:24;
21942 +#endif
21943 + };
21944 + u64 i_bcnt;
21945 + };
21946 + union {
21947 + struct {
21948 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21949 + u32 __reserved4:24;
21950 + u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */
21951 + u32 a_bcnt_lo; /* low 32-bits of 40-bit */
21952 +#else
21953 + u32 a_bcnt_lo; /* low 32-bits of 40-bit */
21954 + u32 a_bcnt_hi:8;/* high 8-bits of 40-bit "Average" */
21955 + u32 __reserved4:24;
21956 +#endif
21957 + };
21958 + u64 a_bcnt;
21959 + };
21960 + union {
21961 + u32 cscn_targ_swp[4];
21962 + u8 __reserved5[16];
21963 + };
21964 +} __packed;
21965 +static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q)
21966 +{
21967 + return be64_to_cpu(q->i_bcnt);
21968 +}
21969 +static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q)
21970 +{
21971 + return be64_to_cpu(q->a_bcnt);
21972 +}
21973 +static inline u64 qm_mcr_cgrtestwrite_i_get64(
21974 + const struct qm_mcr_cgrtestwrite *q)
21975 +{
21976 + return be64_to_cpu(((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo);
21977 +}
21978 +static inline u64 qm_mcr_cgrtestwrite_a_get64(
21979 + const struct qm_mcr_cgrtestwrite *q)
21980 +{
21981 + return be64_to_cpu(((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo);
21982 +}
21983 +/* Macro, so we compile better if 'v' isn't always 64-bit */
21984 +#define qm_mcr_querycgr_i_set64(q, v) \
21985 + do { \
21986 + struct qm_mcr_querycgr *__q931 = (fd); \
21987 + __q931->i_bcnt_hi = upper_32_bits(v); \
21988 + __q931->i_bcnt_lo = lower_32_bits(v); \
21989 + } while (0)
21990 +#define qm_mcr_querycgr_a_set64(q, v) \
21991 + do { \
21992 + struct qm_mcr_querycgr *__q931 = (fd); \
21993 + __q931->a_bcnt_hi = upper_32_bits(v); \
21994 + __q931->a_bcnt_lo = lower_32_bits(v); \
21995 + } while (0)
21996 +struct __qm_mcr_querycongestion {
21997 + u32 __state[8];
21998 +};
21999 +struct qm_mcr_querycongestion {
22000 + u8 __reserved[30];
22001 + /* Access this struct using QM_MCR_QUERYCONGESTION() */
22002 + struct __qm_mcr_querycongestion state;
22003 +} __packed;
22004 +struct qm_mcr_querywq {
22005 + union {
22006 + u16 channel_wq; /* ignores wq (3 lsbits) */
22007 + struct {
22008 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
22009 + u16 id:13; /* qm_channel */
22010 + u16 __reserved:3;
22011 +#else
22012 + u16 __reserved:3;
22013 + u16 id:13; /* qm_channel */
22014 +#endif
22015 + } __packed channel;
22016 + };
22017 + u8 __reserved[28];
22018 + u32 wq_len[8];
22019 +} __packed;
22020 +
22021 +/* QMAN CEETM Management Command Response */
22022 +struct qm_mcr_ceetm_lfqmt_config {
22023 + u8 __reserved1[62];
22024 +} __packed;
22025 +struct qm_mcr_ceetm_lfqmt_query {
22026 + u8 __reserved1[8];
22027 + u16 cqid;
22028 + u8 __reserved2[2];
22029 + u16 dctidx;
22030 + u8 __reserved3[2];
22031 + u16 ccgid;
22032 + u8 __reserved4[44];
22033 +} __packed;
22034 +
22035 +struct qm_mcr_ceetm_cq_config {
22036 + u8 __reserved1[62];
22037 +} __packed;
22038 +
22039 +struct qm_mcr_ceetm_cq_query {
22040 + u8 __reserved1[4];
22041 + u16 ccgid;
22042 + u16 state;
22043 + u32 pfdr_hptr:24;
22044 + u32 pfdr_tptr:24;
22045 + u16 od1_xsfdr;
22046 + u16 od2_xsfdr;
22047 + u16 od3_xsfdr;
22048 + u16 od4_xsfdr;
22049 + u16 od5_xsfdr;
22050 + u16 od6_xsfdr;
22051 + u16 ra1_xsfdr;
22052 + u16 ra2_xsfdr;
22053 + u8 __reserved2;
22054 + u32 frm_cnt:24;
22055 + u8 __reserved333[28];
22056 +} __packed;
22057 +
22058 +struct qm_mcr_ceetm_dct_config {
22059 + u8 __reserved1[62];
22060 +} __packed;
22061 +
22062 +struct qm_mcr_ceetm_dct_query {
22063 + u8 __reserved1[18];
22064 + u32 context_b;
22065 + u64 context_a;
22066 + u8 __reserved2[32];
22067 +} __packed;
22068 +
22069 +struct qm_mcr_ceetm_class_scheduler_config {
22070 + u8 __reserved1[62];
22071 +} __packed;
22072 +
22073 +struct qm_mcr_ceetm_class_scheduler_query {
22074 + u8 __reserved1[9];
22075 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
22076 + u8 gpc_reserved:1;
22077 + u8 gpc_combine_flag:1;
22078 + u8 gpc_prio_b:3;
22079 + u8 gpc_prio_a:3;
22080 +#else
22081 + u8 gpc_prio_a:3;
22082 + u8 gpc_prio_b:3;
22083 + u8 gpc_combine_flag:1;
22084 + u8 gpc_reserved:1;
22085 +#endif
22086 + u16 crem;
22087 + u16 erem;
22088 + u8 w[8];
22089 + u8 __reserved2[5];
22090 + u32 wbfslist:24;
22091 + u32 d8;
22092 + u32 d9;
22093 + u32 d10;
22094 + u32 d11;
22095 + u32 d12;
22096 + u32 d13;
22097 + u32 d14;
22098 + u32 d15;
22099 +} __packed;
22100 +
22101 +struct qm_mcr_ceetm_mapping_shaper_tcfc_config {
22102 + u16 cid;
22103 + u8 __reserved2[60];
22104 +} __packed;
22105 +
22106 +struct qm_mcr_ceetm_mapping_shaper_tcfc_query {
22107 + u16 cid;
22108 + u8 __reserved1;
22109 + union {
22110 + struct {
22111 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
22112 + u8 map_shaped:1;
22113 + u8 map_reserved:4;
22114 + u8 map_lni_id:3;
22115 +#else
22116 + u8 map_lni_id:3;
22117 + u8 map_reserved:4;
22118 + u8 map_shaped:1;
22119 +#endif
22120 + u8 __reserved2[58];
22121 + } __packed channel_mapping_query;
22122 + struct {
22123 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
22124 + u8 map_reserved:5;
22125 + u8 map_lni_id:3;
22126 +#else
22127 + u8 map_lni_id:3;
22128 + u8 map_reserved:5;
22129 +#endif
22130 + u8 __reserved2[58];
22131 + } __packed sp_mapping_query;
22132 + struct {
22133 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
22134 + u8 cpl:1;
22135 + u8 cpl_reserved:2;
22136 + u8 oal:5;
22137 +#else
22138 + u8 oal:5;
22139 + u8 cpl_reserved:2;
22140 + u8 cpl:1;
22141 +#endif
22142 + u32 crtcr:24;
22143 + u32 ertcr:24;
22144 + u16 crtbl;
22145 + u16 ertbl;
22146 + u8 mps;
22147 + u8 __reserved2[15];
22148 + u32 crat;
22149 + u32 erat;
22150 + u8 __reserved3[24];
22151 + } __packed shaper_query;
22152 + struct {
22153 + u8 __reserved1[11];
22154 + u64 lnitcfcc;
22155 + u8 __reserved3[40];
22156 + } __packed tcfc_query;
22157 + };
22158 +} __packed;
22159 +
22160 +struct qm_mcr_ceetm_ccgr_config {
22161 + u8 __reserved1[46];
22162 + union {
22163 + u8 __reserved2[8];
22164 + struct {
22165 + u16 timestamp;
22166 + u16 wr_porb_g;
22167 + u16 wr_prob_y;
22168 + u16 wr_prob_r;
22169 + } __packed test_write;
22170 + };
22171 + u8 __reserved3[8];
22172 +} __packed;
22173 +
22174 +struct qm_mcr_ceetm_ccgr_query {
22175 + u8 __reserved1[6];
22176 + union {
22177 + struct {
22178 +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
22179 + u8 ctl_reserved:1;
22180 + u8 ctl_wr_en_g:1;
22181 + u8 ctl_wr_en_y:1;
22182 + u8 ctl_wr_en_r:1;
22183 + u8 ctl_td_en:1;
22184 + u8 ctl_td_mode:1;
22185 + u8 ctl_cscn_en:1;
22186 + u8 ctl_mode:1;
22187 +#else
22188 + u8 ctl_mode:1;
22189 + u8 ctl_cscn_en:1;
22190 + u8 ctl_td_mode:1;
22191 + u8 ctl_td_en:1;
22192 + u8 ctl_wr_en_r:1;
22193 + u8 ctl_wr_en_y:1;
22194 + u8 ctl_wr_en_g:1;
22195 + u8 ctl_reserved:1;
22196 +#endif
22197 + u8 cdv;
22198 + u8 __reserved2[2];
22199 + u8 oal;
22200 + u8 __reserved3;
22201 + struct qm_cgr_cs_thres cs_thres;
22202 + struct qm_cgr_cs_thres cs_thres_x;
22203 + struct qm_cgr_cs_thres td_thres;
22204 + struct qm_cgr_wr_parm wr_parm_g;
22205 + struct qm_cgr_wr_parm wr_parm_y;
22206 + struct qm_cgr_wr_parm wr_parm_r;
22207 + u16 cscn_targ_dcp;
22208 + u8 dcp_lsn;
22209 + u64 i_cnt:40;
22210 + u8 __reserved4[3];
22211 + u64 a_cnt:40;
22212 + u32 cscn_targ_swp[4];
22213 + } __packed cm_query;
22214 + struct {
22215 + u8 dnc;
22216 + u8 dn0;
22217 + u8 dn1;
22218 + u64 dnba:40;
22219 + u8 __reserved2[2];
22220 + u16 dnth_0;
22221 + u8 __reserved3[2];
22222 + u16 dnth_1;
22223 + u8 __reserved4[10];
22224 + u16 dnacc_0;
22225 + u8 __reserved5[2];
22226 + u16 dnacc_1;
22227 + u8 __reserved6[24];
22228 + } __packed dn_query;
22229 + struct {
22230 + u8 __reserved2[24];
22231 + struct __qm_mcr_querycongestion state;
22232 + } __packed congestion_state;
22233 +
22234 + };
22235 +} __packed;
22236 +
22237 +struct qm_mcr_ceetm_cq_peek_pop_xsfdrread {
22238 + u8 stat;
22239 + u8 __reserved1[11];
22240 + u16 dctidx;
22241 + struct qm_fd fd;
22242 + u8 __reserved2[32];
22243 +} __packed;
22244 +
22245 +struct qm_mcr_ceetm_statistics_query {
22246 + u8 __reserved1[17];
22247 + u64 frm_cnt:40;
22248 + u8 __reserved2[2];
22249 + u64 byte_cnt:48;
22250 + u8 __reserved3[32];
22251 +} __packed;
22252 +
22253 +struct qm_mc_result {
22254 + u8 verb;
22255 + u8 result;
22256 + union {
22257 + struct qm_mcr_initfq initfq;
22258 + struct qm_mcr_queryfq queryfq;
22259 + struct qm_mcr_queryfq_np queryfq_np;
22260 + struct qm_mcr_alterfq alterfq;
22261 + struct qm_mcr_initcgr initcgr;
22262 + struct qm_mcr_cgrtestwrite cgrtestwrite;
22263 + struct qm_mcr_querycgr querycgr;
22264 + struct qm_mcr_querycongestion querycongestion;
22265 + struct qm_mcr_querywq querywq;
22266 + struct qm_mcr_ceetm_lfqmt_config lfqmt_config;
22267 + struct qm_mcr_ceetm_lfqmt_query lfqmt_query;
22268 + struct qm_mcr_ceetm_cq_config cq_config;
22269 + struct qm_mcr_ceetm_cq_query cq_query;
22270 + struct qm_mcr_ceetm_dct_config dct_config;
22271 + struct qm_mcr_ceetm_dct_query dct_query;
22272 + struct qm_mcr_ceetm_class_scheduler_config csch_config;
22273 + struct qm_mcr_ceetm_class_scheduler_query csch_query;
22274 + struct qm_mcr_ceetm_mapping_shaper_tcfc_config mst_config;
22275 + struct qm_mcr_ceetm_mapping_shaper_tcfc_query mst_query;
22276 + struct qm_mcr_ceetm_ccgr_config ccgr_config;
22277 + struct qm_mcr_ceetm_ccgr_query ccgr_query;
22278 + struct qm_mcr_ceetm_cq_peek_pop_xsfdrread cq_ppxr;
22279 + struct qm_mcr_ceetm_statistics_query stats_query;
22280 + };
22281 +} __packed;
22282 +
22283 +#define QM_MCR_VERB_RRID 0x80
22284 +#define QM_MCR_VERB_MASK QM_MCC_VERB_MASK
22285 +#define QM_MCR_VERB_INITFQ_PARKED QM_MCC_VERB_INITFQ_PARKED
22286 +#define QM_MCR_VERB_INITFQ_SCHED QM_MCC_VERB_INITFQ_SCHED
22287 +#define QM_MCR_VERB_QUERYFQ QM_MCC_VERB_QUERYFQ
22288 +#define QM_MCR_VERB_QUERYFQ_NP QM_MCC_VERB_QUERYFQ_NP
22289 +#define QM_MCR_VERB_QUERYWQ QM_MCC_VERB_QUERYWQ
22290 +#define QM_MCR_VERB_QUERYWQ_DEDICATED QM_MCC_VERB_QUERYWQ_DEDICATED
22291 +#define QM_MCR_VERB_ALTER_SCHED QM_MCC_VERB_ALTER_SCHED
22292 +#define QM_MCR_VERB_ALTER_FE QM_MCC_VERB_ALTER_FE
22293 +#define QM_MCR_VERB_ALTER_RETIRE QM_MCC_VERB_ALTER_RETIRE
22294 +#define QM_MCR_VERB_ALTER_OOS QM_MCC_VERB_ALTER_OOS
22295 +#define QM_MCR_RESULT_NULL 0x00
22296 +#define QM_MCR_RESULT_OK 0xf0
22297 +#define QM_MCR_RESULT_ERR_FQID 0xf1
22298 +#define QM_MCR_RESULT_ERR_FQSTATE 0xf2
22299 +#define QM_MCR_RESULT_ERR_NOTEMPTY 0xf3 /* OOS fails if FQ is !empty */
22300 +#define QM_MCR_RESULT_ERR_BADCHANNEL 0xf4
22301 +#define QM_MCR_RESULT_PENDING 0xf8
22302 +#define QM_MCR_RESULT_ERR_BADCOMMAND 0xff
22303 +#define QM_MCR_NP_STATE_FE 0x10
22304 +#define QM_MCR_NP_STATE_R 0x08
22305 +#define QM_MCR_NP_STATE_MASK 0x07 /* Reads FQD::STATE; */
22306 +#define QM_MCR_NP_STATE_OOS 0x00
22307 +#define QM_MCR_NP_STATE_RETIRED 0x01
22308 +#define QM_MCR_NP_STATE_TEN_SCHED 0x02
22309 +#define QM_MCR_NP_STATE_TRU_SCHED 0x03
22310 +#define QM_MCR_NP_STATE_PARKED 0x04
22311 +#define QM_MCR_NP_STATE_ACTIVE 0x05
22312 +#define QM_MCR_NP_PTR_MASK 0x07ff /* for RA[12] & OD[123] */
22313 +#define QM_MCR_NP_RA1_NRA(v) (((v) >> 14) & 0x3) /* FQD::NRA */
22314 +#define QM_MCR_NP_RA2_IT(v) (((v) >> 14) & 0x1) /* FQD::IT */
22315 +#define QM_MCR_NP_OD1_NOD(v) (((v) >> 14) & 0x3) /* FQD::NOD */
22316 +#define QM_MCR_NP_OD3_NPC(v) (((v) >> 14) & 0x3) /* FQD::NPC */
22317 +#define QM_MCR_FQS_ORLPRESENT 0x02 /* ORL fragments to come */
22318 +#define QM_MCR_FQS_NOTEMPTY 0x01 /* FQ has enqueued frames */
22319 +/* This extracts the state for congestion group 'n' from a query response.
22320 + * Eg.
22321 + * u8 cgr = [...];
22322 + * struct qm_mc_result *res = [...];
22323 + * printf("congestion group %d congestion state: %d\n", cgr,
22324 + * QM_MCR_QUERYCONGESTION(&res->querycongestion.state, cgr));
22325 + */
22326 +#define __CGR_WORD(num) (num >> 5)
22327 +#define __CGR_SHIFT(num) (num & 0x1f)
22328 +#define __CGR_NUM (sizeof(struct __qm_mcr_querycongestion) << 3)
22329 +static inline int QM_MCR_QUERYCONGESTION(struct __qm_mcr_querycongestion *p,
22330 + u8 cgr)
22331 +{
22332 + return be32_to_cpu(p->__state[__CGR_WORD(cgr)]) &
22333 + (0x80000000 >> __CGR_SHIFT(cgr));
22334 +}
22335 +
22336 +
22337 +/*********************/
22338 +/* Utility interface */
22339 +/*********************/
22340 +
22341 +/* Represents an allocator over a range of FQIDs. NB, accesses are not locked,
22342 + * spinlock them yourself if needed. */
22343 +struct qman_fqid_pool;
22344 +
22345 +/* Create/destroy a FQID pool, num must be a multiple of 32. NB, _destroy()
22346 + * always succeeds, but returns non-zero if there were "leaked" FQID
22347 + * allocations. */
22348 +struct qman_fqid_pool *qman_fqid_pool_create(u32 fqid_start, u32 num);
22349 +int qman_fqid_pool_destroy(struct qman_fqid_pool *pool);
22350 +/* Alloc/free a FQID from the range. _alloc() returns zero for success. */
22351 +int qman_fqid_pool_alloc(struct qman_fqid_pool *pool, u32 *fqid);
22352 +void qman_fqid_pool_free(struct qman_fqid_pool *pool, u32 fqid);
22353 +u32 qman_fqid_pool_used(struct qman_fqid_pool *pool);
22354 +
22355 +/*******************************************************************/
22356 +/* Managed (aka "shared" or "mux/demux") portal, high-level i/face */
22357 +/*******************************************************************/
22358 +
22359 + /* Portal and Frame Queues */
22360 + /* ----------------------- */
22361 +/* Represents a managed portal */
22362 +struct qman_portal;
22363 +
22364 +/* This object type represents Qman frame queue descriptors (FQD), it is
22365 + * cacheline-aligned, and initialised by qman_create_fq(). The structure is
22366 + * defined further down. */
22367 +struct qman_fq;
22368 +
22369 +/* This object type represents a Qman congestion group, it is defined further
22370 + * down. */
22371 +struct qman_cgr;
22372 +
22373 +struct qman_portal_config {
22374 + /* If the caller enables DQRR stashing (and thus wishes to operate the
22375 + * portal from only one cpu), this is the logical CPU that the portal
22376 + * will stash to. Whether stashing is enabled or not, this setting is
22377 + * also used for any "core-affine" portals, ie. default portals
22378 + * associated to the corresponding cpu. -1 implies that there is no core
22379 + * affinity configured. */
22380 + int cpu;
22381 + /* portal interrupt line */
22382 + int irq;
22383 + /* the unique index of this portal */
22384 + u32 index;
22385 + /* Is this portal shared? (If so, it has coarser locking and demuxes
22386 + * processing on behalf of other CPUs.) */
22387 + int is_shared;
22388 + /* The portal's dedicated channel id, use this value for initialising
22389 + * frame queues to target this portal when scheduled. */
22390 + u16 channel;
22391 + /* A mask of which pool channels this portal has dequeue access to
22392 + * (using QM_SDQCR_CHANNELS_POOL(n) for the bitmask) */
22393 + u32 pools;
22394 +};
22395 +
22396 +/* This enum, and the callback type that returns it, are used when handling
22397 + * dequeued frames via DQRR. Note that for "null" callbacks registered with the
22398 + * portal object (for handling dequeues that do not demux because contextB is
22399 + * NULL), the return value *MUST* be qman_cb_dqrr_consume. */
22400 +enum qman_cb_dqrr_result {
22401 + /* DQRR entry can be consumed */
22402 + qman_cb_dqrr_consume,
22403 + /* Like _consume, but requests parking - FQ must be held-active */
22404 + qman_cb_dqrr_park,
22405 + /* Does not consume, for DCA mode only. This allows out-of-order
22406 + * consumes by explicit calls to qman_dca() and/or the use of implicit
22407 + * DCA via EQCR entries. */
22408 + qman_cb_dqrr_defer,
22409 + /* Stop processing without consuming this ring entry. Exits the current
22410 + * qman_poll_dqrr() or interrupt-handling, as appropriate. If within an
22411 + * interrupt handler, the callback would typically call
22412 + * qman_irqsource_remove(QM_PIRQ_DQRI) before returning this value,
22413 + * otherwise the interrupt will reassert immediately. */
22414 + qman_cb_dqrr_stop,
22415 + /* Like qman_cb_dqrr_stop, but consumes the current entry. */
22416 + qman_cb_dqrr_consume_stop
22417 +};
22418 +typedef enum qman_cb_dqrr_result (*qman_cb_dqrr)(struct qman_portal *qm,
22419 + struct qman_fq *fq,
22420 + const struct qm_dqrr_entry *dqrr);
22421 +
22422 +/* This callback type is used when handling ERNs, FQRNs and FQRLs via MR. They
22423 + * are always consumed after the callback returns. */
22424 +typedef void (*qman_cb_mr)(struct qman_portal *qm, struct qman_fq *fq,
22425 + const struct qm_mr_entry *msg);
22426 +
22427 +/* This callback type is used when handling DCP ERNs */
22428 +typedef void (*qman_cb_dc_ern)(struct qman_portal *qm,
22429 + const struct qm_mr_entry *msg);
22430 +
22431 +/* s/w-visible states. Ie. tentatively scheduled + truly scheduled + active +
22432 + * held-active + held-suspended are just "sched". Things like "retired" will not
22433 + * be assumed until it is complete (ie. QMAN_FQ_STATE_CHANGING is set until
22434 + * then, to indicate it's completing and to gate attempts to retry the retire
22435 + * command). Note, park commands do not set QMAN_FQ_STATE_CHANGING because it's
22436 + * technically impossible in the case of enqueue DCAs (which refer to DQRR ring
22437 + * index rather than the FQ that ring entry corresponds to), so repeated park
22438 + * commands are allowed (if you're silly enough to try) but won't change FQ
22439 + * state, and the resulting park notifications move FQs from "sched" to
22440 + * "parked". */
22441 +enum qman_fq_state {
22442 + qman_fq_state_oos,
22443 + qman_fq_state_parked,
22444 + qman_fq_state_sched,
22445 + qman_fq_state_retired
22446 +};
22447 +
22448 +/* Frame queue objects (struct qman_fq) are stored within memory passed to
22449 + * qman_create_fq(), as this allows stashing of caller-provided demux callback
22450 + * pointers at no extra cost to stashing of (driver-internal) FQ state. If the
22451 + * caller wishes to add per-FQ state and have it benefit from dequeue-stashing,
22452 + * they should;
22453 + *
22454 + * (a) extend the qman_fq structure with their state; eg.
22455 + *
22456 + * // myfq is allocated and driver_fq callbacks filled in;
22457 + * struct my_fq {
22458 + * struct qman_fq base;
22459 + * int an_extra_field;
22460 + * [ ... add other fields to be associated with each FQ ...]
22461 + * } *myfq = some_my_fq_allocator();
22462 + * struct qman_fq *fq = qman_create_fq(fqid, flags, &myfq->base);
22463 + *
22464 + * // in a dequeue callback, access extra fields from 'fq' via a cast;
22465 + * struct my_fq *myfq = (struct my_fq *)fq;
22466 + * do_something_with(myfq->an_extra_field);
22467 + * [...]
22468 + *
22469 + * (b) when and if configuring the FQ for context stashing, specify how ever
22470 + * many cachelines are required to stash 'struct my_fq', to accelerate not
22471 + * only the Qman driver but the callback as well.
22472 + */
22473 +
22474 +struct qman_fq_cb {
22475 + qman_cb_dqrr dqrr; /* for dequeued frames */
22476 + qman_cb_mr ern; /* for s/w ERNs */
22477 + qman_cb_mr fqs; /* frame-queue state changes*/
22478 +};
22479 +
22480 +struct qman_fq {
22481 + /* Caller of qman_create_fq() provides these demux callbacks */
22482 + struct qman_fq_cb cb;
22483 + /* These are internal to the driver, don't touch. In particular, they
22484 + * may change, be removed, or extended (so you shouldn't rely on
22485 + * sizeof(qman_fq) being a constant). */
22486 + spinlock_t fqlock;
22487 + u32 fqid;
22488 + volatile unsigned long flags;
22489 + enum qman_fq_state state;
22490 + int cgr_groupid;
22491 + struct rb_node node;
22492 +#ifdef CONFIG_FSL_QMAN_FQ_LOOKUP
22493 + u32 key;
22494 +#endif
22495 +};
22496 +
22497 +/* This callback type is used when handling congestion group entry/exit.
22498 + * 'congested' is non-zero on congestion-entry, and zero on congestion-exit. */
22499 +typedef void (*qman_cb_cgr)(struct qman_portal *qm,
22500 + struct qman_cgr *cgr, int congested);
22501 +
22502 +struct qman_cgr {
22503 + /* Set these prior to qman_create_cgr() */
22504 + u32 cgrid; /* 0..255, but u32 to allow specials like -1, 256, etc.*/
22505 + qman_cb_cgr cb;
22506 + /* These are private to the driver */
22507 + u16 chan; /* portal channel this object is created on */
22508 + struct list_head node;
22509 +};
22510 +
22511 +/* Flags to qman_create_fq() */
22512 +#define QMAN_FQ_FLAG_NO_ENQUEUE 0x00000001 /* can't enqueue */
22513 +#define QMAN_FQ_FLAG_NO_MODIFY 0x00000002 /* can only enqueue */
22514 +#define QMAN_FQ_FLAG_TO_DCPORTAL 0x00000004 /* consumed by CAAM/PME/Fman */
22515 +#define QMAN_FQ_FLAG_LOCKED 0x00000008 /* multi-core locking */
22516 +#define QMAN_FQ_FLAG_AS_IS 0x00000010 /* query h/w state */
22517 +#define QMAN_FQ_FLAG_DYNAMIC_FQID 0x00000020 /* (de)allocate fqid */
22518 +
22519 +/* Flags to qman_destroy_fq() */
22520 +#define QMAN_FQ_DESTROY_PARKED 0x00000001 /* FQ can be parked or OOS */
22521 +
22522 +/* Flags from qman_fq_state() */
22523 +#define QMAN_FQ_STATE_CHANGING 0x80000000 /* 'state' is changing */
22524 +#define QMAN_FQ_STATE_NE 0x40000000 /* retired FQ isn't empty */
22525 +#define QMAN_FQ_STATE_ORL 0x20000000 /* retired FQ has ORL */
22526 +#define QMAN_FQ_STATE_BLOCKOOS 0xe0000000 /* if any are set, no OOS */
22527 +#define QMAN_FQ_STATE_CGR_EN 0x10000000 /* CGR enabled */
22528 +#define QMAN_FQ_STATE_VDQCR 0x08000000 /* being volatile dequeued */
22529 +
22530 +/* Flags to qman_init_fq() */
22531 +#define QMAN_INITFQ_FLAG_SCHED 0x00000001 /* schedule rather than park */
22532 +#define QMAN_INITFQ_FLAG_LOCAL 0x00000004 /* set dest portal */
22533 +
22534 +/* Flags to qman_volatile_dequeue() */
22535 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
22536 +#define QMAN_VOLATILE_FLAG_WAIT 0x00000001 /* wait if VDQCR is in use */
22537 +#define QMAN_VOLATILE_FLAG_WAIT_INT 0x00000002 /* if wait, interruptible? */
22538 +#define QMAN_VOLATILE_FLAG_FINISH 0x00000004 /* wait till VDQCR completes */
22539 +#endif
22540 +
22541 +/* Flags to qman_enqueue(). NB, the strange numbering is to align with hardware,
22542 + * bit-wise. (NB: the PME API is sensitive to these precise numberings too, so
22543 + * any change here should be audited in PME.) */
22544 +#ifdef CONFIG_FSL_DPA_CAN_WAIT
22545 +#define QMAN_ENQUEUE_FLAG_WAIT 0x00010000 /* wait if EQCR is full */
22546 +#define QMAN_ENQUEUE_FLAG_WAIT_INT 0x00020000 /* if wait, interruptible? */
22547 +#ifdef CONFIG_FSL_DPA_CAN_WAIT_SYNC
22548 +#define QMAN_ENQUEUE_FLAG_WAIT_SYNC 0x00000004 /* if wait, until consumed? */
22549 +#endif
22550 +#endif
22551 +#define QMAN_ENQUEUE_FLAG_WATCH_CGR 0x00080000 /* watch congestion state */
22552 +#define QMAN_ENQUEUE_FLAG_DCA 0x00008000 /* perform enqueue-DCA */
22553 +#define QMAN_ENQUEUE_FLAG_DCA_PARK 0x00004000 /* If DCA, requests park */
22554 +#define QMAN_ENQUEUE_FLAG_DCA_PTR(p) /* If DCA, p is DQRR entry */ \
22555 + (((u32)(p) << 2) & 0x00000f00)
22556 +#define QMAN_ENQUEUE_FLAG_C_GREEN 0x00000000 /* choose one C_*** flag */
22557 +#define QMAN_ENQUEUE_FLAG_C_YELLOW 0x00000008
22558 +#define QMAN_ENQUEUE_FLAG_C_RED 0x00000010
22559 +#define QMAN_ENQUEUE_FLAG_C_OVERRIDE 0x00000018
22560 +/* For the ORP-specific qman_enqueue_orp() variant;
22561 + * - this flag indicates "Not Last In Sequence", ie. all but the final fragment
22562 + * of a frame. */
22563 +#define QMAN_ENQUEUE_FLAG_NLIS 0x01000000
22564 +/* - this flag performs no enqueue but fills in an ORP sequence number that
22565 + * would otherwise block it (eg. if a frame has been dropped). */
22566 +#define QMAN_ENQUEUE_FLAG_HOLE 0x02000000
22567 +/* - this flag performs no enqueue but advances NESN to the given sequence
22568 + * number. */
22569 +#define QMAN_ENQUEUE_FLAG_NESN 0x04000000
22570 +
22571 +/* Flags to qman_modify_cgr() */
22572 +#define QMAN_CGR_FLAG_USE_INIT 0x00000001
22573 +#define QMAN_CGR_MODE_FRAME 0x00000001
22574 +
22575 + /* Portal Management */
22576 + /* ----------------- */
22577 +/**
22578 + * qman_get_portal_config - get portal configuration settings
22579 + *
22580 + * This returns a read-only view of the current cpu's affine portal settings.
22581 + */
22582 +const struct qman_portal_config *qman_get_portal_config(void);
22583 +
22584 +/**
22585 + * qman_irqsource_get - return the portal work that is interrupt-driven
22586 + *
22587 + * Returns a bitmask of QM_PIRQ_**I processing sources that are currently
22588 + * enabled for interrupt handling on the current cpu's affine portal. These
22589 + * sources will trigger the portal interrupt and the interrupt handler (or a
22590 + * tasklet/bottom-half it defers to) will perform the corresponding processing
22591 + * work. The qman_poll_***() functions will only process sources that are not in
22592 + * this bitmask. If the current CPU is sharing a portal hosted on another CPU,
22593 + * this always returns zero.
22594 + */
22595 +u32 qman_irqsource_get(void);
22596 +
22597 +/**
22598 + * qman_irqsource_add - add processing sources to be interrupt-driven
22599 + * @bits: bitmask of QM_PIRQ_**I processing sources
22600 + *
22601 + * Adds processing sources that should be interrupt-driven (rather than
22602 + * processed via qman_poll_***() functions). Returns zero for success, or
22603 + * -EINVAL if the current CPU is sharing a portal hosted on another CPU.
22604 + */
22605 +int qman_irqsource_add(u32 bits);
22606 +
22607 +/**
22608 + * qman_irqsource_remove - remove processing sources from being interrupt-driven
22609 + * @bits: bitmask of QM_PIRQ_**I processing sources
22610 + *
22611 + * Removes processing sources from being interrupt-driven, so that they will
22612 + * instead be processed via qman_poll_***() functions. Returns zero for success,
22613 + * or -EINVAL if the current CPU is sharing a portal hosted on another CPU.
22614 + */
22615 +int qman_irqsource_remove(u32 bits);
22616 +
22617 +/**
22618 + * qman_affine_cpus - return a mask of cpus that have affine portals
22619 + */
22620 +const cpumask_t *qman_affine_cpus(void);
22621 +
22622 +/**
22623 + * qman_affine_channel - return the channel ID of an portal
22624 + * @cpu: the cpu whose affine portal is the subject of the query
22625 + *
22626 + * If @cpu is -1, the affine portal for the current CPU will be used. It is a
22627 + * bug to call this function for any value of @cpu (other than -1) that is not a
22628 + * member of the mask returned from qman_affine_cpus().
22629 + */
22630 +u16 qman_affine_channel(int cpu);
22631 +
22632 +/**
22633 + * qman_get_affine_portal - return the portal pointer affine to cpu
22634 + * @cpu: the cpu whose affine portal is the subject of the query
22635 + *
22636 + */
22637 +void *qman_get_affine_portal(int cpu);
22638 +
22639 +/**
22640 + * qman_poll_dqrr - process DQRR (fast-path) entries
22641 + * @limit: the maximum number of DQRR entries to process
22642 + *
22643 + * Use of this function requires that DQRR processing not be interrupt-driven.
22644 + * Ie. the value returned by qman_irqsource_get() should not include
22645 + * QM_PIRQ_DQRI. If the current CPU is sharing a portal hosted on another CPU,
22646 + * this function will return -EINVAL, otherwise the return value is >=0 and
22647 + * represents the number of DQRR entries processed.
22648 + */
22649 +int qman_poll_dqrr(unsigned int limit);
22650 +
22651 +/**
22652 + * qman_poll_slow - process anything (except DQRR) that isn't interrupt-driven.
22653 + *
22654 + * This function does any portal processing that isn't interrupt-driven. If the
22655 + * current CPU is sharing a portal hosted on another CPU, this function will
22656 + * return (u32)-1, otherwise the return value is a bitmask of QM_PIRQ_* sources
22657 + * indicating what interrupt sources were actually processed by the call.
22658 + */
22659 +u32 qman_poll_slow(void);
22660 +
22661 +/**
22662 + * qman_poll - legacy wrapper for qman_poll_dqrr() and qman_poll_slow()
22663 + *
22664 + * Dispatcher logic on a cpu can use this to trigger any maintenance of the
22665 + * affine portal. There are two classes of portal processing in question;
22666 + * fast-path (which involves demuxing dequeue ring (DQRR) entries and tracking
22667 + * enqueue ring (EQCR) consumption), and slow-path (which involves EQCR
22668 + * thresholds, congestion state changes, etc). This function does whatever
22669 + * processing is not triggered by interrupts.
22670 + *
22671 + * Note, if DQRR and some slow-path processing are poll-driven (rather than
22672 + * interrupt-driven) then this function uses a heuristic to determine how often
22673 + * to run slow-path processing - as slow-path processing introduces at least a
22674 + * minimum latency each time it is run, whereas fast-path (DQRR) processing is
22675 + * close to zero-cost if there is no work to be done. Applications can tune this
22676 + * behaviour themselves by using qman_poll_dqrr() and qman_poll_slow() directly
22677 + * rather than going via this wrapper.
22678 + */
22679 +void qman_poll(void);
22680 +
22681 +/**
22682 + * qman_stop_dequeues - Stop h/w dequeuing to the s/w portal
22683 + *
22684 + * Disables DQRR processing of the portal. This is reference-counted, so
22685 + * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to
22686 + * truly re-enable dequeuing.
22687 + */
22688 +void qman_stop_dequeues(void);
22689 +
22690 +/**
22691 + * qman_start_dequeues - (Re)start h/w dequeuing to the s/w portal
22692 + *
22693 + * Enables DQRR processing of the portal. This is reference-counted, so
22694 + * qman_start_dequeues() must be called as many times as qman_stop_dequeues() to
22695 + * truly re-enable dequeuing.
22696 + */
22697 +void qman_start_dequeues(void);
22698 +
22699 +/**
22700 + * qman_static_dequeue_add - Add pool channels to the portal SDQCR
22701 + * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n)
22702 + *
22703 + * Adds a set of pool channels to the portal's static dequeue command register
22704 + * (SDQCR). The requested pools are limited to those the portal has dequeue
22705 + * access to.
22706 + */
22707 +void qman_static_dequeue_add(u32 pools);
22708 +
22709 +/**
22710 + * qman_static_dequeue_del - Remove pool channels from the portal SDQCR
22711 + * @pools: bit-mask of pool channels, using QM_SDQCR_CHANNELS_POOL(n)
22712 + *
22713 + * Removes a set of pool channels from the portal's static dequeue command
22714 + * register (SDQCR). The requested pools are limited to those the portal has
22715 + * dequeue access to.
22716 + */
22717 +void qman_static_dequeue_del(u32 pools);
22718 +
22719 +/**
22720 + * qman_static_dequeue_get - return the portal's current SDQCR
22721 + *
22722 + * Returns the portal's current static dequeue command register (SDQCR). The
22723 + * entire register is returned, so if only the currently-enabled pool channels
22724 + * are desired, mask the return value with QM_SDQCR_CHANNELS_POOL_MASK.
22725 + */
22726 +u32 qman_static_dequeue_get(void);
22727 +
22728 +/**
22729 + * qman_dca - Perform a Discrete Consumption Acknowledgement
22730 + * @dq: the DQRR entry to be consumed
22731 + * @park_request: indicates whether the held-active @fq should be parked
22732 + *
22733 + * Only allowed in DCA-mode portals, for DQRR entries whose handler callback had
22734 + * previously returned 'qman_cb_dqrr_defer'. NB, as with the other APIs, this
22735 + * does not take a 'portal' argument but implies the core affine portal from the
22736 + * cpu that is currently executing the function. For reasons of locking, this
22737 + * function must be called from the same CPU as that which processed the DQRR
22738 + * entry in the first place.
22739 + */
22740 +void qman_dca(struct qm_dqrr_entry *dq, int park_request);
22741 +
22742 +/**
22743 + * qman_eqcr_is_empty - Determine if portal's EQCR is empty
22744 + *
22745 + * For use in situations where a cpu-affine caller needs to determine when all
22746 + * enqueues for the local portal have been processed by Qman but can't use the
22747 + * QMAN_ENQUEUE_FLAG_WAIT_SYNC flag to do this from the final qman_enqueue().
22748 + * The function forces tracking of EQCR consumption (which normally doesn't
22749 + * happen until enqueue processing needs to find space to put new enqueue
22750 + * commands), and returns zero if the ring still has unprocessed entries,
22751 + * non-zero if it is empty.
22752 + */
22753 +int qman_eqcr_is_empty(void);
22754 +
22755 +/**
22756 + * qman_set_dc_ern - Set the handler for DCP enqueue rejection notifications
22757 + * @handler: callback for processing DCP ERNs
22758 + * @affine: whether this handler is specific to the locally affine portal
22759 + *
22760 + * If a hardware block's interface to Qman (ie. its direct-connect portal, or
22761 + * DCP) is configured not to receive enqueue rejections, then any enqueues
22762 + * through that DCP that are rejected will be sent to a given software portal.
22763 + * If @affine is non-zero, then this handler will only be used for DCP ERNs
22764 + * received on the portal affine to the current CPU. If multiple CPUs share a
22765 + * portal and they all call this function, they will be setting the handler for
22766 + * the same portal! If @affine is zero, then this handler will be global to all
22767 + * portals handled by this instance of the driver. Only those portals that do
22768 + * not have their own affine handler will use the global handler.
22769 + */
22770 +void qman_set_dc_ern(qman_cb_dc_ern handler, int affine);
22771 +
22772 + /* FQ management */
22773 + /* ------------- */
22774 +/**
22775 + * qman_create_fq - Allocates a FQ
22776 + * @fqid: the index of the FQD to encapsulate, must be "Out of Service"
22777 + * @flags: bit-mask of QMAN_FQ_FLAG_*** options
22778 + * @fq: memory for storing the 'fq', with callbacks filled in
22779 + *
22780 + * Creates a frame queue object for the given @fqid, unless the
22781 + * QMAN_FQ_FLAG_DYNAMIC_FQID flag is set in @flags, in which case a FQID is
22782 + * dynamically allocated (or the function fails if none are available). Once
22783 + * created, the caller should not touch the memory at 'fq' except as extended to
22784 + * adjacent memory for user-defined fields (see the definition of "struct
22785 + * qman_fq" for more info). NO_MODIFY is only intended for enqueuing to
22786 + * pre-existing frame-queues that aren't to be otherwise interfered with, it
22787 + * prevents all other modifications to the frame queue. The TO_DCPORTAL flag
22788 + * causes the driver to honour any contextB modifications requested in the
22789 + * qm_init_fq() API, as this indicates the frame queue will be consumed by a
22790 + * direct-connect portal (PME, CAAM, or Fman). When frame queues are consumed by
22791 + * software portals, the contextB field is controlled by the driver and can't be
22792 + * modified by the caller. If the AS_IS flag is specified, management commands
22793 + * will be used on portal @p to query state for frame queue @fqid and construct
22794 + * a frame queue object based on that, rather than assuming/requiring that it be
22795 + * Out of Service.
22796 + */
22797 +int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq);
22798 +
22799 +/**
22800 + * qman_destroy_fq - Deallocates a FQ
22801 + * @fq: the frame queue object to release
22802 + * @flags: bit-mask of QMAN_FQ_FREE_*** options
22803 + *
22804 + * The memory for this frame queue object ('fq' provided in qman_create_fq()) is
22805 + * not deallocated but the caller regains ownership, to do with as desired. The
22806 + * FQ must be in the 'out-of-service' state unless the QMAN_FQ_FREE_PARKED flag
22807 + * is specified, in which case it may also be in the 'parked' state.
22808 + */
22809 +void qman_destroy_fq(struct qman_fq *fq, u32 flags);
22810 +
22811 +/**
22812 + * qman_fq_fqid - Queries the frame queue ID of a FQ object
22813 + * @fq: the frame queue object to query
22814 + */
22815 +u32 qman_fq_fqid(struct qman_fq *fq);
22816 +
22817 +/**
22818 + * qman_fq_state - Queries the state of a FQ object
22819 + * @fq: the frame queue object to query
22820 + * @state: pointer to state enum to return the FQ scheduling state
22821 + * @flags: pointer to state flags to receive QMAN_FQ_STATE_*** bitmask
22822 + *
22823 + * Queries the state of the FQ object, without performing any h/w commands.
22824 + * This captures the state, as seen by the driver, at the time the function
22825 + * executes.
22826 + */
22827 +void qman_fq_state(struct qman_fq *fq, enum qman_fq_state *state, u32 *flags);
22828 +
22829 +/**
22830 + * qman_init_fq - Initialises FQ fields, leaves the FQ "parked" or "scheduled"
22831 + * @fq: the frame queue object to modify, must be 'parked' or new.
22832 + * @flags: bit-mask of QMAN_INITFQ_FLAG_*** options
22833 + * @opts: the FQ-modification settings, as defined in the low-level API
22834 + *
22835 + * The @opts parameter comes from the low-level portal API. Select
22836 + * QMAN_INITFQ_FLAG_SCHED in @flags to cause the frame queue to be scheduled
22837 + * rather than parked. NB, @opts can be NULL.
22838 + *
22839 + * Note that some fields and options within @opts may be ignored or overwritten
22840 + * by the driver;
22841 + * 1. the 'count' and 'fqid' fields are always ignored (this operation only
22842 + * affects one frame queue: @fq).
22843 + * 2. the QM_INITFQ_WE_CONTEXTB option of the 'we_mask' field and the associated
22844 + * 'fqd' structure's 'context_b' field are sometimes overwritten;
22845 + * - if @fq was not created with QMAN_FQ_FLAG_TO_DCPORTAL, then context_b is
22846 + * initialised to a value used by the driver for demux.
22847 + * - if context_b is initialised for demux, so is context_a in case stashing
22848 + * is requested (see item 4).
22849 + * (So caller control of context_b is only possible for TO_DCPORTAL frame queue
22850 + * objects.)
22851 + * 3. if @flags contains QMAN_INITFQ_FLAG_LOCAL, the 'fqd' structure's
22852 + * 'dest::channel' field will be overwritten to match the portal used to issue
22853 + * the command. If the WE_DESTWQ write-enable bit had already been set by the
22854 + * caller, the channel workqueue will be left as-is, otherwise the write-enable
22855 + * bit is set and the workqueue is set to a default of 4. If the "LOCAL" flag
22856 + * isn't set, the destination channel/workqueue fields and the write-enable bit
22857 + * are left as-is.
22858 + * 4. if the driver overwrites context_a/b for demux, then if
22859 + * QM_INITFQ_WE_CONTEXTA is set, the driver will only overwrite
22860 + * context_a.address fields and will leave the stashing fields provided by the
22861 + * user alone, otherwise it will zero out the context_a.stashing fields.
22862 + */
22863 +int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts);
22864 +
22865 +/**
22866 + * qman_schedule_fq - Schedules a FQ
22867 + * @fq: the frame queue object to schedule, must be 'parked'
22868 + *
22869 + * Schedules the frame queue, which must be Parked, which takes it to
22870 + * Tentatively-Scheduled or Truly-Scheduled depending on its fill-level.
22871 + */
22872 +int qman_schedule_fq(struct qman_fq *fq);
22873 +
22874 +/**
22875 + * qman_retire_fq - Retires a FQ
22876 + * @fq: the frame queue object to retire
22877 + * @flags: FQ flags (as per qman_fq_state) if retirement completes immediately
22878 + *
22879 + * Retires the frame queue. This returns zero if it succeeds immediately, +1 if
22880 + * the retirement was started asynchronously, otherwise it returns negative for
22881 + * failure. When this function returns zero, @flags is set to indicate whether
22882 + * the retired FQ is empty and/or whether it has any ORL fragments (to show up
22883 + * as ERNs). Otherwise the corresponding flags will be known when a subsequent
22884 + * FQRN message shows up on the portal's message ring.
22885 + *
22886 + * NB, if the retirement is asynchronous (the FQ was in the Truly Scheduled or
22887 + * Active state), the completion will be via the message ring as a FQRN - but
22888 + * the corresponding callback may occur before this function returns!! Ie. the
22889 + * caller should be prepared to accept the callback as the function is called,
22890 + * not only once it has returned.
22891 + */
22892 +int qman_retire_fq(struct qman_fq *fq, u32 *flags);
22893 +
22894 +/**
22895 + * qman_oos_fq - Puts a FQ "out of service"
22896 + * @fq: the frame queue object to be put out-of-service, must be 'retired'
22897 + *
22898 + * The frame queue must be retired and empty, and if any order restoration list
22899 + * was released as ERNs at the time of retirement, they must all be consumed.
22900 + */
22901 +int qman_oos_fq(struct qman_fq *fq);
22902 +
22903 +/**
22904 + * qman_fq_flow_control - Set the XON/XOFF state of a FQ
22905 + * @fq: the frame queue object to be set to XON/XOFF state, must not be 'oos',
22906 + * or 'retired' or 'parked' state
22907 + * @xon: boolean to set fq in XON or XOFF state
22908 + *
22909 + * The frame should be in Tentatively Scheduled state or Truly Schedule sate,
22910 + * otherwise the IFSI interrupt will be asserted.
22911 + */
22912 +int qman_fq_flow_control(struct qman_fq *fq, int xon);
22913 +
22914 +/**
22915 + * qman_query_fq - Queries FQD fields (via h/w query command)
22916 + * @fq: the frame queue object to be queried
22917 + * @fqd: storage for the queried FQD fields
22918 + */
22919 +int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd);
22920 +
22921 +/**
22922 + * qman_query_fq_np - Queries non-programmable FQD fields
22923 + * @fq: the frame queue object to be queried
22924 + * @np: storage for the queried FQD fields
22925 + */
22926 +int qman_query_fq_np(struct qman_fq *fq, struct qm_mcr_queryfq_np *np);
22927 +
22928 +/**
22929 + * qman_query_wq - Queries work queue lengths
22930 + * @query_dedicated: If non-zero, query length of WQs in the channel dedicated
22931 + * to this software portal. Otherwise, query length of WQs in a
22932 + * channel specified in wq.
22933 + * @wq: storage for the queried WQs lengths. Also specified the channel to
22934 + * to query if query_dedicated is zero.
22935 + */
22936 +int qman_query_wq(u8 query_dedicated, struct qm_mcr_querywq *wq);
22937 +
22938 +/**
22939 + * qman_volatile_dequeue - Issue a volatile dequeue command
22940 + * @fq: the frame queue object to dequeue from
22941 + * @flags: a bit-mask of QMAN_VOLATILE_FLAG_*** options
22942 + * @vdqcr: bit mask of QM_VDQCR_*** options, as per qm_dqrr_vdqcr_set()
22943 + *
22944 + * Attempts to lock access to the portal's VDQCR volatile dequeue functionality.
22945 + * The function will block and sleep if QMAN_VOLATILE_FLAG_WAIT is specified and
22946 + * the VDQCR is already in use, otherwise returns non-zero for failure. If
22947 + * QMAN_VOLATILE_FLAG_FINISH is specified, the function will only return once
22948 + * the VDQCR command has finished executing (ie. once the callback for the last
22949 + * DQRR entry resulting from the VDQCR command has been called). If not using
22950 + * the FINISH flag, completion can be determined either by detecting the
22951 + * presence of the QM_DQRR_STAT_UNSCHEDULED and QM_DQRR_STAT_DQCR_EXPIRED bits
22952 + * in the "stat" field of the "struct qm_dqrr_entry" passed to the FQ's dequeue
22953 + * callback, or by waiting for the QMAN_FQ_STATE_VDQCR bit to disappear from the
22954 + * "flags" retrieved from qman_fq_state().
22955 + */
22956 +int qman_volatile_dequeue(struct qman_fq *fq, u32 flags, u32 vdqcr);
22957 +
22958 +/**
22959 + * qman_enqueue - Enqueue a frame to a frame queue
22960 + * @fq: the frame queue object to enqueue to
22961 + * @fd: a descriptor of the frame to be enqueued
22962 + * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options
22963 + *
22964 + * Fills an entry in the EQCR of portal @qm to enqueue the frame described by
22965 + * @fd. The descriptor details are copied from @fd to the EQCR entry, the 'pid'
22966 + * field is ignored. The return value is non-zero on error, such as ring full
22967 + * (and FLAG_WAIT not specified), congestion avoidance (FLAG_WATCH_CGR
22968 + * specified), etc. If the ring is full and FLAG_WAIT is specified, this
22969 + * function will block. If FLAG_INTERRUPT is set, the EQCI bit of the portal
22970 + * interrupt will assert when Qman consumes the EQCR entry (subject to "status
22971 + * disable", "enable", and "inhibit" registers). If FLAG_DCA is set, Qman will
22972 + * perform an implied "discrete consumption acknowledgement" on the dequeue
22973 + * ring's (DQRR) entry, at the ring index specified by the FLAG_DCA_IDX(x)
22974 + * macro. (As an alternative to issuing explicit DCA actions on DQRR entries,
22975 + * this implicit DCA can delay the release of a "held active" frame queue
22976 + * corresponding to a DQRR entry until Qman consumes the EQCR entry - providing
22977 + * order-preservation semantics in packet-forwarding scenarios.) If FLAG_DCA is
22978 + * set, then FLAG_DCA_PARK can also be set to imply that the DQRR consumption
22979 + * acknowledgement should "park request" the "held active" frame queue. Ie.
22980 + * when the portal eventually releases that frame queue, it will be left in the
22981 + * Parked state rather than Tentatively Scheduled or Truly Scheduled. If the
22982 + * portal is watching congestion groups, the QMAN_ENQUEUE_FLAG_WATCH_CGR flag
22983 + * is requested, and the FQ is a member of a congestion group, then this
22984 + * function returns -EAGAIN if the congestion group is currently congested.
22985 + * Note, this does not eliminate ERNs, as the async interface means we can be
22986 + * sending enqueue commands to an un-congested FQ that becomes congested before
22987 + * the enqueue commands are processed, but it does minimise needless thrashing
22988 + * of an already busy hardware resource by throttling many of the to-be-dropped
22989 + * enqueues "at the source".
22990 + */
22991 +int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd, u32 flags);
22992 +
22993 +typedef int (*qman_cb_precommit) (void *arg);
22994 +/**
22995 + * qman_enqueue_precommit - Enqueue a frame to a frame queue and call cb
22996 + * @fq: the frame queue object to enqueue to
22997 + * @fd: a descriptor of the frame to be enqueued
22998 + * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options
22999 + * @cb: user supplied callback function to invoke before writing commit verb.
23000 + * @cb_arg: callback function argument
23001 + *
23002 + * This is similar to qman_enqueue except that it will invoke a user supplied
23003 + * callback function just before writng the commit verb. This is useful
23004 + * when the user want to do something *just before* enqueuing the request and
23005 + * the enqueue can't fail.
23006 + */
23007 +int qman_enqueue_precommit(struct qman_fq *fq, const struct qm_fd *fd,
23008 + u32 flags, qman_cb_precommit cb, void *cb_arg);
23009 +
23010 +/**
23011 + * qman_enqueue_orp - Enqueue a frame to a frame queue using an ORP
23012 + * @fq: the frame queue object to enqueue to
23013 + * @fd: a descriptor of the frame to be enqueued
23014 + * @flags: bit-mask of QMAN_ENQUEUE_FLAG_*** options
23015 + * @orp: the frame queue object used as an order restoration point.
23016 + * @orp_seqnum: the sequence number of this frame in the order restoration path
23017 + *
23018 + * Similar to qman_enqueue(), but with the addition of an Order Restoration
23019 + * Point (@orp) and corresponding sequence number (@orp_seqnum) for this
23020 + * enqueue operation to employ order restoration. Each frame queue object acts
23021 + * as an Order Definition Point (ODP) by providing each frame dequeued from it
23022 + * with an incrementing sequence number, this value is generally ignored unless
23023 + * that sequence of dequeued frames will need order restoration later. Each
23024 + * frame queue object also encapsulates an Order Restoration Point (ORP), which
23025 + * is a re-assembly context for re-ordering frames relative to their sequence
23026 + * numbers as they are enqueued. The ORP does not have to be within the frame
23027 + * queue that receives the enqueued frame, in fact it is usually the frame
23028 + * queue from which the frames were originally dequeued. For the purposes of
23029 + * order restoration, multiple frames (or "fragments") can be enqueued for a
23030 + * single sequence number by setting the QMAN_ENQUEUE_FLAG_NLIS flag for all
23031 + * enqueues except the final fragment of a given sequence number. Ordering
23032 + * between sequence numbers is guaranteed, even if fragments of different
23033 + * sequence numbers are interlaced with one another. Fragments of the same
23034 + * sequence number will retain the order in which they are enqueued. If no
23035 + * enqueue is to performed, QMAN_ENQUEUE_FLAG_HOLE indicates that the given
23036 + * sequence number is to be "skipped" by the ORP logic (eg. if a frame has been
23037 + * dropped from a sequence), or QMAN_ENQUEUE_FLAG_NESN indicates that the given
23038 + * sequence number should become the ORP's "Next Expected Sequence Number".
23039 + *
23040 + * Side note: a frame queue object can be used purely as an ORP, without
23041 + * carrying any frames at all. Care should be taken not to deallocate a frame
23042 + * queue object that is being actively used as an ORP, as a future allocation
23043 + * of the frame queue object may start using the internal ORP before the
23044 + * previous use has finished.
23045 + */
23046 +int qman_enqueue_orp(struct qman_fq *fq, const struct qm_fd *fd, u32 flags,
23047 + struct qman_fq *orp, u16 orp_seqnum);
23048 +
23049 +/**
23050 + * qman_alloc_fqid_range - Allocate a contiguous range of FQIDs
23051 + * @result: is set by the API to the base FQID of the allocated range
23052 + * @count: the number of FQIDs required
23053 + * @align: required alignment of the allocated range
23054 + * @partial: non-zero if the API can return fewer than @count FQIDs
23055 + *
23056 + * Returns the number of frame queues allocated, or a negative error code. If
23057 + * @partial is non zero, the allocation request may return a smaller range of
23058 + * FQs than requested (though alignment will be as requested). If @partial is
23059 + * zero, the return value will either be 'count' or negative.
23060 + */
23061 +int qman_alloc_fqid_range(u32 *result, u32 count, u32 align, int partial);
23062 +static inline int qman_alloc_fqid(u32 *result)
23063 +{
23064 + int ret = qman_alloc_fqid_range(result, 1, 0, 0);
23065 + return (ret > 0) ? 0 : ret;
23066 +}
23067 +
23068 +/**
23069 + * qman_release_fqid_range - Release the specified range of frame queue IDs
23070 + * @fqid: the base FQID of the range to deallocate
23071 + * @count: the number of FQIDs in the range
23072 + *
23073 + * This function can also be used to seed the allocator with ranges of FQIDs
23074 + * that it can subsequently allocate from.
23075 + */
23076 +void qman_release_fqid_range(u32 fqid, unsigned int count);
23077 +static inline void qman_release_fqid(u32 fqid)
23078 +{
23079 + qman_release_fqid_range(fqid, 1);
23080 +}
23081 +
23082 +void qman_seed_fqid_range(u32 fqid, unsigned int count);
23083 +
23084 +
23085 +int qman_shutdown_fq(u32 fqid);
23086 +
23087 +/**
23088 + * qman_reserve_fqid_range - Reserve the specified range of frame queue IDs
23089 + * @fqid: the base FQID of the range to deallocate
23090 + * @count: the number of FQIDs in the range
23091 + */
23092 +int qman_reserve_fqid_range(u32 fqid, unsigned int count);
23093 +static inline int qman_reserve_fqid(u32 fqid)
23094 +{
23095 + return qman_reserve_fqid_range(fqid, 1);
23096 +}
23097 +
23098 + /* Pool-channel management */
23099 + /* ----------------------- */
23100 +/**
23101 + * qman_alloc_pool_range - Allocate a contiguous range of pool-channel IDs
23102 + * @result: is set by the API to the base pool-channel ID of the allocated range
23103 + * @count: the number of pool-channel IDs required
23104 + * @align: required alignment of the allocated range
23105 + * @partial: non-zero if the API can return fewer than @count
23106 + *
23107 + * Returns the number of pool-channel IDs allocated, or a negative error code.
23108 + * If @partial is non zero, the allocation request may return a smaller range of
23109 + * than requested (though alignment will be as requested). If @partial is zero,
23110 + * the return value will either be 'count' or negative.
23111 + */
23112 +int qman_alloc_pool_range(u32 *result, u32 count, u32 align, int partial);
23113 +static inline int qman_alloc_pool(u32 *result)
23114 +{
23115 + int ret = qman_alloc_pool_range(result, 1, 0, 0);
23116 + return (ret > 0) ? 0 : ret;
23117 +}
23118 +
23119 +/**
23120 + * qman_release_pool_range - Release the specified range of pool-channel IDs
23121 + * @id: the base pool-channel ID of the range to deallocate
23122 + * @count: the number of pool-channel IDs in the range
23123 + */
23124 +void qman_release_pool_range(u32 id, unsigned int count);
23125 +static inline void qman_release_pool(u32 id)
23126 +{
23127 + qman_release_pool_range(id, 1);
23128 +}
23129 +
23130 +/**
23131 + * qman_reserve_pool_range - Reserve the specified range of pool-channel IDs
23132 + * @id: the base pool-channel ID of the range to reserve
23133 + * @count: the number of pool-channel IDs in the range
23134 + */
23135 +int qman_reserve_pool_range(u32 id, unsigned int count);
23136 +static inline int qman_reserve_pool(u32 id)
23137 +{
23138 + return qman_reserve_pool_range(id, 1);
23139 +}
23140 +
23141 +void qman_seed_pool_range(u32 id, unsigned int count);
23142 +
23143 + /* CGR management */
23144 + /* -------------- */
23145 +/**
23146 + * qman_create_cgr - Register a congestion group object
23147 + * @cgr: the 'cgr' object, with fields filled in
23148 + * @flags: QMAN_CGR_FLAG_* values
23149 + * @opts: optional state of CGR settings
23150 + *
23151 + * Registers this object to receiving congestion entry/exit callbacks on the
23152 + * portal affine to the cpu portal on which this API is executed. If opts is
23153 + * NULL then only the callback (cgr->cb) function is registered. If @flags
23154 + * contains QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset
23155 + * any unspecified parameters) will be used rather than a modify hw hardware
23156 + * (which only modifies the specified parameters).
23157 + */
23158 +int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
23159 + struct qm_mcc_initcgr *opts);
23160 +
23161 +/**
23162 + * qman_create_cgr_to_dcp - Register a congestion group object to DCP portal
23163 + * @cgr: the 'cgr' object, with fields filled in
23164 + * @flags: QMAN_CGR_FLAG_* values
23165 + * @dcp_portal: the DCP portal to which the cgr object is registered.
23166 + * @opts: optional state of CGR settings
23167 + *
23168 + */
23169 +int qman_create_cgr_to_dcp(struct qman_cgr *cgr, u32 flags, u16 dcp_portal,
23170 + struct qm_mcc_initcgr *opts);
23171 +
23172 +/**
23173 + * qman_delete_cgr - Deregisters a congestion group object
23174 + * @cgr: the 'cgr' object to deregister
23175 + *
23176 + * "Unplugs" this CGR object from the portal affine to the cpu on which this API
23177 + * is executed. This must be excuted on the same affine portal on which it was
23178 + * created.
23179 + */
23180 +int qman_delete_cgr(struct qman_cgr *cgr);
23181 +
23182 +/**
23183 + * qman_delete_cgr_safe - Deregisters a congestion group object from any CPU
23184 + * @cgr: the 'cgr' object to deregister
23185 + *
23186 + * This will select the proper CPU and run there qman_delete_cgr().
23187 + */
23188 +void qman_delete_cgr_safe(struct qman_cgr *cgr);
23189 +
23190 +/**
23191 + * qman_modify_cgr - Modify CGR fields
23192 + * @cgr: the 'cgr' object to modify
23193 + * @flags: QMAN_CGR_FLAG_* values
23194 + * @opts: the CGR-modification settings
23195 + *
23196 + * The @opts parameter comes from the low-level portal API, and can be NULL.
23197 + * Note that some fields and options within @opts may be ignored or overwritten
23198 + * by the driver, in particular the 'cgrid' field is ignored (this operation
23199 + * only affects the given CGR object). If @flags contains
23200 + * QMAN_CGR_FLAG_USE_INIT, then an init hw command (which will reset any
23201 + * unspecified parameters) will be used rather than a modify hw hardware (which
23202 + * only modifies the specified parameters).
23203 + */
23204 +int qman_modify_cgr(struct qman_cgr *cgr, u32 flags,
23205 + struct qm_mcc_initcgr *opts);
23206 +
23207 +/**
23208 +* qman_query_cgr - Queries CGR fields
23209 +* @cgr: the 'cgr' object to query
23210 +* @result: storage for the queried congestion group record
23211 +*/
23212 +int qman_query_cgr(struct qman_cgr *cgr, struct qm_mcr_querycgr *result);
23213 +
23214 +/**
23215 + * qman_query_congestion - Queries the state of all congestion groups
23216 + * @congestion: storage for the queried state of all congestion groups
23217 + */
23218 +int qman_query_congestion(struct qm_mcr_querycongestion *congestion);
23219 +
23220 +/**
23221 + * qman_alloc_cgrid_range - Allocate a contiguous range of CGR IDs
23222 + * @result: is set by the API to the base CGR ID of the allocated range
23223 + * @count: the number of CGR IDs required
23224 + * @align: required alignment of the allocated range
23225 + * @partial: non-zero if the API can return fewer than @count
23226 + *
23227 + * Returns the number of CGR IDs allocated, or a negative error code.
23228 + * If @partial is non zero, the allocation request may return a smaller range of
23229 + * than requested (though alignment will be as requested). If @partial is zero,
23230 + * the return value will either be 'count' or negative.
23231 + */
23232 +int qman_alloc_cgrid_range(u32 *result, u32 count, u32 align, int partial);
23233 +static inline int qman_alloc_cgrid(u32 *result)
23234 +{
23235 + int ret = qman_alloc_cgrid_range(result, 1, 0, 0);
23236 + return (ret > 0) ? 0 : ret;
23237 +}
23238 +
23239 +/**
23240 + * qman_release_cgrid_range - Release the specified range of CGR IDs
23241 + * @id: the base CGR ID of the range to deallocate
23242 + * @count: the number of CGR IDs in the range
23243 + */
23244 +void qman_release_cgrid_range(u32 id, unsigned int count);
23245 +static inline void qman_release_cgrid(u32 id)
23246 +{
23247 + qman_release_cgrid_range(id, 1);
23248 +}
23249 +
23250 +/**
23251 + * qman_reserve_cgrid_range - Reserve the specified range of CGR ID
23252 + * @id: the base CGR ID of the range to reserve
23253 + * @count: the number of CGR IDs in the range
23254 + */
23255 +int qman_reserve_cgrid_range(u32 id, unsigned int count);
23256 +static inline int qman_reserve_cgrid(u32 id)
23257 +{
23258 + return qman_reserve_cgrid_range(id, 1);
23259 +}
23260 +
23261 +void qman_seed_cgrid_range(u32 id, unsigned int count);
23262 +
23263 +
23264 + /* Helpers */
23265 + /* ------- */
23266 +/**
23267 + * qman_poll_fq_for_init - Check if an FQ has been initialised from OOS
23268 + * @fqid: the FQID that will be initialised by other s/w
23269 + *
23270 + * In many situations, a FQID is provided for communication between s/w
23271 + * entities, and whilst the consumer is responsible for initialising and
23272 + * scheduling the FQ, the producer(s) generally create a wrapper FQ object using
23273 + * and only call qman_enqueue() (no FQ initialisation, scheduling, etc). Ie;
23274 + * qman_create_fq(..., QMAN_FQ_FLAG_NO_MODIFY, ...);
23275 + * However, data can not be enqueued to the FQ until it is initialised out of
23276 + * the OOS state - this function polls for that condition. It is particularly
23277 + * useful for users of IPC functions - each endpoint's Rx FQ is the other
23278 + * endpoint's Tx FQ, so each side can initialise and schedule their Rx FQ object
23279 + * and then use this API on the (NO_MODIFY) Tx FQ object in order to
23280 + * synchronise. The function returns zero for success, +1 if the FQ is still in
23281 + * the OOS state, or negative if there was an error.
23282 + */
23283 +static inline int qman_poll_fq_for_init(struct qman_fq *fq)
23284 +{
23285 + struct qm_mcr_queryfq_np np;
23286 + int err;
23287 + err = qman_query_fq_np(fq, &np);
23288 + if (err)
23289 + return err;
23290 + if ((np.state & QM_MCR_NP_STATE_MASK) == QM_MCR_NP_STATE_OOS)
23291 + return 1;
23292 + return 0;
23293 +}
23294 +
23295 + /* -------------- */
23296 + /* CEETM :: types */
23297 + /* -------------- */
23298 +/**
23299 + * Token Rate Structure
23300 + * Shaping rates are based on a "credit" system and a pre-configured h/w
23301 + * internal timer. The following type represents a shaper "rate" parameter as a
23302 + * fractional number of "tokens". Here's how it works. This (fractional) number
23303 + * of tokens is added to the shaper's "credit" every time the h/w timer elapses
23304 + * (up to a limit which is set by another shaper parameter). Every time a frame
23305 + * is enqueued through a shaper, the shaper deducts as many tokens as there are
23306 + * bytes of data in the enqueued frame. A shaper will not allow itself to
23307 + * enqueue any frames if its token count is negative. As such;
23308 + *
23309 + * The rate at which data is enqueued is limited by the
23310 + * rate at which tokens are added.
23311 + *
23312 + * Therefore if the user knows the period between these h/w timer updates in
23313 + * seconds, they can calculate the maximum traffic rate of the shaper (in
23314 + * bytes-per-second) from the token rate. And vice versa, they can calculate
23315 + * the token rate to use in order to achieve a given traffic rate.
23316 + */
23317 +struct qm_ceetm_rate {
23318 + /* The token rate is; whole + (fraction/8192) */
23319 + u32 whole:11; /* 0..2047 */
23320 + u32 fraction:13; /* 0..8191 */
23321 +};
23322 +
23323 +struct qm_ceetm_weight_code {
23324 + /* The weight code is; 5 msbits + 3 lsbits */
23325 + u8 y:5;
23326 + u8 x:3;
23327 +};
23328 +
23329 +struct qm_ceetm {
23330 + unsigned int idx;
23331 + struct list_head sub_portals;
23332 + struct list_head lnis;
23333 + unsigned int sp_range[2];
23334 + unsigned int lni_range[2];
23335 +};
23336 +
23337 +struct qm_ceetm_sp {
23338 + struct list_head node;
23339 + unsigned int idx;
23340 + unsigned int dcp_idx;
23341 + int is_claimed;
23342 + struct qm_ceetm_lni *lni;
23343 +};
23344 +
23345 +/* Logical Network Interface */
23346 +struct qm_ceetm_lni {
23347 + struct list_head node;
23348 + unsigned int idx;
23349 + unsigned int dcp_idx;
23350 + int is_claimed;
23351 + struct qm_ceetm_sp *sp;
23352 + struct list_head channels;
23353 + int shaper_enable;
23354 + int shaper_couple;
23355 + int oal;
23356 + struct qm_ceetm_rate cr_token_rate;
23357 + struct qm_ceetm_rate er_token_rate;
23358 + u16 cr_token_bucket_limit;
23359 + u16 er_token_bucket_limit;
23360 +};
23361 +
23362 +/* Class Queue Channel */
23363 +struct qm_ceetm_channel {
23364 + struct list_head node;
23365 + unsigned int idx;
23366 + unsigned int lni_idx;
23367 + unsigned int dcp_idx;
23368 + struct list_head class_queues;
23369 + struct list_head ccgs;
23370 + u8 shaper_enable;
23371 + u8 shaper_couple;
23372 + struct qm_ceetm_rate cr_token_rate;
23373 + struct qm_ceetm_rate er_token_rate;
23374 + u16 cr_token_bucket_limit;
23375 + u16 er_token_bucket_limit;
23376 +};
23377 +
23378 +struct qm_ceetm_ccg;
23379 +
23380 +/* This callback type is used when handling congestion entry/exit. The
23381 + * 'cb_ctx' value is the opaque value associated with ccg object.
23382 + * 'congested' is non-zero on congestion-entry, and zero on congestion-exit.
23383 + */
23384 +typedef void (*qman_cb_ccgr)(struct qm_ceetm_ccg *ccg, void *cb_ctx,
23385 + int congested);
23386 +
23387 +/* Class Congestion Group */
23388 +struct qm_ceetm_ccg {
23389 + struct qm_ceetm_channel *parent;
23390 + struct list_head node;
23391 + struct list_head cb_node;
23392 + qman_cb_ccgr cb;
23393 + void *cb_ctx;
23394 + unsigned int idx;
23395 +};
23396 +
23397 +/* Class Queue */
23398 +struct qm_ceetm_cq {
23399 + struct qm_ceetm_channel *parent;
23400 + struct qm_ceetm_ccg *ccg;
23401 + struct list_head node;
23402 + unsigned int idx;
23403 + int is_claimed;
23404 + struct list_head bound_lfqids;
23405 + struct list_head binding_node;
23406 +};
23407 +
23408 +/* Logical Frame Queue */
23409 +struct qm_ceetm_lfq {
23410 + struct qm_ceetm_channel *parent;
23411 + struct list_head node;
23412 + unsigned int idx;
23413 + unsigned int dctidx;
23414 + u64 context_a;
23415 + u32 context_b;
23416 + qman_cb_mr ern;
23417 +};
23418 +
23419 +/**
23420 + * qman_ceetm_bps2tokenrate - Given a desired rate 'bps' measured in bps
23421 + * (ie. bits-per-second), compute the 'token_rate' fraction that best
23422 + * approximates that rate.
23423 + * @bps: the desired shaper rate in bps.
23424 + * @token_rate: the output token rate computed with the given kbps.
23425 + * @rounding: dictates how to round if an exact conversion is not possible; if
23426 + * it is negative then 'token_rate' will round down to the highest value that
23427 + * does not exceed the desired rate, if it is positive then 'token_rate' will
23428 + * round up to the lowest value that is greater than or equal to the desired
23429 + * rate, and if it is zero then it will round to the nearest approximation,
23430 + * whether that be up or down.
23431 + *
23432 + * Return 0 for success, or -EINVAL if prescaler or qman clock is not available.
23433 + */
23434 +int qman_ceetm_bps2tokenrate(u64 bps,
23435 + struct qm_ceetm_rate *token_rate,
23436 + int rounding);
23437 +
23438 +/**
23439 + * qman_ceetm_tokenrate2bps - Given a 'token_rate', compute the
23440 + * corresponding number of 'bps'.
23441 + * @token_rate: the input desired token_rate fraction.
23442 + * @bps: the output shaper rate in bps computed with the give token rate.
23443 + * @rounding: has the same semantics as the previous function.
23444 + *
23445 + * Return 0 for success, or -EINVAL if prescaler or qman clock is not available.
23446 + */
23447 +int qman_ceetm_tokenrate2bps(const struct qm_ceetm_rate *token_rate,
23448 + u64 *bps,
23449 + int rounding);
23450 +
23451 +int qman_alloc_ceetm0_channel_range(u32 *result, u32 count, u32 align,
23452 + int partial);
23453 +static inline int qman_alloc_ceetm0_channel(u32 *result)
23454 +{
23455 + int ret = qman_alloc_ceetm0_channel_range(result, 1, 0, 0);
23456 + return (ret > 0) ? 0 : ret;
23457 +}
23458 +void qman_release_ceetm0_channel_range(u32 channelid, u32 count);
23459 +static inline void qman_release_ceetm0_channelid(u32 channelid)
23460 +{
23461 + qman_release_ceetm0_channel_range(channelid, 1);
23462 +}
23463 +
23464 +int qman_reserve_ceetm0_channel_range(u32 channelid, u32 count);
23465 +static inline int qman_reserve_ceetm0_channelid(u32 channelid)
23466 +{
23467 + return qman_reserve_ceetm0_channel_range(channelid, 1);
23468 +}
23469 +
23470 +void qman_seed_ceetm0_channel_range(u32 channelid, u32 count);
23471 +
23472 +
23473 +int qman_alloc_ceetm1_channel_range(u32 *result, u32 count, u32 align,
23474 + int partial);
23475 +static inline int qman_alloc_ceetm1_channel(u32 *result)
23476 +{
23477 + int ret = qman_alloc_ceetm1_channel_range(result, 1, 0, 0);
23478 + return (ret > 0) ? 0 : ret;
23479 +}
23480 +void qman_release_ceetm1_channel_range(u32 channelid, u32 count);
23481 +static inline void qman_release_ceetm1_channelid(u32 channelid)
23482 +{
23483 + qman_release_ceetm1_channel_range(channelid, 1);
23484 +}
23485 +int qman_reserve_ceetm1_channel_range(u32 channelid, u32 count);
23486 +static inline int qman_reserve_ceetm1_channelid(u32 channelid)
23487 +{
23488 + return qman_reserve_ceetm1_channel_range(channelid, 1);
23489 +}
23490 +
23491 +void qman_seed_ceetm1_channel_range(u32 channelid, u32 count);
23492 +
23493 +
23494 +int qman_alloc_ceetm0_lfqid_range(u32 *result, u32 count, u32 align,
23495 + int partial);
23496 +static inline int qman_alloc_ceetm0_lfqid(u32 *result)
23497 +{
23498 + int ret = qman_alloc_ceetm0_lfqid_range(result, 1, 0, 0);
23499 + return (ret > 0) ? 0 : ret;
23500 +}
23501 +void qman_release_ceetm0_lfqid_range(u32 lfqid, u32 count);
23502 +static inline void qman_release_ceetm0_lfqid(u32 lfqid)
23503 +{
23504 + qman_release_ceetm0_lfqid_range(lfqid, 1);
23505 +}
23506 +int qman_reserve_ceetm0_lfqid_range(u32 lfqid, u32 count);
23507 +static inline int qman_reserve_ceetm0_lfqid(u32 lfqid)
23508 +{
23509 + return qman_reserve_ceetm0_lfqid_range(lfqid, 1);
23510 +}
23511 +
23512 +void qman_seed_ceetm0_lfqid_range(u32 lfqid, u32 count);
23513 +
23514 +
23515 +int qman_alloc_ceetm1_lfqid_range(u32 *result, u32 count, u32 align,
23516 + int partial);
23517 +static inline int qman_alloc_ceetm1_lfqid(u32 *result)
23518 +{
23519 + int ret = qman_alloc_ceetm1_lfqid_range(result, 1, 0, 0);
23520 + return (ret > 0) ? 0 : ret;
23521 +}
23522 +void qman_release_ceetm1_lfqid_range(u32 lfqid, u32 count);
23523 +static inline void qman_release_ceetm1_lfqid(u32 lfqid)
23524 +{
23525 + qman_release_ceetm1_lfqid_range(lfqid, 1);
23526 +}
23527 +int qman_reserve_ceetm1_lfqid_range(u32 lfqid, u32 count);
23528 +static inline int qman_reserve_ceetm1_lfqid(u32 lfqid)
23529 +{
23530 + return qman_reserve_ceetm1_lfqid_range(lfqid, 1);
23531 +}
23532 +
23533 +void qman_seed_ceetm1_lfqid_range(u32 lfqid, u32 count);
23534 +
23535 +
23536 + /* ----------------------------- */
23537 + /* CEETM :: sub-portals */
23538 + /* ----------------------------- */
23539 +
23540 +/**
23541 + * qman_ceetm_claim_sp - Claims the given sub-portal, provided it is available
23542 + * to us and configured for traffic-management.
23543 + * @sp: the returned sub-portal object, if successful.
23544 + * @dcp_id: specifies the desired Fman block (and thus the relevant CEETM
23545 + * instance),
23546 + * @sp_idx" is the desired sub-portal index from 0 to 15.
23547 + *
23548 + * Returns zero for success, or -ENODEV if the sub-portal is in use, or -EINVAL
23549 + * if the sp_idx is out of range.
23550 + *
23551 + * Note that if there are multiple driver domains (eg. a linux kernel versus
23552 + * user-space drivers in USDPAA, or multiple guests running under a hypervisor)
23553 + * then a sub-portal may be accessible by more than one instance of a qman
23554 + * driver and so it may be claimed multiple times. If this is the case, it is
23555 + * up to the system architect to prevent conflicting configuration actions
23556 + * coming from the different driver domains. The qman drivers do not have any
23557 + * behind-the-scenes coordination to prevent this from happening.
23558 + */
23559 +int qman_ceetm_sp_claim(struct qm_ceetm_sp **sp,
23560 + enum qm_dc_portal dcp_idx,
23561 + unsigned int sp_idx);
23562 +
23563 +/**
23564 + * qman_ceetm_sp_release - Releases a previously claimed sub-portal.
23565 + * @sp: the sub-portal to be released.
23566 + *
23567 + * Returns 0 for success, or -EBUSY for failure if the dependencies are not
23568 + * released.
23569 + */
23570 +int qman_ceetm_sp_release(struct qm_ceetm_sp *sp);
23571 +
23572 + /* ----------------------------------- */
23573 + /* CEETM :: logical network interfaces */
23574 + /* ----------------------------------- */
23575 +
23576 +/**
23577 + * qman_ceetm_lni_claim - Claims an unclaimed LNI.
23578 + * @lni: the returned LNI object, if successful.
23579 + * @dcp_id: specifies the desired Fman block (and thus the relevant CEETM
23580 + * instance)
23581 + * @lni_idx: is the desired LNI index.
23582 + *
23583 + * Returns zero for success, or -EINVAL on failure, which will happen if the LNI
23584 + * is not available or has already been claimed (and not yet successfully
23585 + * released), or lni_dix is out of range.
23586 + *
23587 + * Note that there may be multiple driver domains (or instances) that need to
23588 + * transmit out the same LNI, so this claim is only guaranteeing exclusivity
23589 + * within the domain of the driver being called. See qman_ceetm_sp_claim() and
23590 + * qman_ceetm_sp_get_lni() for more information.
23591 + */
23592 +int qman_ceetm_lni_claim(struct qm_ceetm_lni **lni,
23593 + enum qm_dc_portal dcp_id,
23594 + unsigned int lni_idx);
23595 +
23596 +/**
23597 + * qman_ceetm_lni_releaes - Releases a previously claimed LNI.
23598 + * @lni: the lni needs to be released.
23599 + *
23600 + * This will only succeed if all dependent objects have been released.
23601 + * Returns zero for success, or -EBUSY if the dependencies are not released.
23602 + */
23603 +int qman_ceetm_lni_release(struct qm_ceetm_lni *lni);
23604 +
23605 +/**
23606 + * qman_ceetm_sp_set_lni
23607 + * qman_ceetm_sp_get_lni - Set/get the LNI that the sub-portal is currently
23608 + * mapped to.
23609 + * @sp: the given sub-portal.
23610 + * @lni(in "set"function): the LNI object which the sp will be mappaed to.
23611 + * @lni_idx(in "get" function): the LNI index which the sp is mapped to.
23612 + *
23613 + * Returns zero for success, or -EINVAL for the "set" function when this sp-lni
23614 + * mapping has been set, or configure mapping command returns error, and
23615 + * -EINVAL for "get" function when this sp-lni mapping is not set or the query
23616 + * mapping command returns error.
23617 + *
23618 + * This may be useful in situations where multiple driver domains have access
23619 + * to the same sub-portals in order to all be able to transmit out the same
23620 + * physical interface (perhaps they're on different IP addresses or VPNs, so
23621 + * Fman is splitting Rx traffic and here we need to converge Tx traffic). In
23622 + * that case, a control-plane is likely to use qman_ceetm_lni_claim() followed
23623 + * by qman_ceetm_sp_set_lni() to configure the sub-portal, and other domains
23624 + * are likely to use qman_ceetm_sp_get_lni() followed by qman_ceetm_lni_claim()
23625 + * in order to determine the LNI that the control-plane had assigned. This is
23626 + * why the "get" returns an index, whereas the "set" takes an (already claimed)
23627 + * LNI object.
23628 + */
23629 +int qman_ceetm_sp_set_lni(struct qm_ceetm_sp *sp,
23630 + struct qm_ceetm_lni *lni);
23631 +int qman_ceetm_sp_get_lni(struct qm_ceetm_sp *sp,
23632 + unsigned int *lni_idx);
23633 +
23634 +/**
23635 + * qman_ceetm_lni_enable_shaper
23636 + * qman_ceetm_lni_disable_shaper - Enables/disables shaping on the LNI.
23637 + * @lni: the given LNI.
23638 + * @coupled: indicates whether CR and ER are coupled.
23639 + * @oal: the overhead accounting length which is added to the actual length of
23640 + * each frame when performing shaper calculations.
23641 + *
23642 + * When the number of (unused) committed-rate tokens reach the committed-rate
23643 + * token limit, 'coupled' indicates whether surplus tokens should be added to
23644 + * the excess-rate token count (up to the excess-rate token limit).
23645 + * When LNI is claimed, the shaper is disabled by default. The enable function
23646 + * will turn on this shaper for this lni.
23647 + * Whenever a claimed LNI is first enabled for shaping, its committed and
23648 + * excess token rates and limits are zero, so will need to be changed to do
23649 + * anything useful. The shaper can subsequently be enabled/disabled without
23650 + * resetting the shaping parameters, but the shaping parameters will be reset
23651 + * when the LNI is released.
23652 + *
23653 + * Returns zero for success, or errno for "enable" function in the cases as:
23654 + * a) -EINVAL if the shaper is already enabled,
23655 + * b) -EIO if the configure shaper command returns error.
23656 + * For "disable" function, returns:
23657 + * a) -EINVAL if the shaper is has already disabled.
23658 + * b) -EIO if calling configure shaper command returns error.
23659 + */
23660 +int qman_ceetm_lni_enable_shaper(struct qm_ceetm_lni *lni, int coupled,
23661 + int oal);
23662 +int qman_ceetm_lni_disable_shaper(struct qm_ceetm_lni *lni);
23663 +
23664 +/**
23665 + * qman_ceetm_lni_is_shaper_enabled - Check LNI shaper status
23666 + * @lni: the give LNI
23667 + */
23668 +int qman_ceetm_lni_is_shaper_enabled(struct qm_ceetm_lni *lni);
23669 +
23670 +/**
23671 + * qman_ceetm_lni_set_commit_rate
23672 + * qman_ceetm_lni_get_commit_rate
23673 + * qman_ceetm_lni_set_excess_rate
23674 + * qman_ceetm_lni_get_excess_rate - Set/get the shaper CR/ER token rate and
23675 + * token limit for the given LNI.
23676 + * @lni: the given LNI.
23677 + * @token_rate: the desired token rate for "set" fuction, or the token rate of
23678 + * the LNI queried by "get" function.
23679 + * @token_limit: the desired token bucket limit for "set" function, or the token
23680 + * limit of the given LNI queried by "get" function.
23681 + *
23682 + * Returns zero for success. The "set" function returns -EINVAL if the given
23683 + * LNI is unshapped or -EIO if the configure shaper command returns error.
23684 + * The "get" function returns -EINVAL if the token rate or the token limit is
23685 + * not set or the query command returns error.
23686 + */
23687 +int qman_ceetm_lni_set_commit_rate(struct qm_ceetm_lni *lni,
23688 + const struct qm_ceetm_rate *token_rate,
23689 + u16 token_limit);
23690 +int qman_ceetm_lni_get_commit_rate(struct qm_ceetm_lni *lni,
23691 + struct qm_ceetm_rate *token_rate,
23692 + u16 *token_limit);
23693 +int qman_ceetm_lni_set_excess_rate(struct qm_ceetm_lni *lni,
23694 + const struct qm_ceetm_rate *token_rate,
23695 + u16 token_limit);
23696 +int qman_ceetm_lni_get_excess_rate(struct qm_ceetm_lni *lni,
23697 + struct qm_ceetm_rate *token_rate,
23698 + u16 *token_limit);
23699 +/**
23700 + * qman_ceetm_lni_set_commit_rate_bps
23701 + * qman_ceetm_lni_get_commit_rate_bps
23702 + * qman_ceetm_lni_set_excess_rate_bps
23703 + * qman_ceetm_lni_get_excess_rate_bps - Set/get the shaper CR/ER rate
23704 + * and token limit for the given LNI.
23705 + * @lni: the given LNI.
23706 + * @bps: the desired shaping rate in bps for "set" fuction, or the shaping rate
23707 + * of the LNI queried by "get" function.
23708 + * @token_limit: the desired token bucket limit for "set" function, or the token
23709 + * limit of the given LNI queried by "get" function.
23710 + *
23711 + * Returns zero for success. The "set" function returns -EINVAL if the given
23712 + * LNI is unshapped or -EIO if the configure shaper command returns error.
23713 + * The "get" function returns -EINVAL if the token rate or the token limit is
23714 + * not set or the query command returns error.
23715 + */
23716 +int qman_ceetm_lni_set_commit_rate_bps(struct qm_ceetm_lni *lni,
23717 + u64 bps,
23718 + u16 token_limit);
23719 +int qman_ceetm_lni_get_commit_rate_bps(struct qm_ceetm_lni *lni,
23720 + u64 *bps, u16 *token_limit);
23721 +int qman_ceetm_lni_set_excess_rate_bps(struct qm_ceetm_lni *lni,
23722 + u64 bps,
23723 + u16 token_limit);
23724 +int qman_ceetm_lni_get_excess_rate_bps(struct qm_ceetm_lni *lni,
23725 + u64 *bps, u16 *token_limit);
23726 +
23727 +/**
23728 + * qman_ceetm_lni_set_tcfcc
23729 + * qman_ceetm_lni_get_tcfcc - Configure/query "Traffic Class Flow Control".
23730 + * @lni: the given LNI.
23731 + * @cq_level: is between 0 and 15, representing individual class queue levels
23732 + * (CQ0 to CQ7 for every channel) and grouped class queue levels (CQ8 to CQ15
23733 + * for every channel).
23734 + * @traffic_class: is between 0 and 7 when associating a given class queue level
23735 + * to a traffic class, or -1 when disabling traffic class flow control for this
23736 + * class queue level.
23737 + *
23738 + * Return zero for success, or -EINVAL if the cq_level or traffic_class is out
23739 + * of range as indicated above, or -EIO if the configure/query tcfcc command
23740 + * returns error.
23741 + *
23742 + * Refer to the section of QMan CEETM traffic class flow control in the
23743 + * Reference Manual.
23744 + */
23745 +int qman_ceetm_lni_set_tcfcc(struct qm_ceetm_lni *lni,
23746 + unsigned int cq_level,
23747 + int traffic_class);
23748 +int qman_ceetm_lni_get_tcfcc(struct qm_ceetm_lni *lni,
23749 + unsigned int cq_level,
23750 + int *traffic_class);
23751 +
23752 + /* ----------------------------- */
23753 + /* CEETM :: class queue channels */
23754 + /* ----------------------------- */
23755 +
23756 +/**
23757 + * qman_ceetm_channel_claim - Claims an unclaimed CQ channel that is mapped to
23758 + * the given LNI.
23759 + * @channel: the returned class queue channel object, if successful.
23760 + * @lni: the LNI that the channel belongs to.
23761 + *
23762 + * Channels are always initially "unshaped".
23763 + *
23764 + * Return zero for success, or -ENODEV if there is no channel available(all 32
23765 + * channels are claimed) or -EINVAL if the channel mapping command returns
23766 + * error.
23767 + */
23768 +int qman_ceetm_channel_claim(struct qm_ceetm_channel **channel,
23769 + struct qm_ceetm_lni *lni);
23770 +
23771 +/**
23772 + * qman_ceetm_channel_release - Releases a previously claimed CQ channel.
23773 + * @channel: the channel needs to be released.
23774 + *
23775 + * Returns zero for success, or -EBUSY if the dependencies are still in use.
23776 + *
23777 + * Note any shaping of the channel will be cleared to leave it in an unshaped
23778 + * state.
23779 + */
23780 +int qman_ceetm_channel_release(struct qm_ceetm_channel *channel);
23781 +
23782 +/**
23783 + * qman_ceetm_channel_enable_shaper
23784 + * qman_ceetm_channel_disable_shaper - Enables/disables shaping on the channel.
23785 + * @channel: the given channel.
23786 + * @coupled: indicates whether surplus CR tokens should be added to the
23787 + * excess-rate token count (up to the excess-rate token limit) when the number
23788 + * of (unused) committed-rate tokens reach the committed_rate token limit.
23789 + *
23790 + * Whenever a claimed channel is first enabled for shaping, its committed and
23791 + * excess token rates and limits are zero, so will need to be changed to do
23792 + * anything useful. The shaper can subsequently be enabled/disabled without
23793 + * resetting the shaping parameters, but the shaping parameters will be reset
23794 + * when the channel is released.
23795 + *
23796 + * Return 0 for success, or -EINVAL for failure, in the case that the channel
23797 + * shaper has been enabled/disabled or the management command returns error.
23798 + */
23799 +int qman_ceetm_channel_enable_shaper(struct qm_ceetm_channel *channel,
23800 + int coupled);
23801 +int qman_ceetm_channel_disable_shaper(struct qm_ceetm_channel *channel);
23802 +
23803 +/**
23804 + * qman_ceetm_channel_is_shaper_enabled - Check channel shaper status.
23805 + * @channel: the give channel.
23806 + */
23807 +int qman_ceetm_channel_is_shaper_enabled(struct qm_ceetm_channel *channel);
23808 +
23809 +/**
23810 + * qman_ceetm_channel_set_commit_rate
23811 + * qman_ceetm_channel_get_commit_rate
23812 + * qman_ceetm_channel_set_excess_rate
23813 + * qman_ceetm_channel_get_excess_rate - Set/get channel CR/ER shaper parameters.
23814 + * @channel: the given channel.
23815 + * @token_rate: the desired token rate for "set" function, or the queried token
23816 + * rate for "get" function.
23817 + * @token_limit: the desired token limit for "set" function, or the queried
23818 + * token limit for "get" function.
23819 + *
23820 + * Return zero for success. The "set" function returns -EINVAL if the channel
23821 + * is unshaped, or -EIO if the configure shapper command returns error. The
23822 + * "get" function returns -EINVAL if token rate of token limit is not set, or
23823 + * the query shaper command returns error.
23824 + */
23825 +int qman_ceetm_channel_set_commit_rate(struct qm_ceetm_channel *channel,
23826 + const struct qm_ceetm_rate *token_rate,
23827 + u16 token_limit);
23828 +int qman_ceetm_channel_get_commit_rate(struct qm_ceetm_channel *channel,
23829 + struct qm_ceetm_rate *token_rate,
23830 + u16 *token_limit);
23831 +int qman_ceetm_channel_set_excess_rate(struct qm_ceetm_channel *channel,
23832 + const struct qm_ceetm_rate *token_rate,
23833 + u16 token_limit);
23834 +int qman_ceetm_channel_get_excess_rate(struct qm_ceetm_channel *channel,
23835 + struct qm_ceetm_rate *token_rate,
23836 + u16 *token_limit);
23837 +/**
23838 + * qman_ceetm_channel_set_commit_rate_bps
23839 + * qman_ceetm_channel_get_commit_rate_bps
23840 + * qman_ceetm_channel_set_excess_rate_bps
23841 + * qman_ceetm_channel_get_excess_rate_bps - Set/get channel CR/ER shaper
23842 + * parameters.
23843 + * @channel: the given channel.
23844 + * @token_rate: the desired shaper rate in bps for "set" function, or the
23845 + * shaper rate in bps for "get" function.
23846 + * @token_limit: the desired token limit for "set" function, or the queried
23847 + * token limit for "get" function.
23848 + *
23849 + * Return zero for success. The "set" function returns -EINVAL if the channel
23850 + * is unshaped, or -EIO if the configure shapper command returns error. The
23851 + * "get" function returns -EINVAL if token rate of token limit is not set, or
23852 + * the query shaper command returns error.
23853 + */
23854 +int qman_ceetm_channel_set_commit_rate_bps(struct qm_ceetm_channel *channel,
23855 + u64 bps, u16 token_limit);
23856 +int qman_ceetm_channel_get_commit_rate_bps(struct qm_ceetm_channel *channel,
23857 + u64 *bps, u16 *token_limit);
23858 +int qman_ceetm_channel_set_excess_rate_bps(struct qm_ceetm_channel *channel,
23859 + u64 bps, u16 token_limit);
23860 +int qman_ceetm_channel_get_excess_rate_bps(struct qm_ceetm_channel *channel,
23861 + u64 *bps, u16 *token_limit);
23862 +
23863 +/**
23864 + * qman_ceetm_channel_set_weight
23865 + * qman_ceetm_channel_get_weight - Set/get the weight for unshaped channel
23866 + * @channel: the given channel.
23867 + * @token_limit: the desired token limit as the weight of the unshaped channel
23868 + * for "set" function, or the queried token limit for "get" function.
23869 + *
23870 + * The algorithm of unshaped fair queuing (uFQ) is used for unshaped channel.
23871 + * It allows the unshaped channels to be included in the CR time eligible list,
23872 + * and thus use the configured CR token limit value as their fair queuing
23873 + * weight.
23874 + *
23875 + * Return zero for success, or -EINVAL if the channel is a shaped channel or
23876 + * the management command returns error.
23877 + */
23878 +int qman_ceetm_channel_set_weight(struct qm_ceetm_channel *channel,
23879 + u16 token_limit);
23880 +int qman_ceetm_channel_get_weight(struct qm_ceetm_channel *channel,
23881 + u16 *token_limit);
23882 +
23883 +/**
23884 + * qman_ceetm_channel_set_group
23885 + * qman_ceetm_channel_get_group - Set/get the grouping of the class scheduler.
23886 + * @channel: the given channel.
23887 + * @group_b: indicates whether there is group B in this channel.
23888 + * @prio_a: the priority of group A.
23889 + * @prio_b: the priority of group B.
23890 + *
23891 + * There are 8 individual class queues (CQ0-CQ7), and 8 grouped class queues
23892 + * (CQ8-CQ15). If 'group_b' is zero, then all the grouped class queues are in
23893 + * group A, otherwise they are split into group A (CQ8-11) and group B
23894 + * (CQ12-C15). The individual class queues and the group(s) are in strict
23895 + * priority order relative to each other. Within the group(s), the scheduling
23896 + * is not strict priority order, but the result of scheduling within a group
23897 + * is in strict priority order relative to the other class queues in the
23898 + * channel. 'prio_a' and 'prio_b' control the priority order of the groups
23899 + * relative to the individual class queues, and take values from 0-7. Eg. if
23900 + * 'group_b' is non-zero, 'prio_a' is 2 and 'prio_b' is 6, then the strict
23901 + * priority order would be;
23902 + * CQ0, CQ1, CQ2, GROUPA, CQ3, CQ4, CQ5, CQ6, GROUPB, CQ7
23903 + *
23904 + * Return 0 for success. For "set" function, returns -EINVAL if prio_a or
23905 + * prio_b are out of the range 0 - 7 (priority of group A or group B can not
23906 + * be 0, CQ0 is always the highest class queue in this channel.), or -EIO if
23907 + * the configure scheduler command returns error. For "get" function, return
23908 + * -EINVAL if the query scheduler command returns error.
23909 + */
23910 +int qman_ceetm_channel_set_group(struct qm_ceetm_channel *channel,
23911 + int group_b,
23912 + unsigned int prio_a,
23913 + unsigned int prio_b);
23914 +int qman_ceetm_channel_get_group(struct qm_ceetm_channel *channel,
23915 + int *group_b,
23916 + unsigned int *prio_a,
23917 + unsigned int *prio_b);
23918 +
23919 +/**
23920 + * qman_ceetm_channel_set_group_cr_eligibility
23921 + * qman_ceetm_channel_set_group_er_eligibility - Set channel group eligibility
23922 + * @channel: the given channel object
23923 + * @group_b: indicates whether there is group B in this channel.
23924 + * @cre: the commit rate eligibility, 1 for enable, 0 for disable.
23925 + *
23926 + * Return zero for success, or -EINVAL if eligibility setting fails.
23927 +*/
23928 +int qman_ceetm_channel_set_group_cr_eligibility(struct qm_ceetm_channel
23929 + *channel, int group_b, int cre);
23930 +int qman_ceetm_channel_set_group_er_eligibility(struct qm_ceetm_channel
23931 + *channel, int group_b, int ere);
23932 +
23933 +/**
23934 + * qman_ceetm_channel_set_cq_cr_eligibility
23935 + * qman_ceetm_channel_set_cq_er_eligibility - Set channel cq eligibility
23936 + * @channel: the given channel object
23937 + * @idx: is from 0 to 7 (representing CQ0 to CQ7).
23938 + * @cre: the commit rate eligibility, 1 for enable, 0 for disable.
23939 + *
23940 + * Return zero for success, or -EINVAL if eligibility setting fails.
23941 +*/
23942 +int qman_ceetm_channel_set_cq_cr_eligibility(struct qm_ceetm_channel *channel,
23943 + unsigned int idx, int cre);
23944 +int qman_ceetm_channel_set_cq_er_eligibility(struct qm_ceetm_channel *channel,
23945 + unsigned int idx, int ere);
23946 +
23947 + /* --------------------- */
23948 + /* CEETM :: class queues */
23949 + /* --------------------- */
23950 +
23951 +/**
23952 + * qman_ceetm_cq_claim - Claims an individual class queue.
23953 + * @cq: the returned class queue object, if successful.
23954 + * @channel: the class queue channel.
23955 + * @idx: is from 0 to 7 (representing CQ0 to CQ7).
23956 + * @ccg: represents the class congestion group that this class queue should be
23957 + * subscribed to, or NULL if no congestion group membership is desired.
23958 + *
23959 + * Returns zero for success, or -EINVAL if @idx is out of range 0 - 7 or
23960 + * if this class queue has been claimed, or configure class queue command
23961 + * returns error, or returns -ENOMEM if allocating CQ memory fails.
23962 + */
23963 +int qman_ceetm_cq_claim(struct qm_ceetm_cq **cq,
23964 + struct qm_ceetm_channel *channel,
23965 + unsigned int idx,
23966 + struct qm_ceetm_ccg *ccg);
23967 +
23968 +/**
23969 + * qman_ceetm_cq_claim_A - Claims a class queue group A.
23970 + * @cq: the returned class queue object, if successful.
23971 + * @channel: the class queue channel.
23972 + * @idx: is from 8 to 15 if only group A exits, otherwise, it is from 8 to 11.
23973 + * @ccg: represents the class congestion group that this class queue should be
23974 + * subscribed to, or NULL if no congestion group membership is desired.
23975 + *
23976 + * Return zero for success, or -EINVAL if @idx is out the range or if
23977 + * this class queue has been claimed or configure class queue command returns
23978 + * error, or returns -ENOMEM if allocating CQ memory fails.
23979 + */
23980 +int qman_ceetm_cq_claim_A(struct qm_ceetm_cq **cq,
23981 + struct qm_ceetm_channel *channel,
23982 + unsigned int idx,
23983 + struct qm_ceetm_ccg *ccg);
23984 +
23985 +/**
23986 + * qman_ceetm_cq_claim_B - Claims a class queue group B.
23987 + * @cq: the returned class queue object, if successful.
23988 + * @channel: the class queue channel.
23989 + * @idx: is from 0 to 3 (CQ12 to CQ15).
23990 + * @ccg: represents the class congestion group that this class queue should be
23991 + * subscribed to, or NULL if no congestion group membership is desired.
23992 + *
23993 + * Return zero for success, or -EINVAL if @idx is out the range or if
23994 + * this class queue has been claimed or configure class queue command returns
23995 + * error, or returns -ENOMEM if allocating CQ memory fails.
23996 + */
23997 +int qman_ceetm_cq_claim_B(struct qm_ceetm_cq **cq,
23998 + struct qm_ceetm_channel *channel,
23999 + unsigned int idx,
24000 + struct qm_ceetm_ccg *ccg);
24001 +
24002 +/**
24003 + * qman_ceetm_cq_release - Releases a previously claimed class queue.
24004 + * @cq: The class queue to be released.
24005 + *
24006 + * Return zero for success, or -EBUSY if the dependent objects (eg. logical
24007 + * FQIDs) have not been released.
24008 + */
24009 +int qman_ceetm_cq_release(struct qm_ceetm_cq *cq);
24010 +
24011 +/**
24012 + * qman_ceetm_set_queue_weight
24013 + * qman_ceetm_get_queue_weight - Configure/query the weight of a grouped class
24014 + * queue.
24015 + * @cq: the given class queue.
24016 + * @weight_code: the desired weight code to set for the given class queue for
24017 + * "set" function or the queired weight code for "get" function.
24018 + *
24019 + * Grouped class queues have a default weight code of zero, which corresponds to
24020 + * a scheduler weighting of 1. This function can be used to modify a grouped
24021 + * class queue to another weight, (Use the helpers qman_ceetm_wbfs2ratio()
24022 + * and qman_ceetm_ratio2wbfs() to convert between these 'weight_code' values
24023 + * and the corresponding sharing weight.)
24024 + *
24025 + * Returns zero for success, or -EIO if the configure weight command returns
24026 + * error for "set" function, or -EINVAL if the query command returns
24027 + * error for "get" function.
24028 + * See section "CEETM Weighted Scheduling among Grouped Classes" in Reference
24029 + * Manual for weight and weight code.
24030 + */
24031 +int qman_ceetm_set_queue_weight(struct qm_ceetm_cq *cq,
24032 + struct qm_ceetm_weight_code *weight_code);
24033 +int qman_ceetm_get_queue_weight(struct qm_ceetm_cq *cq,
24034 + struct qm_ceetm_weight_code *weight_code);
24035 +
24036 +/**
24037 + * qman_ceetm_set_queue_weight_in_ratio
24038 + * qman_ceetm_get_queue_weight_in_ratio - Configure/query the weight of a
24039 + * grouped class queue.
24040 + * @cq: the given class queue.
24041 + * @ratio: the weight in ratio. It should be the real ratio number multiplied
24042 + * by 100 to get rid of fraction.
24043 + *
24044 + * Returns zero for success, or -EIO if the configure weight command returns
24045 + * error for "set" function, or -EINVAL if the query command returns
24046 + * error for "get" function.
24047 + */
24048 +int qman_ceetm_set_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 ratio);
24049 +int qman_ceetm_get_queue_weight_in_ratio(struct qm_ceetm_cq *cq, u32 *ratio);
24050 +
24051 +/* Weights are encoded using a pseudo-exponential scheme. The weight codes 0,
24052 + * 32, 64, [...] correspond to weights of 1, 2, 4, [...]. The weights
24053 + * corresponding to intermediate weight codes are calculated using linear
24054 + * interpolation on the inverted values. Or put another way, the inverse weights
24055 + * for each 32nd weight code are 1, 1/2, 1/4, [...], and so the intervals
24056 + * between these are divided linearly into 32 intermediate values, the inverses
24057 + * of which form the remaining weight codes.
24058 + *
24059 + * The Weighted Bandwidth Fair Scheduling (WBFS) algorithm provides a form of
24060 + * scheduling within a group of class queues (group A or B). Weights are used to
24061 + * normalise the class queues to an underlying BFS algorithm where all class
24062 + * queues are assumed to require "equal bandwidth". So the weights referred to
24063 + * by the weight codes act as divisors on the size of frames being enqueued. Ie.
24064 + * one class queue in a group is assigned a weight of 2 whilst the other class
24065 + * queues in the group keep the default weight of 1, then the WBFS scheduler
24066 + * will effectively treat all frames enqueued on the weight-2 class queue as
24067 + * having half the number of bytes they really have. Ie. if all other things are
24068 + * equal, that class queue would get twice as much bytes-per-second bandwidth as
24069 + * the others. So weights should be chosen to provide bandwidth ratios between
24070 + * members of the same class queue group. These weights have no bearing on
24071 + * behaviour outside that group's WBFS mechanism though.
24072 + */
24073 +
24074 +/**
24075 + * qman_ceetm_wbfs2ratio - Given a weight code ('wbfs'), an accurate fractional
24076 + * representation of the corresponding weight is given (in order to not lose
24077 + * any precision).
24078 + * @weight_code: The given weight code in WBFS.
24079 + * @numerator: the numerator part of the weight computed by the weight code.
24080 + * @denominator: the denominator part of the weight computed by the weight code
24081 + *
24082 + * Returns zero for success or -EINVAL if the given weight code is illegal.
24083 + */
24084 +int qman_ceetm_wbfs2ratio(struct qm_ceetm_weight_code *weight_code,
24085 + u32 *numerator,
24086 + u32 *denominator);
24087 +/**
24088 + * qman_ceetm_ratio2wbfs - Given a weight, find the nearest possible weight code
24089 + * If the user needs to know how close this is, convert the resulting weight
24090 + * code back to a weight and compare.
24091 + * @numerator: numerator part of the given weight.
24092 + * @denominator: denominator part of the given weight.
24093 + * @weight_code: the weight code computed from the given weight.
24094 + *
24095 + * Returns zero for success, or -ERANGE if "numerator/denominator" is outside
24096 + * the range of weights.
24097 + */
24098 +int qman_ceetm_ratio2wbfs(u32 numerator,
24099 + u32 denominator,
24100 + struct qm_ceetm_weight_code *weight_code,
24101 + int rounding);
24102 +
24103 +#define QMAN_CEETM_FLAG_CLEAR_STATISTICS_COUNTER 0x1
24104 +/**
24105 + * qman_ceetm_cq_get_dequeue_statistics - Get the statistics provided by CEETM
24106 + * CQ counters.
24107 + * @cq: the given CQ object.
24108 + * @flags: indicates whether the statistics counter will be cleared after query.
24109 + * @frame_count: The number of the frames that have been counted since the
24110 + * counter was cleared last time.
24111 + * @byte_count: the number of bytes in all frames that have been counted.
24112 + *
24113 + * Return zero for success or -EINVAL if query statistics command returns error.
24114 + *
24115 + */
24116 +int qman_ceetm_cq_get_dequeue_statistics(struct qm_ceetm_cq *cq, u32 flags,
24117 + u64 *frame_count, u64 *byte_count);
24118 +
24119 +/**
24120 + * qman_ceetm_drain_cq - drain the CQ till it is empty.
24121 + * @cq: the give CQ object.
24122 + * Return 0 for success or -EINVAL for unsuccessful command to empty CQ.
24123 + */
24124 +int qman_ceetm_drain_cq(struct qm_ceetm_cq *cq);
24125 +
24126 + /* ---------------------- */
24127 + /* CEETM :: logical FQIDs */
24128 + /* ---------------------- */
24129 +/**
24130 + * qman_ceetm_lfq_claim - Claims an unused logical FQID, associates it with
24131 + * the given class queue.
24132 + * @lfq: the returned lfq object, if successful.
24133 + * @cq: the class queue which needs to claim a LFQID.
24134 + *
24135 + * Return zero for success, or -ENODEV if no LFQID is available or -ENOMEM if
24136 + * allocating memory for lfq fails, or -EINVAL if configuring LFQMT fails.
24137 + */
24138 +int qman_ceetm_lfq_claim(struct qm_ceetm_lfq **lfq,
24139 + struct qm_ceetm_cq *cq);
24140 +
24141 +/**
24142 + * qman_ceetm_lfq_release - Releases a previously claimed logical FQID.
24143 + * @lfq: the lfq to be released.
24144 + *
24145 + * Return zero for success.
24146 + */
24147 +int qman_ceetm_lfq_release(struct qm_ceetm_lfq *lfq);
24148 +
24149 +/**
24150 + * qman_ceetm_lfq_set_context
24151 + * qman_ceetm_lfq_get_context - Set/get the context_a/context_b pair to the
24152 + * "dequeue context table" associated with the logical FQID.
24153 + * @lfq: the given logical FQ object.
24154 + * @context_a: contextA of the dequeue context.
24155 + * @context_b: contextB of the dequeue context.
24156 + *
24157 + * Returns zero for success, or -EINVAL if there is error to set/get the
24158 + * context pair.
24159 + */
24160 +int qman_ceetm_lfq_set_context(struct qm_ceetm_lfq *lfq,
24161 + u64 context_a,
24162 + u32 context_b);
24163 +int qman_ceetm_lfq_get_context(struct qm_ceetm_lfq *lfq,
24164 + u64 *context_a,
24165 + u32 *context_b);
24166 +
24167 +/**
24168 + * qman_ceetm_create_fq - Initialise a FQ object for the LFQ.
24169 + * @lfq: the given logic fq.
24170 + * @fq: the fq object created for the given logic fq.
24171 + *
24172 + * The FQ object can be used in qman_enqueue() and qman_enqueue_orp() APIs to
24173 + * target a logical FQID (and the class queue it is associated with).
24174 + * Note that this FQ object can only be used for enqueues, and
24175 + * in the case of qman_enqueue_orp() it can not be used as the 'orp' parameter,
24176 + * only as 'fq'. This FQ object can not (and shouldn't) be destroyed, it is only
24177 + * valid as long as the underlying 'lfq' remains claimed. It is the user's
24178 + * responsibility to ensure that the underlying 'lfq' is not released until any
24179 + * enqueues to this FQ object have completed. The only field the user needs to
24180 + * fill in is fq->cb.ern, as that enqueue rejection handler is the callback that
24181 + * could conceivably be called on this FQ object. This API can be called
24182 + * multiple times to create multiple FQ objects referring to the same logical
24183 + * FQID, and any enqueue rejections will respect the callback of the object that
24184 + * issued the enqueue (and will identify the object via the parameter passed to
24185 + * the callback too). There is no 'flags' parameter to this API as there is for
24186 + * qman_create_fq() - the created FQ object behaves as though qman_create_fq()
24187 + * had been called with the single flag QMAN_FQ_FLAG_NO_MODIFY.
24188 + *
24189 + * Returns 0 for success.
24190 + */
24191 +int qman_ceetm_create_fq(struct qm_ceetm_lfq *lfq, struct qman_fq *fq);
24192 +
24193 + /* -------------------------------- */
24194 + /* CEETM :: class congestion groups */
24195 + /* -------------------------------- */
24196 +
24197 +/**
24198 + * qman_ceetm_ccg_claim - Claims an unused CCG.
24199 + * @ccg: the returned CCG object, if successful.
24200 + * @channel: the given class queue channel
24201 + * @cscn: the callback function of this CCG.
24202 + * @cb_ctx: the corresponding context to be used used if state change
24203 + * notifications are later enabled for this CCG.
24204 + *
24205 + * The congestion group is local to the given class queue channel, so only
24206 + * class queues within the channel can be associated with that congestion group.
24207 + * The association of class queues to congestion groups occurs when the class
24208 + * queues are claimed, see qman_ceetm_cq_claim() and related functions.
24209 + * Congestion groups are in a "zero" state when initially claimed, and they are
24210 + * returned to that state when released.
24211 + *
24212 + * Return zero for success, or -EINVAL if no CCG in the channel is available.
24213 + */
24214 +int qman_ceetm_ccg_claim(struct qm_ceetm_ccg **ccg,
24215 + struct qm_ceetm_channel *channel,
24216 + unsigned int idx,
24217 + void (*cscn)(struct qm_ceetm_ccg *,
24218 + void *cb_ctx,
24219 + int congested),
24220 + void *cb_ctx);
24221 +
24222 +/**
24223 + * qman_ceetm_ccg_release - Releases a previously claimed CCG.
24224 + * @ccg: the given ccg.
24225 + *
24226 + * Returns zero for success, or -EBUSY if the given ccg's dependent objects
24227 + * (class queues that are associated with the CCG) have not been released.
24228 + */
24229 +int qman_ceetm_ccg_release(struct qm_ceetm_ccg *ccg);
24230 +
24231 +/* This struct is used to specify attributes for a CCG. The 'we_mask' field
24232 + * controls which CCG attributes are to be updated, and the remainder specify
24233 + * the values for those attributes. A CCG counts either frames or the bytes
24234 + * within those frames, but not both ('mode'). A CCG can optionally cause
24235 + * enqueues to be rejected, due to tail-drop or WRED, or both (they are
24236 + * independent options, 'td_en' and 'wr_en_g,wr_en_y,wr_en_r'). Tail-drop can be
24237 + * level-triggered due to a single threshold ('td_thres') or edge-triggered due
24238 + * to a "congestion state", but not both ('td_mode'). Congestion state has
24239 + * distinct entry and exit thresholds ('cs_thres_in' and 'cs_thres_out'), and
24240 + * notifications can be sent to software the CCG goes in to and out of this
24241 + * congested state ('cscn_en'). */
24242 +struct qm_ceetm_ccg_params {
24243 + /* Boolean fields together in a single bitfield struct */
24244 + struct {
24245 + /* Whether to count bytes or frames. 1==frames */
24246 + u8 mode:1;
24247 + /* En/disable tail-drop. 1==enable */
24248 + u8 td_en:1;
24249 + /* Tail-drop on congestion-state or threshold. 1=threshold */
24250 + u8 td_mode:1;
24251 + /* Generate congestion state change notifications. 1==enable */
24252 + u8 cscn_en:1;
24253 + /* Enable WRED rejections (per colour). 1==enable */
24254 + u8 wr_en_g:1;
24255 + u8 wr_en_y:1;
24256 + u8 wr_en_r:1;
24257 + } __packed;
24258 + /* Tail-drop threshold. See qm_cgr_thres_[gs]et64(). */
24259 + struct qm_cgr_cs_thres td_thres;
24260 + /* Congestion state thresholds, for entry and exit. */
24261 + struct qm_cgr_cs_thres cs_thres_in;
24262 + struct qm_cgr_cs_thres cs_thres_out;
24263 + /* Overhead accounting length. Per-packet "tax", from -128 to +127 */
24264 + signed char oal;
24265 + /* Congestion state change notification for DCP portal, virtual CCGID*/
24266 + /* WRED parameters. */
24267 + struct qm_cgr_wr_parm wr_parm_g;
24268 + struct qm_cgr_wr_parm wr_parm_y;
24269 + struct qm_cgr_wr_parm wr_parm_r;
24270 +};
24271 +/* Bits used in 'we_mask' to qman_ceetm_ccg_set(), controls which attributes of
24272 + * the CCGR are to be updated. */
24273 +#define QM_CCGR_WE_MODE 0x0001 /* mode (bytes/frames) */
24274 +#define QM_CCGR_WE_CS_THRES_IN 0x0002 /* congestion state entry threshold */
24275 +#define QM_CCGR_WE_TD_EN 0x0004 /* congestion state tail-drop enable */
24276 +#define QM_CCGR_WE_CSCN_TUPD 0x0008 /* CSCN target update */
24277 +#define QM_CCGR_WE_CSCN_EN 0x0010 /* congestion notification enable */
24278 +#define QM_CCGR_WE_WR_EN_R 0x0020 /* WRED enable - red */
24279 +#define QM_CCGR_WE_WR_EN_Y 0x0040 /* WRED enable - yellow */
24280 +#define QM_CCGR_WE_WR_EN_G 0x0080 /* WRED enable - green */
24281 +#define QM_CCGR_WE_WR_PARM_R 0x0100 /* WRED parameters - red */
24282 +#define QM_CCGR_WE_WR_PARM_Y 0x0200 /* WRED parameters - yellow */
24283 +#define QM_CCGR_WE_WR_PARM_G 0x0400 /* WRED parameters - green */
24284 +#define QM_CCGR_WE_OAL 0x0800 /* overhead accounting length */
24285 +#define QM_CCGR_WE_CS_THRES_OUT 0x1000 /* congestion state exit threshold */
24286 +#define QM_CCGR_WE_TD_THRES 0x2000 /* tail-drop threshold */
24287 +#define QM_CCGR_WE_TD_MODE 0x4000 /* tail-drop mode (state/threshold) */
24288 +#define QM_CCGR_WE_CDV 0x8000 /* cdv */
24289 +
24290 +/**
24291 + * qman_ceetm_ccg_set
24292 + * qman_ceetm_ccg_get - Configure/query a subset of CCG attributes.
24293 + * @ccg: the given CCG object.
24294 + * @we_mask: the write enable mask.
24295 + * @params: the parameters setting for this ccg
24296 + *
24297 + * Return 0 for success, or -EIO if configure ccg command returns error for
24298 + * "set" function, or -EINVAL if query ccg command returns error for "get"
24299 + * function.
24300 + */
24301 +int qman_ceetm_ccg_set(struct qm_ceetm_ccg *ccg,
24302 + u16 we_mask,
24303 + const struct qm_ceetm_ccg_params *params);
24304 +int qman_ceetm_ccg_get(struct qm_ceetm_ccg *ccg,
24305 + struct qm_ceetm_ccg_params *params);
24306 +
24307 +/** qman_ceetm_cscn_swp_set - Add or remove a software portal from the target
24308 + * mask.
24309 + * qman_ceetm_cscn_swp_get - Query whether a given software portal index is
24310 + * in the cscn target mask.
24311 + * @ccg: the give CCG object.
24312 + * @swp_idx: the index of the software portal.
24313 + * @cscn_enabled: 1: Set the swp to be cscn target. 0: remove the swp from
24314 + * the target mask.
24315 + * @we_mask: the write enable mask.
24316 + * @params: the parameters setting for this ccg
24317 + *
24318 + * Return 0 for success, or -EINVAL if command in set/get function fails.
24319 + */
24320 +int qman_ceetm_cscn_swp_set(struct qm_ceetm_ccg *ccg,
24321 + u16 swp_idx,
24322 + unsigned int cscn_enabled,
24323 + u16 we_mask,
24324 + const struct qm_ceetm_ccg_params *params);
24325 +int qman_ceetm_cscn_swp_get(struct qm_ceetm_ccg *ccg,
24326 + u16 swp_idx,
24327 + unsigned int *cscn_enabled);
24328 +
24329 +/** qman_ceetm_cscn_dcp_set - Add or remove a direct connect portal from the\
24330 + * target mask.
24331 + * qman_ceetm_cscn_swp_get - Query whether a given direct connect portal index
24332 + * is in the cscn target mask.
24333 + * @ccg: the give CCG object.
24334 + * @dcp_idx: the index of the direct connect portal.
24335 + * @vcgid: congestion state change notification for dcp portal, virtual CGID.
24336 + * @cscn_enabled: 1: Set the dcp to be cscn target. 0: remove the dcp from
24337 + * the target mask.
24338 + * @we_mask: the write enable mask.
24339 + * @params: the parameters setting for this ccg
24340 + *
24341 + * Return 0 for success, or -EINVAL if command in set/get function fails.
24342 + */
24343 +int qman_ceetm_cscn_dcp_set(struct qm_ceetm_ccg *ccg,
24344 + u16 dcp_idx,
24345 + u8 vcgid,
24346 + unsigned int cscn_enabled,
24347 + u16 we_mask,
24348 + const struct qm_ceetm_ccg_params *params);
24349 +int qman_ceetm_cscn_dcp_get(struct qm_ceetm_ccg *ccg,
24350 + u16 dcp_idx,
24351 + u8 *vcgid,
24352 + unsigned int *cscn_enabled);
24353 +
24354 +/**
24355 + * qman_ceetm_ccg_get_reject_statistics - Get the statistics provided by
24356 + * CEETM CCG counters.
24357 + * @ccg: the given CCG object.
24358 + * @flags: indicates whether the statistics counter will be cleared after query.
24359 + * @frame_count: The number of the frames that have been counted since the
24360 + * counter was cleared last time.
24361 + * @byte_count: the number of bytes in all frames that have been counted.
24362 + *
24363 + * Return zero for success or -EINVAL if query statistics command returns error.
24364 + *
24365 + */
24366 +int qman_ceetm_ccg_get_reject_statistics(struct qm_ceetm_ccg *ccg, u32 flags,
24367 + u64 *frame_count, u64 *byte_count);
24368 +
24369 +/**
24370 + * qman_ceetm_query_lfqmt - Query the logical frame queue mapping table
24371 + * @lfqid: Logical Frame Queue ID
24372 + * @lfqmt_query: Results of the query command
24373 + *
24374 + * Returns zero for success or -EIO if the query command returns error.
24375 + *
24376 + */
24377 +int qman_ceetm_query_lfqmt(int lfqid,
24378 + struct qm_mcr_ceetm_lfqmt_query *lfqmt_query);
24379 +
24380 +/**
24381 + * qman_ceetm_query_write_statistics - Query (and optionally write) statistics
24382 + * @cid: Target ID (CQID or CCGRID)
24383 + * @dcp_idx: CEETM portal ID
24384 + * @command_type: One of the following:
24385 + * 0 = Query dequeue statistics. CID carries the CQID to be queried.
24386 + * 1 = Query and clear dequeue statistics. CID carries the CQID to be queried
24387 + * 2 = Write dequeue statistics. CID carries the CQID to be written.
24388 + * 3 = Query reject statistics. CID carries the CCGRID to be queried.
24389 + * 4 = Query and clear reject statistics. CID carries the CCGRID to be queried
24390 + * 5 = Write reject statistics. CID carries the CCGRID to be written
24391 + * @frame_count: Frame count value to be written if this is a write command
24392 + * @byte_count: Bytes count value to be written if this is a write command
24393 + *
24394 + * Returns zero for success or -EIO if the query command returns error.
24395 + */
24396 +int qman_ceetm_query_write_statistics(u16 cid, enum qm_dc_portal dcp_idx,
24397 + u16 command_type, u64 frame_count,
24398 + u64 byte_count);
24399 +
24400 +/**
24401 + * qman_set_wpm - Set waterfall power management
24402 + *
24403 + * @wpm_enable: boolean, 1 = enable wpm, 0 = disable wpm.
24404 + *
24405 + * Return 0 for success, return -ENODEV if QMan misc_cfg register is not
24406 + * accessible.
24407 + */
24408 +int qman_set_wpm(int wpm_enable);
24409 +
24410 +/**
24411 + * qman_get_swp - Query the waterfall power management setting
24412 + *
24413 + * @wpm_enable: boolean, 1 = enable wpm, 0 = disable wpm.
24414 + *
24415 + * Return 0 for success, return -ENODEV if QMan misc_cfg register is not
24416 + * accessible.
24417 + */
24418 +int qman_get_wpm(int *wpm_enable);
24419 +
24420 +/* The below qman_p_***() variants might be called in a migration situation
24421 + * (e.g. cpu hotplug). They are used to continue accessing the portal that
24422 + * execution was affine to prior to migration.
24423 + * @qman_portal specifies which portal the APIs will use.
24424 +*/
24425 +const struct qman_portal_config *qman_p_get_portal_config(struct qman_portal
24426 + *p);
24427 +int qman_p_irqsource_add(struct qman_portal *p, u32 bits);
24428 +int qman_p_irqsource_remove(struct qman_portal *p, u32 bits);
24429 +int qman_p_poll_dqrr(struct qman_portal *p, unsigned int limit);
24430 +u32 qman_p_poll_slow(struct qman_portal *p);
24431 +void qman_p_poll(struct qman_portal *p);
24432 +void qman_p_stop_dequeues(struct qman_portal *p);
24433 +void qman_p_start_dequeues(struct qman_portal *p);
24434 +void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools);
24435 +void qman_p_static_dequeue_del(struct qman_portal *p, u32 pools);
24436 +u32 qman_p_static_dequeue_get(struct qman_portal *p);
24437 +void qman_p_dca(struct qman_portal *p, struct qm_dqrr_entry *dq,
24438 + int park_request);
24439 +int qman_p_volatile_dequeue(struct qman_portal *p, struct qman_fq *fq,
24440 + u32 flags __maybe_unused, u32 vdqcr);
24441 +int qman_p_enqueue(struct qman_portal *p, struct qman_fq *fq,
24442 + const struct qm_fd *fd, u32 flags);
24443 +int qman_p_enqueue_orp(struct qman_portal *p, struct qman_fq *fq,
24444 + const struct qm_fd *fd, u32 flags,
24445 + struct qman_fq *orp, u16 orp_seqnum);
24446 +int qman_p_enqueue_precommit(struct qman_portal *p, struct qman_fq *fq,
24447 + const struct qm_fd *fd, u32 flags,
24448 + qman_cb_precommit cb, void *cb_arg);
24449 +#ifdef __cplusplus
24450 +}
24451 +#endif
24452 +
24453 +#endif /* FSL_QMAN_H */
24454 --- /dev/null
24455 +++ b/include/linux/fsl_usdpaa.h
24456 @@ -0,0 +1,372 @@
24457 +/* Copyright 2011-2012 Freescale Semiconductor, Inc.
24458 + *
24459 + * This file is licensed under the terms of the GNU General Public License
24460 + * version 2. This program is licensed "as is" without any warranty of any
24461 + * kind, whether express or implied.
24462 + */
24463 +
24464 +#ifndef FSL_USDPAA_H
24465 +#define FSL_USDPAA_H
24466 +
24467 +#ifdef __cplusplus
24468 +extern "C" {
24469 +#endif
24470 +
24471 +#include <linux/uaccess.h>
24472 +#include <linux/ioctl.h>
24473 +#include <linux/fsl_qman.h> /* For "enum qm_channel" */
24474 +#include <linux/compat.h>
24475 +
24476 +#ifdef CONFIG_FSL_USDPAA
24477 +
24478 +/******************************/
24479 +/* Allocation of resource IDs */
24480 +/******************************/
24481 +
24482 +/* This enum is used to distinguish between the type of underlying object being
24483 + * manipulated. */
24484 +enum usdpaa_id_type {
24485 + usdpaa_id_fqid,
24486 + usdpaa_id_bpid,
24487 + usdpaa_id_qpool,
24488 + usdpaa_id_cgrid,
24489 + usdpaa_id_ceetm0_lfqid,
24490 + usdpaa_id_ceetm0_channelid,
24491 + usdpaa_id_ceetm1_lfqid,
24492 + usdpaa_id_ceetm1_channelid,
24493 + usdpaa_id_max /* <-- not a valid type, represents the number of types */
24494 +};
24495 +#define USDPAA_IOCTL_MAGIC 'u'
24496 +struct usdpaa_ioctl_id_alloc {
24497 + uint32_t base; /* Return value, the start of the allocated range */
24498 + enum usdpaa_id_type id_type; /* what kind of resource(s) to allocate */
24499 + uint32_t num; /* how many IDs to allocate (and return value) */
24500 + uint32_t align; /* must be a power of 2, 0 is treated like 1 */
24501 + int partial; /* whether to allow less than 'num' */
24502 +};
24503 +struct usdpaa_ioctl_id_release {
24504 + /* Input; */
24505 + enum usdpaa_id_type id_type;
24506 + uint32_t base;
24507 + uint32_t num;
24508 +};
24509 +struct usdpaa_ioctl_id_reserve {
24510 + enum usdpaa_id_type id_type;
24511 + uint32_t base;
24512 + uint32_t num;
24513 +};
24514 +
24515 +
24516 +/* ioctl() commands */
24517 +#define USDPAA_IOCTL_ID_ALLOC \
24518 + _IOWR(USDPAA_IOCTL_MAGIC, 0x01, struct usdpaa_ioctl_id_alloc)
24519 +#define USDPAA_IOCTL_ID_RELEASE \
24520 + _IOW(USDPAA_IOCTL_MAGIC, 0x02, struct usdpaa_ioctl_id_release)
24521 +#define USDPAA_IOCTL_ID_RESERVE \
24522 + _IOW(USDPAA_IOCTL_MAGIC, 0x0A, struct usdpaa_ioctl_id_reserve)
24523 +
24524 +/**********************/
24525 +/* Mapping DMA memory */
24526 +/**********************/
24527 +
24528 +/* Maximum length for a map name, including NULL-terminator */
24529 +#define USDPAA_DMA_NAME_MAX 16
24530 +/* Flags for requesting DMA maps. Maps are private+unnamed or sharable+named.
24531 + * For a sharable and named map, specify _SHARED (whether creating one or
24532 + * binding to an existing one). If _SHARED is specified and _CREATE is not, then
24533 + * the mapping must already exist. If _SHARED and _CREATE are specified and the
24534 + * mapping doesn't already exist, it will be created. If _SHARED and _CREATE are
24535 + * specified and the mapping already exists, the mapping will fail unless _LAZY
24536 + * is specified. When mapping to a pre-existing sharable map, the length must be
24537 + * an exact match. Lengths must be a power-of-4 multiple of page size.
24538 + *
24539 + * Note that this does not actually map the memory to user-space, that is done
24540 + * by a subsequent mmap() using the page offset returned from this ioctl(). The
24541 + * ioctl() is what gives the process permission to do this, and a page-offset
24542 + * with which to do so.
24543 + */
24544 +#define USDPAA_DMA_FLAG_SHARE 0x01
24545 +#define USDPAA_DMA_FLAG_CREATE 0x02
24546 +#define USDPAA_DMA_FLAG_LAZY 0x04
24547 +#define USDPAA_DMA_FLAG_RDONLY 0x08
24548 +struct usdpaa_ioctl_dma_map {
24549 + /* Output parameters - virtual and physical addresses */
24550 + void *ptr;
24551 + uint64_t phys_addr;
24552 + /* Input parameter, the length of the region to be created (or if
24553 + * mapping an existing region, this must match it). Must be a power-of-4
24554 + * multiple of page size. */
24555 + uint64_t len;
24556 + /* Input parameter, the USDPAA_DMA_FLAG_* settings. */
24557 + uint32_t flags;
24558 + /* If _FLAG_SHARE is specified, the name of the region to be created (or
24559 + * of the existing mapping to use). */
24560 + char name[USDPAA_DMA_NAME_MAX];
24561 + /* If this ioctl() creates the mapping, this is an input parameter
24562 + * stating whether the region supports locking. If mapping an existing
24563 + * region, this is a return value indicating the same thing. */
24564 + int has_locking;
24565 + /* In the case of a successful map with _CREATE and _LAZY, this return
24566 + * value indicates whether we created the mapped region or whether it
24567 + * already existed. */
24568 + int did_create;
24569 +};
24570 +
24571 +#ifdef CONFIG_COMPAT
24572 +struct usdpaa_ioctl_dma_map_compat {
24573 + /* Output parameters - virtual and physical addresses */
24574 + compat_uptr_t ptr;
24575 + uint64_t phys_addr;
24576 + /* Input parameter, the length of the region to be created (or if
24577 + * mapping an existing region, this must match it). Must be a power-of-4
24578 + * multiple of page size. */
24579 + uint64_t len;
24580 + /* Input parameter, the USDPAA_DMA_FLAG_* settings. */
24581 + uint32_t flags;
24582 + /* If _FLAG_SHARE is specified, the name of the region to be created (or
24583 + * of the existing mapping to use). */
24584 + char name[USDPAA_DMA_NAME_MAX];
24585 + /* If this ioctl() creates the mapping, this is an input parameter
24586 + * stating whether the region supports locking. If mapping an existing
24587 + * region, this is a return value indicating the same thing. */
24588 + int has_locking;
24589 + /* In the case of a successful map with _CREATE and _LAZY, this return
24590 + * value indicates whether we created the mapped region or whether it
24591 + * already existed. */
24592 + int did_create;
24593 +};
24594 +
24595 +#define USDPAA_IOCTL_DMA_MAP_COMPAT \
24596 + _IOWR(USDPAA_IOCTL_MAGIC, 0x03, struct usdpaa_ioctl_dma_map_compat)
24597 +#endif
24598 +
24599 +
24600 +#define USDPAA_IOCTL_DMA_MAP \
24601 + _IOWR(USDPAA_IOCTL_MAGIC, 0x03, struct usdpaa_ioctl_dma_map)
24602 +/* munmap() does not remove the DMA map, just the user-space mapping to it.
24603 + * This ioctl will do both (though you can munmap() before calling the ioctl
24604 + * too). */
24605 +#define USDPAA_IOCTL_DMA_UNMAP \
24606 + _IOW(USDPAA_IOCTL_MAGIC, 0x04, unsigned char)
24607 +/* We implement a cross-process locking scheme per DMA map. Call this ioctl()
24608 + * with a mmap()'d address, and the process will (interruptible) sleep if the
24609 + * lock is already held by another process. Process destruction will
24610 + * automatically clean up any held locks. */
24611 +#define USDPAA_IOCTL_DMA_LOCK \
24612 + _IOW(USDPAA_IOCTL_MAGIC, 0x05, unsigned char)
24613 +#define USDPAA_IOCTL_DMA_UNLOCK \
24614 + _IOW(USDPAA_IOCTL_MAGIC, 0x06, unsigned char)
24615 +
24616 +/***************************************/
24617 +/* Mapping and using QMan/BMan portals */
24618 +/***************************************/
24619 +enum usdpaa_portal_type {
24620 + usdpaa_portal_qman,
24621 + usdpaa_portal_bman,
24622 +};
24623 +
24624 +#define QBMAN_ANY_PORTAL_IDX 0xffffffff
24625 +
24626 +struct usdpaa_ioctl_portal_map {
24627 + /* Input parameter, is a qman or bman portal required. */
24628 +
24629 + enum usdpaa_portal_type type;
24630 + /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
24631 + for don't care. The portal index will be populated by the
24632 + driver when the ioctl() successfully completes */
24633 + uint32_t index;
24634 +
24635 + /* Return value if the map succeeds, this gives the mapped
24636 + * cache-inhibited (cinh) and cache-enabled (cena) addresses. */
24637 + struct usdpaa_portal_map {
24638 + void *cinh;
24639 + void *cena;
24640 + } addr;
24641 + /* Qman-specific return values */
24642 + uint16_t channel;
24643 + uint32_t pools;
24644 +};
24645 +
24646 +#ifdef CONFIG_COMPAT
24647 +struct compat_usdpaa_ioctl_portal_map {
24648 + /* Input parameter, is a qman or bman portal required. */
24649 + enum usdpaa_portal_type type;
24650 + /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
24651 + for don't care. The portal index will be populated by the
24652 + driver when the ioctl() successfully completes */
24653 + uint32_t index;
24654 + /* Return value if the map succeeds, this gives the mapped
24655 + * cache-inhibited (cinh) and cache-enabled (cena) addresses. */
24656 + struct usdpaa_portal_map_compat {
24657 + compat_uptr_t cinh;
24658 + compat_uptr_t cena;
24659 + } addr;
24660 + /* Qman-specific return values */
24661 + uint16_t channel;
24662 + uint32_t pools;
24663 +};
24664 +#define USDPAA_IOCTL_PORTAL_MAP_COMPAT \
24665 + _IOWR(USDPAA_IOCTL_MAGIC, 0x07, struct compat_usdpaa_ioctl_portal_map)
24666 +#define USDPAA_IOCTL_PORTAL_UNMAP_COMPAT \
24667 + _IOW(USDPAA_IOCTL_MAGIC, 0x08, struct usdpaa_portal_map_compat)
24668 +#endif
24669 +
24670 +#define USDPAA_IOCTL_PORTAL_MAP \
24671 + _IOWR(USDPAA_IOCTL_MAGIC, 0x07, struct usdpaa_ioctl_portal_map)
24672 +#define USDPAA_IOCTL_PORTAL_UNMAP \
24673 + _IOW(USDPAA_IOCTL_MAGIC, 0x08, struct usdpaa_portal_map)
24674 +
24675 +struct usdpaa_ioctl_irq_map {
24676 + enum usdpaa_portal_type type; /* Type of portal to map */
24677 + int fd; /* File descriptor that contains the portal */
24678 + void *portal_cinh; /* Cache inhibited area to identify the portal */
24679 +};
24680 +
24681 +#define USDPAA_IOCTL_PORTAL_IRQ_MAP \
24682 + _IOW(USDPAA_IOCTL_MAGIC, 0x09, struct usdpaa_ioctl_irq_map)
24683 +
24684 +#ifdef CONFIG_COMPAT
24685 +
24686 +struct compat_ioctl_irq_map {
24687 + enum usdpaa_portal_type type; /* Type of portal to map */
24688 + compat_int_t fd; /* File descriptor that contains the portal */
24689 + compat_uptr_t portal_cinh; /* Used identify the portal */};
24690 +
24691 +#define USDPAA_IOCTL_PORTAL_IRQ_MAP_COMPAT \
24692 + _IOW(USDPAA_IOCTL_MAGIC, 0x09, struct compat_ioctl_irq_map)
24693 +#endif
24694 +
24695 +/* ioctl to query the amount of DMA memory used in the system */
24696 +struct usdpaa_ioctl_dma_used {
24697 + uint64_t free_bytes;
24698 + uint64_t total_bytes;
24699 +};
24700 +#define USDPAA_IOCTL_DMA_USED \
24701 + _IOR(USDPAA_IOCTL_MAGIC, 0x0B, struct usdpaa_ioctl_dma_used)
24702 +
24703 +/* ioctl to allocate a raw portal */
24704 +struct usdpaa_ioctl_raw_portal {
24705 + /* inputs */
24706 + enum usdpaa_portal_type type; /* Type of portal to allocate */
24707 +
24708 + /* set to non zero to turn on stashing */
24709 + uint8_t enable_stash;
24710 + /* Stashing attributes for the portal */
24711 + uint32_t cpu;
24712 + uint32_t cache;
24713 + uint32_t window;
24714 +
24715 + /* Specifies the stash request queue this portal should use */
24716 + uint8_t sdest;
24717 +
24718 + /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
24719 + * for don't care. The portal index will be populated by the
24720 + * driver when the ioctl() successfully completes */
24721 + uint32_t index;
24722 +
24723 + /* outputs */
24724 + uint64_t cinh;
24725 + uint64_t cena;
24726 +};
24727 +
24728 +#define USDPAA_IOCTL_ALLOC_RAW_PORTAL \
24729 + _IOWR(USDPAA_IOCTL_MAGIC, 0x0C, struct usdpaa_ioctl_raw_portal)
24730 +
24731 +#define USDPAA_IOCTL_FREE_RAW_PORTAL \
24732 + _IOR(USDPAA_IOCTL_MAGIC, 0x0D, struct usdpaa_ioctl_raw_portal)
24733 +
24734 +#ifdef CONFIG_COMPAT
24735 +
24736 +struct compat_ioctl_raw_portal {
24737 + /* inputs */
24738 + enum usdpaa_portal_type type; /* Type of portal to allocate */
24739 +
24740 + /* set to non zero to turn on stashing */
24741 + uint8_t enable_stash;
24742 + /* Stashing attributes for the portal */
24743 + uint32_t cpu;
24744 + uint32_t cache;
24745 + uint32_t window;
24746 + /* Specifies the stash request queue this portal should use */
24747 + uint8_t sdest;
24748 +
24749 + /* Specifes a specific portal index to map or QBMAN_ANY_PORTAL_IDX
24750 + * for don't care. The portal index will be populated by the
24751 + * driver when the ioctl() successfully completes */
24752 + uint32_t index;
24753 +
24754 + /* outputs */
24755 + uint64_t cinh;
24756 + uint64_t cena;
24757 +};
24758 +
24759 +#define USDPAA_IOCTL_ALLOC_RAW_PORTAL_COMPAT \
24760 + _IOWR(USDPAA_IOCTL_MAGIC, 0x0C, struct compat_ioctl_raw_portal)
24761 +
24762 +#define USDPAA_IOCTL_FREE_RAW_PORTAL_COMPAT \
24763 + _IOR(USDPAA_IOCTL_MAGIC, 0x0D, struct compat_ioctl_raw_portal)
24764 +
24765 +#endif
24766 +
24767 +#ifdef __KERNEL__
24768 +
24769 +/* Early-boot hook */
24770 +int __init fsl_usdpaa_init_early(void);
24771 +
24772 +/* Fault-handling in arch/powerpc/mm/mem.c gives USDPAA an opportunity to detect
24773 + * faults within its ranges via this hook. */
24774 +int usdpaa_test_fault(unsigned long pfn, u64 *phys_addr, u64 *size);
24775 +
24776 +#endif /* __KERNEL__ */
24777 +
24778 +#endif /* CONFIG_FSL_USDPAA */
24779 +
24780 +#ifdef __KERNEL__
24781 +/* This interface is needed in a few places and though it's not specific to
24782 + * USDPAA as such, creating a new header for it doesn't make any sense. The
24783 + * qbman kernel driver implements this interface and uses it as the backend for
24784 + * both the FQID and BPID allocators. The fsl_usdpaa driver also uses this
24785 + * interface for tracking per-process allocations handed out to user-space. */
24786 +struct dpa_alloc {
24787 + struct list_head free;
24788 + spinlock_t lock;
24789 + struct list_head used;
24790 +};
24791 +#define DECLARE_DPA_ALLOC(name) \
24792 + struct dpa_alloc name = { \
24793 + .free = { \
24794 + .prev = &name.free, \
24795 + .next = &name.free \
24796 + }, \
24797 + .lock = __SPIN_LOCK_UNLOCKED(name.lock), \
24798 + .used = { \
24799 + .prev = &name.used, \
24800 + .next = &name.used \
24801 + } \
24802 + }
24803 +static inline void dpa_alloc_init(struct dpa_alloc *alloc)
24804 +{
24805 + INIT_LIST_HEAD(&alloc->free);
24806 + INIT_LIST_HEAD(&alloc->used);
24807 + spin_lock_init(&alloc->lock);
24808 +}
24809 +int dpa_alloc_new(struct dpa_alloc *alloc, u32 *result, u32 count, u32 align,
24810 + int partial);
24811 +void dpa_alloc_free(struct dpa_alloc *alloc, u32 base_id, u32 count);
24812 +void dpa_alloc_seed(struct dpa_alloc *alloc, u32 fqid, u32 count);
24813 +
24814 +/* Like 'new' but specifies the desired range, returns -ENOMEM if the entire
24815 + * desired range is not available, or 0 for success. */
24816 +int dpa_alloc_reserve(struct dpa_alloc *alloc, u32 base_id, u32 count);
24817 +/* Pops and returns contiguous ranges from the allocator. Returns -ENOMEM when
24818 + * 'alloc' is empty. */
24819 +int dpa_alloc_pop(struct dpa_alloc *alloc, u32 *result, u32 *count);
24820 +/* Returns 1 if the specified id is alloced, 0 otherwise */
24821 +int dpa_alloc_check(struct dpa_alloc *list, u32 id);
24822 +#endif /* __KERNEL__ */
24823 +
24824 +#ifdef __cplusplus
24825 +}
24826 +#endif
24827 +
24828 +#endif /* FSL_USDPAA_H */