summaryrefslogtreecommitdiff
path: root/drivers/net/fsl-mc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/fsl-mc')
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_portal.c66
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_portal.h22
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_private.h2
-rw-r--r--drivers/net/fsl-mc/dpni.c2
-rw-r--r--drivers/net/fsl-mc/mc.c121
5 files changed, 141 insertions, 72 deletions
diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.c b/drivers/net/fsl-mc/dpio/qbman_portal.c
index dd2a7deee5..5fa8d953e5 100644
--- a/drivers/net/fsl-mc/dpio/qbman_portal.c
+++ b/drivers/net/fsl-mc/dpio/qbman_portal.c
@@ -64,7 +64,7 @@ enum qbman_sdqcr_fc {
struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
{
int ret;
- struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL);
+ struct qbman_swp *p = malloc(sizeof(struct qbman_swp));
if (!p)
return NULL;
@@ -77,7 +77,7 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
qb_attr_code_encode(&code_sdqcr_dct, &p->sdq, qbman_sdqcr_dct_prio_ics);
qb_attr_code_encode(&code_sdqcr_fc, &p->sdq, qbman_sdqcr_fc_up_to_3);
qb_attr_code_encode(&code_sdqcr_tok, &p->sdq, 0xbb);
- p->vdq.busy = 0; /* TODO: convert to atomic_t */
+ atomic_set(&p->vdq.busy, 1);
p->vdq.valid_bit = QB_VALID_BIT;
p->dqrr.next_idx = 0;
p->dqrr.valid_bit = QB_VALID_BIT;
@@ -165,7 +165,6 @@ static struct qb_attr_code code_eq_qd_bin = QB_CODE(4, 0, 16);
static struct qb_attr_code code_eq_qd_pri = QB_CODE(4, 16, 4);
static struct qb_attr_code code_eq_rsp_stash = QB_CODE(5, 16, 1);
static struct qb_attr_code code_eq_rsp_lo = QB_CODE(6, 0, 32);
-static struct qb_attr_code code_eq_rsp_hi = QB_CODE(7, 0, 32);
enum qbman_eq_cmd_e {
/* No enqueue, primarily for plugging ORP gaps for dropped frames */
@@ -197,8 +196,7 @@ void qbman_eq_desc_set_response(struct qbman_eq_desc *d,
{
uint32_t *cl = qb_cl(d);
- qb_attr_code_encode(&code_eq_rsp_lo, cl, lower32(storage_phys));
- qb_attr_code_encode(&code_eq_rsp_hi, cl, upper32(storage_phys));
+ qb_attr_code_encode_64(&code_eq_rsp_lo, (uint64_t *)cl, storage_phys);
qb_attr_code_encode(&code_eq_rsp_stash, cl, !!stash);
}
@@ -253,7 +251,6 @@ static struct qb_attr_code code_pull_numframes = QB_CODE(0, 8, 4);
static struct qb_attr_code code_pull_token = QB_CODE(0, 16, 8);
static struct qb_attr_code code_pull_dqsource = QB_CODE(1, 0, 24);
static struct qb_attr_code code_pull_rsp_lo = QB_CODE(2, 0, 32);
-static struct qb_attr_code code_pull_rsp_hi = QB_CODE(3, 0, 32);
enum qb_pull_dt_e {
qb_pull_dt_channel,
@@ -282,8 +279,7 @@ void qbman_pull_desc_set_storage(struct qbman_pull_desc *d,
}
qb_attr_code_encode(&code_pull_rls, cl, 1);
qb_attr_code_encode(&code_pull_stash, cl, !!stash);
- qb_attr_code_encode(&code_pull_rsp_lo, cl, lower32(storage_phys));
- qb_attr_code_encode(&code_pull_rsp_hi, cl, upper32(storage_phys));
+ qb_attr_code_encode_64(&code_pull_rsp_lo, (uint64_t *)cl, storage_phys);
}
void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, uint8_t numframes)
@@ -316,10 +312,10 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d)
uint32_t *p;
uint32_t *cl = qb_cl(d);
- /* TODO: convert to atomic_t */
- if (s->vdq.busy)
+ if (!atomic_dec_and_test(&s->vdq.busy)) {
+ atomic_inc(&s->vdq.busy);
return -EBUSY;
- s->vdq.busy = 1;
+ }
s->vdq.storage = *(void **)&cl[4];
s->vdq.token = qb_attr_code_decode(&code_pull_token, cl);
p = qbman_cena_write_start(&s->sys, QBMAN_CENA_SWP_VDQCR);
@@ -359,36 +355,44 @@ const struct ldpaa_dq *qbman_swp_dqrr_next(struct qbman_swp *s)
{
uint32_t verb;
uint32_t response_verb;
- const struct ldpaa_dq *dq = qbman_cena_read(&s->sys,
- QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
- const uint32_t *p = qb_cl(dq);
+ uint32_t flags;
+ const struct ldpaa_dq *dq;
+ const uint32_t *p;
+ dq = qbman_cena_read(&s->sys, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+ p = qb_cl(dq);
verb = qb_attr_code_decode(&code_dqrr_verb, p);
- /* If the valid-bit isn't of the expected polarity, nothing there */
+
+ /* If the valid-bit isn't of the expected polarity, nothing there. Note,
+ * in the DQRR reset bug workaround, we shouldn't need to skip these
+ * check, because we've already determined that a new entry is available
+ * and we've invalidated the cacheline before reading it, so the
+ * valid-bit behaviour is repaired and should tell us what we already
+ * knew from reading PI.
+ */
if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) {
qbman_cena_invalidate_prefetch(&s->sys,
- QBMAN_CENA_SWP_DQRR(
- s->dqrr.next_idx));
+ QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
return NULL;
}
/* There's something there. Move "next_idx" attention to the next ring
* entry (and prefetch it) before returning what we found. */
s->dqrr.next_idx++;
- s->dqrr.next_idx &= 3; /* Wrap around at 4 */
+ s->dqrr.next_idx &= QBMAN_DQRR_SIZE - 1; /* Wrap around at 4 */
/* TODO: it's possible to do all this without conditionals, optimise it
* later. */
if (!s->dqrr.next_idx)
s->dqrr.valid_bit ^= QB_VALID_BIT;
- /* VDQCR "no longer busy" hook - if VDQCR shows "busy" and this is a
- * VDQCR result, mark it as non-busy. */
- if (s->vdq.busy) {
- uint32_t flags = ldpaa_dq_flags(dq);
-
- response_verb = qb_attr_code_decode(&code_dqrr_response, &verb);
- if ((response_verb == QBMAN_DQRR_RESPONSE_DQ) &&
- (flags & LDPAA_DQ_STAT_VOLATILE))
- s->vdq.busy = 0;
- }
+
+ /* If this is the final response to a volatile dequeue command
+ indicate that the vdq is no longer busy */
+ flags = ldpaa_dq_flags(dq);
+ response_verb = qb_attr_code_decode(&code_dqrr_response, &verb);
+ if ((response_verb == QBMAN_DQRR_RESPONSE_DQ) &&
+ (flags & LDPAA_DQ_STAT_VOLATILE) &&
+ (flags & LDPAA_DQ_STAT_EXPIRED))
+ atomic_inc(&s->vdq.busy);
+
qbman_cena_invalidate_prefetch(&s->sys,
QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
return dq;
@@ -448,8 +452,10 @@ int qbman_dq_entry_has_newtoken(struct qbman_swp *s,
* reset "busy". We instead base the decision on whether the current
* result is sitting at the first 'storage' location of the busy
* command. */
- if (s->vdq.busy && (s->vdq.storage == dq))
- s->vdq.busy = 0;
+ if (s->vdq.storage == dq) {
+ s->vdq.storage = NULL;
+ atomic_inc(&s->vdq.busy);
+ }
return 1;
}
diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.h b/drivers/net/fsl-mc/dpio/qbman_portal.h
index bb67c3bd06..86e2c3aac4 100644
--- a/drivers/net/fsl-mc/dpio/qbman_portal.h
+++ b/drivers/net/fsl-mc/dpio/qbman_portal.h
@@ -14,6 +14,10 @@
/* Management command result codes */
#define QBMAN_MC_RSLT_OK 0xf0
+/* TBD: as of QBMan 4.1, DQRR will be 8 rather than 4! */
+#define QBMAN_DQRR_SIZE 4
+
+
/* --------------------- */
/* portal data structure */
/* --------------------- */
@@ -48,14 +52,13 @@ struct qbman_swp {
* to whether or not a command can be submitted, not whether or
* not a previously-submitted command is still executing. In
* other words, once proof is seen that the previously-submitted
- * command is executing, "vdq" is no longer "busy". TODO:
- * convert this to "atomic_t" so that it is thread-safe (without
- * locking). */
- int busy;
+ * command is executing, "vdq" is no longer "busy".
+ */
+ atomic_t busy;
uint32_t valid_bit; /* 0x00 or 0x80 */
/* We need to determine when vdq is no longer busy. This depends
* on whether the "busy" (last-submitted) dequeue command is
- * targetting DQRR or main-memory, and detected is based on the
+ * targeting DQRR or main-memory, and detected is based on the
* presence of the dequeue command's "token" showing up in
* dequeue entries in DQRR or main-memory (respectively). Debug
* builds will, when submitting vdq commands, verify that the
@@ -127,6 +130,7 @@ static inline uint32_t qb_attr_code_decode(const struct qb_attr_code *code,
return d32_uint32_t(code->lsoffset, code->width, cacheline[code->word]);
}
+
/* encode a field to a cacheline */
static inline void qb_attr_code_encode(const struct qb_attr_code *code,
uint32_t *cacheline, uint32_t val)
@@ -136,6 +140,12 @@ static inline void qb_attr_code_encode(const struct qb_attr_code *code,
| e32_uint32_t(code->lsoffset, code->width, val);
}
+static inline void qb_attr_code_encode_64(const struct qb_attr_code *code,
+ uint64_t *cacheline, uint64_t val)
+{
+ cacheline[code->word / 2] = val;
+}
+
/* ---------------------- */
/* Descriptors/cachelines */
/* ---------------------- */
@@ -144,7 +154,7 @@ static inline void qb_attr_code_encode(const struct qb_attr_code *code,
* a "descriptor" type that the caller can instantiate however they like.
* Ultimately though, it is just a cacheline of binary storage (or something
* smaller when it is known that the descriptor doesn't need all 64 bytes) for
- * holding pre-formatted pieces of harware commands. The performance-critical
+ * holding pre-formatted pieces of hardware commands. The performance-critical
* code can then copy these descriptors directly into hardware command
* registers more efficiently than trying to construct/format commands
* on-the-fly. The API user sees the descriptor as an array of 32-bit words in
diff --git a/drivers/net/fsl-mc/dpio/qbman_private.h b/drivers/net/fsl-mc/dpio/qbman_private.h
index 2d2556b755..f1f16b828b 100644
--- a/drivers/net/fsl-mc/dpio/qbman_private.h
+++ b/drivers/net/fsl-mc/dpio/qbman_private.h
@@ -9,7 +9,7 @@
#include <errno.h>
#include <asm/io.h>
#include <linux/types.h>
-#include <linux/compat.h>
+#include <asm/atomic.h>
#include <malloc.h>
#include <fsl-mc/fsl_qbman_base.h>
diff --git a/drivers/net/fsl-mc/dpni.c b/drivers/net/fsl-mc/dpni.c
index b384401295..7bc2504f8c 100644
--- a/drivers/net/fsl-mc/dpni.c
+++ b/drivers/net/fsl-mc/dpni.c
@@ -313,7 +313,7 @@ int dpni_set_counter(struct fsl_mc_io *mc_io,
int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
uint16_t token,
- struct dpni_link_cfg *cfg)
+ const struct dpni_link_cfg *cfg)
{
struct mc_command cmd = { 0 };
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
index c5c44bcab0..62a68c2744 100644
--- a/drivers/net/fsl-mc/mc.c
+++ b/drivers/net/fsl-mc/mc.c
@@ -3,13 +3,15 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
+#include <common.h>
#include <errno.h>
#include <asm/io.h>
+#include <libfdt.h>
+#include <fdt_support.h>
#include <fsl-mc/fsl_mc.h>
#include <fsl-mc/fsl_mc_sys.h>
#include <fsl-mc/fsl_mc_private.h>
#include <fsl-mc/fsl_dpmng.h>
-#include <fsl_debug_server.h>
#include <fsl-mc/fsl_dprc.h>
#include <fsl-mc/fsl_dpio.h>
#include <fsl-mc/fsl_qbman_portal.h>
@@ -186,6 +188,36 @@ static int calculate_mc_private_ram_params(u64 mc_private_ram_start_addr,
return 0;
}
+static int mc_fixup_dpc(u64 dpc_addr)
+{
+ void *blob = (void *)dpc_addr;
+ int nodeoffset;
+
+ /* delete any existing ICID pools */
+ nodeoffset = fdt_path_offset(blob, "/resources/icid_pools");
+ if (fdt_del_node(blob, nodeoffset) < 0)
+ printf("\nfsl-mc: WARNING: could not delete ICID pool\n");
+
+ /* add a new pool */
+ nodeoffset = fdt_path_offset(blob, "/resources");
+ if (nodeoffset < 0) {
+ printf("\nfsl-mc: ERROR: DPC is missing /resources\n");
+ return -EINVAL;
+ }
+ nodeoffset = fdt_add_subnode(blob, nodeoffset, "icid_pools");
+ nodeoffset = fdt_add_subnode(blob, nodeoffset, "icid_pool@0");
+ do_fixup_by_path_u32(blob, "/resources/icid_pools/icid_pool@0",
+ "base_icid", FSL_DPAA2_STREAM_ID_START, 1);
+ do_fixup_by_path_u32(blob, "/resources/icid_pools/icid_pool@0",
+ "num",
+ FSL_DPAA2_STREAM_ID_END -
+ FSL_DPAA2_STREAM_ID_START + 1, 1);
+
+ flush_dcache_range(dpc_addr, dpc_addr + fdt_totalsize(blob));
+
+ return 0;
+}
+
static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
{
u64 mc_dpc_offset;
@@ -225,13 +257,13 @@ static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
* Don't return with error here, since the MC firmware can
* still boot without a DPC
*/
- printf("fsl-mc: WARNING: No DPC image found\n");
+ printf("\nfsl-mc: WARNING: No DPC image found");
return 0;
}
dpc_size = fdt_totalsize(dpc_fdt_hdr);
if (dpc_size > CONFIG_SYS_LS_MC_DPC_MAX_LENGTH) {
- printf("fsl-mc: ERROR: Bad DPC image (too large: %d)\n",
+ printf("\nfsl-mc: ERROR: Bad DPC image (too large: %d)\n",
dpc_size);
return -EINVAL;
}
@@ -240,6 +272,9 @@ static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
(u64)dpc_fdt_hdr, dpc_size, mc_ram_addr + mc_dpc_offset);
#endif /* not defined CONFIG_SYS_LS_MC_DPC_IN_DDR */
+ if (mc_fixup_dpc(mc_ram_addr + mc_dpc_offset))
+ return -EINVAL;
+
dump_ram_words("DPC", (void *)(mc_ram_addr + mc_dpc_offset));
return 0;
}
@@ -279,13 +314,13 @@ static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size)
error = fdt_check_header(dpl_fdt_hdr);
if (error != 0) {
- printf("fsl-mc: ERROR: Bad DPL image (bad header)\n");
+ printf("\nfsl-mc: ERROR: Bad DPL image (bad header)\n");
return error;
}
dpl_size = fdt_totalsize(dpl_fdt_hdr);
if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) {
- printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n",
+ printf("\nfsl-mc: ERROR: Bad DPL image (too large: %d)\n",
dpl_size);
return -EINVAL;
}
@@ -322,6 +357,23 @@ static unsigned long get_mc_boot_timeout_ms(void)
return timeout_ms;
}
+#ifdef CONFIG_SYS_LS_MC_AIOP_IMG_IN_NOR
+static int load_mc_aiop_img(u64 mc_ram_addr, size_t mc_ram_size)
+{
+ void *aiop_img;
+
+ /*
+ * Load the MC AIOP image in the MC private DRAM block:
+ */
+
+ aiop_img = (void *)CONFIG_SYS_LS_MC_AIOP_IMG_ADDR;
+ mc_copy_image("MC AIOP image",
+ (u64)aiop_img, CONFIG_SYS_LS_MC_AIOP_IMG_MAX_LENGTH,
+ mc_ram_addr + CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET);
+
+ return 0;
+}
+#endif
static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
{
u32 reg_gsr;
@@ -330,7 +382,6 @@ static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
dmb();
- debug("Polling mc_ccsr_regs->reg_gsr ...\n");
assert(timeout_ms > 0);
for (;;) {
udelay(1000); /* throttle polling */
@@ -345,10 +396,7 @@ static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
}
if (timeout_ms == 0) {
- if (booting_mc)
- printf("fsl-mc: timeout booting management complex firmware\n");
- else
- printf("fsl-mc: timeout deploying data path layout\n");
+ printf("ERROR: timeout\n");
/* TODO: Get an error status from an MC CCSR register */
return -ETIMEDOUT;
@@ -361,15 +409,13 @@ static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
* appropriate errno, so that the status property is set to
* failure in the fsl,dprc device tree node.
*/
- if (booting_mc) {
- printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n",
- reg_gsr);
- } else {
- printf("fsl-mc: WARNING: Data path layout deployed with error (GSR: %#x)\n",
- reg_gsr);
- }
+ printf("WARNING: Firmware returned an error (GSR: %#x)\n",
+ reg_gsr);
+ } else {
+ printf("SUCCESS\n");
}
+
*final_reg_gsr = reg_gsr;
return 0;
}
@@ -403,13 +449,6 @@ int mc_init(void)
gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size;
}
-#ifdef CONFIG_FSL_DEBUG_SERVER
- /*
- * FIXME: I don't think this is right. See get_dram_size_to_hide()
- */
- mc_ram_addr -= debug_server_get_dram_block_size();
-#endif
-
error = calculate_mc_private_ram_params(mc_ram_addr,
mc_ram_size,
&mc_ram_aligned_base_addr,
@@ -454,6 +493,12 @@ int mc_init(void)
if (error != 0)
goto out;
+#ifdef CONFIG_SYS_LS_MC_AIOP_IMG_IN_NOR
+ error = load_mc_aiop_img(mc_ram_addr, mc_ram_size);
+ if (error != 0)
+ goto out;
+#endif
+
debug("mc_ccsr_regs %p\n", mc_ccsr_regs);
dump_mc_ccsr_regs(mc_ccsr_regs);
@@ -465,14 +510,14 @@ int mc_init(void)
out_le32(&mc_ccsr_regs->reg_mcfbalr, reg_mcfbalr);
out_le32(&mc_ccsr_regs->reg_mcfbahr,
(u32)(mc_ram_aligned_base_addr >> 32));
- out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK);
+ out_le32(&mc_ccsr_regs->reg_mcfapr, FSL_BYPASS_AMQ);
/*
* Tell the MC that we want delayed DPL deployment.
*/
out_le32(&mc_ccsr_regs->reg_gsr, 0xDD00);
- printf("\nfsl-mc: Booting Management Complex ...\n");
+ printf("\nfsl-mc: Booting Management Complex ... ");
/*
* Deassert reset and release MC core 0 to run
@@ -509,9 +554,14 @@ int mc_init(void)
goto out;
}
- if (MC_VER_MAJOR != mc_ver_info.major)
+ if (MC_VER_MAJOR != mc_ver_info.major) {
printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n",
mc_ver_info.major, MC_VER_MAJOR);
+ printf("fsl-mc: Update the Management Complex firmware\n");
+
+ error = -ENODEV;
+ goto out;
+ }
if (MC_VER_MINOR != mc_ver_info.minor)
printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n",
@@ -525,13 +575,14 @@ int mc_init(void)
* Tell the MC to deploy the DPL:
*/
out_le32(&mc_ccsr_regs->reg_gsr, 0x0);
- printf("\nfsl-mc: Deploying data path layout ...\n");
+ printf("fsl-mc: Deploying data path layout ... ");
error = wait_for_mc(false, &reg_gsr);
if (error != 0)
goto out;
+
out:
if (error != 0)
- mc_boot_status = -error;
+ mc_boot_status = error;
else
mc_boot_status = 0;
@@ -600,14 +651,16 @@ int dpio_init(struct dprc_obj_desc obj_desc)
printf("dpio_enable() failed %d\n", err);
goto err_get_enable;
}
- debug("ce_paddr=0x%llx, ci_paddr=0x%llx, portalid=%d, prios=%d\n",
- attr.qbman_portal_ce_paddr,
- attr.qbman_portal_ci_paddr,
+ debug("ce_offset=0x%llx, ci_offset=0x%llx, portalid=%d, prios=%d\n",
+ attr.qbman_portal_ce_offset,
+ attr.qbman_portal_ci_offset,
attr.qbman_portal_id,
attr.num_priorities);
- p_des.cena_bar = (void *)attr.qbman_portal_ce_paddr;
- p_des.cinh_bar = (void *)attr.qbman_portal_ci_paddr;
+ p_des.cena_bar = (void *)(SOC_QBMAN_PORTALS_BASE_ADDR
+ + attr.qbman_portal_ce_offset);
+ p_des.cinh_bar = (void *)(SOC_QBMAN_PORTALS_BASE_ADDR
+ + attr.qbman_portal_ci_offset);
dflt_dpio->sw_portal = qbman_swp_init(&p_des);
if (dflt_dpio->sw_portal == NULL) {