X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fnet%2Fldpaa_eth%2Fldpaa_eth.c;h=48343dce1c4ff6e186d2177d0cfbf59c45162f93;hb=b641dd3ec8dc3f6b18d2fa945ac3ab597063d191;hp=4de7586408e48171ab030e5bad711c3d15c93a90;hpb=7c0e5d865ff0b86dfce492b656238919c659d756;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/net/ldpaa_eth/ldpaa_eth.c b/drivers/net/ldpaa_eth/ldpaa_eth.c index 4de7586..48343dc 100644 --- a/drivers/net/ldpaa_eth/ldpaa_eth.c +++ b/drivers/net/ldpaa_eth/ldpaa_eth.c @@ -1,28 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2014 Freescale Semiconductor - * - * SPDX-License-Identifier: GPL-2.0+ + * Copyright 2014-2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP */ #include +#include #include #include #include #include #include #include +#include #include +#include +#include #include "ldpaa_eth.h" -#undef CONFIG_PHYLIB +#ifdef CONFIG_PHYLIB +#ifdef CONFIG_DM_ETH +static void init_phy(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + + priv->phy = dm_eth_phy_connect(dev); + + if (!priv->phy) + return; + + phy_config(priv->phy); +} +#else static int init_phy(struct eth_device *dev) { - /*TODO for external PHY */ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; + struct phy_device *phydev = NULL; + struct mii_dev *bus; + int phy_addr, phy_num; + int ret = 0; - return 0; + bus = wriop_get_mdio(priv->dpmac_id); + if (bus == NULL) + return 0; + + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phy_addr = wriop_get_phy_address(priv->dpmac_id, phy_num); + if (phy_addr < 0) + continue; + + phydev = phy_connect(bus, phy_addr, dev, + wriop_get_enet_if(priv->dpmac_id)); + if (!phydev) { + printf("Failed to connect\n"); + ret = -ENODEV; + break; + } + wriop_set_phy_dev(priv->dpmac_id, phy_num, phydev); + ret = phy_config(phydev); + if (ret) + break; + } + + if (ret) { + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); + if (!phydev) + continue; + + free(phydev); + wriop_set_phy_dev(priv->dpmac_id, phy_num, NULL); + } + } + + return ret; +} +#endif +#endif + +#ifdef DEBUG + +#define DPNI_STATS_PER_PAGE 6 + +static const char *dpni_statistics[][DPNI_STATS_PER_PAGE] = { + { + "DPNI_CNT_ING_ALL_FRAMES", + "DPNI_CNT_ING_ALL_BYTES", + "DPNI_CNT_ING_MCAST_FRAMES", + "DPNI_CNT_ING_MCAST_BYTES", + "DPNI_CNT_ING_BCAST_FRAMES", + "DPNI_CNT_ING_BCAST_BYTES", + }, { + "DPNI_CNT_EGR_ALL_FRAMES", + "DPNI_CNT_EGR_ALL_BYTES", + "DPNI_CNT_EGR_MCAST_FRAMES", + "DPNI_CNT_EGR_MCAST_BYTES", + "DPNI_CNT_EGR_BCAST_FRAMES", + "DPNI_CNT_EGR_BCAST_BYTES", + }, { + "DPNI_CNT_ING_FILTERED_FRAMES", + "DPNI_CNT_ING_DISCARDED_FRAMES", + "DPNI_CNT_ING_NOBUFFER_DISCARDS", + "DPNI_CNT_EGR_DISCARDED_FRAMES", + "DPNI_CNT_EGR_CNF_FRAMES", + "" + }, +}; + +static void print_dpni_stats(const char *strings[], + struct dpni_statistics dpni_stats) +{ + uint64_t *stat; + int i; + + stat = (uint64_t *)&dpni_stats; + for (i = 0; i < DPNI_STATS_PER_PAGE; i++) { + if (strcmp(strings[i], "\0") == 0) + break; + printf("%s= %llu\n", strings[i], *stat); + stat++; + } +} + +static void ldpaa_eth_get_dpni_counter(void) +{ + int err = 0; + unsigned int page = 0; + struct dpni_statistics dpni_stats; + + printf("DPNI counters ..\n"); + for (page = 0; page < 3; page++) { + err = dpni_get_statistics(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, page, + &dpni_stats); + if (err < 0) { + printf("dpni_get_statistics: failed:"); + printf("%d for page[%d]\n", err, page); + return; + } + print_dpni_stats(dpni_statistics[page], dpni_stats); + } } +#ifdef CONFIG_DM_ETH +static void ldpaa_eth_get_dpmac_counter(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else +static void ldpaa_eth_get_dpmac_counter(struct eth_device *net_dev) +{ + struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; +#endif + int err = 0; + u64 value; + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_BYTE, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_BYTE failed\n"); + return; + } + printf("\nDPMAC counters ..\n"); + printf("DPMAC_CNT_ING_BYTE=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_FRAME_DISCARD, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_FRAME_DISCARD failed\n"); + return; + } + printf("DPMAC_CNT_ING_FRAME_DISCARD=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_ALIGN_ERR, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_ALIGN_ERR failed\n"); + return; + } + printf("DPMAC_CNT_ING_ALIGN_ERR =%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_BYTE, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_BYTE failed\n"); + return; + } + printf("DPMAC_CNT_ING_BYTE=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_ING_ERR_FRAME, + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_ING_ERR_FRAME failed\n"); + return; + } + printf("DPMAC_CNT_ING_ERR_FRAME=%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_EGR_BYTE , + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_EGR_BYTE failed\n"); + return; + } + printf("DPMAC_CNT_EGR_BYTE =%lld\n", value); + + err = dpmac_get_counter(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, + DPMAC_CNT_EGR_ERR_FRAME , + &value); + if (err < 0) { + printf("dpmac_get_counter: DPMAC_CNT_EGR_ERR_FRAME failed\n"); + return; + } + printf("DPMAC_CNT_EGR_ERR_FRAME =%lld\n", value); +} +#endif + static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv, const struct dpaa_fd *fd) { @@ -46,7 +251,7 @@ static void ldpaa_eth_rx(struct ldpaa_eth_priv *priv, /* Read the frame annotation status word and check for errors */ fas = (struct ldpaa_fas *) ((uint8_t *)(fd_addr) + - priv->buf_layout.private_data_size); + dflt_dpni->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", @@ -79,9 +284,16 @@ error: return; } +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_pull_dequeue_rx(struct udevice *dev, + int flags, uchar **packetp) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)dev->priv; +#endif const struct ldpaa_dq *dq; const struct dpaa_fd *fd; int i = 5, err = 0, status; @@ -138,9 +350,15 @@ static int ldpaa_eth_pull_dequeue_rx(struct eth_device *dev) return err; } +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_tx(struct udevice *dev, void *buf, int len) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else 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; +#endif struct dpaa_fd fd; u64 buffer_start; int data_offset, err; @@ -161,7 +379,7 @@ static int ldpaa_eth_tx(struct eth_device *net_dev, void *buf, int len) &buffer_start, 1); } while (err == -EBUSY); - if (err < 0) { + if (err <= 0) { printf("qbman_swp_acquire() failed\n"); return -ENOMEM; } @@ -216,15 +434,125 @@ error: return err; } +static struct phy_device *ldpaa_get_phydev(struct ldpaa_eth_priv *priv) +{ +#ifdef CONFIG_DM_ETH + return priv->phy; +#else +#ifdef CONFIG_PHYLIB + struct phy_device *phydev = NULL; + int phy_num; + + /* start the phy devices one by one and update the dpmac state */ + for (phy_num = 0; phy_num < WRIOP_MAX_PHY_NUM; phy_num++) { + phydev = wriop_get_phy_dev(priv->dpmac_id, phy_num); + if (phydev) + return phydev; + } + return NULL; +#endif + return NULL; +#endif +} + +static int ldpaa_get_dpmac_state(struct ldpaa_eth_priv *priv, + struct dpmac_link_state *state) +{ + phy_interface_t enet_if; + struct phy_device *phydev = NULL; + int err; + + /* let's start off with maximum capabilities */ + enet_if = wriop_get_enet_if(priv->dpmac_id); + switch (enet_if) { + case PHY_INTERFACE_MODE_XGMII: + state->rate = SPEED_10000; + break; + default: + state->rate = SPEED_1000; + break; + } + + state->up = 1; + state->options |= DPMAC_LINK_OPT_AUTONEG; + phydev = ldpaa_get_phydev(priv); + + if (phydev) { + err = phy_startup(phydev); + if (err) { + printf("%s: Could not initialize\n", phydev->dev->name); + state->up = 0; + } else if (phydev->link) { + state->rate = min(state->rate, (uint32_t)phydev->speed); + if (!phydev->duplex) + state->options |= DPMAC_LINK_OPT_HALF_DUPLEX; + if (!phydev->autoneg) + state->options &= ~DPMAC_LINK_OPT_AUTONEG; + } else { + state->up = 0; + } + } + + if (!phydev) + state->options &= ~DPMAC_LINK_OPT_AUTONEG; + + if (!state->up) { + state->rate = 0; + state->options = 0; + return -ENOLINK; + } + + return 0; +} + +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_open(struct udevice *dev) +{ + struct eth_pdata *plat = dev_get_platdata(dev); + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else 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; - uint8_t mac_addr[6]; - int err; +#endif + struct dpmac_link_state dpmac_link_state = { 0 }; +#ifdef DEBUG + struct dpni_link_state link_state; +#endif + int err = 0; + struct dpni_queue d_queue; +#ifdef CONFIG_DM_ETH + if (eth_is_active(dev)) + return 0; +#else if (net_dev->state == ETH_STATE_ACTIVE) return 0; +#endif + + if (get_mc_boot_status() != 0) { + printf("ERROR (MC is not booted)\n"); + return -ENODEV; + } + + if (get_dpl_apply_status() == 0) { + printf("ERROR (DPL is deployed. No device available)\n"); + return -ENODEV; + } + + /* DPMAC initialization */ + err = ldpaa_dpmac_setup(priv); + if (err < 0) + goto err_dpmac_setup; + + err = ldpaa_get_dpmac_state(priv, &dpmac_link_state); + if (err < 0) + goto err_dpmac_bind; + + /* DPMAC binding DPNI */ + err = ldpaa_dpmac_bind(priv); + if (err) + goto err_dpmac_bind; /* DPNI initialization */ err = ldpaa_dpni_setup(priv); @@ -238,95 +566,152 @@ static int ldpaa_eth_open(struct eth_device *net_dev, bd_t *bd) /* DPNI binding DPBP */ err = ldpaa_dpni_bind(priv); if (err) - goto err_bind; + goto err_dpni_bind; - err = dpni_get_primary_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpni_handle, mac_addr); +#ifdef CONFIG_DM_ETH + err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, plat->enetaddr); +#else + err = dpni_add_mac_addr(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, net_dev->enetaddr); +#endif if (err) { - printf("dpni_get_primary_mac_addr() failed\n"); + printf("dpni_add_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; + err = dpni_enable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); + if (err < 0) { + printf("dpni_enable() failed\n"); + return err; } -#ifdef CONFIG_PHYLIB - /* TODO Check this path */ - err = phy_startup(priv->phydev); - if (err) { - printf("%s: Could not initialize\n", priv->phydev->dev->name); + err = dpmac_set_link_state(dflt_mc_io, MC_CMD_NO_FLAGS, + priv->dpmac_handle, &dpmac_link_state); + if (err < 0) { + printf("dpmac_set_link_state() failed\n"); return err; } -#else - priv->phydev->speed = SPEED_1000; - priv->phydev->link = 1; - priv->phydev->duplex = DUPLEX_FULL; -#endif - err = dpni_enable(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); +#ifdef DEBUG + printf("DPMAC link status: %d - ", dpmac_link_state.up); + dpmac_link_state.up == 0 ? printf("down\n") : + dpmac_link_state.up == 1 ? printf("up\n") : printf("error state\n"); + + err = dpni_get_link_state(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, &link_state); if (err < 0) { - printf("dpni_enable() failed\n"); + printf("dpni_get_link_state() failed\n"); return err; } - /* TODO: support multiple Rx flows */ - err = dpni_get_rx_flow(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle, - 0, 0, &rx_queue_attr); + printf("DPNI link status: %d - ", link_state.up); + link_state.up == 0 ? printf("down\n") : + link_state.up == 1 ? printf("up\n") : printf("error state\n"); +#endif + + memset(&d_queue, 0, sizeof(struct dpni_queue)); + err = dpni_get_queue(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, DPNI_QUEUE_RX, + 0, 0, &d_queue); if (err) { - printf("dpni_get_rx_flow() failed\n"); - goto err_rx_flow; + printf("dpni_get_queue failed\n"); + goto err_get_queue; } - priv->rx_dflt_fqid = rx_queue_attr.fqid; + priv->rx_dflt_fqid = d_queue.fqid; - err = dpni_get_qdid(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle, + err = dpni_get_qdid(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle, &priv->tx_qdid); if (err) { printf("dpni_get_qdid() failed\n"); goto err_qdid; } - if (!priv->phydev->link) - printf("%s: No link.\n", priv->phydev->dev->name); - - return priv->phydev->link ? 0 : -1; + return dpmac_link_state.up; err_qdid: -err_rx_flow: - dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); -err_bind: +err_get_queue: + dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); +err_dpni_bind: ldpaa_dpbp_free(); err_dpbp_setup: - dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); + dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); err_dpni_setup: +err_dpmac_bind: + dpmac_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle); + dpmac_destroy(dflt_mc_io, + dflt_dprc_handle, + MC_CMD_NO_FLAGS, priv->dpmac_id); +err_dpmac_setup: return err; } +#ifdef CONFIG_DM_ETH +static void ldpaa_eth_stop(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); +#else static void ldpaa_eth_stop(struct eth_device *net_dev) { struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; +#endif + struct phy_device *phydev = NULL; int err = 0; +#ifdef CONFIG_DM_ETH + if (!eth_is_active(dev)) + return; +#else if ((net_dev->state == ETH_STATE_PASSIVE) || (net_dev->state == ETH_STATE_INIT)) return; +#endif + +#ifdef DEBUG + ldpaa_eth_get_dpni_counter(); +#ifdef CONFIG_DM_ETH + ldpaa_eth_get_dpmac_counter(dev); +#else + ldpaa_eth_get_dpmac_counter(net_dev); +#endif +#endif + + err = dprc_disconnect(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dprc_handle, &dpmac_endpoint); + if (err < 0) + printf("dprc_disconnect() failed dpmac_endpoint\n"); + + err = dpmac_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpmac_handle); + if (err < 0) + printf("dpmac_close() failed\n"); + + err = dpmac_destroy(dflt_mc_io, + dflt_dprc_handle, + MC_CMD_NO_FLAGS, + priv->dpmac_id); + if (err < 0) + printf("dpmac_destroy() failed\n"); + /* Stop Tx and Rx traffic */ - err = dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); + err = dpni_disable(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); if (err < 0) printf("dpni_disable() failed\n"); -#ifdef CONFIG_PHYLIB - phy_shutdown(priv->phydev); -#endif + phydev = ldpaa_get_phydev(priv); + if (phydev) + phy_shutdown(phydev); + /* Free DPBP handle and reset. */ ldpaa_dpbp_free(); - dpni_reset(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); - dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); + + dpni_reset(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); + if (err < 0) + printf("dpni_reset() failed\n"); + + dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); + if (err < 0) + printf("dpni_close() failed\n"); } static void ldpaa_dpbp_drain_cnt(int count) @@ -368,7 +753,7 @@ static int ldpaa_bp_add_7(uint16_t bpid) struct qbman_release_desc rd; for (i = 0; i < 7; i++) { - addr = memalign(L1_CACHE_BYTES, LDPAA_ETH_RX_BUFFER_SIZE); + addr = memalign(LDPAA_ETH_BUF_ALIGN, LDPAA_ETH_RX_BUFFER_SIZE); if (!addr) { printf("addr allocation failed\n"); goto err_alloc; @@ -442,6 +827,7 @@ static int ldpaa_dpbp_setup(void) } 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); @@ -467,56 +853,176 @@ static void ldpaa_dpbp_free(void) dpbp_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpbp->dpbp_handle); } +static int ldpaa_dpmac_version_check(struct fsl_mc_io *mc_io, + struct ldpaa_eth_priv *priv) +{ + int error; + uint16_t major_ver, minor_ver; + + error = dpmac_get_api_version(dflt_mc_io, 0, + &major_ver, + &minor_ver); + if ((major_ver < DPMAC_VER_MAJOR) || + (major_ver == DPMAC_VER_MAJOR && minor_ver < DPMAC_VER_MINOR)) { + printf("DPMAC version mismatch found %u.%u,", + major_ver, minor_ver); + printf("supported version is %u.%u\n", + DPMAC_VER_MAJOR, DPMAC_VER_MINOR); + return error; + } + + return error; +} + +static int ldpaa_dpmac_setup(struct ldpaa_eth_priv *priv) +{ + int err = 0; + struct dpmac_cfg dpmac_cfg; + + dpmac_cfg.mac_id = priv->dpmac_id; + + err = dpmac_create(dflt_mc_io, + dflt_dprc_handle, + MC_CMD_NO_FLAGS, &dpmac_cfg, + &priv->dpmac_id); + if (err) + printf("dpmac_create() failed\n"); + + err = ldpaa_dpmac_version_check(dflt_mc_io, priv); + if (err < 0) { + printf("ldpaa_dpmac_version_check() failed: %d\n", err); + goto err_version_check; + } + + err = dpmac_open(dflt_mc_io, + MC_CMD_NO_FLAGS, + priv->dpmac_id, + &priv->dpmac_handle); + if (err < 0) { + printf("dpmac_open() failed: %d\n", err); + goto err_open; + } + + return err; + +err_open: +err_version_check: + dpmac_destroy(dflt_mc_io, + dflt_dprc_handle, + MC_CMD_NO_FLAGS, priv->dpmac_id); + + return err; +} + +static int ldpaa_dpmac_bind(struct ldpaa_eth_priv *priv) +{ + int err = 0; + struct dprc_connection_cfg dprc_connection_cfg = { + /* If both rates are zero the connection */ + /* will be configured in "best effort" mode. */ + .committed_rate = 0, + .max_rate = 0 + }; + +#ifdef DEBUG + struct dprc_endpoint dbg_endpoint; + int state = 0; +#endif + + memset(&dpmac_endpoint, 0, sizeof(struct dprc_endpoint)); + strcpy(dpmac_endpoint.type, "dpmac"); + dpmac_endpoint.id = priv->dpmac_id; + + memset(&dpni_endpoint, 0, sizeof(struct dprc_endpoint)); + strcpy(dpni_endpoint.type, "dpni"); + dpni_endpoint.id = dflt_dpni->dpni_id; + + err = dprc_connect(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dprc_handle, + &dpmac_endpoint, + &dpni_endpoint, + &dprc_connection_cfg); + if (err) + printf("dprc_connect() failed\n"); + +#ifdef DEBUG + err = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dprc_handle, &dpni_endpoint, + &dbg_endpoint, &state); + printf("%s, DPMAC Type= %s\n", __func__, dbg_endpoint.type); + printf("%s, DPMAC ID= %d\n", __func__, dbg_endpoint.id); + printf("%s, DPMAC State= %d\n", __func__, state); + + memset(&dbg_endpoint, 0, sizeof(struct dprc_endpoint)); + err = dprc_get_connection(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dprc_handle, &dpmac_endpoint, + &dbg_endpoint, &state); + printf("%s, DPNI Type= %s\n", __func__, dbg_endpoint.type); + printf("%s, DPNI ID= %d\n", __func__, dbg_endpoint.id); + printf("%s, DPNI State= %d\n", __func__, state); +#endif + return err; +} + 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, MC_CMD_NO_FLAGS, priv->dpni_id, - &priv->dpni_handle); + err = dpni_open(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_id, + &dflt_dpni->dpni_handle); if (err) { printf("dpni_open() failed\n"); goto err_open; } - err = dpni_get_attributes(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpni_handle, &priv->dpni_attrs); + dflt_dpni->dpni_handle, + &dflt_dpni->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 | + dflt_dpni->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; + DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE | + DPNI_BUF_LAYOUT_OPT_DATA_ALIGN; + dflt_dpni->buf_layout.pass_parser_result = true; + dflt_dpni->buf_layout.pass_frame_status = true; + dflt_dpni->buf_layout.private_data_size = LDPAA_ETH_SWA_SIZE; + /* HW erratum mandates data alignment in multiples of 256 */ + dflt_dpni->buf_layout.data_align = LDPAA_ETH_BUF_ALIGN; + /* ...rx, ... */ - err = dpni_set_rx_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpni_handle, &priv->buf_layout); + err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + &dflt_dpni->buf_layout, DPNI_QUEUE_RX); if (err) { - printf("dpni_set_rx_buffer_layout() failed"); + printf("dpni_set_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, MC_CMD_NO_FLAGS, - priv->dpni_handle, &priv->buf_layout); + /* remove Rx-only options */ + dflt_dpni->buf_layout.options &= ~(DPNI_BUF_LAYOUT_OPT_DATA_ALIGN | + DPNI_BUF_LAYOUT_OPT_PARSER_RESULT); + err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + &dflt_dpni->buf_layout, DPNI_QUEUE_TX); if (err) { - printf("dpni_set_tx_buffer_layout() failed"); + printf("dpni_set_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, MC_CMD_NO_FLAGS, - priv->dpni_handle, - &priv->buf_layout); + dflt_dpni->buf_layout.options &= ~DPNI_BUF_LAYOUT_OPT_PRIVATE_DATA_SIZE; + err = dpni_set_buffer_layout(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + &dflt_dpni->buf_layout, + DPNI_QUEUE_TX_CONFIRM); if (err) { - printf("dpni_set_tx_conf_buffer_layout() failed"); + printf("dpni_set_buffer_layout() failed"); goto err_buf_layout; } @@ -524,7 +1030,8 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) * required tx data offset. */ err = dpni_get_tx_data_offset(dflt_mc_io, MC_CMD_NO_FLAGS, - priv->dpni_handle, &priv->tx_data_offset); + dflt_dpni->dpni_handle, + &priv->tx_data_offset); if (err) { printf("dpni_get_tx_data_offset() failed\n"); goto err_data_offset; @@ -542,7 +1049,7 @@ static int ldpaa_dpni_setup(struct ldpaa_eth_priv *priv) err_data_offset: err_buf_layout: err_get_attr: - dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle); + dpni_close(dflt_mc_io, MC_CMD_NO_FLAGS, dflt_dpni->dpni_handle); err_open: return err; } @@ -550,56 +1057,163 @@ err_open: static int ldpaa_dpni_bind(struct ldpaa_eth_priv *priv) { struct dpni_pools_cfg pools_params; - struct dpni_tx_flow_cfg dflt_tx_flow; + struct dpni_queue tx_queue; int err = 0; + memset(&pools_params, 0, sizeof(pools_params)); 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, MC_CMD_NO_FLAGS, priv->dpni_handle, - &pools_params); + err = dpni_set_pools(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->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)); + memset(&tx_queue, 0, sizeof(struct dpni_queue)); + + err = dpni_set_queue(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + DPNI_QUEUE_TX, 0, 0, &tx_queue); + + if (err) { + printf("dpni_set_queue() failed\n"); + return err; + } - dflt_tx_flow.options = DPNI_TX_FLOW_OPT_ONLY_TX_ERROR; - dflt_tx_flow.conf_err_cfg.use_default_queue = 0; - dflt_tx_flow.conf_err_cfg.errors_only = 1; - err = dpni_set_tx_flow(dflt_mc_io, MC_CMD_NO_FLAGS, priv->dpni_handle, - &priv->tx_flow_id, &dflt_tx_flow); + err = dpni_set_tx_confirmation_mode(dflt_mc_io, MC_CMD_NO_FLAGS, + dflt_dpni->dpni_handle, + DPNI_CONF_DISABLE); if (err) { - printf("dpni_set_tx_flow() failed\n"); + printf("dpni_set_tx_confirmation_mode() failed\n"); return err; } return 0; } -static int ldpaa_eth_netdev_init(struct eth_device *net_dev) +#ifdef CONFIG_DM_ETH +static int ldpaa_eth_probe(struct udevice *dev) +{ + struct ofnode_phandle_args phandle; + + /* Nothing to do if there is no "phy-handle" in the DTS node */ + if (dev_read_phandle_with_args(dev, "phy-handle", NULL, + 0, 0, &phandle)) { + return 0; + } + + init_phy(dev); + + return 0; +} + +static uint32_t ldpaa_eth_get_dpmac_id(struct udevice *dev) +{ + int port_node = dev_of_offset(dev); + + return fdtdec_get_uint(gd->fdt_blob, port_node, "reg", -1); +} + +static const char *ldpaa_eth_get_phy_mode_str(struct udevice *dev) +{ + int port_node = dev_of_offset(dev); + const char *phy_mode_str; + + phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, + "phy-connection-type", NULL); + if (phy_mode_str) + return phy_mode_str; + + phy_mode_str = fdt_getprop(gd->fdt_blob, port_node, "phy-mode", NULL); + return phy_mode_str; +} + +static int ldpaa_eth_bind(struct udevice *dev) +{ + const char *phy_mode_str = NULL; + uint32_t dpmac_id; + char eth_name[16]; + int phy_mode = -1; + + phy_mode_str = ldpaa_eth_get_phy_mode_str(dev); + if (phy_mode_str) + phy_mode = phy_get_interface_by_name(phy_mode_str); + if (phy_mode == -1) { + dev_err(dev, "incorrect phy mode\n"); + return -EINVAL; + } + + dpmac_id = ldpaa_eth_get_dpmac_id(dev); + if (dpmac_id == -1) { + dev_err(dev, "missing reg field from the dpmac node\n"); + return -EINVAL; + } + + sprintf(eth_name, "DPMAC%d@%s", dpmac_id, phy_mode_str); + device_set_name(dev, eth_name); + + return 0; +} + +static int ldpaa_eth_ofdata_to_platdata(struct udevice *dev) +{ + struct ldpaa_eth_priv *priv = dev_get_priv(dev); + const char *phy_mode_str; + + priv->dpmac_id = ldpaa_eth_get_dpmac_id(dev); + phy_mode_str = ldpaa_eth_get_phy_mode_str(dev); + priv->phy_mode = phy_get_interface_by_name(phy_mode_str); + + return 0; +} + +static const struct eth_ops ldpaa_eth_ops = { + .start = ldpaa_eth_open, + .send = ldpaa_eth_tx, + .recv = ldpaa_eth_pull_dequeue_rx, + .stop = ldpaa_eth_stop, +}; + +static const struct udevice_id ldpaa_eth_of_ids[] = { + { .compatible = "fsl,qoriq-mc-dpmac" }, +}; + +U_BOOT_DRIVER(ldpaa_eth) = { + .name = "ldpaa_eth", + .id = UCLASS_ETH, + .of_match = ldpaa_eth_of_ids, + .ofdata_to_platdata = ldpaa_eth_ofdata_to_platdata, + .bind = ldpaa_eth_bind, + .probe = ldpaa_eth_probe, + .ops = &ldpaa_eth_ops, + .priv_auto_alloc_size = sizeof(struct ldpaa_eth_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), +}; + +#else + +static int ldpaa_eth_netdev_init(struct eth_device *net_dev, + phy_interface_t enet_if) { int err; struct ldpaa_eth_priv *priv = (struct ldpaa_eth_priv *)net_dev->priv; - sprintf(net_dev->name, "DPNI%d", priv->dpni_id); + snprintf(net_dev->name, ETH_NAME_LEN, "DPMAC%d@%s", priv->dpmac_id, + phy_interface_strings[enet_if]); 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; +#ifdef CONFIG_PHYLIB + err = init_phy(net_dev); + if (err < 0) + return err; +#endif err = eth_register(net_dev); if (err < 0) { @@ -610,13 +1224,12 @@ static int ldpaa_eth_netdev_init(struct eth_device *net_dev) return 0; } -int ldpaa_eth_init(struct dprc_obj_desc obj_desc) +int ldpaa_eth_init(int dpmac_id, phy_interface_t enet_if) { 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) { @@ -629,15 +1242,17 @@ int ldpaa_eth_init(struct dprc_obj_desc obj_desc) priv = (struct ldpaa_eth_priv *)malloc(sizeof(struct ldpaa_eth_priv)); if (!priv) { printf("ldpaa_eth_priv malloc() failed\n"); + free(net_dev); 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; + priv->dpmac_id = dpmac_id; + debug("%s dpmac_id=%d\n", __func__, dpmac_id); - err = ldpaa_eth_netdev_init(net_dev); + err = ldpaa_eth_netdev_init(net_dev, enet_if); if (err) goto err_netdev_init; @@ -651,3 +1266,4 @@ err_netdev_init: return err; } +#endif