* Copyright 2019 NXP
*/
+#include <sys/epoll.h>
#include <rte_kvargs.h>
#include <rte_ethdev_vdev.h>
#include <rte_bus_vdev.h>
+#include <rte_ether.h>
#include <dpaa_of.h>
#include "pfe_logs.h"
return 0;
}
+static uint16_t
+pfe_recv_pkts_on_intr(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+ struct hif_client_rx_queue *queue = rxq;
+ struct pfe_eth_priv_s *priv = queue->priv;
+ struct epoll_event epoll_ev;
+ uint64_t ticks = 1; /* 1 msec */
+ int ret;
+ int have_something, work_done;
+
+#define RESET_STATUS (HIF_INT | HIF_RXPKT_INT)
+
+ /*TODO can we remove this cleanup from here?*/
+ pfe_tx_do_cleanup(priv->pfe);
+ have_something = pfe_hif_rx_process(priv->pfe, nb_pkts);
+ work_done = hif_lib_receive_pkt(rxq, priv->pfe->hif.shm->pool,
+ rx_pkts, nb_pkts);
+
+ if (!have_something || !work_done) {
+ writel(RESET_STATUS, HIF_INT_SRC);
+ writel(readl(HIF_INT_ENABLE) | HIF_RXPKT_INT, HIF_INT_ENABLE);
+ ret = epoll_wait(priv->pfe->hif.epoll_fd, &epoll_ev, 1, ticks);
+ if (ret < 0 && errno != EINTR)
+ PFE_PMD_ERR("epoll_wait fails with %d\n", errno);
+ }
+
+ return work_done;
+}
+
+static uint16_t
+pfe_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
+{
+ struct hif_client_rx_queue *queue = rxq;
+ struct pfe_eth_priv_s *priv = queue->priv;
+ struct rte_mempool *pool;
+
+ /*TODO can we remove this cleanup from here?*/
+ pfe_tx_do_cleanup(priv->pfe);
+ pfe_hif_rx_process(priv->pfe, nb_pkts);
+ pool = priv->pfe->hif.shm->pool;
+
+ return hif_lib_receive_pkt(rxq, pool, rx_pkts, nb_pkts);
+}
+
+static uint16_t
+pfe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ struct hif_client_tx_queue *queue = tx_queue;
+ struct pfe_eth_priv_s *priv = queue->priv;
+ struct rte_eth_stats *stats = &priv->stats;
+ int i;
+
+ for (i = 0; i < nb_pkts; i++) {
+ if (tx_pkts[i]->nb_segs > 1) {
+ struct rte_mbuf *mbuf;
+ int j;
+
+ hif_lib_xmit_pkt(&priv->client, queue->queue_id,
+ (void *)(size_t)rte_pktmbuf_iova(tx_pkts[i]),
+ tx_pkts[i]->buf_addr + tx_pkts[i]->data_off,
+ tx_pkts[i]->data_len, 0x0, HIF_FIRST_BUFFER,
+ tx_pkts[i]);
+
+ mbuf = tx_pkts[i]->next;
+ for (j = 0; j < (tx_pkts[i]->nb_segs - 2); j++) {
+ hif_lib_xmit_pkt(&priv->client, queue->queue_id,
+ (void *)(size_t)rte_pktmbuf_iova(mbuf),
+ mbuf->buf_addr + mbuf->data_off,
+ mbuf->data_len,
+ 0x0, 0x0, mbuf);
+ mbuf = mbuf->next;
+ }
+
+ hif_lib_xmit_pkt(&priv->client, queue->queue_id,
+ (void *)(size_t)rte_pktmbuf_iova(mbuf),
+ mbuf->buf_addr + mbuf->data_off,
+ mbuf->data_len,
+ 0x0, HIF_LAST_BUFFER | HIF_DATA_VALID,
+ mbuf);
+ } else {
+ hif_lib_xmit_pkt(&priv->client, queue->queue_id,
+ (void *)(size_t)rte_pktmbuf_iova(tx_pkts[i]),
+ tx_pkts[i]->buf_addr + tx_pkts[i]->data_off,
+ tx_pkts[i]->pkt_len, 0 /*ctrl*/,
+ HIF_FIRST_BUFFER | HIF_LAST_BUFFER |
+ HIF_DATA_VALID,
+ tx_pkts[i]);
+ }
+ stats->obytes += tx_pkts[i]->pkt_len;
+ hif_tx_dma_start();
+ }
+ stats->opackets += nb_pkts;
+ pfe_tx_do_cleanup(priv->pfe);
+
+ return nb_pkts;
+}
+
+static uint16_t
+pfe_dummy_xmit_pkts(__rte_unused void *tx_queue,
+ __rte_unused struct rte_mbuf **tx_pkts,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
+static uint16_t
+pfe_dummy_recv_pkts(__rte_unused void *rxq,
+ __rte_unused struct rte_mbuf **rx_pkts,
+ __rte_unused uint16_t nb_pkts)
+{
+ return 0;
+}
+
static int
pfe_eth_open(struct rte_eth_dev *dev)
{
" failed", client->id);
goto err0;
}
+ } else {
+ /* Freeing the packets if already exists */
+ int ret = 0;
+ struct rte_mbuf *rx_pkts[32];
+ /* TODO multiqueue support */
+ ret = hif_lib_receive_pkt(&client->rx_q[0],
+ hif_shm->pool, rx_pkts, 32);
+ while (ret) {
+ int i;
+ for (i = 0; i < ret; i++)
+ rte_pktmbuf_free(rx_pkts[i]);
+ ret = hif_lib_receive_pkt(&client->rx_q[0],
+ hif_shm->pool,
+ rx_pkts, 32);
+ }
}
} else {
/* Register client driver with HIF */
}
}
rc = pfe_eth_start(priv);
+ dev->rx_pkt_burst = &pfe_recv_pkts;
+ dev->tx_pkt_burst = &pfe_xmit_pkts;
+ /* If no prefetch is configured. */
+ if (getenv("PFE_INTR_SUPPORT")) {
+ dev->rx_pkt_burst = &pfe_recv_pkts_on_intr;
+ PFE_PMD_INFO("PFE INTERRUPT Mode enabled");
+ }
+
err0:
return rc;
gemac_disable(priv->EMAC_baseaddr);
gpi_disable(priv->GPI_baseaddr);
+
+ dev->rx_pkt_burst = &pfe_dummy_recv_pkts;
+ dev->tx_pkt_burst = &pfe_dummy_xmit_pkts;
}
static void
dev_info->max_rx_queues = dev->data->nb_rx_queues;
dev_info->max_tx_queues = dev->data->nb_tx_queues;
dev_info->min_rx_bufsize = HIF_RX_PKT_MIN_SIZE;
+ dev_info->min_mtu = RTE_ETHER_MIN_MTU;
dev_info->rx_offload_capa = dev_rx_offloads_sup;
dev_info->tx_offload_capa = dev_tx_offloads_sup;
- if (pfe_svr == SVR_LS1012A_REV1)
+ if (pfe_svr == SVR_LS1012A_REV1) {
dev_info->max_rx_pktlen = MAX_MTU_ON_REV1 + PFE_ETH_OVERHEAD;
- else
+ dev_info->max_mtu = MAX_MTU_ON_REV1;
+ } else {
dev_info->max_rx_pktlen = JUMBO_FRAME_SIZE;
+ dev_info->max_mtu = JUMBO_FRAME_SIZE - PFE_ETH_OVERHEAD;
+ }
return 0;
}
return 0;
}
+static const uint32_t *
+pfe_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+ static const uint32_t ptypes[] = {
+ /*todo -= add more types */
+ RTE_PTYPE_L2_ETHER,
+ RTE_PTYPE_L3_IPV4,
+ RTE_PTYPE_L3_IPV4_EXT,
+ RTE_PTYPE_L3_IPV6,
+ RTE_PTYPE_L3_IPV6_EXT,
+ RTE_PTYPE_L4_TCP,
+ RTE_PTYPE_L4_UDP,
+ RTE_PTYPE_L4_SCTP
+ };
+
+ if (dev->rx_pkt_burst == pfe_recv_pkts ||
+ dev->rx_pkt_burst == pfe_recv_pkts_on_intr)
+ return ptypes;
+ return NULL;
+}
+
+static int
+pfe_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ int ret;
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ uint16_t frame_size = mtu + RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN;
+
+ /*TODO Support VLAN*/
+ ret = gemac_set_rx(priv->EMAC_baseaddr, frame_size);
+ if (!ret)
+ dev->data->mtu = mtu;
+
+ return ret;
+}
+
+/* pfe_eth_enet_addr_byte_mac
+ */
+static int
+pfe_eth_enet_addr_byte_mac(u8 *enet_byte_addr,
+ struct pfe_mac_addr *enet_addr)
+{
+ if (!enet_byte_addr || !enet_addr) {
+ return -1;
+
+ } else {
+ enet_addr->bottom = enet_byte_addr[0] |
+ (enet_byte_addr[1] << 8) |
+ (enet_byte_addr[2] << 16) |
+ (enet_byte_addr[3] << 24);
+ enet_addr->top = enet_byte_addr[4] |
+ (enet_byte_addr[5] << 8);
+ return 0;
+ }
+}
+
+static int
+pfe_dev_set_mac_addr(struct rte_eth_dev *dev,
+ struct rte_ether_addr *addr)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ struct pfe_mac_addr spec_addr;
+ int ret;
+
+ ret = pfe_eth_enet_addr_byte_mac(addr->addr_bytes, &spec_addr);
+ if (ret)
+ return ret;
+
+ gemac_set_laddrN(priv->EMAC_baseaddr,
+ (struct pfe_mac_addr *)&spec_addr, 1);
+ rte_ether_addr_copy(addr, &dev->data->mac_addrs[0]);
+ return 0;
+}
+
+static int
+pfe_stats_get(struct rte_eth_dev *dev,
+ struct rte_eth_stats *stats)
+{
+ struct pfe_eth_priv_s *priv = dev->data->dev_private;
+ struct rte_eth_stats *eth_stats = &priv->stats;
+
+ if (stats == NULL)
+ return -1;
+
+ memset(stats, 0, sizeof(struct rte_eth_stats));
+
+ stats->ipackets = eth_stats->ipackets;
+ stats->ibytes = eth_stats->ibytes;
+ stats->opackets = eth_stats->opackets;
+ stats->obytes = eth_stats->obytes;
+
+ return 0;
+}
+
static const struct eth_dev_ops ops = {
.dev_start = pfe_eth_open,
.dev_stop = pfe_eth_stop,
.rx_queue_release = pfe_rx_queue_release,
.tx_queue_setup = pfe_tx_queue_setup,
.tx_queue_release = pfe_tx_queue_release,
+ .dev_supported_ptypes_get = pfe_supported_ptypes_get,
+ .mtu_set = pfe_mtu_set,
+ .mac_addr_set = pfe_dev_set_mac_addr,
+ .stats_get = pfe_stats_get,
};
static int
struct pfe_eth_priv_s *priv = NULL;
struct ls1012a_eth_platform_data *einfo;
struct ls1012a_pfe_platform_data *pfe_info;
+ struct rte_ether_addr addr;
int err;
eth_dev = rte_eth_vdev_allocate(vdev, sizeof(*priv));
goto err0;
}
+ memcpy(addr.addr_bytes, priv->einfo->mac_addr,
+ ETH_ALEN);
+
+ pfe_dev_set_mac_addr(eth_dev, &addr);
+ rte_ether_addr_copy(&addr, ð_dev->data->mac_addrs[0]);
+
eth_dev->data->mtu = 1500;
eth_dev->dev_ops = &ops;
pfe_eth_stop(eth_dev);