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/Makefile6
-rw-r--r--drivers/net/fsl-mc/dpbp.c102
-rw-r--r--drivers/net/fsl-mc/dpio/Makefile9
-rw-r--r--drivers/net/fsl-mc/dpio/dpio.c102
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_portal.c593
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_portal.h157
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_private.h169
-rw-r--r--drivers/net/fsl-mc/dpio/qbman_sys.h290
-rw-r--r--drivers/net/fsl-mc/dpmng.c65
-rw-r--r--drivers/net/fsl-mc/dpni.c506
-rw-r--r--drivers/net/fsl-mc/dprc.c283
-rw-r--r--drivers/net/fsl-mc/fsl_dpmng_cmd.h32
-rw-r--r--drivers/net/fsl-mc/mc.c702
-rw-r--r--drivers/net/fsl-mc/mc_sys.c6
14 files changed, 2810 insertions, 212 deletions
diff --git a/drivers/net/fsl-mc/Makefile b/drivers/net/fsl-mc/Makefile
index 206ac6be07..7563a5fdd3 100644
--- a/drivers/net/fsl-mc/Makefile
+++ b/drivers/net/fsl-mc/Makefile
@@ -7,4 +7,8 @@
# Layerscape MC driver
obj-y += mc.o \
mc_sys.o \
- dpmng.o
+ dpmng.o \
+ dprc.o \
+ dpbp.o \
+ dpni.o
+obj-y += dpio/
diff --git a/drivers/net/fsl-mc/dpbp.c b/drivers/net/fsl-mc/dpbp.c
new file mode 100644
index 0000000000..3853e58ef9
--- /dev/null
+++ b/drivers/net/fsl-mc/dpbp.c
@@ -0,0 +1,102 @@
+/*
+ * Freescale Layerscape MC I/O wrapper
+ *
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ * Author: German Rivera <German.Rivera@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <fsl-mc/fsl_mc_sys.h>
+#include <fsl-mc/fsl_mc_cmd.h>
+#include <fsl-mc/fsl_dpbp.h>
+
+int dpbp_open(struct fsl_mc_io *mc_io, int dpbp_id, uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_OPEN,
+ MC_CMD_PRI_LOW, 0);
+ DPBP_CMD_OPEN(cmd, dpbp_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return err;
+}
+
+int dpbp_close(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_CLOSE, MC_CMD_PRI_HIGH,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpbp_enable(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_ENABLE, MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpbp_disable(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_DISABLE,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpbp_reset(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_RESET,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpbp_get_attributes(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpbp_attr *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPBP_CMDID_GET_ATTR,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPBP_RSP_GET_ATTRIBUTES(cmd, attr);
+
+ return 0;
+}
diff --git a/drivers/net/fsl-mc/dpio/Makefile b/drivers/net/fsl-mc/dpio/Makefile
new file mode 100644
index 0000000000..1ccefc0db2
--- /dev/null
+++ b/drivers/net/fsl-mc/dpio/Makefile
@@ -0,0 +1,9 @@
+#
+# Copyright 2014 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+# Layerscape MC DPIO driver
+obj-y += dpio.o \
+ qbman_portal.o
diff --git a/drivers/net/fsl-mc/dpio/dpio.c b/drivers/net/fsl-mc/dpio/dpio.c
new file mode 100644
index 0000000000..b07eff7e3c
--- /dev/null
+++ b/drivers/net/fsl-mc/dpio/dpio.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <fsl-mc/fsl_mc_sys.h>
+#include <fsl-mc/fsl_mc_cmd.h>
+#include <fsl-mc/fsl_dpio.h>
+
+int dpio_open(struct fsl_mc_io *mc_io, int dpio_id, uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_OPEN,
+ MC_CMD_PRI_LOW, 0);
+ DPIO_CMD_OPEN(cmd, dpio_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dpio_close(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_CLOSE,
+ MC_CMD_PRI_HIGH, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpio_enable(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_ENABLE,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpio_disable(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_DISABLE,
+ MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpio_reset(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpio_get_attributes(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpio_attr *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPIO_CMDID_GET_ATTR,
+ MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPIO_RSP_GET_ATTR(cmd, attr);
+
+ return 0;
+}
diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.c b/drivers/net/fsl-mc/dpio/qbman_portal.c
new file mode 100644
index 0000000000..dd2a7deee5
--- /dev/null
+++ b/drivers/net/fsl-mc/dpio/qbman_portal.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "qbman_portal.h"
+
+/* QBMan portal management command codes */
+#define QBMAN_MC_ACQUIRE 0x30
+#define QBMAN_WQCHAN_CONFIGURE 0x46
+
+/* CINH register offsets */
+#define QBMAN_CINH_SWP_EQAR 0x8c0
+#define QBMAN_CINH_SWP_DCAP 0xac0
+#define QBMAN_CINH_SWP_SDQCR 0xb00
+#define QBMAN_CINH_SWP_RAR 0xcc0
+
+/* CENA register offsets */
+#define QBMAN_CENA_SWP_EQCR(n) (0x000 + ((uint32_t)(n) << 6))
+#define QBMAN_CENA_SWP_DQRR(n) (0x200 + ((uint32_t)(n) << 6))
+#define QBMAN_CENA_SWP_RCR(n) (0x400 + ((uint32_t)(n) << 6))
+#define QBMAN_CENA_SWP_CR 0x600
+#define QBMAN_CENA_SWP_RR(vb) (0x700 + ((uint32_t)(vb) >> 1))
+#define QBMAN_CENA_SWP_VDQCR 0x780
+
+/* Reverse mapping of QBMAN_CENA_SWP_DQRR() */
+#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)p & 0xff) >> 6)
+
+/*******************************/
+/* Pre-defined attribute codes */
+/*******************************/
+
+struct qb_attr_code code_generic_verb = QB_CODE(0, 0, 7);
+struct qb_attr_code code_generic_rslt = QB_CODE(0, 8, 8);
+
+/*************************/
+/* SDQCR attribute codes */
+/*************************/
+
+/* we put these here because at least some of them are required by
+ * qbman_swp_init() */
+struct qb_attr_code code_sdqcr_dct = QB_CODE(0, 24, 2);
+struct qb_attr_code code_sdqcr_fc = QB_CODE(0, 29, 1);
+struct qb_attr_code code_sdqcr_tok = QB_CODE(0, 16, 8);
+#define CODE_SDQCR_DQSRC(n) QB_CODE(0, n, 1)
+enum qbman_sdqcr_dct {
+ qbman_sdqcr_dct_null = 0,
+ qbman_sdqcr_dct_prio_ics,
+ qbman_sdqcr_dct_active_ics,
+ qbman_sdqcr_dct_active
+};
+enum qbman_sdqcr_fc {
+ qbman_sdqcr_fc_one = 0,
+ qbman_sdqcr_fc_up_to_3 = 1
+};
+
+/*********************************/
+/* Portal constructor/destructor */
+/*********************************/
+
+/* Software portals should always be in the power-on state when we initialise,
+ * due to the CCSR-based portal reset functionality that MC has. */
+struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d)
+{
+ int ret;
+ struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL);
+
+ if (!p)
+ return NULL;
+ p->desc = d;
+#ifdef QBMAN_CHECKING
+ p->mc.check = swp_mc_can_start;
+#endif
+ p->mc.valid_bit = QB_VALID_BIT;
+ p->sdq = 0;
+ 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 */
+ p->vdq.valid_bit = QB_VALID_BIT;
+ p->dqrr.next_idx = 0;
+ p->dqrr.valid_bit = QB_VALID_BIT;
+ ret = qbman_swp_sys_init(&p->sys, d);
+ if (ret) {
+ free(p);
+ printf("qbman_swp_sys_init() failed %d\n", ret);
+ return NULL;
+ }
+ qbman_cinh_write(&p->sys, QBMAN_CINH_SWP_SDQCR, p->sdq);
+ return p;
+}
+
+/***********************/
+/* Management commands */
+/***********************/
+
+/*
+ * Internal code common to all types of management commands.
+ */
+
+void *qbman_swp_mc_start(struct qbman_swp *p)
+{
+ void *ret;
+#ifdef QBMAN_CHECKING
+ BUG_ON(p->mc.check != swp_mc_can_start);
+#endif
+ ret = qbman_cena_write_start(&p->sys, QBMAN_CENA_SWP_CR);
+#ifdef QBMAN_CHECKING
+ if (!ret)
+ p->mc.check = swp_mc_can_submit;
+#endif
+ return ret;
+}
+
+void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb)
+{
+ uint32_t *v = cmd;
+#ifdef QBMAN_CHECKING
+ BUG_ON(!p->mc.check != swp_mc_can_submit);
+#endif
+ lwsync();
+ /* TBD: "|=" is going to hurt performance. Need to move as many fields
+ * out of word zero, and for those that remain, the "OR" needs to occur
+ * at the caller side. This debug check helps to catch cases where the
+ * caller wants to OR but has forgotten to do so. */
+ BUG_ON((*v & cmd_verb) != *v);
+ *v = cmd_verb | p->mc.valid_bit;
+ qbman_cena_write_complete(&p->sys, QBMAN_CENA_SWP_CR, cmd);
+ /* TODO: add prefetch support for GPP */
+#ifdef QBMAN_CHECKING
+ p->mc.check = swp_mc_can_poll;
+#endif
+}
+
+void *qbman_swp_mc_result(struct qbman_swp *p)
+{
+ uint32_t *ret, verb;
+#ifdef QBMAN_CHECKING
+ BUG_ON(p->mc.check != swp_mc_can_poll);
+#endif
+ ret = qbman_cena_read(&p->sys, QBMAN_CENA_SWP_RR(p->mc.valid_bit));
+ /* Remove the valid-bit - command completed iff the rest is non-zero */
+ verb = ret[0] & ~QB_VALID_BIT;
+ if (!verb)
+ return NULL;
+#ifdef QBMAN_CHECKING
+ p->mc.check = swp_mc_can_start;
+#endif
+ p->mc.valid_bit ^= QB_VALID_BIT;
+ return ret;
+}
+
+/***********/
+/* Enqueue */
+/***********/
+
+/* These should be const, eventually */
+static struct qb_attr_code code_eq_cmd = QB_CODE(0, 0, 2);
+static struct qb_attr_code code_eq_orp_en = QB_CODE(0, 2, 1);
+static struct qb_attr_code code_eq_tgt_id = QB_CODE(2, 0, 24);
+/* static struct qb_attr_code code_eq_tag = QB_CODE(3, 0, 32); */
+static struct qb_attr_code code_eq_qd_en = QB_CODE(0, 4, 1);
+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 */
+ qbman_eq_cmd_empty,
+ /* DMA an enqueue response once complete */
+ qbman_eq_cmd_respond,
+ /* DMA an enqueue response only if the enqueue fails */
+ qbman_eq_cmd_respond_reject
+};
+
+void qbman_eq_desc_clear(struct qbman_eq_desc *d)
+{
+ memset(d, 0, sizeof(*d));
+}
+
+void qbman_eq_desc_set_no_orp(struct qbman_eq_desc *d, int respond_success)
+{
+ uint32_t *cl = qb_cl(d);
+
+ qb_attr_code_encode(&code_eq_orp_en, cl, 0);
+ qb_attr_code_encode(&code_eq_cmd, cl,
+ respond_success ? qbman_eq_cmd_respond :
+ qbman_eq_cmd_respond_reject);
+}
+
+void qbman_eq_desc_set_response(struct qbman_eq_desc *d,
+ dma_addr_t storage_phys,
+ int stash)
+{
+ 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(&code_eq_rsp_stash, cl, !!stash);
+}
+
+
+void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, uint32_t qdid,
+ uint32_t qd_bin, uint32_t qd_prio)
+{
+ uint32_t *cl = qb_cl(d);
+
+ qb_attr_code_encode(&code_eq_qd_en, cl, 1);
+ qb_attr_code_encode(&code_eq_tgt_id, cl, qdid);
+ qb_attr_code_encode(&code_eq_qd_bin, cl, qd_bin);
+ qb_attr_code_encode(&code_eq_qd_pri, cl, qd_prio);
+}
+
+#define EQAR_IDX(eqar) ((eqar) & 0x7)
+#define EQAR_VB(eqar) ((eqar) & 0x80)
+#define EQAR_SUCCESS(eqar) ((eqar) & 0x100)
+
+int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d,
+ const struct qbman_fd *fd)
+{
+ uint32_t *p;
+ const uint32_t *cl = qb_cl(d);
+ uint32_t eqar = qbman_cinh_read(&s->sys, QBMAN_CINH_SWP_EQAR);
+ debug("EQAR=%08x\n", eqar);
+ if (!EQAR_SUCCESS(eqar))
+ return -EBUSY;
+ p = qbman_cena_write_start(&s->sys,
+ QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)));
+ word_copy(&p[1], &cl[1], 7);
+ word_copy(&p[8], fd, sizeof(*fd) >> 2);
+ lwsync();
+ /* Set the verb byte, have to substitute in the valid-bit */
+ p[0] = cl[0] | EQAR_VB(eqar);
+ qbman_cena_write_complete(&s->sys,
+ QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar)),
+ p);
+ return 0;
+}
+
+/***************************/
+/* Volatile (pull) dequeue */
+/***************************/
+
+/* These should be const, eventually */
+static struct qb_attr_code code_pull_dct = QB_CODE(0, 0, 2);
+static struct qb_attr_code code_pull_dt = QB_CODE(0, 2, 2);
+static struct qb_attr_code code_pull_rls = QB_CODE(0, 4, 1);
+static struct qb_attr_code code_pull_stash = QB_CODE(0, 5, 1);
+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,
+ qb_pull_dt_workqueue,
+ qb_pull_dt_framequeue
+};
+
+void qbman_pull_desc_clear(struct qbman_pull_desc *d)
+{
+ memset(d, 0, sizeof(*d));
+}
+
+void qbman_pull_desc_set_storage(struct qbman_pull_desc *d,
+ struct ldpaa_dq *storage,
+ dma_addr_t storage_phys,
+ int stash)
+{
+ uint32_t *cl = qb_cl(d);
+
+ /* Squiggle the pointer 'storage' into the extra 2 words of the
+ * descriptor (which aren't copied to the hw command) */
+ *(void **)&cl[4] = storage;
+ if (!storage) {
+ qb_attr_code_encode(&code_pull_rls, cl, 0);
+ return;
+ }
+ 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));
+}
+
+void qbman_pull_desc_set_numframes(struct qbman_pull_desc *d, uint8_t numframes)
+{
+ uint32_t *cl = qb_cl(d);
+
+ BUG_ON(!numframes || (numframes > 16));
+ qb_attr_code_encode(&code_pull_numframes, cl,
+ (uint32_t)(numframes - 1));
+}
+
+void qbman_pull_desc_set_token(struct qbman_pull_desc *d, uint8_t token)
+{
+ uint32_t *cl = qb_cl(d);
+
+ qb_attr_code_encode(&code_pull_token, cl, token);
+}
+
+void qbman_pull_desc_set_fq(struct qbman_pull_desc *d, uint32_t fqid)
+{
+ uint32_t *cl = qb_cl(d);
+
+ qb_attr_code_encode(&code_pull_dct, cl, 1);
+ qb_attr_code_encode(&code_pull_dt, cl, qb_pull_dt_framequeue);
+ qb_attr_code_encode(&code_pull_dqsource, cl, fqid);
+}
+
+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)
+ 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);
+ word_copy(&p[1], &cl[1], 3);
+ lwsync();
+ /* Set the verb byte, have to substitute in the valid-bit */
+ p[0] = cl[0] | s->vdq.valid_bit;
+ s->vdq.valid_bit ^= QB_VALID_BIT;
+ qbman_cena_write_complete(&s->sys, QBMAN_CENA_SWP_VDQCR, p);
+ return 0;
+}
+
+/****************/
+/* Polling DQRR */
+/****************/
+
+static struct qb_attr_code code_dqrr_verb = QB_CODE(0, 0, 8);
+static struct qb_attr_code code_dqrr_response = QB_CODE(0, 0, 7);
+static struct qb_attr_code code_dqrr_stat = QB_CODE(0, 8, 8);
+
+#define QBMAN_DQRR_RESPONSE_DQ 0x60
+#define QBMAN_DQRR_RESPONSE_FQRN 0x21
+#define QBMAN_DQRR_RESPONSE_FQRNI 0x22
+#define QBMAN_DQRR_RESPONSE_FQPN 0x24
+#define QBMAN_DQRR_RESPONSE_FQDAN 0x25
+#define QBMAN_DQRR_RESPONSE_CDAN 0x26
+#define QBMAN_DQRR_RESPONSE_CSCN_MEM 0x27
+#define QBMAN_DQRR_RESPONSE_CGCU 0x28
+#define QBMAN_DQRR_RESPONSE_BPSCN 0x29
+#define QBMAN_DQRR_RESPONSE_CSCN_WQ 0x2a
+
+
+/* NULL return if there are no unconsumed DQRR entries. Returns a DQRR entry
+ * only once, so repeated calls can return a sequence of DQRR entries, without
+ * requiring they be consumed immediately or in any particular order. */
+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);
+
+ verb = qb_attr_code_decode(&code_dqrr_verb, p);
+ /* If the valid-bit isn't of the expected polarity, nothing there */
+ if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) {
+ qbman_cena_invalidate_prefetch(&s->sys,
+ 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 */
+ /* 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;
+ }
+ qbman_cena_invalidate_prefetch(&s->sys,
+ QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx));
+ return dq;
+}
+
+/* Consume DQRR entries previously returned from qbman_swp_dqrr_next(). */
+void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct ldpaa_dq *dq)
+{
+ qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP, QBMAN_IDX_FROM_DQRR(dq));
+}
+
+/*********************************/
+/* Polling user-provided storage */
+/*********************************/
+
+void qbman_dq_entry_set_oldtoken(struct ldpaa_dq *dq,
+ unsigned int num_entries,
+ uint8_t oldtoken)
+{
+ memset(dq, oldtoken, num_entries * sizeof(*dq));
+}
+
+int qbman_dq_entry_has_newtoken(struct qbman_swp *s,
+ const struct ldpaa_dq *dq,
+ uint8_t newtoken)
+{
+ /* To avoid converting the little-endian DQ entry to host-endian prior
+ * to us knowing whether there is a valid entry or not (and run the
+ * risk of corrupting the incoming hardware LE write), we detect in
+ * hardware endianness rather than host. This means we need a different
+ * "code" depending on whether we are BE or LE in software, which is
+ * where DQRR_TOK_OFFSET comes in... */
+ static struct qb_attr_code code_dqrr_tok_detect =
+ QB_CODE(0, DQRR_TOK_OFFSET, 8);
+ /* The user trying to poll for a result treats "dq" as const. It is
+ * however the same address that was provided to us non-const in the
+ * first place, for directing hardware DMA to. So we can cast away the
+ * const because it is mutable from our perspective. */
+ uint32_t *p = qb_cl((struct ldpaa_dq *)dq);
+ uint32_t token;
+
+ token = qb_attr_code_decode(&code_dqrr_tok_detect, &p[1]);
+ if (token != newtoken)
+ return 0;
+
+ /* Only now do we convert from hardware to host endianness. Also, as we
+ * are returning success, the user has promised not to call us again, so
+ * there's no risk of us converting the endianness twice... */
+ make_le32_n(p, 16);
+
+ /* VDQCR "no longer busy" hook - not quite the same as DQRR, because the
+ * fact "VDQCR" shows busy doesn't mean that the result we're looking at
+ * is from the same command. Eg. we may be looking at our 10th dequeue
+ * result from our first VDQCR command, yet the second dequeue command
+ * could have been kicked off already, after seeing the 1st result. Ie.
+ * the result we're looking at is not necessarily proof that we can
+ * 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;
+ return 1;
+}
+
+/********************************/
+/* Categorising dequeue entries */
+/********************************/
+
+static inline int __qbman_dq_entry_is_x(const struct ldpaa_dq *dq, uint32_t x)
+{
+ const uint32_t *p = qb_cl(dq);
+ uint32_t response_verb = qb_attr_code_decode(&code_dqrr_response, p);
+
+ return response_verb == x;
+}
+
+int qbman_dq_entry_is_DQ(const struct ldpaa_dq *dq)
+{
+ return __qbman_dq_entry_is_x(dq, QBMAN_DQRR_RESPONSE_DQ);
+}
+
+/*********************************/
+/* Parsing frame dequeue results */
+/*********************************/
+
+/* These APIs assume qbman_dq_entry_is_DQ() is TRUE */
+
+uint32_t ldpaa_dq_flags(const struct ldpaa_dq *dq)
+{
+ const uint32_t *p = qb_cl(dq);
+
+ return qb_attr_code_decode(&code_dqrr_stat, p);
+}
+
+const struct dpaa_fd *ldpaa_dq_fd(const struct ldpaa_dq *dq)
+{
+ const uint32_t *p = qb_cl(dq);
+
+ return (const struct dpaa_fd *)&p[8];
+}
+
+/******************/
+/* Buffer release */
+/******************/
+
+/* These should be const, eventually */
+/* static struct qb_attr_code code_release_num = QB_CODE(0, 0, 3); */
+static struct qb_attr_code code_release_set_me = QB_CODE(0, 5, 1);
+static struct qb_attr_code code_release_bpid = QB_CODE(0, 16, 16);
+
+void qbman_release_desc_clear(struct qbman_release_desc *d)
+{
+ uint32_t *cl;
+
+ memset(d, 0, sizeof(*d));
+ cl = qb_cl(d);
+ qb_attr_code_encode(&code_release_set_me, cl, 1);
+}
+
+void qbman_release_desc_set_bpid(struct qbman_release_desc *d, uint32_t bpid)
+{
+ uint32_t *cl = qb_cl(d);
+
+ qb_attr_code_encode(&code_release_bpid, cl, bpid);
+}
+
+#define RAR_IDX(rar) ((rar) & 0x7)
+#define RAR_VB(rar) ((rar) & 0x80)
+#define RAR_SUCCESS(rar) ((rar) & 0x100)
+
+int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d,
+ const uint64_t *buffers, unsigned int num_buffers)
+{
+ uint32_t *p;
+ const uint32_t *cl = qb_cl(d);
+ uint32_t rar = qbman_cinh_read(&s->sys, QBMAN_CINH_SWP_RAR);
+ debug("RAR=%08x\n", rar);
+ if (!RAR_SUCCESS(rar))
+ return -EBUSY;
+ BUG_ON(!num_buffers || (num_buffers > 7));
+ /* Start the release command */
+ p = qbman_cena_write_start(&s->sys,
+ QBMAN_CENA_SWP_RCR(RAR_IDX(rar)));
+ /* Copy the caller's buffer pointers to the command */
+ u64_to_le32_copy(&p[2], buffers, num_buffers);
+ lwsync();
+ /* Set the verb byte, have to substitute in the valid-bit and the number
+ * of buffers. */
+ p[0] = cl[0] | RAR_VB(rar) | num_buffers;
+ qbman_cena_write_complete(&s->sys,
+ QBMAN_CENA_SWP_RCR(RAR_IDX(rar)),
+ p);
+ return 0;
+}
+
+/*******************/
+/* Buffer acquires */
+/*******************/
+
+/* These should be const, eventually */
+static struct qb_attr_code code_acquire_bpid = QB_CODE(0, 16, 16);
+static struct qb_attr_code code_acquire_num = QB_CODE(1, 0, 3);
+static struct qb_attr_code code_acquire_r_num = QB_CODE(1, 0, 3);
+
+int qbman_swp_acquire(struct qbman_swp *s, uint32_t bpid, uint64_t *buffers,
+ unsigned int num_buffers)
+{
+ uint32_t *p;
+ uint32_t verb, rslt, num;
+
+ BUG_ON(!num_buffers || (num_buffers > 7));
+
+ /* Start the management command */
+ p = qbman_swp_mc_start(s);
+
+ if (!p)
+ return -EBUSY;
+
+ /* Encode the caller-provided attributes */
+ qb_attr_code_encode(&code_acquire_bpid, p, bpid);
+ qb_attr_code_encode(&code_acquire_num, p, num_buffers);
+
+ /* Complete the management command */
+ p = qbman_swp_mc_complete(s, p, p[0] | QBMAN_MC_ACQUIRE);
+
+ /* Decode the outcome */
+ verb = qb_attr_code_decode(&code_generic_verb, p);
+ rslt = qb_attr_code_decode(&code_generic_rslt, p);
+ num = qb_attr_code_decode(&code_acquire_r_num, p);
+ BUG_ON(verb != QBMAN_MC_ACQUIRE);
+
+ /* Determine success or failure */
+ if (unlikely(rslt != QBMAN_MC_RSLT_OK)) {
+ printf("Acquire buffers from BPID 0x%x failed, code=0x%02x\n",
+ bpid, rslt);
+ return -EIO;
+ }
+ BUG_ON(num > num_buffers);
+ /* Copy the acquired buffers to the caller's array */
+ u64_from_le32_copy(buffers, &p[2], num);
+ return (int)num;
+}
diff --git a/drivers/net/fsl-mc/dpio/qbman_portal.h b/drivers/net/fsl-mc/dpio/qbman_portal.h
new file mode 100644
index 0000000000..bb67c3bd06
--- /dev/null
+++ b/drivers/net/fsl-mc/dpio/qbman_portal.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "qbman_private.h"
+#include <fsl-mc/fsl_qbman_portal.h>
+#include <fsl-mc/fsl_dpaa_fd.h>
+
+/* All QBMan command and result structures use this "valid bit" encoding */
+#define QB_VALID_BIT ((uint32_t)0x80)
+
+/* Management command result codes */
+#define QBMAN_MC_RSLT_OK 0xf0
+
+/* --------------------- */
+/* portal data structure */
+/* --------------------- */
+
+struct qbman_swp {
+ const struct qbman_swp_desc *desc;
+ /* The qbman_sys (ie. arch/OS-specific) support code can put anything it
+ * needs in here. */
+ struct qbman_swp_sys sys;
+ /* Management commands */
+ struct {
+#ifdef QBMAN_CHECKING
+ enum swp_mc_check {
+ swp_mc_can_start, /* call __qbman_swp_mc_start() */
+ swp_mc_can_submit, /* call __qbman_swp_mc_submit() */
+ swp_mc_can_poll, /* call __qbman_swp_mc_result() */
+ } check;
+#endif
+ uint32_t valid_bit; /* 0x00 or 0x80 */
+ } mc;
+ /* Push dequeues */
+ uint32_t sdq;
+ /* Volatile dequeues */
+ struct {
+ /* VDQCR supports a "1 deep pipeline", meaning that if you know
+ * the last-submitted command is already executing in the
+ * hardware (as evidenced by at least 1 valid dequeue result),
+ * you can write another dequeue command to the register, the
+ * hardware will start executing it as soon as the
+ * already-executing command terminates. (This minimises latency
+ * and stalls.) With that in mind, this "busy" variable refers
+ * 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;
+ 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
+ * 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
+ * dequeue result location is not already equal to the command's
+ * token value. */
+ struct ldpaa_dq *storage; /* NULL if DQRR */
+ uint32_t token;
+ } vdq;
+ /* DQRR */
+ struct {
+ uint32_t next_idx;
+ uint32_t valid_bit;
+ } dqrr;
+};
+
+/* -------------------------- */
+/* portal management commands */
+/* -------------------------- */
+
+/* Different management commands all use this common base layer of code to issue
+ * commands and poll for results. The first function returns a pointer to where
+ * the caller should fill in their MC command (though they should ignore the
+ * verb byte), the second function commits merges in the caller-supplied command
+ * verb (which should not include the valid-bit) and submits the command to
+ * hardware, and the third function checks for a completed response (returns
+ * non-NULL if only if the response is complete). */
+void *qbman_swp_mc_start(struct qbman_swp *p);
+void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, uint32_t cmd_verb);
+void *qbman_swp_mc_result(struct qbman_swp *p);
+
+/* Wraps up submit + poll-for-result */
+static inline void *qbman_swp_mc_complete(struct qbman_swp *swp, void *cmd,
+ uint32_t cmd_verb)
+{
+ int loopvar;
+
+ qbman_swp_mc_submit(swp, cmd, cmd_verb);
+ DBG_POLL_START(loopvar);
+ do {
+ DBG_POLL_CHECK(loopvar);
+ cmd = qbman_swp_mc_result(swp);
+ } while (!cmd);
+ return cmd;
+}
+
+/* ------------ */
+/* qb_attr_code */
+/* ------------ */
+
+/* This struct locates a sub-field within a QBMan portal (CENA) cacheline which
+ * is either serving as a configuration command or a query result. The
+ * representation is inherently little-endian, as the indexing of the words is
+ * itself little-endian in nature and layerscape is little endian for anything
+ * that crosses a word boundary too (64-bit fields are the obvious examples).
+ */
+struct qb_attr_code {
+ unsigned int word; /* which uint32_t[] array member encodes the field */
+ unsigned int lsoffset; /* encoding offset from ls-bit */
+ unsigned int width; /* encoding width. (bool must be 1.) */
+};
+
+/* Macros to define codes */
+#define QB_CODE(a, b, c) { a, b, c}
+
+/* decode a field from a cacheline */
+static inline uint32_t qb_attr_code_decode(const struct qb_attr_code *code,
+ const uint32_t *cacheline)
+{
+ 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)
+{
+ cacheline[code->word] =
+ r32_uint32_t(code->lsoffset, code->width, cacheline[code->word])
+ | e32_uint32_t(code->lsoffset, code->width, val);
+}
+
+/* ---------------------- */
+/* Descriptors/cachelines */
+/* ---------------------- */
+
+/* To avoid needless dynamic allocation, the driver API often gives the caller
+ * 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
+ * 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
+ * order for the compiler to know its size, but the internal details are not
+ * exposed. The following macro is used within the driver for converting *any*
+ * descriptor pointer to a usable array pointer. The use of a macro (instead of
+ * an inline) is necessary to work with different descriptor types and to work
+ * correctly with const and non-const inputs (and similarly-qualified outputs).
+ */
+#define qb_cl(d) (&(d)->dont_manipulate_directly[0])
diff --git a/drivers/net/fsl-mc/dpio/qbman_private.h b/drivers/net/fsl-mc/dpio/qbman_private.h
new file mode 100644
index 0000000000..2d2556b755
--- /dev/null
+++ b/drivers/net/fsl-mc/dpio/qbman_private.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* Perform extra checking */
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <linux/types.h>
+#include <linux/compat.h>
+#include <malloc.h>
+#include <fsl-mc/fsl_qbman_base.h>
+
+#define QBMAN_CHECKING
+
+/* Any time there is a register interface which we poll on, this provides a
+ * "break after x iterations" scheme for it. It's handy for debugging, eg.
+ * where you don't want millions of lines of log output from a polling loop
+ * that won't, because such things tend to drown out the earlier log output
+ * that might explain what caused the problem. (NB: put ";" after each macro!)
+ * TODO: we should probably remove this once we're done sanitising the
+ * simulator...
+ */
+#define DBG_POLL_START(loopvar) (loopvar = 10)
+#define DBG_POLL_CHECK(loopvar) \
+ do {if (!(loopvar--)) BUG_ON(NULL == "DBG_POLL_CHECK"); } while (0)
+
+/* For CCSR or portal-CINH registers that contain fields at arbitrary offsets
+ * and widths, these macro-generated encode/decode/isolate/remove inlines can
+ * be used.
+ *
+ * Eg. to "d"ecode a 14-bit field out of a register (into a "uint16_t" type),
+ * where the field is located 3 bits "up" from the least-significant bit of the
+ * register (ie. the field location within the 32-bit register corresponds to a
+ * mask of 0x0001fff8), you would do;
+ * uint16_t field = d32_uint16_t(3, 14, reg_value);
+ *
+ * Or to "e"ncode a 1-bit boolean value (input type is "int", zero is FALSE,
+ * non-zero is TRUE, so must convert all non-zero inputs to 1, hence the "!!"
+ * operator) into a register at bit location 0x00080000 (19 bits "in" from the
+ * LS bit), do;
+ * reg_value |= e32_int(19, 1, !!field);
+ *
+ * If you wish to read-modify-write a register, such that you leave the 14-bit
+ * field as-is but have all other fields set to zero, then "i"solate the 14-bit
+ * value using;
+ * reg_value = i32_uint16_t(3, 14, reg_value);
+ *
+ * Alternatively, you could "r"emove the 1-bit boolean field (setting it to
+ * zero) but leaving all other fields as-is;
+ * reg_val = r32_int(19, 1, reg_value);
+ *
+ */
+#define MAKE_MASK32(width) (width == 32 ? 0xffffffff : \
+ (uint32_t)((1 << width) - 1))
+#define DECLARE_CODEC32(t) \
+static inline uint32_t e32_##t(uint32_t lsoffset, uint32_t width, t val) \
+{ \
+ BUG_ON(width > (sizeof(t) * 8)); \
+ return ((uint32_t)val & MAKE_MASK32(width)) << lsoffset; \
+} \
+static inline t d32_##t(uint32_t lsoffset, uint32_t width, uint32_t val) \
+{ \
+ BUG_ON(width > (sizeof(t) * 8)); \
+ return (t)((val >> lsoffset) & MAKE_MASK32(width)); \
+} \
+static inline uint32_t i32_##t(uint32_t lsoffset, uint32_t width, \
+ uint32_t val) \
+{ \
+ BUG_ON(width > (sizeof(t) * 8)); \
+ return e32_##t(lsoffset, width, d32_##t(lsoffset, width, val)); \
+} \
+static inline uint32_t r32_##t(uint32_t lsoffset, uint32_t width, \
+ uint32_t val) \
+{ \
+ BUG_ON(width > (sizeof(t) * 8)); \
+ return ~(MAKE_MASK32(width) << lsoffset) & val; \
+}
+DECLARE_CODEC32(uint32_t)
+DECLARE_CODEC32(uint16_t)
+DECLARE_CODEC32(uint8_t)
+DECLARE_CODEC32(int)
+
+ /*********************/
+ /* Debugging assists */
+ /*********************/
+
+static inline void __hexdump(unsigned long start, unsigned long end,
+ unsigned long p, size_t sz, const unsigned char *c)
+{
+ while (start < end) {
+ unsigned int pos = 0;
+ char buf[64];
+ int nl = 0;
+
+ pos += sprintf(buf + pos, "%08lx: ", start);
+ do {
+ if ((start < p) || (start >= (p + sz)))
+ pos += sprintf(buf + pos, "..");
+ else
+ pos += sprintf(buf + pos, "%02x", *(c++));
+ if (!(++start & 15)) {
+ buf[pos++] = '\n';
+ nl = 1;
+ } else {
+ nl = 0;
+ if (!(start & 1))
+ buf[pos++] = ' ';
+ if (!(start & 3))
+ buf[pos++] = ' ';
+ }
+ } while (start & 15);
+ if (!nl)
+ buf[pos++] = '\n';
+ buf[pos] = '\0';
+ debug("%s", buf);
+ }
+}
+static inline void hexdump(const void *ptr, size_t sz)
+{
+ unsigned long p = (unsigned long)ptr;
+ unsigned long start = p & ~(unsigned long)15;
+ unsigned long end = (p + sz + 15) & ~(unsigned long)15;
+ const unsigned char *c = ptr;
+
+ __hexdump(start, end, p, sz, c);
+}
+
+#if defined(__BIG_ENDIAN)
+#define DQRR_TOK_OFFSET 0
+#else
+#define DQRR_TOK_OFFSET 24
+#endif
+
+/* Similarly-named functions */
+#define upper32(a) upper_32_bits(a)
+#define lower32(a) lower_32_bits(a)
+
+ /****************/
+ /* arch assists */
+ /****************/
+
+static inline void dcbz(void *ptr)
+{
+ uint32_t *p = ptr;
+ BUG_ON((unsigned long)ptr & 63);
+ p[0] = 0;
+ p[1] = 0;
+ p[2] = 0;
+ p[3] = 0;
+ p[4] = 0;
+ p[5] = 0;
+ p[6] = 0;
+ p[7] = 0;
+ p[8] = 0;
+ p[9] = 0;
+ p[10] = 0;
+ p[11] = 0;
+ p[12] = 0;
+ p[13] = 0;
+ p[14] = 0;
+ p[15] = 0;
+}
+
+#define lwsync()
+
+#include "qbman_sys.h"
diff --git a/drivers/net/fsl-mc/dpio/qbman_sys.h b/drivers/net/fsl-mc/dpio/qbman_sys.h
new file mode 100644
index 0000000000..235d641bd4
--- /dev/null
+++ b/drivers/net/fsl-mc/dpio/qbman_sys.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* qbman_sys_decl.h and qbman_sys.h are the two platform-specific files in the
+ * driver. They are only included via qbman_private.h, which is itself a
+ * platform-independent file and is included by all the other driver source.
+ *
+ * qbman_sys_decl.h is included prior to all other declarations and logic, and
+ * it exists to provide compatibility with any linux interfaces our
+ * single-source driver code is dependent on (eg. kmalloc). Ie. this file
+ * provides linux compatibility.
+ *
+ * This qbman_sys.h header, on the other hand, is included *after* any common
+ * and platform-neutral declarations and logic in qbman_private.h, and exists to
+ * implement any platform-specific logic of the qbman driver itself. Ie. it is
+ * *not* to provide linux compatibility.
+ */
+
+/* Trace the 3 different classes of read/write access to QBMan. #undef as
+ * required. */
+#undef QBMAN_CCSR_TRACE
+#undef QBMAN_CINH_TRACE
+#undef QBMAN_CENA_TRACE
+
+/* Temporarily define this to get around the fact that cache enabled mapping is
+ * not working right now. Will remove this after uboot could map the cache
+ * enabled portal memory.
+ */
+#define QBMAN_CINH_ONLY
+
+static inline void word_copy(void *d, const void *s, unsigned int cnt)
+{
+ uint32_t *dd = d;
+ const uint32_t *ss = s;
+
+ while (cnt--)
+ *(dd++) = *(ss++);
+}
+
+/* Currently, the CENA support code expects each 32-bit word to be written in
+ * host order, and these are converted to hardware (little-endian) order on
+ * command submission. However, 64-bit quantities are must be written (and read)
+ * as two 32-bit words with the least-significant word first, irrespective of
+ * host endianness. */
+static inline void u64_to_le32_copy(void *d, const uint64_t *s,
+ unsigned int cnt)
+{
+ uint32_t *dd = d;
+ const uint32_t *ss = (const uint32_t *)s;
+
+ while (cnt--) {
+ /* TBD: the toolchain was choking on the use of 64-bit types up
+ * until recently so this works entirely with 32-bit variables.
+ * When 64-bit types become usable again, investigate better
+ * ways of doing this. */
+#if defined(__BIG_ENDIAN)
+ *(dd++) = ss[1];
+ *(dd++) = ss[0];
+ ss += 2;
+#else
+ *(dd++) = *(ss++);
+ *(dd++) = *(ss++);
+#endif
+ }
+}
+static inline void u64_from_le32_copy(uint64_t *d, const void *s,
+ unsigned int cnt)
+{
+ const uint32_t *ss = s;
+ uint32_t *dd = (uint32_t *)d;
+
+ while (cnt--) {
+#if defined(__BIG_ENDIAN)
+ dd[1] = *(ss++);
+ dd[0] = *(ss++);
+ dd += 2;
+#else
+ *(dd++) = *(ss++);
+ *(dd++) = *(ss++);
+#endif
+ }
+}
+
+/* Convert a host-native 32bit value into little endian */
+#if defined(__BIG_ENDIAN)
+static inline uint32_t make_le32(uint32_t val)
+{
+ return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
+ ((val & 0xff0000) >> 8) | ((val & 0xff000000) >> 24);
+}
+#else
+#define make_le32(val) (val)
+#endif
+static inline void make_le32_n(uint32_t *val, unsigned int num)
+{
+ while (num--) {
+ *val = make_le32(*val);
+ val++;
+ }
+}
+
+ /******************/
+ /* Portal access */
+ /******************/
+struct qbman_swp_sys {
+ /* On GPP, the sys support for qbman_swp is here. The CENA region isi
+ * not an mmap() of the real portal registers, but an allocated
+ * place-holder, because the actual writes/reads to/from the portal are
+ * marshalled from these allocated areas using QBMan's "MC access
+ * registers". CINH accesses are atomic so there's no need for a
+ * place-holder. */
+ void *cena;
+ void __iomem *addr_cena;
+ void __iomem *addr_cinh;
+};
+
+/* P_OFFSET is (ACCESS_CMD,0,12) - offset within the portal
+ * C is (ACCESS_CMD,12,1) - is inhibited? (0==CENA, 1==CINH)
+ * SWP_IDX is (ACCESS_CMD,16,10) - Software portal index
+ * P is (ACCESS_CMD,28,1) - (0==special portal, 1==any portal)
+ * T is (ACCESS_CMD,29,1) - Command type (0==READ, 1==WRITE)
+ * E is (ACCESS_CMD,31,1) - Command execute (1 to issue, poll for 0==complete)
+ */
+
+static inline void qbman_cinh_write(struct qbman_swp_sys *s, uint32_t offset,
+ uint32_t val)
+{
+ __raw_writel(val, s->addr_cinh + offset);
+#ifdef QBMAN_CINH_TRACE
+ pr_info("qbman_cinh_write(%p:0x%03x) 0x%08x\n",
+ s->addr_cinh, offset, val);
+#endif
+}
+
+static inline uint32_t qbman_cinh_read(struct qbman_swp_sys *s, uint32_t offset)
+{
+ uint32_t reg = __raw_readl(s->addr_cinh + offset);
+
+#ifdef QBMAN_CINH_TRACE
+ pr_info("qbman_cinh_read(%p:0x%03x) 0x%08x\n",
+ s->addr_cinh, offset, reg);
+#endif
+ return reg;
+}
+
+static inline void *qbman_cena_write_start(struct qbman_swp_sys *s,
+ uint32_t offset)
+{
+ void *shadow = s->cena + offset;
+
+#ifdef QBMAN_CENA_TRACE
+ pr_info("qbman_cena_write_start(%p:0x%03x) %p\n",
+ s->addr_cena, offset, shadow);
+#endif
+ BUG_ON(offset & 63);
+ dcbz(shadow);
+ return shadow;
+}
+
+static inline void qbman_cena_write_complete(struct qbman_swp_sys *s,
+ uint32_t offset, void *cmd)
+{
+ const uint32_t *shadow = cmd;
+ int loop;
+
+#ifdef QBMAN_CENA_TRACE
+ pr_info("qbman_cena_write_complete(%p:0x%03x) %p\n",
+ s->addr_cena, offset, shadow);
+ hexdump(cmd, 64);
+#endif
+ for (loop = 15; loop >= 0; loop--)
+#ifdef QBMAN_CINH_ONLY
+ __raw_writel(shadow[loop], s->addr_cinh +
+ offset + loop * 4);
+#else
+ __raw_writel(shadow[loop], s->addr_cena +
+ offset + loop * 4);
+#endif
+}
+
+static inline void *qbman_cena_read(struct qbman_swp_sys *s, uint32_t offset)
+{
+ uint32_t *shadow = s->cena + offset;
+ unsigned int loop;
+
+#ifdef QBMAN_CENA_TRACE
+ pr_info("qbman_cena_read(%p:0x%03x) %p\n",
+ s->addr_cena, offset, shadow);
+#endif
+
+ for (loop = 0; loop < 16; loop++)
+#ifdef QBMAN_CINH_ONLY
+ shadow[loop] = __raw_readl(s->addr_cinh + offset
+ + loop * 4);
+#else
+ shadow[loop] = __raw_readl(s->addr_cena + offset
+ + loop * 4);
+#endif
+#ifdef QBMAN_CENA_TRACE
+ hexdump(shadow, 64);
+#endif
+ return shadow;
+}
+
+static inline void qbman_cena_invalidate_prefetch(struct qbman_swp_sys *s,
+ uint32_t offset)
+{
+}
+
+ /******************/
+ /* Portal support */
+ /******************/
+
+/* The SWP_CFG portal register is special, in that it is used by the
+ * platform-specific code rather than the platform-independent code in
+ * qbman_portal.c. So use of it is declared locally here. */
+#define QBMAN_CINH_SWP_CFG 0xd00
+
+/* For MC portal use, we always configure with
+ * DQRR_MF is (SWP_CFG,20,3) - DQRR max fill (<- 0x4)
+ * EST is (SWP_CFG,16,3) - EQCR_CI stashing threshold (<- 0x0)
+ * RPM is (SWP_CFG,12,2) - RCR production notification mode (<- 0x3)
+ * DCM is (SWP_CFG,10,2) - DQRR consumption notification mode (<- 0x2)
+ * EPM is (SWP_CFG,8,2) - EQCR production notification mode (<- 0x3)
+ * SD is (SWP_CFG,5,1) - memory stashing drop enable (<- FALSE)
+ * SP is (SWP_CFG,4,1) - memory stashing priority (<- TRUE)
+ * SE is (SWP_CFG,3,1) - memory stashing enable (<- 0x0)
+ * DP is (SWP_CFG,2,1) - dequeue stashing priority (<- TRUE)
+ * DE is (SWP_CFG,1,1) - dequeue stashing enable (<- 0x0)
+ * EP is (SWP_CFG,0,1) - EQCR_CI stashing priority (<- FALSE)
+ */
+static inline uint32_t qbman_set_swp_cfg(uint8_t max_fill, uint8_t wn,
+ uint8_t est, uint8_t rpm, uint8_t dcm,
+ uint8_t epm, int sd, int sp, int se,
+ int dp, int de, int ep)
+{
+ uint32_t reg;
+
+ reg = e32_uint8_t(20, 3, max_fill) | e32_uint8_t(16, 3, est) |
+ e32_uint8_t(12, 2, rpm) | e32_uint8_t(10, 2, dcm) |
+ e32_uint8_t(8, 2, epm) | e32_int(5, 1, sd) |
+ e32_int(4, 1, sp) | e32_int(3, 1, se) | e32_int(2, 1, dp) |
+ e32_int(1, 1, de) | e32_int(0, 1, ep) | e32_uint8_t(14, 1, wn);
+ return reg;
+}
+
+static inline int qbman_swp_sys_init(struct qbman_swp_sys *s,
+ const struct qbman_swp_desc *d)
+{
+ uint32_t reg;
+
+ s->addr_cena = d->cena_bar;
+ s->addr_cinh = d->cinh_bar;
+ s->cena = (void *)valloc(CONFIG_SYS_PAGE_SIZE);
+ memset((void *)s->cena, 0x00, CONFIG_SYS_PAGE_SIZE);
+ if (!s->cena) {
+ printf("Could not allocate page for cena shadow\n");
+ return -1;
+ }
+
+#ifdef QBMAN_CHECKING
+ /* We should never be asked to initialise for a portal that isn't in
+ * the power-on state. (Ie. don't forget to reset portals when they are
+ * decommissioned!)
+ */
+ reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
+ BUG_ON(reg);
+#endif
+#ifdef QBMAN_CINH_ONLY
+ reg = qbman_set_swp_cfg(4, 1, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0);
+#else
+ reg = qbman_set_swp_cfg(4, 0, 0, 3, 2, 3, 0, 1, 0, 1, 0, 0);
+#endif
+ qbman_cinh_write(s, QBMAN_CINH_SWP_CFG, reg);
+ reg = qbman_cinh_read(s, QBMAN_CINH_SWP_CFG);
+ if (!reg) {
+ printf("The portal is not enabled!\n");
+ free(s->cena);
+ return -1;
+ }
+ return 0;
+}
+
+static inline void qbman_swp_sys_finish(struct qbman_swp_sys *s)
+{
+ free((void *)s->cena);
+}
diff --git a/drivers/net/fsl-mc/dpmng.c b/drivers/net/fsl-mc/dpmng.c
index cc14c7b755..01ee1126a9 100644
--- a/drivers/net/fsl-mc/dpmng.c
+++ b/drivers/net/fsl-mc/dpmng.c
@@ -1,4 +1,4 @@
-/* Copyright 2014 Freescale Semiconductor Inc.
+/* Copyright 2013-2015 Freescale Semiconductor Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -26,66 +26,3 @@ int mc_get_version(struct fsl_mc_io *mc_io, struct mc_version *mc_ver_info)
return 0;
}
-
-int dpmng_reset_aiop(struct fsl_mc_io *mc_io, int container_id,
- int aiop_tile_id)
-{
- struct mc_command cmd = { 0 };
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMNG_CMDID_RESET_AIOP,
- MC_CMD_PRI_LOW, 0);
- DPMNG_CMD_RESET_AIOP(cmd, container_id, aiop_tile_id);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-int dpmng_load_aiop(struct fsl_mc_io *mc_io,
- int container_id,
- int aiop_tile_id,
- uint64_t img_iova,
- uint32_t img_size)
-{
- struct mc_command cmd = { 0 };
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMNG_CMDID_LOAD_AIOP,
- MC_CMD_PRI_LOW,
- 0);
- DPMNG_CMD_LOAD_AIOP(cmd, container_id, aiop_tile_id, img_size,
- img_iova);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-int dpmng_run_aiop(struct fsl_mc_io *mc_io,
- int container_id,
- int aiop_tile_id,
- const struct dpmng_aiop_run_cfg *cfg)
-{
- struct mc_command cmd = { 0 };
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMNG_CMDID_RUN_AIOP,
- MC_CMD_PRI_LOW,
- 0);
- DPMNG_CMD_RUN_AIOP(cmd, container_id, aiop_tile_id, cfg);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
-
-int dpmng_reset_mc_portal(struct fsl_mc_io *mc_io)
-{
- struct mc_command cmd = { 0 };
-
- /* prepare command */
- cmd.header = mc_encode_cmd_header(DPMNG_CMDID_RESET_MC_PORTAL,
- MC_CMD_PRI_LOW,
- 0);
-
- /* send command to mc*/
- return mc_send_command(mc_io, &cmd);
-}
diff --git a/drivers/net/fsl-mc/dpni.c b/drivers/net/fsl-mc/dpni.c
new file mode 100644
index 0000000000..b384401295
--- /dev/null
+++ b/drivers/net/fsl-mc/dpni.c
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2013-2015 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <fsl-mc/fsl_mc_sys.h>
+#include <fsl-mc/fsl_mc_cmd.h>
+#include <fsl-mc/fsl_dpni.h>
+
+int dpni_open(struct fsl_mc_io *mc_io, int dpni_id, uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_OPEN,
+ MC_CMD_PRI_LOW, 0);
+ DPNI_CMD_OPEN(cmd, dpni_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dpni_close(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_CLOSE,
+ MC_CMD_PRI_HIGH, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_set_pools(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dpni_pools_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_POOLS,
+ MC_CMD_PRI_LOW,
+ token);
+ DPNI_CMD_SET_POOLS(cmd, cfg);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_enable(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ENABLE,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_disable(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_DISABLE,
+ MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_reset(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_RESET,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_attributes(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpni_attr *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_ATTR,
+ MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_ATTR(cmd, attr);
+
+ return 0;
+}
+
+int dpni_get_rx_buffer_layout(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpni_buffer_layout *layout)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_BUFFER_LAYOUT,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_RX_BUFFER_LAYOUT(cmd, layout);
+
+ return 0;
+}
+
+int dpni_set_rx_buffer_layout(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dpni_buffer_layout *layout)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_BUFFER_LAYOUT,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_RX_BUFFER_LAYOUT(cmd, layout);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_tx_buffer_layout(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpni_buffer_layout *layout)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_BUFFER_LAYOUT,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_TX_BUFFER_LAYOUT(cmd, layout);
+
+ return 0;
+}
+
+int dpni_set_tx_buffer_layout(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dpni_buffer_layout *layout)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_BUFFER_LAYOUT,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_TX_BUFFER_LAYOUT(cmd, layout);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_tx_conf_buffer_layout(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpni_buffer_layout *layout)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_CONF_BUFFER_LAYOUT,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_TX_CONF_BUFFER_LAYOUT(cmd, layout);
+
+ return 0;
+}
+
+int dpni_set_tx_conf_buffer_layout(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dpni_buffer_layout *layout)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_CONF_BUFFER_LAYOUT,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_TX_CONF_BUFFER_LAYOUT(cmd, layout);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_qdid(struct fsl_mc_io *mc_io, uint16_t token, uint16_t *qdid)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_QDID,
+ MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_QDID(cmd, *qdid);
+
+ return 0;
+}
+
+int dpni_get_tx_data_offset(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ uint16_t *data_offset)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_DATA_OFFSET,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_TX_DATA_OFFSET(cmd, *data_offset);
+
+ return 0;
+}
+
+int dpni_get_counter(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ enum dpni_counter counter,
+ uint64_t *value)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_COUNTER,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_GET_COUNTER(cmd, counter);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_COUNTER(cmd, *value);
+
+ return 0;
+}
+
+int dpni_set_counter(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ enum dpni_counter counter,
+ uint64_t value)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_COUNTER,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_COUNTER(cmd, counter, value);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_set_link_cfg(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpni_link_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_LINK_CFG,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_LINK_CFG(cmd, cfg);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_link_state(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dpni_link_state *state)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_LINK_STATE,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_LINK_STATE(cmd, state);
+
+ return 0;
+}
+
+
+int dpni_set_primary_mac_addr(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const uint8_t mac_addr[6])
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_PRIM_MAC,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_PRIMARY_MAC_ADDR(cmd, mac_addr);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_primary_mac_addr(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ uint8_t mac_addr[6])
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_PRIM_MAC,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_PRIMARY_MAC_ADDR(cmd, mac_addr);
+
+ return 0;
+}
+
+int dpni_add_mac_addr(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const uint8_t mac_addr[6])
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_ADD_MAC_ADDR,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_ADD_MAC_ADDR(cmd, mac_addr);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_remove_mac_addr(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const uint8_t mac_addr[6])
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_REMOVE_MAC_ADDR,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_REMOVE_MAC_ADDR(cmd, mac_addr);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_set_tx_flow(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ uint16_t *flow_id,
+ const struct dpni_tx_flow_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_TX_FLOW,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_TX_FLOW(cmd, *flow_id, cfg);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_SET_TX_FLOW(cmd, *flow_id);
+
+ return 0;
+}
+
+int dpni_get_tx_flow(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ uint16_t flow_id,
+ struct dpni_tx_flow_attr *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_TX_FLOW,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_GET_TX_FLOW(cmd, flow_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_TX_FLOW(cmd, attr);
+
+ return 0;
+}
+
+int dpni_set_rx_flow(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ uint8_t tc_id,
+ uint16_t flow_id,
+ const struct dpni_queue_cfg *cfg)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_SET_RX_FLOW,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_SET_RX_FLOW(cmd, tc_id, flow_id, cfg);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dpni_get_rx_flow(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ uint8_t tc_id,
+ uint16_t flow_id,
+ struct dpni_queue_attr *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPNI_CMDID_GET_RX_FLOW,
+ MC_CMD_PRI_LOW, token);
+ DPNI_CMD_GET_RX_FLOW(cmd, tc_id, flow_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPNI_RSP_GET_RX_FLOW(cmd, attr);
+
+ return 0;
+}
diff --git a/drivers/net/fsl-mc/dprc.c b/drivers/net/fsl-mc/dprc.c
new file mode 100644
index 0000000000..d481200243
--- /dev/null
+++ b/drivers/net/fsl-mc/dprc.c
@@ -0,0 +1,283 @@
+/*
+ * Freescale Layerscape MC I/O wrapper
+ *
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
+ * Author: German Rivera <German.Rivera@freescale.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <fsl-mc/fsl_mc_sys.h>
+#include <fsl-mc/fsl_mc_cmd.h>
+#include <fsl-mc/fsl_dprc.h>
+
+int dprc_get_container_id(struct fsl_mc_io *mc_io, int *container_id)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONT_ID,
+ MC_CMD_PRI_LOW, 0);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_CONTAINER_ID(cmd, *container_id);
+
+ return 0;
+}
+
+int dprc_open(struct fsl_mc_io *mc_io, int container_id, uint16_t *token)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_OPEN, MC_CMD_PRI_LOW,
+ 0);
+ DPRC_CMD_OPEN(cmd, container_id);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ *token = MC_CMD_HDR_READ_TOKEN(cmd.header);
+
+ return 0;
+}
+
+int dprc_close(struct fsl_mc_io *mc_io, uint16_t token)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CLOSE, MC_CMD_PRI_HIGH,
+ token);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dprc_reset_container(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ int child_container_id)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_RESET_CONT,
+ MC_CMD_PRI_LOW, token);
+ DPRC_CMD_RESET_CONTAINER(cmd, child_container_id);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dprc_get_attributes(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ struct dprc_attributes *attr)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_ATTR,
+ MC_CMD_PRI_LOW,
+ token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_ATTRIBUTES(cmd, attr);
+
+ return 0;
+}
+
+int dprc_get_obj_count(struct fsl_mc_io *mc_io, uint16_t token, int *obj_count)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_COUNT,
+ MC_CMD_PRI_LOW, token);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_OBJ_COUNT(cmd, *obj_count);
+
+ return 0;
+}
+
+int dprc_get_obj(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ int obj_index,
+ struct dprc_obj_desc *obj_desc)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ,
+ MC_CMD_PRI_LOW,
+ token);
+ DPRC_CMD_GET_OBJ(cmd, obj_index);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_OBJ(cmd, obj_desc);
+
+ return 0;
+}
+
+int dprc_get_res_count(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ char *type,
+ int *res_count)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ *res_count = 0;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_COUNT,
+ MC_CMD_PRI_LOW, token);
+ DPRC_CMD_GET_RES_COUNT(cmd, type);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_RES_COUNT(cmd, *res_count);
+
+ return 0;
+}
+
+int dprc_get_res_ids(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ char *type,
+ struct dprc_res_ids_range_desc *range_desc)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_RES_IDS,
+ MC_CMD_PRI_LOW, token);
+ DPRC_CMD_GET_RES_IDS(cmd, range_desc, type);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_RES_IDS(cmd, range_desc);
+
+ return 0;
+}
+
+int dprc_get_obj_region(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ char *obj_type,
+ int obj_id,
+ uint8_t region_index,
+ struct dprc_region_desc *region_desc)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG,
+ MC_CMD_PRI_LOW, token);
+ DPRC_CMD_GET_OBJ_REGION(cmd, obj_type, obj_id, region_index);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_OBJ_REGION(cmd, region_desc);
+
+ return 0;
+}
+
+int dprc_connect(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dprc_endpoint *endpoint1,
+ const struct dprc_endpoint *endpoint2)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_CONNECT,
+ MC_CMD_PRI_LOW,
+ token);
+ DPRC_CMD_CONNECT(cmd, endpoint1, endpoint2);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dprc_disconnect(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dprc_endpoint *endpoint)
+{
+ struct mc_command cmd = { 0 };
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_DISCONNECT,
+ MC_CMD_PRI_LOW,
+ token);
+ DPRC_CMD_DISCONNECT(cmd, endpoint);
+
+ /* send command to mc*/
+ return mc_send_command(mc_io, &cmd);
+}
+
+int dprc_get_connection(struct fsl_mc_io *mc_io,
+ uint16_t token,
+ const struct dprc_endpoint *endpoint1,
+ struct dprc_endpoint *endpoint2,
+ int *state)
+{
+ struct mc_command cmd = { 0 };
+ int err;
+
+ /* prepare command */
+ cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION,
+ MC_CMD_PRI_LOW,
+ token);
+ DPRC_CMD_GET_CONNECTION(cmd, endpoint1);
+
+ /* send command to mc*/
+ err = mc_send_command(mc_io, &cmd);
+ if (err)
+ return err;
+
+ /* retrieve response parameters */
+ DPRC_RSP_GET_CONNECTION(cmd, endpoint2, *state);
+
+ return 0;
+}
diff --git a/drivers/net/fsl-mc/fsl_dpmng_cmd.h b/drivers/net/fsl-mc/fsl_dpmng_cmd.h
index c9fe021f45..33f84f39bb 100644
--- a/drivers/net/fsl-mc/fsl_dpmng_cmd.h
+++ b/drivers/net/fsl-mc/fsl_dpmng_cmd.h
@@ -1,4 +1,4 @@
-/* Copyright 2014 Freescale Semiconductor Inc.
+/* Copyright 2013-2015 Freescale Semiconductor Inc.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -7,10 +7,6 @@
/* Command IDs */
#define DPMNG_CMDID_GET_VERSION 0x831
-#define DPMNG_CMDID_RESET_AIOP 0x832
-#define DPMNG_CMDID_LOAD_AIOP 0x833
-#define DPMNG_CMDID_RUN_AIOP 0x834
-#define DPMNG_CMDID_RESET_MC_PORTAL 0x835
/* cmd, param, offset, width, type, arg_name */
#define DPMNG_RSP_GET_VERSION(cmd, mc_ver_info) \
@@ -20,30 +16,4 @@ do { \
MC_RSP_OP(cmd, 1, 0, 32, uint32_t, mc_ver_info->minor); \
} while (0)
-/* cmd, param, offset, width, type, arg_name */
-#define DPMNG_CMD_RESET_AIOP(cmd, container_id, aiop_tile_id) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 32, int, aiop_tile_id); \
- MC_CMD_OP(cmd, 0, 32, 32, int, container_id); \
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMNG_CMD_LOAD_AIOP(cmd, container_id, aiop_tile_id, img_size, \
- img_iova) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 32, int, aiop_tile_id); \
- MC_CMD_OP(cmd, 0, 32, 32, int, container_id); \
- MC_CMD_OP(cmd, 1, 0, 32, uint32_t, img_size); \
- MC_CMD_OP(cmd, 2, 0, 64, uint64_t, img_iova); \
-} while (0)
-
-/* cmd, param, offset, width, type, arg_name */
-#define DPMNG_CMD_RUN_AIOP(cmd, container_id, aiop_tile_id, cfg) \
-do { \
- MC_CMD_OP(cmd, 0, 0, 32, int, aiop_tile_id); \
- MC_CMD_OP(cmd, 0, 32, 32, int, container_id); \
- MC_CMD_OP(cmd, 1, 0, 32, uint32_t, cfg->cores_mask); \
- MC_CMD_OP(cmd, 2, 0, 64, uint64_t, cfg->options); \
-} while (0)
-
#endif /* __FSL_DPMNG_CMD_H */
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
index 74b0085301..c5c44bcab0 100644
--- a/drivers/net/fsl-mc/mc.c
+++ b/drivers/net/fsl-mc/mc.c
@@ -3,16 +3,75 @@
*
* SPDX-License-Identifier: GPL-2.0+
*/
-
#include <errno.h>
#include <asm/io.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>
+
+#define MC_RAM_BASE_ADDR_ALIGNMENT (512UL * 1024 * 1024)
+#define MC_RAM_BASE_ADDR_ALIGNMENT_MASK (~(MC_RAM_BASE_ADDR_ALIGNMENT - 1))
+#define MC_RAM_SIZE_ALIGNMENT (256UL * 1024 * 1024)
+
+#define MC_MEM_SIZE_ENV_VAR "mcmemsize"
+#define MC_BOOT_TIMEOUT_ENV_VAR "mcboottimeout"
DECLARE_GLOBAL_DATA_PTR;
static int mc_boot_status;
+struct fsl_mc_io *dflt_mc_io = NULL;
+uint16_t dflt_dprc_handle = 0;
+struct fsl_dpbp_obj *dflt_dpbp = NULL;
+struct fsl_dpio_obj *dflt_dpio = NULL;
+uint16_t dflt_dpio_handle = 0;
+
+#ifdef DEBUG
+void dump_ram_words(const char *title, void *addr)
+{
+ int i;
+ uint32_t *words = addr;
+
+ printf("Dumping beginning of %s (%p):\n", title, addr);
+ for (i = 0; i < 16; i++)
+ printf("%#x ", words[i]);
+ printf("\n");
+}
+
+void dump_mc_ccsr_regs(struct mc_ccsr_registers __iomem *mc_ccsr_regs)
+{
+ printf("MC CCSR registers:\n"
+ "reg_gcr1 %#x\n"
+ "reg_gsr %#x\n"
+ "reg_sicbalr %#x\n"
+ "reg_sicbahr %#x\n"
+ "reg_sicapr %#x\n"
+ "reg_mcfbalr %#x\n"
+ "reg_mcfbahr %#x\n"
+ "reg_mcfapr %#x\n"
+ "reg_psr %#x\n",
+ mc_ccsr_regs->reg_gcr1,
+ mc_ccsr_regs->reg_gsr,
+ mc_ccsr_regs->reg_sicbalr,
+ mc_ccsr_regs->reg_sicbahr,
+ mc_ccsr_regs->reg_sicapr,
+ mc_ccsr_regs->reg_mcfbalr,
+ mc_ccsr_regs->reg_mcfbahr,
+ mc_ccsr_regs->reg_mcfapr,
+ mc_ccsr_regs->reg_psr);
+}
+#else
+
+#define dump_ram_words(title, addr)
+#define dump_mc_ccsr_regs(mc_ccsr_regs)
+
+#endif /* DEBUG */
+
+#ifndef CONFIG_SYS_LS_MC_FW_IN_DDR
/**
* Copying MC firmware or DPL image to DDR
*/
@@ -21,6 +80,7 @@ static int mc_copy_image(const char *title,
{
debug("%s copied to address %p\n", title, (void *)mc_ram_addr);
memcpy((void *)mc_ram_addr, (void *)image_addr, image_size);
+ flush_dcache_range(mc_ram_addr, mc_ram_addr + image_size);
return 0;
}
@@ -82,23 +142,254 @@ int parse_mc_firmware_fit_image(const void **raw_image_addr,
return 0;
}
+#endif
+
+/*
+ * Calculates the values to be used to specify the address range
+ * for the MC private DRAM block, in the MCFBALR/MCFBAHR registers.
+ * It returns the highest 512MB-aligned address within the given
+ * address range, in '*aligned_base_addr', and the number of 256 MiB
+ * blocks in it, in 'num_256mb_blocks'.
+ */
+static int calculate_mc_private_ram_params(u64 mc_private_ram_start_addr,
+ size_t mc_ram_size,
+ u64 *aligned_base_addr,
+ u8 *num_256mb_blocks)
+{
+ u64 addr;
+ u16 num_blocks;
+
+ if (mc_ram_size % MC_RAM_SIZE_ALIGNMENT != 0) {
+ printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n",
+ mc_ram_size);
+ return -EINVAL;
+ }
+
+ num_blocks = mc_ram_size / MC_RAM_SIZE_ALIGNMENT;
+ if (num_blocks < 1 || num_blocks > 0xff) {
+ printf("fsl-mc: ERROR: invalid MC private RAM size (%lu)\n",
+ mc_ram_size);
+ return -EINVAL;
+ }
+
+ addr = (mc_private_ram_start_addr + mc_ram_size - 1) &
+ MC_RAM_BASE_ADDR_ALIGNMENT_MASK;
+
+ if (addr < mc_private_ram_start_addr) {
+ printf("fsl-mc: ERROR: bad start address %#llx\n",
+ mc_private_ram_start_addr);
+ return -EFAULT;
+ }
+
+ *aligned_base_addr = addr;
+ *num_256mb_blocks = num_blocks;
+ return 0;
+}
+
+static int load_mc_dpc(u64 mc_ram_addr, size_t mc_ram_size)
+{
+ u64 mc_dpc_offset;
+#ifndef CONFIG_SYS_LS_MC_DPC_IN_DDR
+ int error;
+ void *dpc_fdt_hdr;
+ int dpc_size;
+#endif
+
+#ifdef CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET
+ BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET & 0x3) != 0 ||
+ CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET > 0xffffffff);
+
+ mc_dpc_offset = CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET;
+#else
+#error "CONFIG_SYS_LS_MC_DRAM_DPC_OFFSET not defined"
+#endif
+
+ /*
+ * Load the MC DPC blob in the MC private DRAM block:
+ */
+#ifdef CONFIG_SYS_LS_MC_DPC_IN_DDR
+ printf("MC DPC is preloaded to %#llx\n", mc_ram_addr + mc_dpc_offset);
+#else
+ /*
+ * Get address and size of the DPC blob stored in flash:
+ */
+#ifdef CONFIG_SYS_LS_MC_DPC_IN_NOR
+ dpc_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPC_ADDR;
+#else
+#error "No CONFIG_SYS_LS_MC_DPC_IN_xxx defined"
+#endif
+
+ error = fdt_check_header(dpc_fdt_hdr);
+ if (error != 0) {
+ /*
+ * 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");
+ 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",
+ dpc_size);
+ return -EINVAL;
+ }
+
+ mc_copy_image("MC DPC blob",
+ (u64)dpc_fdt_hdr, dpc_size, mc_ram_addr + mc_dpc_offset);
+#endif /* not defined CONFIG_SYS_LS_MC_DPC_IN_DDR */
+
+ dump_ram_words("DPC", (void *)(mc_ram_addr + mc_dpc_offset));
+ return 0;
+}
-int mc_init(bd_t *bis)
+static int load_mc_dpl(u64 mc_ram_addr, size_t mc_ram_size)
+{
+ u64 mc_dpl_offset;
+#ifndef CONFIG_SYS_LS_MC_DPL_IN_DDR
+ int error;
+ void *dpl_fdt_hdr;
+ int dpl_size;
+#endif
+
+#ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET
+ BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 ||
+ CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff);
+
+ mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET;
+#else
+#error "CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET not defined"
+#endif
+
+ /*
+ * Load the MC DPL blob in the MC private DRAM block:
+ */
+#ifdef CONFIG_SYS_LS_MC_DPL_IN_DDR
+ printf("MC DPL is preloaded to %#llx\n", mc_ram_addr + mc_dpl_offset);
+#else
+ /*
+ * Get address and size of the DPL blob stored in flash:
+ */
+#ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR
+ dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR;
+#else
+#error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined"
+#endif
+
+ error = fdt_check_header(dpl_fdt_hdr);
+ if (error != 0) {
+ printf("fsl-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",
+ dpl_size);
+ return -EINVAL;
+ }
+
+ mc_copy_image("MC DPL blob",
+ (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset);
+#endif /* not defined CONFIG_SYS_LS_MC_DPL_IN_DDR */
+
+ dump_ram_words("DPL", (void *)(mc_ram_addr + mc_dpl_offset));
+ return 0;
+}
+
+/**
+ * Return the MC boot timeout value in milliseconds
+ */
+static unsigned long get_mc_boot_timeout_ms(void)
+{
+ unsigned long timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS;
+
+ char *timeout_ms_env_var = getenv(MC_BOOT_TIMEOUT_ENV_VAR);
+
+ if (timeout_ms_env_var) {
+ timeout_ms = simple_strtoul(timeout_ms_env_var, NULL, 10);
+ if (timeout_ms == 0) {
+ printf("fsl-mc: WARNING: Invalid value for \'"
+ MC_BOOT_TIMEOUT_ENV_VAR
+ "\' environment variable: %lu\n",
+ timeout_ms);
+
+ timeout_ms = CONFIG_SYS_LS_MC_BOOT_TIMEOUT_MS;
+ }
+ }
+
+ return timeout_ms;
+}
+
+static int wait_for_mc(bool booting_mc, u32 *final_reg_gsr)
+{
+ u32 reg_gsr;
+ u32 mc_fw_boot_status;
+ unsigned long timeout_ms = get_mc_boot_timeout_ms();
+ 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 */
+ reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr);
+ mc_fw_boot_status = (reg_gsr & GSR_FS_MASK);
+ if (mc_fw_boot_status & 0x1)
+ break;
+
+ timeout_ms--;
+ if (timeout_ms == 0)
+ break;
+ }
+
+ 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");
+
+ /* TODO: Get an error status from an MC CCSR register */
+ return -ETIMEDOUT;
+ }
+
+ if (mc_fw_boot_status != 0x1) {
+ /*
+ * TODO: Identify critical errors from the GSR register's FS
+ * field and for those errors, set error to -ENODEV or other
+ * 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);
+ }
+ }
+
+ *final_reg_gsr = reg_gsr;
+ return 0;
+}
+
+int mc_init(void)
{
int error = 0;
- int timeout = 200000;
+ int portal_id = 0;
struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR;
u64 mc_ram_addr;
- u64 mc_dpl_offset;
u32 reg_gsr;
- u32 mc_fw_boot_status;
- void *dpl_fdt_hdr;
- int dpl_size;
+ u32 reg_mcfbalr;
+#ifndef CONFIG_SYS_LS_MC_FW_IN_DDR
const void *raw_image_addr;
size_t raw_image_size = 0;
- struct fsl_mc_io mc_io;
- int portal_id;
+#endif
struct mc_version mc_ver_info;
+ u64 mc_ram_aligned_base_addr;
+ u8 mc_ram_num_256mb_blocks;
+ size_t mc_ram_size = mc_get_dram_block_size();
/*
* The MC private DRAM block was already carved at the end of DRAM
@@ -112,6 +403,20 @@ int mc_init(bd_t *bis)
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,
+ &mc_ram_num_256mb_blocks);
+ if (error != 0)
+ goto out;
+
/*
* Management Complex cores should be held at reset out of POR.
* U-boot should be the first software to touch MC. To be safe,
@@ -127,6 +432,9 @@ int mc_init(bd_t *bis)
out_le32(&mc_ccsr_regs->reg_gcr1, 0);
dmb();
+#ifdef CONFIG_SYS_LS_MC_FW_IN_DDR
+ printf("MC firmware is preloaded to %#llx\n", mc_ram_addr);
+#else
error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size);
if (error != 0)
goto out;
@@ -135,83 +443,34 @@ int mc_init(bd_t *bis)
*/
mc_copy_image("MC Firmware",
(u64)raw_image_addr, raw_image_size, mc_ram_addr);
-
- /*
- * Get address and size of the DPL blob stored in flash:
- */
-#ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR
- dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR;
-#else
-#error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined"
#endif
+ dump_ram_words("firmware", (void *)mc_ram_addr);
- error = fdt_check_header(dpl_fdt_hdr);
- if (error != 0) {
- printf("fsl-mc: ERROR: Bad DPL image (bad header)\n");
- goto out;
- }
-
- 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",
- dpl_size);
- error = -EINVAL;
+ error = load_mc_dpc(mc_ram_addr, mc_ram_size);
+ if (error != 0)
goto out;
- }
- /*
- * Calculate offset in the MC private DRAM block at which the MC DPL
- * blob is to be placed:
- */
-#ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET
- BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 ||
- CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff);
-
- mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET;
-#else
- mc_dpl_offset = mc_get_dram_block_size() -
- roundup(CONFIG_SYS_LS_MC_DPL_MAX_LENGTH, 4096);
-
- if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) {
- printf("%s: Invalid MC DPL offset: %llu\n",
- __func__, mc_dpl_offset);
- error = -EINVAL;
+ error = load_mc_dpl(mc_ram_addr, mc_ram_size);
+ if (error != 0)
goto out;
- }
-#endif
-
- /*
- * Load the MC DPL blob at the far end of the MC private DRAM block:
- *
- * TODO: Should we place the DPL at a different location to match
- * assumptions of MC firmware about its memory layout?
- */
- mc_copy_image("MC DPL blob",
- (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset);
debug("mc_ccsr_regs %p\n", mc_ccsr_regs);
+ dump_mc_ccsr_regs(mc_ccsr_regs);
/*
- * Tell MC where the MC Firmware image was loaded in DDR:
+ * Tell MC what is the address range of the DRAM block assigned to it:
*/
- out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr);
- out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32));
+ reg_mcfbalr = (u32)mc_ram_aligned_base_addr |
+ (mc_ram_num_256mb_blocks - 1);
+ 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);
/*
- * Tell MC where the DPL blob was loaded in DDR, by indicating
- * its offset relative to the beginning of the DDR block
- * allocated to the MC firmware. The MC firmware is responsible
- * for checking that there is no overlap between the DPL blob
- * and the runtime heap and stack of the MC firmware itself.
- *
- * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of
- * the GSR MC CCSR register. So, this offset is assumed to be 4-byte
- * aligned.
- * Care must be taken not to write 1s into bits 31 and 30 of the GSR in
- * this case as the SoC COP or PIC will be signaled.
+ * Tell the MC that we want delayed DPL deployment.
*/
- out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2));
+ out_le32(&mc_ccsr_regs->reg_gsr, 0xDD00);
printf("\nfsl-mc: Booting Management Complex ...\n");
@@ -219,38 +478,9 @@ int mc_init(bd_t *bis)
* Deassert reset and release MC core 0 to run
*/
out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST);
- dmb();
- debug("Polling mc_ccsr_regs->reg_gsr ...\n");
-
- for (;;) {
- reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr);
- mc_fw_boot_status = (reg_gsr & GSR_FS_MASK);
- if (mc_fw_boot_status & 0x1)
- break;
-
- udelay(1000); /* throttle polling */
- if (timeout-- <= 0)
- break;
- }
-
- if (timeout <= 0) {
- printf("fsl-mc: timeout booting management complex firmware\n");
-
- /* TODO: Get an error status from an MC CCSR register */
- error = -ETIMEDOUT;
+ error = wait_for_mc(true, &reg_gsr);
+ if (error != 0)
goto out;
- }
-
- if (mc_fw_boot_status != 0x1) {
- /*
- * TODO: Identify critical errors from the GSR register's FS
- * field and for those errors, set error to -ENODEV or other
- * appropriate errno, so that the status property is set to
- * failure in the fsl,dprc device tree node.
- */
- printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n",
- reg_gsr);
- }
/*
* TODO: need to obtain the portal_id for the root container from the
@@ -259,13 +489,20 @@ int mc_init(bd_t *bis)
portal_id = 0;
/*
- * Check that the MC firmware is responding portal commands:
+ * Initialize the global default MC portal
+ * And check that the MC firmware is responding portal commands:
*/
- mc_io.mmio_regs = SOC_MC_PORTAL_ADDR(portal_id);
+ dflt_mc_io = (struct fsl_mc_io *)malloc(sizeof(struct fsl_mc_io));
+ if (!dflt_mc_io) {
+ printf(" No memory: malloc() failed\n");
+ return -ENOMEM;
+ }
+
+ dflt_mc_io->mmio_regs = SOC_MC_PORTAL_ADDR(portal_id);
debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n",
- portal_id, mc_io.mmio_regs);
+ portal_id, dflt_mc_io->mmio_regs);
- error = mc_get_version(&mc_io, &mc_ver_info);
+ error = mc_get_version(dflt_mc_io, &mc_ver_info);
if (error != 0) {
printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n",
error);
@@ -282,7 +519,16 @@ int mc_init(bd_t *bis)
printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n",
mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision,
- mc_fw_boot_status);
+ reg_gsr & GSR_FS_MASK);
+
+ /*
+ * Tell the MC to deploy the DPL:
+ */
+ out_le32(&mc_ccsr_regs->reg_gsr, 0x0);
+ printf("\nfsl-mc: Deploying data path layout ...\n");
+ error = wait_for_mc(false, &reg_gsr);
+ if (error != 0)
+ goto out;
out:
if (error != 0)
mc_boot_status = -error;
@@ -299,12 +545,242 @@ int get_mc_boot_status(void)
/**
* Return the actual size of the MC private DRAM block.
- *
- * NOTE: For now this function always returns the minimum required size,
- * However, in the future, the actual size may be obtained from an environment
- * variable.
*/
unsigned long mc_get_dram_block_size(void)
{
- return CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE;
+ unsigned long dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE;
+
+ char *dram_block_size_env_var = getenv(MC_MEM_SIZE_ENV_VAR);
+
+ if (dram_block_size_env_var) {
+ dram_block_size = simple_strtoul(dram_block_size_env_var, NULL,
+ 10);
+
+ if (dram_block_size < CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE) {
+ printf("fsl-mc: WARNING: Invalid value for \'"
+ MC_MEM_SIZE_ENV_VAR
+ "\' environment variable: %lu\n",
+ dram_block_size);
+
+ dram_block_size = CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE;
+ }
+ }
+
+ return dram_block_size;
+}
+
+int dpio_init(struct dprc_obj_desc obj_desc)
+{
+ struct qbman_swp_desc p_des;
+ struct dpio_attr attr;
+ int err = 0;
+
+ dflt_dpio = (struct fsl_dpio_obj *)malloc(sizeof(struct fsl_dpio_obj));
+ if (!dflt_dpio) {
+ printf(" No memory: malloc() failed\n");
+ return -ENOMEM;
+ }
+
+ dflt_dpio->dpio_id = obj_desc.id;
+
+ err = dpio_open(dflt_mc_io, obj_desc.id, &dflt_dpio_handle);
+ if (err) {
+ printf("dpio_open() failed\n");
+ goto err_open;
+ }
+
+ err = dpio_get_attributes(dflt_mc_io, dflt_dpio_handle, &attr);
+ if (err) {
+ printf("dpio_get_attributes() failed %d\n", err);
+ goto err_get_attr;
+ }
+
+ err = dpio_enable(dflt_mc_io, dflt_dpio_handle);
+ if (err) {
+ 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,
+ 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;
+
+ dflt_dpio->sw_portal = qbman_swp_init(&p_des);
+ if (dflt_dpio->sw_portal == NULL) {
+ printf("qbman_swp_init() failed\n");
+ goto err_get_swp_init;
+ }
+ return 0;
+
+err_get_swp_init:
+err_get_enable:
+ dpio_disable(dflt_mc_io, dflt_dpio_handle);
+err_get_attr:
+ dpio_close(dflt_mc_io, dflt_dpio_handle);
+err_open:
+ free(dflt_dpio);
+ return err;
+}
+
+int dpbp_init(struct dprc_obj_desc obj_desc)
+{
+ dflt_dpbp = (struct fsl_dpbp_obj *)malloc(sizeof(struct fsl_dpbp_obj));
+ if (!dflt_dpbp) {
+ printf(" No memory: malloc() failed\n");
+ return -ENOMEM;
+ }
+ dflt_dpbp->dpbp_attr.id = obj_desc.id;
+
+ return 0;
+}
+
+int dprc_init_container_obj(struct dprc_obj_desc obj_desc, uint16_t dprc_handle)
+{
+ int error = 0, state = 0;
+ struct dprc_endpoint dpni_endpoint, dpmac_endpoint;
+ if (!strcmp(obj_desc.type, "dpbp")) {
+ if (!dflt_dpbp) {
+ error = dpbp_init(obj_desc);
+ if (error < 0)
+ printf("dpbp_init failed\n");
+ }
+ } else if (!strcmp(obj_desc.type, "dpio")) {
+ if (!dflt_dpio) {
+ error = dpio_init(obj_desc);
+ if (error < 0)
+ printf("dpio_init failed\n");
+ }
+ } else if (!strcmp(obj_desc.type, "dpni")) {
+ strcpy(dpni_endpoint.type, obj_desc.type);
+ dpni_endpoint.id = obj_desc.id;
+ error = dprc_get_connection(dflt_mc_io, dprc_handle,
+ &dpni_endpoint, &dpmac_endpoint, &state);
+ if (!strcmp(dpmac_endpoint.type, "dpmac"))
+ error = ldpaa_eth_init(obj_desc);
+ if (error < 0)
+ printf("ldpaa_eth_init failed\n");
+ }
+
+ return error;
+}
+
+int dprc_scan_container_obj(uint16_t dprc_handle, char *obj_type, int i)
+{
+ int error = 0;
+ struct dprc_obj_desc obj_desc;
+
+ memset((void *)&obj_desc, 0x00, sizeof(struct dprc_obj_desc));
+
+ error = dprc_get_obj(dflt_mc_io, dprc_handle,
+ i, &obj_desc);
+ if (error < 0) {
+ printf("dprc_get_obj(i=%d) failed: %d\n",
+ i, error);
+ return error;
+ }
+
+ if (!strcmp(obj_desc.type, obj_type)) {
+ debug("Discovered object: type %s, id %d, req %s\n",
+ obj_desc.type, obj_desc.id, obj_type);
+
+ error = dprc_init_container_obj(obj_desc, dprc_handle);
+ if (error < 0) {
+ printf("dprc_init_container_obj(i=%d) failed: %d\n",
+ i, error);
+ return error;
+ }
+ }
+
+ return error;
+}
+
+int fsl_mc_ldpaa_init(bd_t *bis)
+{
+ int i, error = 0;
+ int dprc_opened = 0, container_id;
+ int num_child_objects = 0;
+
+ error = mc_init();
+ if (error < 0)
+ goto error;
+
+ error = dprc_get_container_id(dflt_mc_io, &container_id);
+ if (error < 0) {
+ printf("dprc_get_container_id() failed: %d\n", error);
+ goto error;
+ }
+
+ debug("fsl-mc: Container id=0x%x\n", container_id);
+
+ error = dprc_open(dflt_mc_io, container_id, &dflt_dprc_handle);
+ if (error < 0) {
+ printf("dprc_open() failed: %d\n", error);
+ goto error;
+ }
+ dprc_opened = true;
+
+ error = dprc_get_obj_count(dflt_mc_io,
+ dflt_dprc_handle,
+ &num_child_objects);
+ if (error < 0) {
+ printf("dprc_get_obj_count() failed: %d\n", error);
+ goto error;
+ }
+ debug("Total child in container %d = %d\n", container_id,
+ num_child_objects);
+
+ if (num_child_objects != 0) {
+ /*
+ * Discover objects currently in the DPRC container in the MC:
+ */
+ for (i = 0; i < num_child_objects; i++)
+ error = dprc_scan_container_obj(dflt_dprc_handle,
+ "dpbp", i);
+
+ for (i = 0; i < num_child_objects; i++)
+ error = dprc_scan_container_obj(dflt_dprc_handle,
+ "dpio", i);
+
+ for (i = 0; i < num_child_objects; i++)
+ error = dprc_scan_container_obj(dflt_dprc_handle,
+ "dpni", i);
+ }
+error:
+ if (dprc_opened)
+ dprc_close(dflt_mc_io, dflt_dprc_handle);
+
+ return error;
+}
+
+void fsl_mc_ldpaa_exit(bd_t *bis)
+{
+ int err;
+
+ if (get_mc_boot_status() == 0) {
+ err = dpio_disable(dflt_mc_io, dflt_dpio_handle);
+ if (err < 0) {
+ printf("dpio_disable() failed: %d\n", err);
+ return;
+ }
+ err = dpio_reset(dflt_mc_io, dflt_dpio_handle);
+ if (err < 0) {
+ printf("dpio_reset() failed: %d\n", err);
+ return;
+ }
+ err = dpio_close(dflt_mc_io, dflt_dpio_handle);
+ if (err < 0) {
+ printf("dpio_close() failed: %d\n", err);
+ return;
+ }
+
+ free(dflt_dpio);
+ free(dflt_dpbp);
+ }
+
+ if (dflt_mc_io)
+ free(dflt_mc_io);
}
diff --git a/drivers/net/fsl-mc/mc_sys.c b/drivers/net/fsl-mc/mc_sys.c
index 7c8e003ad0..3fc1f98341 100644
--- a/drivers/net/fsl-mc/mc_sys.c
+++ b/drivers/net/fsl-mc/mc_sys.c
@@ -1,7 +1,7 @@
/*
* Freescale Layerscape MC I/O wrapper
*
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
* Author: German Rivera <German.Rivera@freescale.com>
*
* SPDX-License-Identifier: GPL-2.0+
@@ -32,7 +32,7 @@ int mc_send_command(struct fsl_mc_io *mc_io,
struct mc_command *cmd)
{
enum mc_cmd_status status;
- int timeout = 2000;
+ int timeout = 6000;
mc_write_command(mc_io->mmio_regs, cmd);
@@ -52,7 +52,7 @@ int mc_send_command(struct fsl_mc_io *mc_io,
if (status != MC_CMD_STATUS_OK) {
printf("Error: MC command failed (portal: %p, obj handle: %#x, command: %#x, status: %#x)\n",
mc_io->mmio_regs,
- (unsigned int)MC_CMD_HDR_READ_AUTHID(cmd->header),
+ (unsigned int)MC_CMD_HDR_READ_TOKEN(cmd->header),
(unsigned int)MC_CMD_HDR_READ_CMDID(cmd->header),
(unsigned int)status);