162306a36Sopenharmony_ci/* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
462306a36Sopenharmony_ci * modification, are permitted provided that the following conditions are met:
562306a36Sopenharmony_ci *     * Redistributions of source code must retain the above copyright
662306a36Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer.
762306a36Sopenharmony_ci *     * Redistributions in binary form must reproduce the above copyright
862306a36Sopenharmony_ci *	 notice, this list of conditions and the following disclaimer in the
962306a36Sopenharmony_ci *	 documentation and/or other materials provided with the distribution.
1062306a36Sopenharmony_ci *     * Neither the name of Freescale Semiconductor nor the
1162306a36Sopenharmony_ci *	 names of its contributors may be used to endorse or promote products
1262306a36Sopenharmony_ci *	 derived from this software without specific prior written permission.
1362306a36Sopenharmony_ci *
1462306a36Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
1562306a36Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
1662306a36Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any
1762306a36Sopenharmony_ci * later version.
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
2062306a36Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2162306a36Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2262306a36Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
2362306a36Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2462306a36Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2562306a36Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
2662306a36Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2762306a36Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2862306a36Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#include "bman_priv.h"
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define IRQNAME		"BMan portal %d"
3462306a36Sopenharmony_ci#define MAX_IRQNAME	16	/* big enough for "BMan portal %d" */
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Portal register assists */
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
3962306a36Sopenharmony_ci/* Cache-inhibited register offsets */
4062306a36Sopenharmony_ci#define BM_REG_RCR_PI_CINH	0x3000
4162306a36Sopenharmony_ci#define BM_REG_RCR_CI_CINH	0x3100
4262306a36Sopenharmony_ci#define BM_REG_RCR_ITR		0x3200
4362306a36Sopenharmony_ci#define BM_REG_CFG		0x3300
4462306a36Sopenharmony_ci#define BM_REG_SCN(n)		(0x3400 + ((n) << 6))
4562306a36Sopenharmony_ci#define BM_REG_ISR		0x3e00
4662306a36Sopenharmony_ci#define BM_REG_IER		0x3e40
4762306a36Sopenharmony_ci#define BM_REG_ISDR		0x3e80
4862306a36Sopenharmony_ci#define BM_REG_IIR		0x3ec0
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci/* Cache-enabled register offsets */
5162306a36Sopenharmony_ci#define BM_CL_CR		0x0000
5262306a36Sopenharmony_ci#define BM_CL_RR0		0x0100
5362306a36Sopenharmony_ci#define BM_CL_RR1		0x0140
5462306a36Sopenharmony_ci#define BM_CL_RCR		0x1000
5562306a36Sopenharmony_ci#define BM_CL_RCR_PI_CENA	0x3000
5662306a36Sopenharmony_ci#define BM_CL_RCR_CI_CENA	0x3100
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci#else
5962306a36Sopenharmony_ci/* Cache-inhibited register offsets */
6062306a36Sopenharmony_ci#define BM_REG_RCR_PI_CINH	0x0000
6162306a36Sopenharmony_ci#define BM_REG_RCR_CI_CINH	0x0004
6262306a36Sopenharmony_ci#define BM_REG_RCR_ITR		0x0008
6362306a36Sopenharmony_ci#define BM_REG_CFG		0x0100
6462306a36Sopenharmony_ci#define BM_REG_SCN(n)		(0x0200 + ((n) << 2))
6562306a36Sopenharmony_ci#define BM_REG_ISR		0x0e00
6662306a36Sopenharmony_ci#define BM_REG_IER		0x0e04
6762306a36Sopenharmony_ci#define BM_REG_ISDR		0x0e08
6862306a36Sopenharmony_ci#define BM_REG_IIR		0x0e0c
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Cache-enabled register offsets */
7162306a36Sopenharmony_ci#define BM_CL_CR		0x0000
7262306a36Sopenharmony_ci#define BM_CL_RR0		0x0100
7362306a36Sopenharmony_ci#define BM_CL_RR1		0x0140
7462306a36Sopenharmony_ci#define BM_CL_RCR		0x1000
7562306a36Sopenharmony_ci#define BM_CL_RCR_PI_CENA	0x3000
7662306a36Sopenharmony_ci#define BM_CL_RCR_CI_CENA	0x3100
7762306a36Sopenharmony_ci#endif
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci/*
8062306a36Sopenharmony_ci * Portal modes.
8162306a36Sopenharmony_ci *   Enum types;
8262306a36Sopenharmony_ci *     pmode == production mode
8362306a36Sopenharmony_ci *     cmode == consumption mode,
8462306a36Sopenharmony_ci *   Enum values use 3 letter codes. First letter matches the portal mode,
8562306a36Sopenharmony_ci *   remaining two letters indicate;
8662306a36Sopenharmony_ci *     ci == cache-inhibited portal register
8762306a36Sopenharmony_ci *     ce == cache-enabled portal register
8862306a36Sopenharmony_ci *     vb == in-band valid-bit (cache-enabled)
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cienum bm_rcr_pmode {		/* matches BCSP_CFG::RPM */
9162306a36Sopenharmony_ci	bm_rcr_pci = 0,		/* PI index, cache-inhibited */
9262306a36Sopenharmony_ci	bm_rcr_pce = 1,		/* PI index, cache-enabled */
9362306a36Sopenharmony_ci	bm_rcr_pvb = 2		/* valid-bit */
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_cienum bm_rcr_cmode {		/* s/w-only */
9662306a36Sopenharmony_ci	bm_rcr_cci,		/* CI index, cache-inhibited */
9762306a36Sopenharmony_ci	bm_rcr_cce		/* CI index, cache-enabled */
9862306a36Sopenharmony_ci};
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* --- Portal structures --- */
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#define BM_RCR_SIZE		8
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci/* Release Command */
10662306a36Sopenharmony_cistruct bm_rcr_entry {
10762306a36Sopenharmony_ci	union {
10862306a36Sopenharmony_ci		struct {
10962306a36Sopenharmony_ci			u8 _ncw_verb; /* writes to this are non-coherent */
11062306a36Sopenharmony_ci			u8 bpid; /* used with BM_RCR_VERB_CMD_BPID_SINGLE */
11162306a36Sopenharmony_ci			u8 __reserved1[62];
11262306a36Sopenharmony_ci		};
11362306a36Sopenharmony_ci		struct bm_buffer bufs[8];
11462306a36Sopenharmony_ci	};
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci#define BM_RCR_VERB_VBIT		0x80
11762306a36Sopenharmony_ci#define BM_RCR_VERB_CMD_MASK		0x70	/* one of two values; */
11862306a36Sopenharmony_ci#define BM_RCR_VERB_CMD_BPID_SINGLE	0x20
11962306a36Sopenharmony_ci#define BM_RCR_VERB_CMD_BPID_MULTI	0x30
12062306a36Sopenharmony_ci#define BM_RCR_VERB_BUFCOUNT_MASK	0x0f	/* values 1..8 */
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistruct bm_rcr {
12362306a36Sopenharmony_ci	struct bm_rcr_entry *ring, *cursor;
12462306a36Sopenharmony_ci	u8 ci, available, ithresh, vbit;
12562306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
12662306a36Sopenharmony_ci	u32 busy;
12762306a36Sopenharmony_ci	enum bm_rcr_pmode pmode;
12862306a36Sopenharmony_ci	enum bm_rcr_cmode cmode;
12962306a36Sopenharmony_ci#endif
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci/* MC (Management Command) command */
13362306a36Sopenharmony_cistruct bm_mc_command {
13462306a36Sopenharmony_ci	u8 _ncw_verb; /* writes to this are non-coherent */
13562306a36Sopenharmony_ci	u8 bpid; /* used by acquire command */
13662306a36Sopenharmony_ci	u8 __reserved[62];
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci#define BM_MCC_VERB_VBIT		0x80
13962306a36Sopenharmony_ci#define BM_MCC_VERB_CMD_MASK		0x70	/* where the verb contains; */
14062306a36Sopenharmony_ci#define BM_MCC_VERB_CMD_ACQUIRE		0x10
14162306a36Sopenharmony_ci#define BM_MCC_VERB_CMD_QUERY		0x40
14262306a36Sopenharmony_ci#define BM_MCC_VERB_ACQUIRE_BUFCOUNT	0x0f	/* values 1..8 go here */
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/* MC result, Acquire and Query Response */
14562306a36Sopenharmony_ciunion bm_mc_result {
14662306a36Sopenharmony_ci	struct {
14762306a36Sopenharmony_ci		u8 verb;
14862306a36Sopenharmony_ci		u8 bpid;
14962306a36Sopenharmony_ci		u8 __reserved[62];
15062306a36Sopenharmony_ci	};
15162306a36Sopenharmony_ci	struct bm_buffer bufs[8];
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci#define BM_MCR_VERB_VBIT		0x80
15462306a36Sopenharmony_ci#define BM_MCR_VERB_CMD_MASK		BM_MCC_VERB_CMD_MASK
15562306a36Sopenharmony_ci#define BM_MCR_VERB_CMD_ACQUIRE		BM_MCC_VERB_CMD_ACQUIRE
15662306a36Sopenharmony_ci#define BM_MCR_VERB_CMD_QUERY		BM_MCC_VERB_CMD_QUERY
15762306a36Sopenharmony_ci#define BM_MCR_VERB_CMD_ERR_INVALID	0x60
15862306a36Sopenharmony_ci#define BM_MCR_VERB_CMD_ERR_ECC		0x70
15962306a36Sopenharmony_ci#define BM_MCR_VERB_ACQUIRE_BUFCOUNT	BM_MCC_VERB_ACQUIRE_BUFCOUNT /* 0..8 */
16062306a36Sopenharmony_ci#define BM_MCR_TIMEOUT			10000 /* us */
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistruct bm_mc {
16362306a36Sopenharmony_ci	struct bm_mc_command *cr;
16462306a36Sopenharmony_ci	union bm_mc_result *rr;
16562306a36Sopenharmony_ci	u8 rridx, vbit;
16662306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
16762306a36Sopenharmony_ci	enum {
16862306a36Sopenharmony_ci		/* Can only be _mc_start()ed */
16962306a36Sopenharmony_ci		mc_idle,
17062306a36Sopenharmony_ci		/* Can only be _mc_commit()ed or _mc_abort()ed */
17162306a36Sopenharmony_ci		mc_user,
17262306a36Sopenharmony_ci		/* Can only be _mc_retry()ed */
17362306a36Sopenharmony_ci		mc_hw
17462306a36Sopenharmony_ci	} state;
17562306a36Sopenharmony_ci#endif
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistruct bm_addr {
17962306a36Sopenharmony_ci	void *ce;		/* cache-enabled */
18062306a36Sopenharmony_ci	__be32 *ce_be;		/* Same as above but for direct access */
18162306a36Sopenharmony_ci	void __iomem *ci;	/* cache-inhibited */
18262306a36Sopenharmony_ci};
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistruct bm_portal {
18562306a36Sopenharmony_ci	struct bm_addr addr;
18662306a36Sopenharmony_ci	struct bm_rcr rcr;
18762306a36Sopenharmony_ci	struct bm_mc mc;
18862306a36Sopenharmony_ci} ____cacheline_aligned;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci/* Cache-inhibited register access. */
19162306a36Sopenharmony_cistatic inline u32 bm_in(struct bm_portal *p, u32 offset)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	return ioread32be(p->addr.ci + offset);
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic inline void bm_out(struct bm_portal *p, u32 offset, u32 val)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	iowrite32be(val, p->addr.ci + offset);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/* Cache Enabled Portal Access */
20262306a36Sopenharmony_cistatic inline void bm_cl_invalidate(struct bm_portal *p, u32 offset)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	dpaa_invalidate(p->addr.ce + offset);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic inline void bm_cl_touch_ro(struct bm_portal *p, u32 offset)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	dpaa_touch_ro(p->addr.ce + offset);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic inline u32 bm_ce_in(struct bm_portal *p, u32 offset)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	return be32_to_cpu(*(p->addr.ce_be + (offset/4)));
21562306a36Sopenharmony_ci}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistruct bman_portal {
21862306a36Sopenharmony_ci	struct bm_portal p;
21962306a36Sopenharmony_ci	/* interrupt sources processed by portal_isr(), configurable */
22062306a36Sopenharmony_ci	unsigned long irq_sources;
22162306a36Sopenharmony_ci	/* probing time config params for cpu-affine portals */
22262306a36Sopenharmony_ci	const struct bm_portal_config *config;
22362306a36Sopenharmony_ci	char irqname[MAX_IRQNAME];
22462306a36Sopenharmony_ci};
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic cpumask_t affine_mask;
22762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(affine_mask_lock);
22862306a36Sopenharmony_cistatic DEFINE_PER_CPU(struct bman_portal, bman_affine_portal);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic inline struct bman_portal *get_affine_portal(void)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	return &get_cpu_var(bman_affine_portal);
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_cistatic inline void put_affine_portal(void)
23662306a36Sopenharmony_ci{
23762306a36Sopenharmony_ci	put_cpu_var(bman_affine_portal);
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci/*
24162306a36Sopenharmony_ci * This object type refers to a pool, it isn't *the* pool. There may be
24262306a36Sopenharmony_ci * more than one such object per BMan buffer pool, eg. if different users of the
24362306a36Sopenharmony_ci * pool are operating via different portals.
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_cistruct bman_pool {
24662306a36Sopenharmony_ci	/* index of the buffer pool to encapsulate (0-63) */
24762306a36Sopenharmony_ci	u32 bpid;
24862306a36Sopenharmony_ci	/* Used for hash-table admin when using depletion notifications. */
24962306a36Sopenharmony_ci	struct bman_portal *portal;
25062306a36Sopenharmony_ci	struct bman_pool *next;
25162306a36Sopenharmony_ci};
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic u32 poll_portal_slow(struct bman_portal *p, u32 is);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic irqreturn_t portal_isr(int irq, void *ptr)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	struct bman_portal *p = ptr;
25862306a36Sopenharmony_ci	struct bm_portal *portal = &p->p;
25962306a36Sopenharmony_ci	u32 clear = p->irq_sources;
26062306a36Sopenharmony_ci	u32 is = bm_in(portal, BM_REG_ISR) & p->irq_sources;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	if (unlikely(!is))
26362306a36Sopenharmony_ci		return IRQ_NONE;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	clear |= poll_portal_slow(p, is);
26662306a36Sopenharmony_ci	bm_out(portal, BM_REG_ISR, clear);
26762306a36Sopenharmony_ci	return IRQ_HANDLED;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/* --- RCR API --- */
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci#define RCR_SHIFT	ilog2(sizeof(struct bm_rcr_entry))
27362306a36Sopenharmony_ci#define RCR_CARRY	(uintptr_t)(BM_RCR_SIZE << RCR_SHIFT)
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci/* Bit-wise logic to wrap a ring pointer by clearing the "carry bit" */
27662306a36Sopenharmony_cistatic struct bm_rcr_entry *rcr_carryclear(struct bm_rcr_entry *p)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	uintptr_t addr = (uintptr_t)p;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	addr &= ~RCR_CARRY;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return (struct bm_rcr_entry *)addr;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
28662306a36Sopenharmony_ci/* Bit-wise logic to convert a ring pointer to a ring index */
28762306a36Sopenharmony_cistatic int rcr_ptr2idx(struct bm_rcr_entry *e)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	return ((uintptr_t)e >> RCR_SHIFT) & (BM_RCR_SIZE - 1);
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci#endif
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci/* Increment the 'cursor' ring pointer, taking 'vbit' into account */
29462306a36Sopenharmony_cistatic inline void rcr_inc(struct bm_rcr *rcr)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	/* increment to the next RCR pointer and handle overflow and 'vbit' */
29762306a36Sopenharmony_ci	struct bm_rcr_entry *partial = rcr->cursor + 1;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	rcr->cursor = rcr_carryclear(partial);
30062306a36Sopenharmony_ci	if (partial != rcr->cursor)
30162306a36Sopenharmony_ci		rcr->vbit ^= BM_RCR_VERB_VBIT;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic int bm_rcr_get_avail(struct bm_portal *portal)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return rcr->available;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int bm_rcr_get_fill(struct bm_portal *portal)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	return BM_RCR_SIZE - 1 - rcr->available;
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void bm_rcr_set_ithresh(struct bm_portal *portal, u8 ithresh)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	rcr->ithresh = ithresh;
32362306a36Sopenharmony_ci	bm_out(portal, BM_REG_RCR_ITR, ithresh);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void bm_rcr_cce_prefetch(struct bm_portal *portal)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	__maybe_unused struct bm_rcr *rcr = &portal->rcr;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	DPAA_ASSERT(rcr->cmode == bm_rcr_cce);
33162306a36Sopenharmony_ci	bm_cl_touch_ro(portal, BM_CL_RCR_CI_CENA);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic u8 bm_rcr_cce_update(struct bm_portal *portal)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
33762306a36Sopenharmony_ci	u8 diff, old_ci = rcr->ci;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	DPAA_ASSERT(rcr->cmode == bm_rcr_cce);
34062306a36Sopenharmony_ci	rcr->ci = bm_ce_in(portal, BM_CL_RCR_CI_CENA) & (BM_RCR_SIZE - 1);
34162306a36Sopenharmony_ci	bm_cl_invalidate(portal, BM_CL_RCR_CI_CENA);
34262306a36Sopenharmony_ci	diff = dpaa_cyc_diff(BM_RCR_SIZE, old_ci, rcr->ci);
34362306a36Sopenharmony_ci	rcr->available += diff;
34462306a36Sopenharmony_ci	return diff;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic inline struct bm_rcr_entry *bm_rcr_start(struct bm_portal *portal)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	DPAA_ASSERT(!rcr->busy);
35262306a36Sopenharmony_ci	if (!rcr->available)
35362306a36Sopenharmony_ci		return NULL;
35462306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
35562306a36Sopenharmony_ci	rcr->busy = 1;
35662306a36Sopenharmony_ci#endif
35762306a36Sopenharmony_ci	dpaa_zero(rcr->cursor);
35862306a36Sopenharmony_ci	return rcr->cursor;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic inline void bm_rcr_pvb_commit(struct bm_portal *portal, u8 myverb)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
36462306a36Sopenharmony_ci	struct bm_rcr_entry *rcursor;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	DPAA_ASSERT(rcr->busy);
36762306a36Sopenharmony_ci	DPAA_ASSERT(rcr->pmode == bm_rcr_pvb);
36862306a36Sopenharmony_ci	DPAA_ASSERT(rcr->available >= 1);
36962306a36Sopenharmony_ci	dma_wmb();
37062306a36Sopenharmony_ci	rcursor = rcr->cursor;
37162306a36Sopenharmony_ci	rcursor->_ncw_verb = myverb | rcr->vbit;
37262306a36Sopenharmony_ci	dpaa_flush(rcursor);
37362306a36Sopenharmony_ci	rcr_inc(rcr);
37462306a36Sopenharmony_ci	rcr->available--;
37562306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
37662306a36Sopenharmony_ci	rcr->busy = 0;
37762306a36Sopenharmony_ci#endif
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int bm_rcr_init(struct bm_portal *portal, enum bm_rcr_pmode pmode,
38162306a36Sopenharmony_ci		       enum bm_rcr_cmode cmode)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
38462306a36Sopenharmony_ci	u32 cfg;
38562306a36Sopenharmony_ci	u8 pi;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	rcr->ring = portal->addr.ce + BM_CL_RCR;
38862306a36Sopenharmony_ci	rcr->ci = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1);
38962306a36Sopenharmony_ci	pi = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1);
39062306a36Sopenharmony_ci	rcr->cursor = rcr->ring + pi;
39162306a36Sopenharmony_ci	rcr->vbit = (bm_in(portal, BM_REG_RCR_PI_CINH) & BM_RCR_SIZE) ?
39262306a36Sopenharmony_ci		BM_RCR_VERB_VBIT : 0;
39362306a36Sopenharmony_ci	rcr->available = BM_RCR_SIZE - 1
39462306a36Sopenharmony_ci		- dpaa_cyc_diff(BM_RCR_SIZE, rcr->ci, pi);
39562306a36Sopenharmony_ci	rcr->ithresh = bm_in(portal, BM_REG_RCR_ITR);
39662306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
39762306a36Sopenharmony_ci	rcr->busy = 0;
39862306a36Sopenharmony_ci	rcr->pmode = pmode;
39962306a36Sopenharmony_ci	rcr->cmode = cmode;
40062306a36Sopenharmony_ci#endif
40162306a36Sopenharmony_ci	cfg = (bm_in(portal, BM_REG_CFG) & 0xffffffe0)
40262306a36Sopenharmony_ci		| (pmode & 0x3); /* BCSP_CFG::RPM */
40362306a36Sopenharmony_ci	bm_out(portal, BM_REG_CFG, cfg);
40462306a36Sopenharmony_ci	return 0;
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_cistatic void bm_rcr_finish(struct bm_portal *portal)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
41062306a36Sopenharmony_ci	struct bm_rcr *rcr = &portal->rcr;
41162306a36Sopenharmony_ci	int i;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	DPAA_ASSERT(!rcr->busy);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	i = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1);
41662306a36Sopenharmony_ci	if (i != rcr_ptr2idx(rcr->cursor))
41762306a36Sopenharmony_ci		pr_crit("losing uncommitted RCR entries\n");
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	i = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1);
42062306a36Sopenharmony_ci	if (i != rcr->ci)
42162306a36Sopenharmony_ci		pr_crit("missing existing RCR completions\n");
42262306a36Sopenharmony_ci	if (rcr->ci != rcr_ptr2idx(rcr->cursor))
42362306a36Sopenharmony_ci		pr_crit("RCR destroyed unquiesced\n");
42462306a36Sopenharmony_ci#endif
42562306a36Sopenharmony_ci}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci/* --- Management command API --- */
42862306a36Sopenharmony_cistatic int bm_mc_init(struct bm_portal *portal)
42962306a36Sopenharmony_ci{
43062306a36Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	mc->cr = portal->addr.ce + BM_CL_CR;
43362306a36Sopenharmony_ci	mc->rr = portal->addr.ce + BM_CL_RR0;
43462306a36Sopenharmony_ci	mc->rridx = (mc->cr->_ncw_verb & BM_MCC_VERB_VBIT) ?
43562306a36Sopenharmony_ci		    0 : 1;
43662306a36Sopenharmony_ci	mc->vbit = mc->rridx ? BM_MCC_VERB_VBIT : 0;
43762306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
43862306a36Sopenharmony_ci	mc->state = mc_idle;
43962306a36Sopenharmony_ci#endif
44062306a36Sopenharmony_ci	return 0;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic void bm_mc_finish(struct bm_portal *portal)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
44662306a36Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_idle);
44962306a36Sopenharmony_ci	if (mc->state != mc_idle)
45062306a36Sopenharmony_ci		pr_crit("Losing incomplete MC command\n");
45162306a36Sopenharmony_ci#endif
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_cistatic inline struct bm_mc_command *bm_mc_start(struct bm_portal *portal)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_idle);
45962306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
46062306a36Sopenharmony_ci	mc->state = mc_user;
46162306a36Sopenharmony_ci#endif
46262306a36Sopenharmony_ci	dpaa_zero(mc->cr);
46362306a36Sopenharmony_ci	return mc->cr;
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_cistatic inline void bm_mc_commit(struct bm_portal *portal, u8 myverb)
46762306a36Sopenharmony_ci{
46862306a36Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
46962306a36Sopenharmony_ci	union bm_mc_result *rr = mc->rr + mc->rridx;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_user);
47262306a36Sopenharmony_ci	dma_wmb();
47362306a36Sopenharmony_ci	mc->cr->_ncw_verb = myverb | mc->vbit;
47462306a36Sopenharmony_ci	dpaa_flush(mc->cr);
47562306a36Sopenharmony_ci	dpaa_invalidate_touch_ro(rr);
47662306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
47762306a36Sopenharmony_ci	mc->state = mc_hw;
47862306a36Sopenharmony_ci#endif
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic inline union bm_mc_result *bm_mc_result(struct bm_portal *portal)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct bm_mc *mc = &portal->mc;
48462306a36Sopenharmony_ci	union bm_mc_result *rr = mc->rr + mc->rridx;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	DPAA_ASSERT(mc->state == mc_hw);
48762306a36Sopenharmony_ci	/*
48862306a36Sopenharmony_ci	 * The inactive response register's verb byte always returns zero until
48962306a36Sopenharmony_ci	 * its command is submitted and completed. This includes the valid-bit,
49062306a36Sopenharmony_ci	 * in case you were wondering...
49162306a36Sopenharmony_ci	 */
49262306a36Sopenharmony_ci	if (!rr->verb) {
49362306a36Sopenharmony_ci		dpaa_invalidate_touch_ro(rr);
49462306a36Sopenharmony_ci		return NULL;
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	mc->rridx ^= 1;
49762306a36Sopenharmony_ci	mc->vbit ^= BM_MCC_VERB_VBIT;
49862306a36Sopenharmony_ci#ifdef CONFIG_FSL_DPAA_CHECKING
49962306a36Sopenharmony_ci	mc->state = mc_idle;
50062306a36Sopenharmony_ci#endif
50162306a36Sopenharmony_ci	return rr;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_cistatic inline int bm_mc_result_timeout(struct bm_portal *portal,
50562306a36Sopenharmony_ci				       union bm_mc_result **mcr)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	int timeout = BM_MCR_TIMEOUT;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	do {
51062306a36Sopenharmony_ci		*mcr = bm_mc_result(portal);
51162306a36Sopenharmony_ci		if (*mcr)
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci		udelay(1);
51462306a36Sopenharmony_ci	} while (--timeout);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	return timeout;
51762306a36Sopenharmony_ci}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci/* Disable all BSCN interrupts for the portal */
52062306a36Sopenharmony_cistatic void bm_isr_bscn_disable(struct bm_portal *portal)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	bm_out(portal, BM_REG_SCN(0), 0);
52362306a36Sopenharmony_ci	bm_out(portal, BM_REG_SCN(1), 0);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_cistatic int bman_create_portal(struct bman_portal *portal,
52762306a36Sopenharmony_ci			      const struct bm_portal_config *c)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	struct bm_portal *p;
53062306a36Sopenharmony_ci	int ret;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	p = &portal->p;
53362306a36Sopenharmony_ci	/*
53462306a36Sopenharmony_ci	 * prep the low-level portal struct with the mapped addresses from the
53562306a36Sopenharmony_ci	 * config, everything that follows depends on it and "config" is more
53662306a36Sopenharmony_ci	 * for (de)reference...
53762306a36Sopenharmony_ci	 */
53862306a36Sopenharmony_ci	p->addr.ce = c->addr_virt_ce;
53962306a36Sopenharmony_ci	p->addr.ce_be = c->addr_virt_ce;
54062306a36Sopenharmony_ci	p->addr.ci = c->addr_virt_ci;
54162306a36Sopenharmony_ci	if (bm_rcr_init(p, bm_rcr_pvb, bm_rcr_cce)) {
54262306a36Sopenharmony_ci		dev_err(c->dev, "RCR initialisation failed\n");
54362306a36Sopenharmony_ci		goto fail_rcr;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci	if (bm_mc_init(p)) {
54662306a36Sopenharmony_ci		dev_err(c->dev, "MC initialisation failed\n");
54762306a36Sopenharmony_ci		goto fail_mc;
54862306a36Sopenharmony_ci	}
54962306a36Sopenharmony_ci	/*
55062306a36Sopenharmony_ci	 * Default to all BPIDs disabled, we enable as required at
55162306a36Sopenharmony_ci	 * run-time.
55262306a36Sopenharmony_ci	 */
55362306a36Sopenharmony_ci	bm_isr_bscn_disable(p);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* Write-to-clear any stale interrupt status bits */
55662306a36Sopenharmony_ci	bm_out(p, BM_REG_ISDR, 0xffffffff);
55762306a36Sopenharmony_ci	portal->irq_sources = 0;
55862306a36Sopenharmony_ci	bm_out(p, BM_REG_IER, 0);
55962306a36Sopenharmony_ci	bm_out(p, BM_REG_ISR, 0xffffffff);
56062306a36Sopenharmony_ci	snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
56162306a36Sopenharmony_ci	if (request_irq(c->irq, portal_isr, 0, portal->irqname,	portal)) {
56262306a36Sopenharmony_ci		dev_err(c->dev, "request_irq() failed\n");
56362306a36Sopenharmony_ci		goto fail_irq;
56462306a36Sopenharmony_ci	}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
56762306a36Sopenharmony_ci		goto fail_affinity;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/* Need RCR to be empty before continuing */
57062306a36Sopenharmony_ci	ret = bm_rcr_get_fill(p);
57162306a36Sopenharmony_ci	if (ret) {
57262306a36Sopenharmony_ci		dev_err(c->dev, "RCR unclean\n");
57362306a36Sopenharmony_ci		goto fail_rcr_empty;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci	/* Success */
57662306a36Sopenharmony_ci	portal->config = c;
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	bm_out(p, BM_REG_ISDR, 0);
57962306a36Sopenharmony_ci	bm_out(p, BM_REG_IIR, 0);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	return 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_cifail_rcr_empty:
58462306a36Sopenharmony_cifail_affinity:
58562306a36Sopenharmony_ci	free_irq(c->irq, portal);
58662306a36Sopenharmony_cifail_irq:
58762306a36Sopenharmony_ci	bm_mc_finish(p);
58862306a36Sopenharmony_cifail_mc:
58962306a36Sopenharmony_ci	bm_rcr_finish(p);
59062306a36Sopenharmony_cifail_rcr:
59162306a36Sopenharmony_ci	return -EIO;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_cistruct bman_portal *bman_create_affine_portal(const struct bm_portal_config *c)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	struct bman_portal *portal;
59762306a36Sopenharmony_ci	int err;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	portal = &per_cpu(bman_affine_portal, c->cpu);
60062306a36Sopenharmony_ci	err = bman_create_portal(portal, c);
60162306a36Sopenharmony_ci	if (err)
60262306a36Sopenharmony_ci		return NULL;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	spin_lock(&affine_mask_lock);
60562306a36Sopenharmony_ci	cpumask_set_cpu(c->cpu, &affine_mask);
60662306a36Sopenharmony_ci	spin_unlock(&affine_mask_lock);
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	return portal;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_cistatic u32 poll_portal_slow(struct bman_portal *p, u32 is)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	u32 ret = is;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (is & BM_PIRQ_RCRI) {
61662306a36Sopenharmony_ci		bm_rcr_cce_update(&p->p);
61762306a36Sopenharmony_ci		bm_rcr_set_ithresh(&p->p, 0);
61862306a36Sopenharmony_ci		bm_out(&p->p, BM_REG_ISR, BM_PIRQ_RCRI);
61962306a36Sopenharmony_ci		is &= ~BM_PIRQ_RCRI;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* There should be no status register bits left undefined */
62362306a36Sopenharmony_ci	DPAA_ASSERT(!is);
62462306a36Sopenharmony_ci	return ret;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ciint bman_p_irqsource_add(struct bman_portal *p, u32 bits)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	unsigned long irqflags;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	local_irq_save(irqflags);
63262306a36Sopenharmony_ci	p->irq_sources |= bits & BM_PIRQ_VISIBLE;
63362306a36Sopenharmony_ci	bm_out(&p->p, BM_REG_IER, p->irq_sources);
63462306a36Sopenharmony_ci	local_irq_restore(irqflags);
63562306a36Sopenharmony_ci	return 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ciint bm_shutdown_pool(u32 bpid)
63962306a36Sopenharmony_ci{
64062306a36Sopenharmony_ci	int err = 0;
64162306a36Sopenharmony_ci	struct bm_mc_command *bm_cmd;
64262306a36Sopenharmony_ci	union bm_mc_result *bm_res;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	struct bman_portal *p = get_affine_portal();
64662306a36Sopenharmony_ci	while (1) {
64762306a36Sopenharmony_ci		/* Acquire buffers until empty */
64862306a36Sopenharmony_ci		bm_cmd = bm_mc_start(&p->p);
64962306a36Sopenharmony_ci		bm_cmd->bpid = bpid;
65062306a36Sopenharmony_ci		bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1);
65162306a36Sopenharmony_ci		if (!bm_mc_result_timeout(&p->p, &bm_res)) {
65262306a36Sopenharmony_ci			pr_crit("BMan Acquire Command timedout\n");
65362306a36Sopenharmony_ci			err = -ETIMEDOUT;
65462306a36Sopenharmony_ci			goto done;
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci		if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) {
65762306a36Sopenharmony_ci			/* Pool is empty */
65862306a36Sopenharmony_ci			goto done;
65962306a36Sopenharmony_ci		}
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_cidone:
66262306a36Sopenharmony_ci	put_affine_portal();
66362306a36Sopenharmony_ci	return err;
66462306a36Sopenharmony_ci}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_cistruct gen_pool *bm_bpalloc;
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_cistatic int bm_alloc_bpid_range(u32 *result, u32 count)
66962306a36Sopenharmony_ci{
67062306a36Sopenharmony_ci	unsigned long addr;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	addr = gen_pool_alloc(bm_bpalloc, count);
67362306a36Sopenharmony_ci	if (!addr)
67462306a36Sopenharmony_ci		return -ENOMEM;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	*result = addr & ~DPAA_GENALLOC_OFF;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	return 0;
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic int bm_release_bpid(u32 bpid)
68262306a36Sopenharmony_ci{
68362306a36Sopenharmony_ci	int ret;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	ret = bm_shutdown_pool(bpid);
68662306a36Sopenharmony_ci	if (ret) {
68762306a36Sopenharmony_ci		pr_debug("BPID %d leaked\n", bpid);
68862306a36Sopenharmony_ci		return ret;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	gen_pool_free(bm_bpalloc, bpid | DPAA_GENALLOC_OFF, 1);
69262306a36Sopenharmony_ci	return 0;
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_cistruct bman_pool *bman_new_pool(void)
69662306a36Sopenharmony_ci{
69762306a36Sopenharmony_ci	struct bman_pool *pool = NULL;
69862306a36Sopenharmony_ci	u32 bpid;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (bm_alloc_bpid_range(&bpid, 1))
70162306a36Sopenharmony_ci		return NULL;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	pool = kmalloc(sizeof(*pool), GFP_KERNEL);
70462306a36Sopenharmony_ci	if (!pool)
70562306a36Sopenharmony_ci		goto err;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	pool->bpid = bpid;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	return pool;
71062306a36Sopenharmony_cierr:
71162306a36Sopenharmony_ci	bm_release_bpid(bpid);
71262306a36Sopenharmony_ci	return NULL;
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ciEXPORT_SYMBOL(bman_new_pool);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_civoid bman_free_pool(struct bman_pool *pool)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	bm_release_bpid(pool->bpid);
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	kfree(pool);
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ciEXPORT_SYMBOL(bman_free_pool);
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ciint bman_get_bpid(const struct bman_pool *pool)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	return pool->bpid;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ciEXPORT_SYMBOL(bman_get_bpid);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_cistatic void update_rcr_ci(struct bman_portal *p, int avail)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	if (avail)
73362306a36Sopenharmony_ci		bm_rcr_cce_prefetch(&p->p);
73462306a36Sopenharmony_ci	else
73562306a36Sopenharmony_ci		bm_rcr_cce_update(&p->p);
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ciint bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct bman_portal *p;
74162306a36Sopenharmony_ci	struct bm_rcr_entry *r;
74262306a36Sopenharmony_ci	unsigned long irqflags;
74362306a36Sopenharmony_ci	int avail, timeout = 1000; /* 1ms */
74462306a36Sopenharmony_ci	int i = num - 1;
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	DPAA_ASSERT(num > 0 && num <= 8);
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	do {
74962306a36Sopenharmony_ci		p = get_affine_portal();
75062306a36Sopenharmony_ci		local_irq_save(irqflags);
75162306a36Sopenharmony_ci		avail = bm_rcr_get_avail(&p->p);
75262306a36Sopenharmony_ci		if (avail < 2)
75362306a36Sopenharmony_ci			update_rcr_ci(p, avail);
75462306a36Sopenharmony_ci		r = bm_rcr_start(&p->p);
75562306a36Sopenharmony_ci		local_irq_restore(irqflags);
75662306a36Sopenharmony_ci		put_affine_portal();
75762306a36Sopenharmony_ci		if (likely(r))
75862306a36Sopenharmony_ci			break;
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		udelay(1);
76162306a36Sopenharmony_ci	} while (--timeout);
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	if (unlikely(!timeout))
76462306a36Sopenharmony_ci		return -ETIMEDOUT;
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci	p = get_affine_portal();
76762306a36Sopenharmony_ci	local_irq_save(irqflags);
76862306a36Sopenharmony_ci	/*
76962306a36Sopenharmony_ci	 * we can copy all but the first entry, as this can trigger badness
77062306a36Sopenharmony_ci	 * with the valid-bit
77162306a36Sopenharmony_ci	 */
77262306a36Sopenharmony_ci	bm_buffer_set64(r->bufs, bm_buffer_get64(bufs));
77362306a36Sopenharmony_ci	bm_buffer_set_bpid(r->bufs, pool->bpid);
77462306a36Sopenharmony_ci	if (i)
77562306a36Sopenharmony_ci		memcpy(&r->bufs[1], &bufs[1], i * sizeof(bufs[0]));
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
77862306a36Sopenharmony_ci			  (num & BM_RCR_VERB_BUFCOUNT_MASK));
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	local_irq_restore(irqflags);
78162306a36Sopenharmony_ci	put_affine_portal();
78262306a36Sopenharmony_ci	return 0;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ciEXPORT_SYMBOL(bman_release);
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ciint bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	struct bman_portal *p = get_affine_portal();
78962306a36Sopenharmony_ci	struct bm_mc_command *mcc;
79062306a36Sopenharmony_ci	union bm_mc_result *mcr;
79162306a36Sopenharmony_ci	int ret;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	DPAA_ASSERT(num > 0 && num <= 8);
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	mcc = bm_mc_start(&p->p);
79662306a36Sopenharmony_ci	mcc->bpid = pool->bpid;
79762306a36Sopenharmony_ci	bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
79862306a36Sopenharmony_ci		     (num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
79962306a36Sopenharmony_ci	if (!bm_mc_result_timeout(&p->p, &mcr)) {
80062306a36Sopenharmony_ci		put_affine_portal();
80162306a36Sopenharmony_ci		pr_crit("BMan Acquire Timeout\n");
80262306a36Sopenharmony_ci		return -ETIMEDOUT;
80362306a36Sopenharmony_ci	}
80462306a36Sopenharmony_ci	ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
80562306a36Sopenharmony_ci	if (bufs)
80662306a36Sopenharmony_ci		memcpy(&bufs[0], &mcr->bufs[0], num * sizeof(bufs[0]));
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	put_affine_portal();
80962306a36Sopenharmony_ci	if (ret != num)
81062306a36Sopenharmony_ci		ret = -ENOMEM;
81162306a36Sopenharmony_ci	return ret;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ciEXPORT_SYMBOL(bman_acquire);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ciconst struct bm_portal_config *
81662306a36Sopenharmony_cibman_get_bm_portal_config(const struct bman_portal *portal)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	return portal->config;
81962306a36Sopenharmony_ci}
820