f-stack/dpdk/drivers/bus/dpaa/base/qbman/bman.c

395 lines
10 KiB
C
Raw Normal View History

/*-
* This file is provided under a dual BSD/GPLv2 license. When using or
* redistributing this file, you may do so under either license.
*
* BSD LICENSE
*
* Copyright 2008-2016 Freescale Semiconductor Inc.
* Copyright 2017 NXP.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the above-listed copyright holders nor the
* names of any contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* GPL LICENSE SUMMARY
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that License or (at your option) any
* later version.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "bman.h"
#include <rte_branch_prediction.h>
/* Compilation constants */
#define RCR_THRESH 2 /* reread h/w CI when running out of space */
#define IRQNAME "BMan portal %d"
#define MAX_IRQNAME 16 /* big enough for "BMan portal %d" */
struct bman_portal {
struct bm_portal p;
/* 2-element array. pools[0] is mask, pools[1] is snapshot. */
struct bman_depletion *pools;
int thresh_set;
unsigned long irq_sources;
u32 slowpoll; /* only used when interrupts are off */
/* When the cpu-affine portal is activated, this is non-NULL */
const struct bm_portal_config *config;
char irqname[MAX_IRQNAME];
};
static cpumask_t affine_mask;
static DEFINE_SPINLOCK(affine_mask_lock);
static RTE_DEFINE_PER_LCORE(struct bman_portal, bman_affine_portal);
static inline struct bman_portal *get_affine_portal(void)
{
return &RTE_PER_LCORE(bman_affine_portal);
}
/*
* This object type refers to a pool, it isn't *the* pool. There may be
* more than one such object per BMan buffer pool, eg. if different users of
* the pool are operating via different portals.
*/
struct bman_pool {
struct bman_pool_params params;
/* Used for hash-table admin when using depletion notifications. */
struct bman_portal *portal;
struct bman_pool *next;
#ifdef RTE_LIBRTE_DPAA_HWDEBUG
atomic_t in_use;
#endif
};
static inline
struct bman_portal *bman_create_portal(struct bman_portal *portal,
const struct bm_portal_config *c)
{
struct bm_portal *p;
const struct bman_depletion *pools = &c->mask;
int ret;
u8 bpid = 0;
p = &portal->p;
/*
* prep the low-level portal struct with the mapped addresses from the
* config, everything that follows depends on it and "config" is more
* for (de)reference...
*/
p->addr.ce = c->addr_virt[DPAA_PORTAL_CE];
p->addr.ci = c->addr_virt[DPAA_PORTAL_CI];
if (bm_rcr_init(p, bm_rcr_pvb, bm_rcr_cce)) {
pr_err("Bman RCR initialisation failed\n");
return NULL;
}
if (bm_mc_init(p)) {
pr_err("Bman MC initialisation failed\n");
goto fail_mc;
}
portal->pools = kmalloc(2 * sizeof(*pools), GFP_KERNEL);
if (!portal->pools)
goto fail_pools;
portal->pools[0] = *pools;
bman_depletion_init(portal->pools + 1);
while (bpid < bman_pool_max) {
/*
* Default to all BPIDs disabled, we enable as required at
* run-time.
*/
bm_isr_bscn_mask(p, bpid, 0);
bpid++;
}
portal->slowpoll = 0;
/* Write-to-clear any stale interrupt status bits */
bm_isr_disable_write(p, 0xffffffff);
portal->irq_sources = 0;
bm_isr_enable_write(p, portal->irq_sources);
bm_isr_status_clear(p, 0xffffffff);
snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
if (request_irq(c->irq, NULL, 0, portal->irqname,
portal)) {
pr_err("request_irq() failed\n");
goto fail_irq;
}
/* Need RCR to be empty before continuing */
ret = bm_rcr_get_fill(p);
if (ret) {
pr_err("Bman RCR unclean\n");
goto fail_rcr_empty;
}
/* Success */
portal->config = c;
bm_isr_disable_write(p, 0);
bm_isr_uninhibit(p);
return portal;
fail_rcr_empty:
free_irq(c->irq, portal);
fail_irq:
kfree(portal->pools);
fail_pools:
bm_mc_finish(p);
fail_mc:
bm_rcr_finish(p);
return NULL;
}
struct bman_portal *
bman_create_affine_portal(const struct bm_portal_config *c)
{
struct bman_portal *portal = get_affine_portal();
/*This function is called from the context which is already affine to
*CPU or in other words this in non-migratable to other CPUs.
*/
portal = bman_create_portal(portal, c);
if (portal) {
spin_lock(&affine_mask_lock);
CPU_SET(c->cpu, &affine_mask);
spin_unlock(&affine_mask_lock);
}
return portal;
}
static inline
void bman_destroy_portal(struct bman_portal *bm)
{
const struct bm_portal_config *pcfg;
pcfg = bm->config;
bm_rcr_cce_update(&bm->p);
bm_rcr_cce_update(&bm->p);
free_irq(pcfg->irq, bm);
kfree(bm->pools);
bm_mc_finish(&bm->p);
bm_rcr_finish(&bm->p);
bm->config = NULL;
}
const struct
bm_portal_config *bman_destroy_affine_portal(void)
{
struct bman_portal *bm = get_affine_portal();
const struct bm_portal_config *pcfg;
pcfg = bm->config;
bman_destroy_portal(bm);
spin_lock(&affine_mask_lock);
CPU_CLR(pcfg->cpu, &affine_mask);
spin_unlock(&affine_mask_lock);
return pcfg;
}
int
bman_get_portal_index(void)
{
struct bman_portal *p = get_affine_portal();
return p->config->index;
}
static const u32 zero_thresholds[4] = {0, 0, 0, 0};
struct bman_pool *bman_new_pool(const struct bman_pool_params *params)
{
struct bman_pool *pool = NULL;
u32 bpid;
if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID) {
int ret = bman_alloc_bpid(&bpid);
if (ret)
return NULL;
} else {
if (params->bpid >= bman_pool_max)
return NULL;
bpid = params->bpid;
}
if (params->flags & BMAN_POOL_FLAG_THRESH) {
int ret = bm_pool_set(bpid, params->thresholds);
if (ret)
goto err;
}
pool = kmalloc(sizeof(*pool), GFP_KERNEL);
if (!pool)
goto err;
pool->params = *params;
#ifdef RTE_LIBRTE_DPAA_HWDEBUG
atomic_set(&pool->in_use, 1);
#endif
if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
pool->params.bpid = bpid;
return pool;
err:
if (params->flags & BMAN_POOL_FLAG_THRESH)
bm_pool_set(bpid, zero_thresholds);
if (params->flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
bman_release_bpid(bpid);
kfree(pool);
return NULL;
}
void bman_free_pool(struct bman_pool *pool)
{
if (pool->params.flags & BMAN_POOL_FLAG_THRESH)
bm_pool_set(pool->params.bpid, zero_thresholds);
if (pool->params.flags & BMAN_POOL_FLAG_DYNAMIC_BPID)
bman_release_bpid(pool->params.bpid);
kfree(pool);
}
const struct bman_pool_params *bman_get_params(const struct bman_pool *pool)
{
return &pool->params;
}
static void update_rcr_ci(struct bman_portal *p, int avail)
{
if (avail)
bm_rcr_cce_prefetch(&p->p);
else
bm_rcr_cce_update(&p->p);
}
#define BMAN_BUF_MASK 0x0000fffffffffffful
int bman_release(struct bman_pool *pool, const struct bm_buffer *bufs, u8 num,
u32 flags __maybe_unused)
{
struct bman_portal *p;
struct bm_rcr_entry *r;
u32 i = num - 1;
u8 avail;
#ifdef RTE_LIBRTE_DPAA_HWDEBUG
if (!num || (num > 8))
return -EINVAL;
if (pool->params.flags & BMAN_POOL_FLAG_NO_RELEASE)
return -EINVAL;
#endif
p = get_affine_portal();
avail = bm_rcr_get_avail(&p->p);
if (avail < 2)
update_rcr_ci(p, avail);
r = bm_rcr_start(&p->p);
if (unlikely(!r))
return -EBUSY;
/*
* we can copy all but the first entry, as this can trigger badness
* with the valid-bit
*/
r->bufs[0].opaque =
cpu_to_be64(((u64)pool->params.bpid << 48) |
(bufs[0].opaque & BMAN_BUF_MASK));
if (i) {
for (i = 1; i < num; i++)
r->bufs[i].opaque =
cpu_to_be64(bufs[i].opaque & BMAN_BUF_MASK);
}
bm_rcr_pvb_commit(&p->p, BM_RCR_VERB_CMD_BPID_SINGLE |
(num & BM_RCR_VERB_BUFCOUNT_MASK));
return 0;
}
int bman_acquire(struct bman_pool *pool, struct bm_buffer *bufs, u8 num,
u32 flags __maybe_unused)
{
struct bman_portal *p = get_affine_portal();
struct bm_mc_command *mcc;
struct bm_mc_result *mcr;
int ret, i;
#ifdef RTE_LIBRTE_DPAA_HWDEBUG
if (!num || (num > 8))
return -EINVAL;
if (pool->params.flags & BMAN_POOL_FLAG_ONLY_RELEASE)
return -EINVAL;
#endif
mcc = bm_mc_start(&p->p);
mcc->acquire.bpid = pool->params.bpid;
bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE |
(num & BM_MCC_VERB_ACQUIRE_BUFCOUNT));
while (!(mcr = bm_mc_result(&p->p)))
cpu_relax();
ret = mcr->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT;
if (bufs) {
for (i = 0; i < num; i++)
bufs[i].opaque =
be64_to_cpu(mcr->acquire.bufs[i].opaque);
}
if (ret != num)
ret = -ENOMEM;
return ret;
}
int bman_query_pools(struct bm_pool_state *state)
{
struct bman_portal *p = get_affine_portal();
struct bm_mc_result *mcr;
bm_mc_start(&p->p);
bm_mc_commit(&p->p, BM_MCC_VERB_CMD_QUERY);
while (!(mcr = bm_mc_result(&p->p)))
cpu_relax();
DPAA_ASSERT((mcr->verb & BM_MCR_VERB_CMD_MASK) ==
BM_MCR_VERB_CMD_QUERY);
*state = mcr->query;
state->as.state.state[0] = be32_to_cpu(state->as.state.state[0]);
state->as.state.state[1] = be32_to_cpu(state->as.state.state[1]);
state->ds.state.state[0] = be32_to_cpu(state->ds.state.state[0]);
state->ds.state.state[1] = be32_to_cpu(state->ds.state.state[1]);
return 0;
}
u32 bman_query_free_buffers(struct bman_pool *pool)
{
return bm_pool_free_buffers(pool->params.bpid);
}
int bman_update_pool_thresholds(struct bman_pool *pool, const u32 *thresholds)
{
u32 bpid;
bpid = bman_get_params(pool)->bpid;
return bm_pool_set(bpid, thresholds);
}
int bman_shutdown_pool(u32 bpid)
{
struct bman_portal *p = get_affine_portal();
return bm_shutdown_pool(&p->p, bpid);
}