--- /dev/null
+/*
+ * Copyright (C) 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <malloc.h>
+#include <net.h>
+#include <hwconfig.h>
+#include <phy.h>
+#include <linux/compat.h>
+
+#include "ldpaa_eth.h"
+
+static int init_phy(struct eth_device *dev)
+{
+ /*TODO for external PHY */
+
+ return 0;
+}
+
+static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv,
+ const struct dpaa_fd *fd)
+{
+ u64 fd_addr;
+ uint16_t fd_offset;
+ uint32_t fd_length;
+ struct ldpaa_fas *fas;
+ uint32_t status, err;
+ struct qbman_release_desc releasedesc;
+ struct qbman_swp *swp = dflt_dpio->sw_portal;
+
+ invalidate_dcache_all();
+
+ fd_addr = ldpaa_fd_get_addr(fd);
+ fd_offset = ldpaa_fd_get_offset(fd);
+ fd_length = ldpaa_fd_get_len(fd);
+
+ debug("Rx frame:data addr=0x%p size=0x%x\n", (u64 *)fd_addr, fd_length);
+
+ if (fd->simple.frc & LDPAA_FD_FRC_FASV) {
+ /* Read the frame annotation status word and check for errors */
+ fas = (struct ldpaa_fas *)
+ ((uint8_t *)(fd_addr) +
+ priv->buf_layout.private_data_size);
+ status = le32_to_cpu(fas->status);
+ if (status & LDPAA_ETH_RX_ERR_MASK) {
+ printf("Rx frame error(s): 0x%08x\n",
+ status & LDPAA_ETH_RX_ERR_MASK);
+ goto error;
+ } else if (status & LDPAA_ETH_RX_UNSUPP_MASK) {
+ printf("Unsupported feature in bitmask: 0x%08x\n",
+ status & LDPAA_ETH_RX_UNSUPP_MASK);
+ goto error;
+ }
+ }
+
+ debug("Rx frame: To Upper layer\n");
+ net_process_received_packet((uint8_t *)(fd_addr) + fd_offset,
+ fd_length);
+
+error:
+ qbman_release_desc_clear(&releasedesc);
+ qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid);
+ do {
+ /* Release buffer into the QBMAN */
+ err = qbman_swp_release(swp, &releasedesc, &fd_addr, 1);
+ } while (err == -EBUSY);
+ return;
+}
+
+static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev)
+{
+ struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv;
+ const struct ldpaa_dq *dq;
+ const struct dpaa_fd *fd;
+ int i = 5, err = 0, status;
+ static struct qbman_pull_desc pulldesc;
+ struct qbman_swp *swp = dflt_dpio->sw_portal;
+
+ qbman_pull_desc_clear(&pulldesc);
+ qbman_pull_desc_set_numframes(&pulldesc, 1);
+ qbman_pull_desc_set_fq(&pulldesc, priv->rx_dflt_fqid);
+
+ while (--i) {
+ err = qbman_swp_pull(swp, &pulldesc);
+ if (err < 0) {
+ printf("Dequeue frames error:0x%08x\n", err);
+ continue;
+ }
+
+ dq = qbman_swp_dqrr_next(swp);
+ if (dq) {
+ /* Check for valid frame. If not sent a consume
+ * confirmation to QBMAN otherwise give it to NADK
+ * application and then send consume confirmation to
+ * QBMAN.
+ */
+ status = (uint8_t)ldpaa_dq_flags(dq);
+ if ((status & LDPAA_DQ_STAT_VALIDFRAME) == 0) {
+ debug("Dequeue RX frames:");
+ debug("No frame delivered\n");
+
+ qbman_swp_dqrr_consume(swp, dq);
+ break;
+ }
+
+ fd = ldpaa_dq_fd(dq);
+
+ /* Obtain FD and process it */
+ ldpaa_eth_rx(priv, fd);
+ qbman_swp_dqrr_consume(swp, dq);
+ break;
+ }
+ }
+
+ return err;
+}
+
+static void ldpaa_eth_tx_conf(struct ldpaa_eth_priv *priv,
+ const struct dpaa_fd *fd)
+{
+ uint64_t fd_addr;
+ struct ldpaa_fas *fas;
+ uint32_t status, err;
+ struct qbman_release_desc releasedesc;
+ struct qbman_swp *swp = dflt_dpio->sw_portal;
+
+ invalidate_dcache_all();
+ fd_addr = ldpaa_fd_get_addr(fd);
+
+
+ debug("TX Conf frame:data addr=0x%p\n", (u64 *)fd_addr);
+
+ /* Check the status from the Frame Annotation */
+ if (fd->simple.frc & LDPAA_FD_FRC_FASV) {
+ fas = (struct ldpaa_fas *)
+ ((uint8_t *)(fd_addr) +
+ priv->buf_layout.private_data_size);
+ status = le32_to_cpu(fas->status);
+ if (status & LDPAA_ETH_TXCONF_ERR_MASK) {
+ printf("TxConf frame error(s): 0x%08x\n",
+ status & LDPAA_ETH_TXCONF_ERR_MASK);
+ }
+ }
+
+ qbman_release_desc_clear(&releasedesc);
+ qbman_release_desc_set_bpid(&releasedesc, dflt_dpbp->dpbp_attr.bpid);
+ do {
+ /* Release buffer into the QBMAN */
+ err = qbman_swp_release(swp, &releasedesc, &fd_addr, 1);
+ } while (err == -EBUSY);
+}
+
+static int ldpaa_eth_pull_dequeue_tx_conf(struct ldpaa_eth_priv *priv)
+{
+ const struct ldpaa_dq *dq;
+ const struct dpaa_fd *fd;
+ int err = 0;
+ int i = 5, status;
+ static struct qbman_pull_desc pulldesc;
+ struct qbman_swp *swp = dflt_dpio->sw_portal;
+
+ qbman_pull_desc_clear(&pulldesc);
+ qbman_pull_desc_set_numframes(&pulldesc, 1);
+ qbman_pull_desc_set_fq(&pulldesc, priv->tx_conf_fqid);
+
+ while (--i) {
+ err = qbman_swp_pull(swp, &pulldesc);
+ if (err < 0) {
+ printf("Dequeue TX conf frames error:0x%08x\n", err);
+ continue;
+ }
+
+ dq = qbman_swp_dqrr_next(swp);
+ if (dq) {
+ /* Check for valid frame. If not sent a consume
+ * confirmation to QBMAN otherwise give it to NADK
+ * application and then send consume confirmation to
+ * QBMAN.
+ */
+ status = (uint8_t)ldpaa_dq_flags(dq);
+ if ((status & LDPAA_DQ_STAT_VALIDFRAME) == 0) {
+ debug("Dequeue TX conf frames:");
+ debug("No frame is delivered\n");
+
+ qbman_swp_dqrr_consume(swp, dq);
+ break;
+ }
+ fd = ldpaa_dq_fd(dq);
+
+ ldpaa_eth_tx_conf(priv, fd);
+ qbman_swp_dqrr_consume(swp, dq);
+ break;
+ }
+ }
+
+ return err;
+}
+
+static int ldpaa_eth_tx(struct eth_device *net_dev, void *buf, int len)
+{
+ struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
+ struct dpaa_fd fd;
+ u64 buffer_start;
+ int data_offset, err;
+ struct qbman_swp *swp = dflt_dpio->sw_portal;
+ struct qbman_eq_desc ed;
+
+ /* Setup the FD fields */
+ memset(&fd, 0, sizeof(fd));
+
+ data_offset = priv->tx_data_offset;
+
+ do {
+ err = qbman_swp_acquire(dflt_dpio->sw_portal,
+ dflt_dpbp->dpbp_attr.bpid,
+ &buffer_start, 1);
+ } while (err == -EBUSY);
+
+ if (err < 0) {
+ printf("qbman_swp_acquire() failed\n");
+ return -ENOMEM;
+ }
+
+ debug("TX data: malloc buffer start=0x%p\n", (u64 *)buffer_start);
+
+ memcpy(((uint8_t *)(buffer_start) + data_offset), buf, len);
+
+ flush_dcache_range(buffer_start, LDPAA_ETH_RX_BUFFER_SIZE);
+
+ ldpaa_fd_set_addr(&fd, (u64)buffer_start);
+ ldpaa_fd_set_offset(&fd, (uint16_t)(data_offset));
+ ldpaa_fd_set_bpid(&fd, dflt_dpbp->dpbp_attr.bpid);
+ ldpaa_fd_set_len(&fd, len);
+
+ fd.simple.ctrl = LDPAA_FD_CTRL_ASAL | LDPAA_FD_CTRL_PTA |
+ LDPAA_FD_CTRL_PTV1;
+
+ qbman_eq_desc_clear(&ed);
+ qbman_eq_desc_set_no_orp(&ed, 0);
+ qbman_eq_desc_set_qd(&ed, priv->tx_qdid, priv->tx_flow_id, 0);
+ err = qbman_swp_enqueue(swp, &ed, (const struct qbman_fd *)(&fd));
+ if (err < 0)
+ printf("error enqueueing Tx frame\n");
+
+ mdelay(1);
+
+ err = ldpaa_eth_pull_dequeue_tx_conf(priv);
+ if (err < 0)
+ printf("error Tx Conf frame\n");
+
+ return err;
+}
+
+static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd)
+{
+ struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
+ struct dpni_queue_attr rx_queue_attr;
+ struct dpni_tx_flow_attr tx_flow_attr;
+ uint8_t mac_addr[6];
+ int err;
+
+ if (net_dev->state == ETH_STATE_ACTIVE)
+ return 0;
+
+ /* DPNI initialization */
+ err = ldpaa_dpni_setup(priv);
+ if (err < 0)
+ goto err_dpni_setup;
+
+ err = ldpaa_dpbp_setup();
+ if (err < 0)
+ goto err_dpbp_setup;
+
+ /* DPNI binding DPBP */
+ err = ldpaa_dpni_bind(priv);
+ if (err)
+ goto err_bind;
+
+ err = dpni_get_primary_mac_addr(dflt_mc_io, priv->dpni_handle,
+ mac_addr);
+ if (err) {
+ printf("dpni_get_primary_mac_addr() failed\n");
+ return err;
+ }
+
+ memcpy(net_dev->enetaddr, mac_addr, 0x6);
+
+ /* setup the MAC address */
+ if (net_dev->enetaddr[0] & 0x01) {
+ printf("%s: MacAddress is multcast address\n", __func__);
+ return 1;
+ }
+
+#ifdef CONFIG_PHYLIB
+ /* TODO Check this path */
+ ret = phy_startup(priv->phydev);
+ if (ret) {
+ printf("%s: Could not initialize\n", priv->phydev->dev->name);
+ return ret;
+ }
+#else
+ priv->phydev->speed = SPEED_1000;
+ priv->phydev->link = 1;
+ priv->phydev->duplex = DUPLEX_FULL;
+#endif
+
+ err = dpni_enable(dflt_mc_io, priv->dpni_handle);
+ if (err < 0) {
+ printf("dpni_enable() failed\n");
+ return err;
+ }
+
+ /* TODO: support multiple Rx flows */
+ err = dpni_get_rx_flow(dflt_mc_io, priv->dpni_handle, 0, 0,
+ &rx_queue_attr);
+ if (err) {
+ printf("dpni_get_rx_flow() failed\n");
+ goto err_rx_flow;
+ }
+
+ priv->rx_dflt_fqid = rx_queue_attr.fqid;
+
+ err = dpni_get_qdid(dflt_mc_io, priv->dpni_handle, &priv->tx_qdid);
+ if (err) {
+ printf("dpni_get_qdid() failed\n");
+ goto err_qdid;
+ }
+
+ err = dpni_get_tx_flow(dflt_mc_io, priv->dpni_handle, priv->tx_flow_id,
+ &tx_flow_attr);
+ if (err) {
+ printf("dpni_get_tx_flow() failed\n");
+ goto err_tx_flow;
+ }
+
+ priv->tx_conf_fqid = tx_flow_attr.conf_err_attr.queue_attr.fqid;
+
+ if (!priv->phydev->link)
+ printf("%s: No link.\n", priv->phydev->dev->name);
+
+ return priv->phydev->link ? 0 : -1;
+
+err_tx_flow:
+err_qdid:
+err_rx_flow:
+ dpni_disable(dflt_mc_io, priv->dpni_handle);
+err_bind:
+ ldpaa_dpbp_free();
+err_dpbp_setup:
+ dpni_close(dflt_mc_io, priv->dpni_handle);
+err_dpni_setup:
+ return err;
+}
+
+static void ldpaa_eth_stop(struct eth_device *net_dev)
+{
+ struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
+ int err = 0;
+
+ if (net_dev->state == ETH_STATE_PASSIVE)
+ return;
+ /* Stop Tx and Rx traffic */
+ err = dpni_disable(dflt_mc_io, priv->dpni_handle);
+ if (err < 0)
+ printf("dpni_disable() failed\n");
+
+#ifdef CONFIG_PHYLIB
+ phy_shutdown(priv->phydev);
+#endif
+
+ ldpaa_dpbp_free();
+ dpni_reset(dflt_mc_io, priv->dpni_handle);
+ dpni_close(dflt_mc_io, priv->dpni_handle);
+}
+
+static void ldpaa_dpbp_drain_cnt(int count)
+{
+ uint64_t buf_array[7];
+ void *addr;
+ int ret, i;
+
+ BUG_ON(count > 7);
+
+ do {
+ ret = qbman_swp_acquire(dflt_dpio->sw_portal,
+ dflt_dpbp->dpbp_attr.bpid,
+ buf_array, count);
+ if (ret < 0) {
+ printf("qbman_swp_acquire() failed\n");
+ return;
+ }
+ for (i = 0; i < ret; i++) {
+ addr = (void *)buf_array[i];
+ debug("Free: buffer addr =0x%p\n", addr);
+ free(addr);
+ }
+ } while (ret);
+}
+
+static void ldpaa_dpbp_drain(void)
+{
+ int i;
+ for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7)
+ ldpaa_dpbp_drain_cnt(7);
+}
+
+static int ldpaa_bp_add_7(uint16_t bpid)
+{
+ uint64_t buf_array[7];
+ u8 *addr;
+ int i;
+ struct qbman_release_desc rd;
+
+ for (i = 0; i < 7; i++) {
+ addr = memalign(L1_CACHE_BYTES, LDPAA_ETH_RX_BUFFER_SIZE);
+ if (!addr) {
+ printf("addr allocation failed\n");
+ goto err_alloc;
+ }
+ memset(addr, 0x00, LDPAA_ETH_RX_BUFFER_SIZE);
+
+ buf_array[i] = (uint64_t)addr;
+ debug("Release: buffer addr =0x%p\n", addr);
+ }
+
+release_bufs:
+ /* In case the portal is busy, retry until successful.
+ * This function is guaranteed to succeed in a reasonable amount
+ * of time.
+ */
+
+ do {
+ mdelay(1);
+ qbman_release_desc_clear(&rd);
+ qbman_release_desc_set_bpid(&rd, bpid);
+ } while (qbman_swp_release(dflt_dpio->sw_portal, &rd, buf_array, i));
+
+ return i;
+
+err_alloc:
+ if (i)
+ goto release_bufs;
+
+ return 0;
+}
+
+static int ldpaa_dpbp_seed(uint16_t bpid)
+{
+ int i;
+ int count;
+
+ for (i = 0; i < LDPAA_ETH_NUM_BUFS; i += 7) {
+ count = ldpaa_bp_add_7(bpid);
+ if (count < 7)
+ printf("Buffer Seed= %d\n", count);
+ }
+
+ return 0;
+}
+
+static int ldpaa_dpbp_setup(void)
+{
+ int err;
+
+ err = dpbp_open(dflt_mc_io, dflt_dpbp->dpbp_attr.id,
+ &dflt_dpbp->dpbp_handle);
+ if (err) {
+ printf("dpbp_open() failed\n");
+ goto err_open;
+ }
+
+ err = dpbp_enable(dflt_mc_io, dflt_dpbp->dpbp_handle);
+ if (err) {
+ printf("dpbp_enable() failed\n");
+ goto err_enable;
+ }
+
+ err = dpbp_get_attributes(dflt_mc_io, dflt_dpbp->dpbp_handle,
+ &dflt_dpbp->dpbp_attr);
+ if (err) {
+ printf("dpbp_get_attributes() failed\n");
+ goto err_get_attr;
+ }
+
+ err = ldpaa_dpbp_seed(dflt_dpbp->dpbp_attr.bpid);
+ if (err) {
+ printf("Buffer seeding failed for DPBP %d (bpid=%d)\n",
+ dflt_dpbp->dpbp_attr.id, dflt_dpbp->dpbp_attr.bpid);
+ goto err_seed;
+ }
+
+ return 0;
+
+err_seed:
+err_get_attr:
+ dpbp_disable(dflt_mc_io, dflt_dpbp->dpbp_handle);
+err_enable:
+ dpbp_close(dflt_mc_io, dflt_dpbp->dpbp_handle);
+err_open:
+ return err;
+}
+
+static void ldpaa_dpbp_free(void)
+{
+ ldpaa_dpbp_drain();
+ dpbp_disable(dflt_mc_io, dflt_dpbp->dpbp_handle);
+ dpbp_reset(dflt_mc_io, dflt_dpbp->dpbp_handle);
+ dpbp_close(dflt_mc_io, dflt_dpbp->dpbp_handle);
+}
+
+static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv)
+{
+ int err;
+
+ /* and get a handle for the DPNI this interface is associate with */
+ err = dpni_open(dflt_mc_io, priv->dpni_id, &priv->dpni_handle);
+ if (err) {
+ printf("dpni_open() failed\n");
+ goto err_open;
+ }
+
+ err = dpni_get_attributes(dflt_mc_io, priv->dpni_handle,
+ &priv->dpni_attrs);
+ if (err) {
+ printf("dpni_get_attributes() failed (err=%d)\n", err);
+ goto err_get_attr;
+ }
+
+ /* Configure our buffers' layout */
+ priv->buf_layout.options = DPNI_BUF_LAYOUT_OPT_PARSER_RESULT |
+ DPNI_BUF_LAYOUT_OPT_FRAME_STATUS |
+ DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
+ priv->buf_layout.pass_parser_result = true;
+ priv->buf_layout.pass_frame_status = true;
+ priv->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE;
+ /* ...rx, ... */
+ err = dpni_set_rx_buffer_layout(dflt_mc_io, priv->dpni_handle,
+ &priv->buf_layout);
+ if (err) {
+ printf("dpni_set_rx_buffer_layout() failed");
+ goto err_buf_layout;
+ }
+
+ /* ... tx, ... */
+ priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PARSER_RESULT;
+ err = dpni_set_tx_buffer_layout(dflt_mc_io, priv->dpni_handle,
+ &priv->buf_layout);
+ if (err) {
+ printf("dpni_set_tx_buffer_layout() failed");
+ goto err_buf_layout;
+ }
+
+ /* ... tx-confirm. */
+ priv->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE;
+ err = dpni_set_tx_conf_buffer_layout(dflt_mc_io, priv->dpni_handle,
+ &priv->buf_layout);
+ if (err) {
+ printf("dpni_set_tx_conf_buffer_layout() failed");
+ goto err_buf_layout;
+ }
+
+ /* Now that we've set our tx buffer layout, retrieve the minimum
+ * required tx data offset.
+ */
+ err = dpni_get_tx_data_offset(dflt_mc_io, priv->dpni_handle,
+ &priv->tx_data_offset);
+ if (err) {
+ printf("dpni_get_tx_data_offset() failed\n");
+ goto err_data_offset;
+ }
+
+ /* Warn in case TX data offset is not multiple of 64 bytes. */
+ WARN_ON(priv->tx_data_offset % 64);
+
+ /* Accomodate SWA space. */
+ priv->tx_data_offset += LDPAA_ETH_SWA_SIZE;
+ debug("priv->tx_data_offset=%d\n", priv->tx_data_offset);
+
+ return 0;
+
+err_data_offset:
+err_buf_layout:
+err_get_attr:
+ dpni_close(dflt_mc_io, priv->dpni_handle);
+err_open:
+ return err;
+}
+
+static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv)
+{
+ struct dpni_pools_cfg pools_params;
+ struct dpni_tx_flow_cfg dflt_tx_flow;
+ int err = 0;
+
+ pools_params.num_dpbp = 1;
+ pools_params.pools[0].dpbp_id = (uint16_t)dflt_dpbp->dpbp_attr.id;
+ pools_params.pools[0].buffer_size = LDPAA_ETH_RX_BUFFER_SIZE;
+ err = dpni_set_pools(dflt_mc_io, priv->dpni_handle, &pools_params);
+ if (err) {
+ printf("dpni_set_pools() failed\n");
+ return err;
+ }
+
+ priv->tx_flow_id = DPNI_NEW_FLOW_ID;
+ memset(&dflt_tx_flow, 0, sizeof(dflt_tx_flow));
+
+ err = dpni_set_tx_flow(dflt_mc_io, priv->dpni_handle,
+ &priv->tx_flow_id, &dflt_tx_flow);
+ if (err) {
+ printf("dpni_set_tx_flow() failed\n");
+ return err;
+ }
+
+ return 0;
+}
+
+static int ldpaa_eth_netdev_init(struct eth_device *net_dev)
+{
+ int err;
+ struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv;
+
+ if (priv->type == LDPAA_ETH_1G_E)
+ sprintf(net_dev->name, "DTSEC%d", priv->dpni_id);
+ else
+ sprintf(net_dev->name, "TGEC%d", priv->dpni_id);
+
+ net_dev->iobase = 0;
+ net_dev->init = ldpaa_eth_open;
+ net_dev->halt = ldpaa_eth_stop;
+ net_dev->send = ldpaa_eth_tx;
+ net_dev->recv = ldpaa_eth_pull_dequeue_rx;
+/*
+ TODO: PHY MDIO information
+ priv->bus = info->bus;
+ priv->phyaddr = info->phy_addr;
+ priv->enet_if = info->enet_if;
+*/
+
+ if (init_phy(net_dev))
+ return 0;
+
+ err = eth_register(net_dev);
+ if (err < 0) {
+ printf("eth_register() = %d\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+int ldpaa_eth_init(struct dprc_obj_desc obj_desc)
+{
+ struct eth_device *net_dev = NULL;
+ struct ldpaa_eth_priv *priv = NULL;
+ int err = 0;
+
+
+ /* Net device */
+ net_dev = (struct eth_device *)malloc(sizeof(struct eth_device));
+ if (!net_dev) {
+ printf("eth_device malloc() failed\n");
+ return -ENOMEM;
+ }
+ memset(net_dev, 0, sizeof(struct eth_device));
+
+ /* alloc the ldpaa ethernet private struct */
+ priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv));
+ if (!priv) {
+ printf("ldpaa_eth_priv malloc() failed\n");
+ return -ENOMEM;
+ }
+ memset(priv, 0, sizeof(struct ldpaa_eth_priv));
+
+ net_dev->priv = (void *)priv;
+ priv->net_dev = (struct eth_device *)net_dev;
+ priv->dpni_id = obj_desc.id;
+
+ err = ldpaa_eth_netdev_init(net_dev);
+ if (err)
+ goto err_netdev_init;
+
+ debug("ldpaa ethernet: Probed interface %s\n", net_dev->name);
+ return 0;
+
+err_netdev_init:
+ free(priv);
+ net_dev->priv = NULL;
+ free(net_dev);
+
+ return err;
+}
--- /dev/null
+/*
+ * Copyright (C) 2014 Freescale Semiconductor
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LDPAA_ETH_H
+#define __LDPAA_ETH_H
+
+#include <linux/netdevice.h>
+#include <fsl-mc/fsl_mc.h>
+#include <fsl-mc/fsl_dpaa_fd.h>
+#include <fsl-mc/fsl_dprc.h>
+#include <fsl-mc/fsl_dpni.h>
+#include <fsl-mc/fsl_dpbp.h>
+#include <fsl-mc/fsl_dpio.h>
+#include <fsl-mc/fsl_qbman_portal.h>
+#include <fsl-mc/fsl_mc_private.h>
+
+
+enum ldpaa_eth_type {
+ LDPAA_ETH_1G_E,
+ LDPAA_ETH_10G_E,
+};
+
+/* Arbitrary values for now, but we'll need to tune */
+#define LDPAA_ETH_NUM_BUFS (2 * 7)
+#define LDPAA_ETH_REFILL_THRESH (LDPAA_ETH_NUM_BUFS/2)
+#define LDPAA_ETH_RX_BUFFER_SIZE 2048
+
+/* Hardware requires alignment for ingress/egress buffer addresses
+ * and ingress buffer lengths.
+ */
+#define LDPAA_ETH_BUF_ALIGN 64
+
+/* So far we're only accomodating a skb backpointer in the frame's
+ * software annotation, but the hardware options are either 0 or 64.
+ */
+#define LDPAA_ETH_SWA_SIZE 64
+
+/* Annotation valid bits in FD FRC */
+#define LDPAA_FD_FRC_FASV 0x8000
+#define LDPAA_FD_FRC_FAEADV 0x4000
+#define LDPAA_FD_FRC_FAPRV 0x2000
+#define LDPAA_FD_FRC_FAIADV 0x1000
+#define LDPAA_FD_FRC_FASWOV 0x0800
+#define LDPAA_FD_FRC_FAICFDV 0x0400
+
+/* Annotation bits in FD CTRL */
+#define LDPAA_FD_CTRL_ASAL 0x00020000 /* ASAL = 128 */
+#define LDPAA_FD_CTRL_PTA 0x00800000
+#define LDPAA_FD_CTRL_PTV1 0x00400000
+
+/* TODO: we may want to move this and other WRIOP related defines
+ * to a separate header
+ */
+/* Frame annotation status */
+struct ldpaa_fas {
+ u8 reserved;
+ u8 ppid;
+ __le16 ifpid;
+ __le32 status;
+} __packed;
+
+/* Debug frame, otherwise supposed to be discarded */
+#define LDPAA_ETH_FAS_DISC 0x80000000
+/* MACSEC frame */
+#define LDPAA_ETH_FAS_MS 0x40000000
+#define LDPAA_ETH_FAS_PTP 0x08000000
+/* Ethernet multicast frame */
+#define LDPAA_ETH_FAS_MC 0x04000000
+/* Ethernet broadcast frame */
+#define LDPAA_ETH_FAS_BC 0x02000000
+#define LDPAA_ETH_FAS_KSE 0x00040000
+#define LDPAA_ETH_FAS_EOFHE 0x00020000
+#define LDPAA_ETH_FAS_MNLE 0x00010000
+#define LDPAA_ETH_FAS_TIDE 0x00008000
+#define LDPAA_ETH_FAS_PIEE 0x00004000
+/* Frame length error */
+#define LDPAA_ETH_FAS_FLE 0x00002000
+/* Frame physical error; our favourite pastime */
+#define LDPAA_ETH_FAS_FPE 0x00001000
+#define LDPAA_ETH_FAS_PTE 0x00000080
+#define LDPAA_ETH_FAS_ISP 0x00000040
+#define LDPAA_ETH_FAS_PHE 0x00000020
+#define LDPAA_ETH_FAS_BLE 0x00000010
+/* L3 csum validation performed */
+#define LDPAA_ETH_FAS_L3CV 0x00000008
+/* L3 csum error */
+#define LDPAA_ETH_FAS_L3CE 0x00000004
+/* L4 csum validation performed */
+#define LDPAA_ETH_FAS_L4CV 0x00000002
+/* L4 csum error */
+#define LDPAA_ETH_FAS_L4CE 0x00000001
+/* These bits always signal errors */
+#define LDPAA_ETH_RX_ERR_MASK (LDPAA_ETH_FAS_DISC | \
+ LDPAA_ETH_FAS_KSE | \
+ LDPAA_ETH_FAS_EOFHE | \
+ LDPAA_ETH_FAS_MNLE | \
+ LDPAA_ETH_FAS_TIDE | \
+ LDPAA_ETH_FAS_PIEE | \
+ LDPAA_ETH_FAS_FLE | \
+ LDPAA_ETH_FAS_FPE | \
+ LDPAA_ETH_FAS_PTE | \
+ LDPAA_ETH_FAS_ISP | \
+ LDPAA_ETH_FAS_PHE | \
+ LDPAA_ETH_FAS_BLE | \
+ LDPAA_ETH_FAS_L3CE | \
+ LDPAA_ETH_FAS_L4CE)
+/* Unsupported features in the ingress */
+#define LDPAA_ETH_RX_UNSUPP_MASK LDPAA_ETH_FAS_MS
+/* TODO trim down the bitmask; not all of them apply to Tx-confirm */
+#define LDPAA_ETH_TXCONF_ERR_MASK (LDPAA_ETH_FAS_KSE | \
+ LDPAA_ETH_FAS_EOFHE | \
+ LDPAA_ETH_FAS_MNLE | \
+ LDPAA_ETH_FAS_TIDE)
+
+struct ldpaa_eth_priv {
+ struct eth_device *net_dev;
+ int dpni_id;
+ uint16_t dpni_handle;
+ struct dpni_attr dpni_attrs;
+ /* Insofar as the MC is concerned, we're using one layout on all 3 types
+ * of buffers (Rx, Tx, Tx-Conf).
+ */
+ struct dpni_buffer_layout buf_layout;
+ uint16_t tx_data_offset;
+
+ uint32_t rx_dflt_fqid;
+ uint16_t tx_qdid;
+ uint32_t tx_conf_fqid;
+ uint16_t tx_flow_id;
+
+ enum ldpaa_eth_type type; /* 1G or 10G ethernet */
+ phy_interface_t enet_if;
+ struct mii_dev *bus;
+ struct phy_device *phydev;
+ int phyaddr;
+
+};
+
+extern struct fsl_mc_io *dflt_mc_io;
+extern struct fsl_dpbp_obj *dflt_dpbp;
+extern struct fsl_dpio_obj *dflt_dpio;
+
+static void ldpaa_dpbp_drain_cnt(int count);
+static void ldpaa_dpbp_drain(void);
+static int ldpaa_dpbp_seed(uint16_t bpid);
+static void ldpaa_dpbp_free(void);
+static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv);
+static int ldpaa_dpbp_setup(void);
+static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv);
+#endif /* __LDPAA_H */