18c2ecf20Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
28c2ecf20Sopenharmony_ci *
38c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
48c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
58c2ecf20Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
68c2ecf20Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer.
78c2ecf20Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
88c2ecf20Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer in the
98c2ecf20Sopenharmony_ci *	 documentation and/or other materials provided with the distribution.
108c2ecf20Sopenharmony_ci *     * Neither the name of Freescale Semiconductor nor the
118c2ecf20Sopenharmony_ci *	 names of its contributors may be used to endorse or promote products
128c2ecf20Sopenharmony_ci *	 derived from this software without specific prior written permission.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
158c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
168c2ecf20Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any
178c2ecf20Sopenharmony_ci * later version.
188c2ecf20Sopenharmony_ci *
198c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
208c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
218c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
228c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
238c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
248c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
258c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
268c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
278c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
288c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
298c2ecf20Sopenharmony_ci */
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#include "bman_priv.h"
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define IRQNAME		"BMan portal %d"
348c2ecf20Sopenharmony_ci#define MAX_IRQNAME	16	/* big enough for "BMan portal %d" */
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci/* Portal register assists */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
398c2ecf20Sopenharmony_ci/* Cache-inhibited register offsets */
408c2ecf20Sopenharmony_ci#define BM_REG_RCR_PI_CINH	0x3000
418c2ecf20Sopenharmony_ci#define BM_REG_RCR_CI_CINH	0x3100
428c2ecf20Sopenharmony_ci#define BM_REG_RCR_ITR		0x3200
438c2ecf20Sopenharmony_ci#define BM_REG_CFG		0x3300
448c2ecf20Sopenharmony_ci#define BM_REG_SCN(n)		(0x3400 + ((n) << 6))
458c2ecf20Sopenharmony_ci#define BM_REG_ISR		0x3e00
468c2ecf20Sopenharmony_ci#define BM_REG_IER		0x3e40
478c2ecf20Sopenharmony_ci#define BM_REG_ISDR		0x3e80
488c2ecf20Sopenharmony_ci#define BM_REG_IIR		0x3ec0
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Cache-enabled register offsets */
518c2ecf20Sopenharmony_ci#define BM_CL_CR		0x0000
528c2ecf20Sopenharmony_ci#define BM_CL_RR0		0x0100
538c2ecf20Sopenharmony_ci#define BM_CL_RR1		0x0140
548c2ecf20Sopenharmony_ci#define BM_CL_RCR		0x1000
558c2ecf20Sopenharmony_ci#define BM_CL_RCR_PI_CENA	0x3000
568c2ecf20Sopenharmony_ci#define BM_CL_RCR_CI_CENA	0x3100
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#else
598c2ecf20Sopenharmony_ci/* Cache-inhibited register offsets */
608c2ecf20Sopenharmony_ci#define BM_REG_RCR_PI_CINH	0x0000
618c2ecf20Sopenharmony_ci#define BM_REG_RCR_CI_CINH	0x0004
628c2ecf20Sopenharmony_ci#define BM_REG_RCR_ITR		0x0008
638c2ecf20Sopenharmony_ci#define BM_REG_CFG		0x0100
648c2ecf20Sopenharmony_ci#define BM_REG_SCN(n)		(0x0200 + ((n) << 2))
658c2ecf20Sopenharmony_ci#define BM_REG_ISR		0x0e00
668c2ecf20Sopenharmony_ci#define BM_REG_IER		0x0e04
678c2ecf20Sopenharmony_ci#define BM_REG_ISDR		0x0e08
688c2ecf20Sopenharmony_ci#define BM_REG_IIR		0x0e0c
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/* Cache-enabled register offsets */
718c2ecf20Sopenharmony_ci#define BM_CL_CR		0x0000
728c2ecf20Sopenharmony_ci#define BM_CL_RR0		0x0100
738c2ecf20Sopenharmony_ci#define BM_CL_RR1		0x0140
748c2ecf20Sopenharmony_ci#define BM_CL_RCR		0x1000
758c2ecf20Sopenharmony_ci#define BM_CL_RCR_PI_CENA	0x3000
768c2ecf20Sopenharmony_ci#define BM_CL_RCR_CI_CENA	0x3100
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * Portal modes.
818c2ecf20Sopenharmony_ci *   Enum types;
828c2ecf20Sopenharmony_ci *     pmode == production mode
838c2ecf20Sopenharmony_ci *     cmode == consumption mode,
848c2ecf20Sopenharmony_ci *   Enum values use 3 letter codes. First letter matches the portal mode,
858c2ecf20Sopenharmony_ci *   remaining two letters indicate;
868c2ecf20Sopenharmony_ci *     ci == cache-inhibited portal register
878c2ecf20Sopenharmony_ci *     ce == cache-enabled portal register
888c2ecf20Sopenharmony_ci *     vb == in-band valid-bit (cache-enabled)
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_cienum bm_rcr_pmode {		/* matches BCSP_CFG::RPM */
918c2ecf20Sopenharmony_ci	bm_rcr_pci = 0,		/* PI index, cache-inhibited */
928c2ecf20Sopenharmony_ci	bm_rcr_pce = 1,		/* PI index, cache-enabled */
938c2ecf20Sopenharmony_ci	bm_rcr_pvb = 2		/* valid-bit */
948c2ecf20Sopenharmony_ci};
958c2ecf20Sopenharmony_cienum bm_rcr_cmode {		/* s/w-only */
968c2ecf20Sopenharmony_ci	bm_rcr_cci,		/* CI index, cache-inhibited */
978c2ecf20Sopenharmony_ci	bm_rcr_cce		/* CI index, cache-enabled */
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/* --- Portal structures --- */
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci#define BM_RCR_SIZE		8
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci/* Release Command */
1068c2ecf20Sopenharmony_cistruct bm_rcr_entry {
1078c2ecf20Sopenharmony_ci	union {
1088c2ecf20Sopenharmony_ci		struct {
1098c2ecf20Sopenharmony_ci			u8 _ncw_verb; /* writes to this are non-coherent */
1108c2ecf20Sopenharmony_ci			u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */
1118c2ecf20Sopenharmony_ci			u8 __reserved1[62];
1128c2ecf20Sopenharmony_ci		};
1138c2ecf20Sopenharmony_ci		struct bm_buffer bufs[8];
1148c2ecf20Sopenharmony_ci	};
1158c2ecf20Sopenharmony_ci};
1168c2ecf20Sopenharmony_ci#define BM_RCR_VERB_VBIT		0x80
1178c2ecf20Sopenharmony_ci#define BM_RCR_VERB_CMD_MASK		0x70	/* one of two values; */
1188c2ecf20Sopenharmony_ci#define BM_RCR_VERB_CMD_BPID_SINGLE	0x20
1198c2ecf20Sopenharmony_ci#define BM_RCR_VERB_CMD_BPID_MULTI	0x30
1208c2ecf20Sopenharmony_ci#define BM_RCR_VERB_BUFCOUNT_MASK	0x0f	/* values 1..8 */
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistruct bm_rcr {
1238c2ecf20Sopenharmony_ci	struct bm_rcr_entry *ring, *cursor;
1248c2ecf20Sopenharmony_ci	u8 ci, available, ithresh, vbit;
1258c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
1268c2ecf20Sopenharmony_ci	u32 busy;
1278c2ecf20Sopenharmony_ci	enum bm_rcr_pmode pmode;
1288c2ecf20Sopenharmony_ci	enum bm_rcr_cmode cmode;
1298c2ecf20Sopenharmony_ci#endif
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* MC (Management Command) command */
1338c2ecf20Sopenharmony_cistruct bm_mc_command {
1348c2ecf20Sopenharmony_ci	u8 _ncw_verb; /* writes to this are non-coherent */
1358c2ecf20Sopenharmony_ci	u8 bpid; /* used by acquire command */
1368c2ecf20Sopenharmony_ci	u8 __reserved[62];
1378c2ecf20Sopenharmony_ci};
1388c2ecf20Sopenharmony_ci#define BM_MCC_VERB_VBIT		0x80
1398c2ecf20Sopenharmony_ci#define BM_MCC_VERB_CMD_MASK		0x70	/* where the verb contains; */
1408c2ecf20Sopenharmony_ci#define BM_MCC_VERB_CMD_ACQUIRE		0x10
1418c2ecf20Sopenharmony_ci#define BM_MCC_VERB_CMD_QUERY		0x40
1428c2ecf20Sopenharmony_ci#define BM_MCC_VERB_ACQUIRE_BUFCOUNT	0x0f	/* values 1..8 go here */
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/* MC result, Acquire and Query Response */
1458c2ecf20Sopenharmony_ciunion bm_mc_result {
1468c2ecf20Sopenharmony_ci	struct {
1478c2ecf20Sopenharmony_ci		u8 verb;
1488c2ecf20Sopenharmony_ci		u8 bpid;
1498c2ecf20Sopenharmony_ci		u8 __reserved[62];
1508c2ecf20Sopenharmony_ci	};
1518c2ecf20Sopenharmony_ci	struct bm_buffer bufs[8];
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci#define BM_MCR_VERB_VBIT		0x80
1548c2ecf20Sopenharmony_ci#define BM_MCR_VERB_CMD_MASK		BM_MCC_VERB_CMD_MASK
1558c2ecf20Sopenharmony_ci#define BM_MCR_VERB_CMD_ACQUIRE		BM_MCC_VERB_CMD_ACQUIRE
1568c2ecf20Sopenharmony_ci#define BM_MCR_VERB_CMD_QUERY		BM_MCC_VERB_CMD_QUERY
1578c2ecf20Sopenharmony_ci#define BM_MCR_VERB_CMD_ERR_INVALID	0x60
1588c2ecf20Sopenharmony_ci#define BM_MCR_VERB_CMD_ERR_ECC		0x70
1598c2ecf20Sopenharmony_ci#define BM_MCR_VERB_ACQUIRE_BUFCOUNT	BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */
1608c2ecf20Sopenharmony_ci#define BM_MCR_TIMEOUT			10000 /* us */
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistruct bm_mc {
1638c2ecf20Sopenharmony_ci	struct bm_mc_command *cr;
1648c2ecf20Sopenharmony_ci	union bm_mc_result *rr;
1658c2ecf20Sopenharmony_ci	u8 rridx, vbit;
1668c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
1678c2ecf20Sopenharmony_ci	enum {
1688c2ecf20Sopenharmony_ci		/* Can only be _mc_start()ed */
1698c2ecf20Sopenharmony_ci		mc_idle,
1708c2ecf20Sopenharmony_ci		/* Can only be _mc_commit()ed or _mc_abort()ed */
1718c2ecf20Sopenharmony_ci		mc_user,
1728c2ecf20Sopenharmony_ci		/* Can only be _mc_retry()ed */
1738c2ecf20Sopenharmony_ci		mc_hw
1748c2ecf20Sopenharmony_ci	} state;
1758c2ecf20Sopenharmony_ci#endif
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistruct bm_addr {
1798c2ecf20Sopenharmony_ci	void *ce;		/* cache-enabled */
1808c2ecf20Sopenharmony_ci	__be32 *ce_be;		/* Same as above but for direct access */
1818c2ecf20Sopenharmony_ci	void __iomem *ci;	/* cache-inhibited */
1828c2ecf20Sopenharmony_ci};
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistruct bm_portal {
1858c2ecf20Sopenharmony_ci	struct bm_addr addr;
1868c2ecf20Sopenharmony_ci	struct bm_rcr rcr;
1878c2ecf20Sopenharmony_ci	struct bm_mc mc;
1888c2ecf20Sopenharmony_ci} ____cacheline_aligned;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci/* Cache-inhibited register access. */
1918c2ecf20Sopenharmony_cistatic inline u32 bm_in(struct bm_portal *p, u32 offset)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	return ioread32be(p->addr.ci + offset);
1948c2ecf20Sopenharmony_ci}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic inline void bm_out(struct bm_portal *p, u32 offset, u32 val)
1978c2ecf20Sopenharmony_ci{
1988c2ecf20Sopenharmony_ci	iowrite32be(val, p->addr.ci + offset);
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/* Cache Enabled Portal Access */
2028c2ecf20Sopenharmony_cistatic inline void bm_cl_invalidate(struct bm_portal *p, u32 offset)
2038c2ecf20Sopenharmony_ci{
2048c2ecf20Sopenharmony_ci	dpaa_invalidate(p->addr.ce + offset);
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic inline void bm_cl_touch_ro(struct bm_portal *p, u32 offset)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	dpaa_touch_ro(p->addr.ce + offset);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic inline u32 bm_ce_in(struct bm_portal *p, u32 offset)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	return be32_to_cpu(*(p->addr.ce_be + (offset/4)));
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistruct bman_portal {
2188c2ecf20Sopenharmony_ci	struct bm_portal p;
2198c2ecf20Sopenharmony_ci	/* interrupt sources processed by portal_isr(), configurable */
2208c2ecf20Sopenharmony_ci	unsigned long irq_sources;
2218c2ecf20Sopenharmony_ci	/* probing time config params for cpu-affine portals */
2228c2ecf20Sopenharmony_ci	const struct bm_portal_config *config;
2238c2ecf20Sopenharmony_ci	char irqname[MAX_IRQNAME];
2248c2ecf20Sopenharmony_ci};
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic cpumask_t affine_mask;
2278c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(affine_mask_lock);
2288c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct bman_portal, bman_affine_portal);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_cistatic inline struct bman_portal *get_affine_portal(void)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	return &get_cpu_var(bman_affine_portal);
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic inline void put_affine_portal(void)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	put_cpu_var(bman_affine_portal);
2388c2ecf20Sopenharmony_ci}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci/*
2418c2ecf20Sopenharmony_ci * This object type refers to a pool, it isn't *the* pool. There may be
2428c2ecf20Sopenharmony_ci * more than one such object per BMan buffer pool, eg. if different users of the
2438c2ecf20Sopenharmony_ci * pool are operating via different portals.
2448c2ecf20Sopenharmony_ci */
2458c2ecf20Sopenharmony_cistruct bman_pool {
2468c2ecf20Sopenharmony_ci	/* index of the buffer pool to encapsulate (0-63) */
2478c2ecf20Sopenharmony_ci	u32 bpid;
2488c2ecf20Sopenharmony_ci	/* Used for hash-table admin when using depletion notifications. */
2498c2ecf20Sopenharmony_ci	struct bman_portal *portal;
2508c2ecf20Sopenharmony_ci	struct bman_pool *next;
2518c2ecf20Sopenharmony_ci};
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic u32 poll_portal_slow(struct bman_portal *p, u32 is);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_cistatic irqreturn_t portal_isr(int irq, void *ptr)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct bman_portal *p = ptr;
2588c2ecf20Sopenharmony_ci	struct bm_portal *portal = &p->p;
2598c2ecf20Sopenharmony_ci	u32 clear = p->irq_sources;
2608c2ecf20Sopenharmony_ci	u32 is = bm_in(portal, BM_REG_ISR) & p->irq_sources;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (unlikely(!is))
2638c2ecf20Sopenharmony_ci		return IRQ_NONE;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	clear |= poll_portal_slow(p, is);
2668c2ecf20Sopenharmony_ci	bm_out(portal, BM_REG_ISR, clear);
2678c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/* --- RCR API --- */
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci#define RCR_SHIFT	ilog2(sizeof(struct bm_rcr_entry))
2738c2ecf20Sopenharmony_ci#define RCR_CARRY	(uintptr_t)(BM_RCR_SIZE << RCR_SHIFT)
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */
2768c2ecf20Sopenharmony_cistatic struct bm_rcr_entry *rcr_carryclear(struct bm_rcr_entry *p)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	uintptr_t addr = (uintptr_t)p;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci	addr &= ~RCR_CARRY;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	return (struct bm_rcr_entry *)addr;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
2868c2ecf20Sopenharmony_ci/* Bit-wise logic to convert a ring pointer to a ring index */
2878c2ecf20Sopenharmony_cistatic int rcr_ptr2idx(struct bm_rcr_entry *e)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	return ((uintptr_t)e >> RCR_SHIFT) & (BM_RCR_SIZE - 1);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci#endif
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci/* Increment the 'cursor' ring pointer, taking 'vbit' into account */
2948c2ecf20Sopenharmony_cistatic inline void rcr_inc(struct bm_rcr *rcr)
2958c2ecf20Sopenharmony_ci{
2968c2ecf20Sopenharmony_ci	/* increment to the next RCR pointer and handle overflow and 'vbit' */
2978c2ecf20Sopenharmony_ci	struct bm_rcr_entry *partial = rcr->cursor + 1;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	rcr->cursor = rcr_carryclear(partial);
3008c2ecf20Sopenharmony_ci	if (partial != rcr->cursor)
3018c2ecf20Sopenharmony_ci		rcr->vbit ^= BM_RCR_VERB_VBIT;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic int bm_rcr_get_avail(struct bm_portal *portal)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return rcr->available;
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic int bm_rcr_get_fill(struct bm_portal *portal)
3128c2ecf20Sopenharmony_ci{
3138c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	return BM_RCR_SIZE - 1 - rcr->available;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	rcr->ithresh = ithresh;
3238c2ecf20Sopenharmony_ci	bm_out(portal, BM_REG_RCR_ITR, ithresh);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic void bm_rcr_cce_prefetch(struct bm_portal *portal)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	__maybe_unused struct bm_rcr *rcr = &portal->rcr;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	DPAA_ASSERT(rcr->cmode == bm_rcr_cce);
3318c2ecf20Sopenharmony_ci	bm_cl_touch_ro(portal, BM_CL_RCR_CI_CENA);
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic u8 bm_rcr_cce_update(struct bm_portal *portal)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3378c2ecf20Sopenharmony_ci	u8 diff, old_ci = rcr->ci;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	DPAA_ASSERT(rcr->cmode == bm_rcr_cce);
3408c2ecf20Sopenharmony_ci	rcr->ci = bm_ce_in(portal, BM_CL_RCR_CI_CENA) & (BM_RCR_SIZE - 1);
3418c2ecf20Sopenharmony_ci	bm_cl_invalidate(portal, BM_CL_RCR_CI_CENA);
3428c2ecf20Sopenharmony_ci	diff = dpaa_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci);
3438c2ecf20Sopenharmony_ci	rcr->available += diff;
3448c2ecf20Sopenharmony_ci	return diff;
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_cistatic inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	DPAA_ASSERT(!rcr->busy);
3528c2ecf20Sopenharmony_ci	if (!rcr->available)
3538c2ecf20Sopenharmony_ci		return NULL;
3548c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
3558c2ecf20Sopenharmony_ci	rcr->busy = 1;
3568c2ecf20Sopenharmony_ci#endif
3578c2ecf20Sopenharmony_ci	dpaa_zero(rcr->cursor);
3588c2ecf20Sopenharmony_ci	return rcr->cursor;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3648c2ecf20Sopenharmony_ci	struct bm_rcr_entry *rcursor;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	DPAA_ASSERT(rcr->busy);
3678c2ecf20Sopenharmony_ci	DPAA_ASSERT(rcr->pmode == bm_rcr_pvb);
3688c2ecf20Sopenharmony_ci	DPAA_ASSERT(rcr->available >= 1);
3698c2ecf20Sopenharmony_ci	dma_wmb();
3708c2ecf20Sopenharmony_ci	rcursor = rcr->cursor;
3718c2ecf20Sopenharmony_ci	rcursor->_ncw_verb = myverb | rcr->vbit;
3728c2ecf20Sopenharmony_ci	dpaa_flush(rcursor);
3738c2ecf20Sopenharmony_ci	rcr_inc(rcr);
3748c2ecf20Sopenharmony_ci	rcr->available--;
3758c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
3768c2ecf20Sopenharmony_ci	rcr->busy = 0;
3778c2ecf20Sopenharmony_ci#endif
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode,
3818c2ecf20Sopenharmony_ci		       enum bm_rcr_cmode cmode)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
3848c2ecf20Sopenharmony_ci	u32 cfg;
3858c2ecf20Sopenharmony_ci	u8 pi;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	rcr->ring = portal->addr.ce + BM_CL_RCR;
3888c2ecf20Sopenharmony_ci	rcr->ci = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1);
3898c2ecf20Sopenharmony_ci	pi = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1);
3908c2ecf20Sopenharmony_ci	rcr->cursor = rcr->ring + pi;
3918c2ecf20Sopenharmony_ci	rcr->vbit = (bm_in(portal, BM_REG_RCR_PI_CINH) & BM_RCR_SIZE) ?
3928c2ecf20Sopenharmony_ci		BM_RCR_VERB_VBIT : 0;
3938c2ecf20Sopenharmony_ci	rcr->available = BM_RCR_SIZE - 1
3948c2ecf20Sopenharmony_ci		- dpaa_cyc_diff(BM_RCR_SIZE, rcr->ci, pi);
3958c2ecf20Sopenharmony_ci	rcr->ithresh = bm_in(portal, BM_REG_RCR_ITR);
3968c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
3978c2ecf20Sopenharmony_ci	rcr->busy = 0;
3988c2ecf20Sopenharmony_ci	rcr->pmode = pmode;
3998c2ecf20Sopenharmony_ci	rcr->cmode = cmode;
4008c2ecf20Sopenharmony_ci#endif
4018c2ecf20Sopenharmony_ci	cfg = (bm_in(portal, BM_REG_CFG) & 0xffffffe0)
4028c2ecf20Sopenharmony_ci		| (pmode & 0x3); /* BCSP_CFG::RPM */
4038c2ecf20Sopenharmony_ci	bm_out(portal, BM_REG_CFG, cfg);
4048c2ecf20Sopenharmony_ci	return 0;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void bm_rcr_finish(struct bm_portal *portal)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
4108c2ecf20Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
4118c2ecf20Sopenharmony_ci	int i;
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci	DPAA_ASSERT(!rcr->busy);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	i = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1);
4168c2ecf20Sopenharmony_ci	if (i != rcr_ptr2idx(rcr->cursor))
4178c2ecf20Sopenharmony_ci		pr_crit("losing uncommitted RCR entries\n");
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	i = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1);
4208c2ecf20Sopenharmony_ci	if (i != rcr->ci)
4218c2ecf20Sopenharmony_ci		pr_crit("missing existing RCR completions\n");
4228c2ecf20Sopenharmony_ci	if (rcr->ci != rcr_ptr2idx(rcr->cursor))
4238c2ecf20Sopenharmony_ci		pr_crit("RCR destroyed unquiesced\n");
4248c2ecf20Sopenharmony_ci#endif
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci/* --- Management command API --- */
4288c2ecf20Sopenharmony_cistatic int bm_mc_init(struct bm_portal *portal)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	mc->cr = portal->addr.ce + BM_CL_CR;
4338c2ecf20Sopenharmony_ci	mc->rr = portal->addr.ce + BM_CL_RR0;
4348c2ecf20Sopenharmony_ci	mc->rridx = (mc->cr->_ncw_verb & BM_MCC_VERB_VBIT) ?
4358c2ecf20Sopenharmony_ci		    0 : 1;
4368c2ecf20Sopenharmony_ci	mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0;
4378c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
4388c2ecf20Sopenharmony_ci	mc->state = mc_idle;
4398c2ecf20Sopenharmony_ci#endif
4408c2ecf20Sopenharmony_ci	return 0;
4418c2ecf20Sopenharmony_ci}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_cistatic void bm_mc_finish(struct bm_portal *portal)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
4468c2ecf20Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_idle);
4498c2ecf20Sopenharmony_ci	if (mc->state != mc_idle)
4508c2ecf20Sopenharmony_ci		pr_crit("Losing incomplete MC command\n");
4518c2ecf20Sopenharmony_ci#endif
4528c2ecf20Sopenharmony_ci}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cistatic inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal)
4558c2ecf20Sopenharmony_ci{
4568c2ecf20Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_idle);
4598c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
4608c2ecf20Sopenharmony_ci	mc->state = mc_user;
4618c2ecf20Sopenharmony_ci#endif
4628c2ecf20Sopenharmony_ci	dpaa_zero(mc->cr);
4638c2ecf20Sopenharmony_ci	return mc->cr;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic inline void bm_mc_commit(struct bm_portal *portal, u8 myverb)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
4698c2ecf20Sopenharmony_ci	union bm_mc_result *rr = mc->rr + mc->rridx;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_user);
4728c2ecf20Sopenharmony_ci	dma_wmb();
4738c2ecf20Sopenharmony_ci	mc->cr->_ncw_verb = myverb | mc->vbit;
4748c2ecf20Sopenharmony_ci	dpaa_flush(mc->cr);
4758c2ecf20Sopenharmony_ci	dpaa_invalidate_touch_ro(rr);
4768c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
4778c2ecf20Sopenharmony_ci	mc->state = mc_hw;
4788c2ecf20Sopenharmony_ci#endif
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_cistatic inline union bm_mc_result *bm_mc_result(struct bm_portal *portal)
4828c2ecf20Sopenharmony_ci{
4838c2ecf20Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
4848c2ecf20Sopenharmony_ci	union bm_mc_result *rr = mc->rr + mc->rridx;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_hw);
4878c2ecf20Sopenharmony_ci	/*
4888c2ecf20Sopenharmony_ci	 * The inactive response register's verb byte always returns zero until
4898c2ecf20Sopenharmony_ci	 * its command is submitted and completed. This includes the valid-bit,
4908c2ecf20Sopenharmony_ci	 * in case you were wondering...
4918c2ecf20Sopenharmony_ci	 */
4928c2ecf20Sopenharmony_ci	if (!rr->verb) {
4938c2ecf20Sopenharmony_ci		dpaa_invalidate_touch_ro(rr);
4948c2ecf20Sopenharmony_ci		return NULL;
4958c2ecf20Sopenharmony_ci	}
4968c2ecf20Sopenharmony_ci	mc->rridx ^= 1;
4978c2ecf20Sopenharmony_ci	mc->vbit ^= BM_MCC_VERB_VBIT;
4988c2ecf20Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
4998c2ecf20Sopenharmony_ci	mc->state = mc_idle;
5008c2ecf20Sopenharmony_ci#endif
5018c2ecf20Sopenharmony_ci	return rr;
5028c2ecf20Sopenharmony_ci}
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_cistatic inline int bm_mc_result_timeout(struct bm_portal *portal,
5058c2ecf20Sopenharmony_ci				       union bm_mc_result **mcr)
5068c2ecf20Sopenharmony_ci{
5078c2ecf20Sopenharmony_ci	int timeout = BM_MCR_TIMEOUT;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	do {
5108c2ecf20Sopenharmony_ci		*mcr = bm_mc_result(portal);
5118c2ecf20Sopenharmony_ci		if (*mcr)
5128c2ecf20Sopenharmony_ci			break;
5138c2ecf20Sopenharmony_ci		udelay(1);
5148c2ecf20Sopenharmony_ci	} while (--timeout);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci	return timeout;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci/* Disable all BSCN interrupts for the portal */
5208c2ecf20Sopenharmony_cistatic void bm_isr_bscn_disable(struct bm_portal *portal)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	bm_out(portal, BM_REG_SCN(0), 0);
5238c2ecf20Sopenharmony_ci	bm_out(portal, BM_REG_SCN(1), 0);
5248c2ecf20Sopenharmony_ci}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_cistatic int bman_create_portal(struct bman_portal *portal,
5278c2ecf20Sopenharmony_ci			      const struct bm_portal_config *c)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct bm_portal *p;
5308c2ecf20Sopenharmony_ci	int ret;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	p = &portal->p;
5338c2ecf20Sopenharmony_ci	/*
5348c2ecf20Sopenharmony_ci	 * prep the low-level portal struct with the mapped addresses from the
5358c2ecf20Sopenharmony_ci	 * config, everything that follows depends on it and "config" is more
5368c2ecf20Sopenharmony_ci	 * for (de)reference...
5378c2ecf20Sopenharmony_ci	 */
5388c2ecf20Sopenharmony_ci	p->addr.ce = c->addr_virt_ce;
5398c2ecf20Sopenharmony_ci	p->addr.ce_be = c->addr_virt_ce;
5408c2ecf20Sopenharmony_ci	p->addr.ci = c->addr_virt_ci;
5418c2ecf20Sopenharmony_ci	if (bm_rcr_init(p, bm_rcr_pvb, bm_rcr_cce)) {
5428c2ecf20Sopenharmony_ci		dev_err(c->dev, "RCR initialisation failed\n");
5438c2ecf20Sopenharmony_ci		goto fail_rcr;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci	if (bm_mc_init(p)) {
5468c2ecf20Sopenharmony_ci		dev_err(c->dev, "MC initialisation failed\n");
5478c2ecf20Sopenharmony_ci		goto fail_mc;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci	/*
5508c2ecf20Sopenharmony_ci	 * Default to all BPIDs disabled, we enable as required at
5518c2ecf20Sopenharmony_ci	 * run-time.
5528c2ecf20Sopenharmony_ci	 */
5538c2ecf20Sopenharmony_ci	bm_isr_bscn_disable(p);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	/* Write-to-clear any stale interrupt status bits */
5568c2ecf20Sopenharmony_ci	bm_out(p, BM_REG_ISDR, 0xffffffff);
5578c2ecf20Sopenharmony_ci	portal->irq_sources = 0;
5588c2ecf20Sopenharmony_ci	bm_out(p, BM_REG_IER, 0);
5598c2ecf20Sopenharmony_ci	bm_out(p, BM_REG_ISR, 0xffffffff);
5608c2ecf20Sopenharmony_ci	snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
5618c2ecf20Sopenharmony_ci	if (request_irq(c->irq, portal_isr, 0, portal->irqname,	portal)) {
5628c2ecf20Sopenharmony_ci		dev_err(c->dev, "request_irq() failed\n");
5638c2ecf20Sopenharmony_ci		goto fail_irq;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
5678c2ecf20Sopenharmony_ci		goto fail_affinity;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* Need RCR to be empty before continuing */
5708c2ecf20Sopenharmony_ci	ret = bm_rcr_get_fill(p);
5718c2ecf20Sopenharmony_ci	if (ret) {
5728c2ecf20Sopenharmony_ci		dev_err(c->dev, "RCR unclean\n");
5738c2ecf20Sopenharmony_ci		goto fail_rcr_empty;
5748c2ecf20Sopenharmony_ci	}
5758c2ecf20Sopenharmony_ci	/* Success */
5768c2ecf20Sopenharmony_ci	portal->config = c;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	bm_out(p, BM_REG_ISDR, 0);
5798c2ecf20Sopenharmony_ci	bm_out(p, BM_REG_IIR, 0);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return 0;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cifail_rcr_empty:
5848c2ecf20Sopenharmony_cifail_affinity:
5858c2ecf20Sopenharmony_ci	free_irq(c->irq, portal);
5868c2ecf20Sopenharmony_cifail_irq:
5878c2ecf20Sopenharmony_ci	bm_mc_finish(p);
5888c2ecf20Sopenharmony_cifail_mc:
5898c2ecf20Sopenharmony_ci	bm_rcr_finish(p);
5908c2ecf20Sopenharmony_cifail_rcr:
5918c2ecf20Sopenharmony_ci	return -EIO;
5928c2ecf20Sopenharmony_ci}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_cistruct bman_portal *bman_create_affine_portal(const struct bm_portal_config *c)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct bman_portal *portal;
5978c2ecf20Sopenharmony_ci	int err;
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci	portal = &per_cpu(bman_affine_portal, c->cpu);
6008c2ecf20Sopenharmony_ci	err = bman_create_portal(portal, c);
6018c2ecf20Sopenharmony_ci	if (err)
6028c2ecf20Sopenharmony_ci		return NULL;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	spin_lock(&affine_mask_lock);
6058c2ecf20Sopenharmony_ci	cpumask_set_cpu(c->cpu, &affine_mask);
6068c2ecf20Sopenharmony_ci	spin_unlock(&affine_mask_lock);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	return portal;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic u32 poll_portal_slow(struct bman_portal *p, u32 is)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	u32 ret = is;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	if (is & BM_PIRQ_RCRI) {
6168c2ecf20Sopenharmony_ci		bm_rcr_cce_update(&p->p);
6178c2ecf20Sopenharmony_ci		bm_rcr_set_ithresh(&p->p, 0);
6188c2ecf20Sopenharmony_ci		bm_out(&p->p, BM_REG_ISR, BM_PIRQ_RCRI);
6198c2ecf20Sopenharmony_ci		is &= ~BM_PIRQ_RCRI;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	/* There should be no status register bits left undefined */
6238c2ecf20Sopenharmony_ci	DPAA_ASSERT(!is);
6248c2ecf20Sopenharmony_ci	return ret;
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ciint bman_p_irqsource_add(struct bman_portal *p, u32 bits)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	unsigned long irqflags;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci	local_irq_save(irqflags);
6328c2ecf20Sopenharmony_ci	p->irq_sources |= bits & BM_PIRQ_VISIBLE;
6338c2ecf20Sopenharmony_ci	bm_out(&p->p, BM_REG_IER, p->irq_sources);
6348c2ecf20Sopenharmony_ci	local_irq_restore(irqflags);
6358c2ecf20Sopenharmony_ci	return 0;
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ciint bm_shutdown_pool(u32 bpid)
6398c2ecf20Sopenharmony_ci{
6408c2ecf20Sopenharmony_ci	int err = 0;
6418c2ecf20Sopenharmony_ci	struct bm_mc_command *bm_cmd;
6428c2ecf20Sopenharmony_ci	union bm_mc_result *bm_res;
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	struct bman_portal *p = get_affine_portal();
6468c2ecf20Sopenharmony_ci	while (1) {
6478c2ecf20Sopenharmony_ci		/* Acquire buffers until empty */
6488c2ecf20Sopenharmony_ci		bm_cmd = bm_mc_start(&p->p);
6498c2ecf20Sopenharmony_ci		bm_cmd->bpid = bpid;
6508c2ecf20Sopenharmony_ci		bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1);
6518c2ecf20Sopenharmony_ci		if (!bm_mc_result_timeout(&p->p, &bm_res)) {
6528c2ecf20Sopenharmony_ci			pr_crit("BMan Acquire Command timedout\n");
6538c2ecf20Sopenharmony_ci			err = -ETIMEDOUT;
6548c2ecf20Sopenharmony_ci			goto done;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci		if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) {
6578c2ecf20Sopenharmony_ci			/* Pool is empty */
6588c2ecf20Sopenharmony_ci			goto done;
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_cidone:
6628c2ecf20Sopenharmony_ci	put_affine_portal();
6638c2ecf20Sopenharmony_ci	return err;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistruct gen_pool *bm_bpalloc;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic int bm_alloc_bpid_range(u32 *result, u32 count)
6698c2ecf20Sopenharmony_ci{
6708c2ecf20Sopenharmony_ci	unsigned long addr;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	addr = gen_pool_alloc(bm_bpalloc, count);
6738c2ecf20Sopenharmony_ci	if (!addr)
6748c2ecf20Sopenharmony_ci		return -ENOMEM;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	*result = addr & ~DPAA_GENALLOC_OFF;
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	return 0;
6798c2ecf20Sopenharmony_ci}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_cistatic int bm_release_bpid(u32 bpid)
6828c2ecf20Sopenharmony_ci{
6838c2ecf20Sopenharmony_ci	int ret;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	ret = bm_shutdown_pool(bpid);
6868c2ecf20Sopenharmony_ci	if (ret) {
6878c2ecf20Sopenharmony_ci		pr_debug("BPID %d leaked\n", bpid);
6888c2ecf20Sopenharmony_ci		return ret;
6898c2ecf20Sopenharmony_ci	}
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	gen_pool_free(bm_bpalloc, bpid | DPAA_GENALLOC_OFF, 1);
6928c2ecf20Sopenharmony_ci	return 0;
6938c2ecf20Sopenharmony_ci}
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistruct bman_pool *bman_new_pool(void)
6968c2ecf20Sopenharmony_ci{
6978c2ecf20Sopenharmony_ci	struct bman_pool *pool = NULL;
6988c2ecf20Sopenharmony_ci	u32 bpid;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	if (bm_alloc_bpid_range(&bpid, 1))
7018c2ecf20Sopenharmony_ci		return NULL;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	pool = kmalloc(sizeof(*pool), GFP_KERNEL);
7048c2ecf20Sopenharmony_ci	if (!pool)
7058c2ecf20Sopenharmony_ci		goto err;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	pool->bpid = bpid;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	return pool;
7108c2ecf20Sopenharmony_cierr:
7118c2ecf20Sopenharmony_ci	bm_release_bpid(bpid);
7128c2ecf20Sopenharmony_ci	kfree(pool);
7138c2ecf20Sopenharmony_ci	return NULL;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bman_new_pool);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_civoid bman_free_pool(struct bman_pool *pool)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	bm_release_bpid(pool->bpid);
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	kfree(pool);
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bman_free_pool);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ciint bman_get_bpid(const struct bman_pool *pool)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	return pool->bpid;
7288c2ecf20Sopenharmony_ci}
7298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bman_get_bpid);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic void update_rcr_ci(struct bman_portal *p, int avail)
7328c2ecf20Sopenharmony_ci{
7338c2ecf20Sopenharmony_ci	if (avail)
7348c2ecf20Sopenharmony_ci		bm_rcr_cce_prefetch(&p->p);
7358c2ecf20Sopenharmony_ci	else
7368c2ecf20Sopenharmony_ci		bm_rcr_cce_update(&p->p);
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ciint bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct bman_portal *p;
7428c2ecf20Sopenharmony_ci	struct bm_rcr_entry *r;
7438c2ecf20Sopenharmony_ci	unsigned long irqflags;
7448c2ecf20Sopenharmony_ci	int avail, timeout = 1000; /* 1ms */
7458c2ecf20Sopenharmony_ci	int i = num - 1;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	DPAA_ASSERT(num > 0 && num <= 8);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	do {
7508c2ecf20Sopenharmony_ci		p = get_affine_portal();
7518c2ecf20Sopenharmony_ci		local_irq_save(irqflags);
7528c2ecf20Sopenharmony_ci		avail = bm_rcr_get_avail(&p->p);
7538c2ecf20Sopenharmony_ci		if (avail < 2)
7548c2ecf20Sopenharmony_ci			update_rcr_ci(p, avail);
7558c2ecf20Sopenharmony_ci		r = bm_rcr_start(&p->p);
7568c2ecf20Sopenharmony_ci		local_irq_restore(irqflags);
7578c2ecf20Sopenharmony_ci		put_affine_portal();
7588c2ecf20Sopenharmony_ci		if (likely(r))
7598c2ecf20Sopenharmony_ci			break;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci		udelay(1);
7628c2ecf20Sopenharmony_ci	} while (--timeout);
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	if (unlikely(!timeout))
7658c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	p = get_affine_portal();
7688c2ecf20Sopenharmony_ci	local_irq_save(irqflags);
7698c2ecf20Sopenharmony_ci	/*
7708c2ecf20Sopenharmony_ci	 * we can copy all but the first entry, as this can trigger badness
7718c2ecf20Sopenharmony_ci	 * with the valid-bit
7728c2ecf20Sopenharmony_ci	 */
7738c2ecf20Sopenharmony_ci	bm_buffer_set64(r->bufs, bm_buffer_get64(bufs));
7748c2ecf20Sopenharmony_ci	bm_buffer_set_bpid(r->bufs, pool->bpid);
7758c2ecf20Sopenharmony_ci	if (i)
7768c2ecf20Sopenharmony_ci		memcpy(&r->bufs[1], &bufs[1], i * sizeof(bufs[0]));
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
7798c2ecf20Sopenharmony_ci			  (num & BM_RCR_VERB_BUFCOUNT_MASK));
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	local_irq_restore(irqflags);
7828c2ecf20Sopenharmony_ci	put_affine_portal();
7838c2ecf20Sopenharmony_ci	return 0;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bman_release);
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ciint bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	struct bman_portal *p = get_affine_portal();
7908c2ecf20Sopenharmony_ci	struct bm_mc_command *mcc;
7918c2ecf20Sopenharmony_ci	union bm_mc_result *mcr;
7928c2ecf20Sopenharmony_ci	int ret;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	DPAA_ASSERT(num > 0 && num <= 8);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	mcc = bm_mc_start(&p->p);
7978c2ecf20Sopenharmony_ci	mcc->bpid = pool->bpid;
7988c2ecf20Sopenharmony_ci	bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
7998c2ecf20Sopenharmony_ci		     (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
8008c2ecf20Sopenharmony_ci	if (!bm_mc_result_timeout(&p->p, &mcr)) {
8018c2ecf20Sopenharmony_ci		put_affine_portal();
8028c2ecf20Sopenharmony_ci		pr_crit("BMan Acquire Timeout\n");
8038c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci	ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
8068c2ecf20Sopenharmony_ci	if (bufs)
8078c2ecf20Sopenharmony_ci		memcpy(&bufs[0], &mcr->bufs[0], num * sizeof(bufs[0]));
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	put_affine_portal();
8108c2ecf20Sopenharmony_ci	if (ret != num)
8118c2ecf20Sopenharmony_ci		ret = -ENOMEM;
8128c2ecf20Sopenharmony_ci	return ret;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ciEXPORT_SYMBOL(bman_acquire);
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ciconst struct bm_portal_config *
8178c2ecf20Sopenharmony_cibman_get_bm_portal_config(const struct bman_portal *portal)
8188c2ecf20Sopenharmony_ci{
8198c2ecf20Sopenharmony_ci	return portal->config;
8208c2ecf20Sopenharmony_ci}
821