@@ -53,6 +53,7 @@ drivers = [
'qede',
'ring',
'sfc',
+ 'shared_mem',
'softnic',
'tap',
'thunderx',
new file mode 100644
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2023 Intel Corporation
+
+if is_windows
+ build = false
+ reason = 'not supported on Windows'
+endif
+
+sources = files('shared_mem_eth.c')
+deps += 'bus_shared_mem'
+require_iova_in_mbuf = false
new file mode 100644
@@ -0,0 +1,295 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#include <rte_common.h>
+#include <shared_mem_bus.h>
+#include <ethdev_driver.h>
+
+RTE_LOG_REGISTER_DEFAULT(shared_mem_eth_logtype, DEBUG);
+#define SHM_ETH_LOG(level, fmt, args...) rte_log(RTE_LOG_ ## level, \
+ shared_mem_eth_logtype, "## SHARED MEM ETH: %s(): " fmt "\n", __func__, ##args)
+#define SHM_ETH_ERR(fmt, args...) SHM_ETH_LOG(ERR, fmt, ## args)
+#define SHM_ETH_INFO(fmt, args...) SHM_ETH_LOG(INFO, fmt, ## args)
+#define SHM_ETH_DEBUG(fmt, args...) SHM_ETH_LOG(DEBUG, fmt, ## args)
+
+struct shm_eth_stats {
+ uint64_t rx_pkts;
+ uint64_t tx_pkts;
+ uint64_t rx_bytes;
+ uint64_t tx_bytes;
+};
+
+struct shm_eth_private {
+ struct rte_ether_addr addr;
+ struct rte_ring *rx;
+ struct rte_ring *tx;
+ struct shm_eth_stats stats;
+};
+
+static struct rte_mempool *rx_mp; /* TODO: use one per queue */
+
+static int
+shm_eth_configure(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+
+static int
+shm_eth_start(struct rte_eth_dev *dev)
+{
+ struct shm_eth_private *priv = dev->data->dev_private;
+
+ struct eth_shared_mem_msg msg = (struct eth_shared_mem_msg){
+ .type = MSG_TYPE_START,
+ };
+ rte_shm_bus_send_message(&msg, sizeof(msg));
+
+ rte_shm_bus_recv_message(&msg, sizeof(msg));
+ if (msg.type != MSG_TYPE_ACK) {
+ SHM_ETH_ERR("Didn't get ack from host\n");
+ return -1;
+ }
+
+ memset(&priv->stats, 0, sizeof(priv->stats));
+ return 0;
+}
+
+static int
+shm_eth_stop(struct rte_eth_dev *dev __rte_unused)
+{
+ return 0;
+}
+
+static int
+shm_eth_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
+{
+ *info = (struct rte_eth_dev_info){
+ .driver_name = dev->device->driver->name,
+ .max_rx_queues = 1,
+ .max_tx_queues = 1,
+ .max_mac_addrs = 1,
+ .min_mtu = 64,
+ .max_mtu = UINT16_MAX,
+ .max_rx_pktlen = UINT16_MAX,
+ .nb_rx_queues = 1,
+ .nb_tx_queues = 1,
+ .tx_desc_lim = { .nb_max = 8192, .nb_min = 128, .nb_align = 64 },
+ .rx_desc_lim = { .nb_max = 8192, .nb_min = 128, .nb_align = 64 },
+ };
+ return 0;
+}
+
+static int
+shm_eth_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ dev->data->mtu = mtu;
+ return 0;
+}
+
+static int
+shm_eth_link_update(struct rte_eth_dev *dev, int wait __rte_unused)
+{
+ dev->data->dev_link = (struct rte_eth_link){
+ .link_speed = RTE_ETH_SPEED_NUM_100G,
+ .link_duplex = 1,
+ .link_autoneg = 1,
+ .link_status = 1,
+ };
+ return 0;
+}
+
+static int
+shm_eth_rx_queue_setup(struct rte_eth_dev *dev, uint16_t rx_queue_id,
+ uint16_t nb_rx_desc,
+ unsigned int socket_id,
+ const struct rte_eth_rxconf *rx_conf,
+ struct rte_mempool *mb_pool)
+{
+ RTE_SET_USED(rx_conf);
+
+ struct shm_eth_private *priv = dev->data->dev_private;
+ char ring_name[32];
+
+ if (rte_shm_bus_get_mem_offset(mb_pool) == (uintptr_t)-1) {
+ SHM_ETH_ERR("Mempool not in shared memory");
+ return -1;
+ }
+ snprintf(ring_name, sizeof(ring_name), "shm_eth_rxr%u", rx_queue_id);
+ priv->rx = rte_ring_create(ring_name, nb_rx_desc, socket_id, RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (priv->rx == NULL)
+ return -1;
+ SHM_ETH_INFO("RX ring @ %p\n", priv->rx);
+ if (rte_shm_bus_get_mem_offset(priv->rx) == (uintptr_t)-1) {
+ SHM_ETH_ERR("Ring not created on shared memory.");
+ return -1;
+ }
+ dev->data->rx_queues[rx_queue_id] = priv;
+
+ SHM_ETH_INFO("Mempool offset is: %p", (void *)rte_shm_bus_get_mem_offset(mb_pool));
+ SHM_ETH_INFO("Rx queue offset is: %p", (void *)rte_shm_bus_get_mem_offset(priv->rx));
+
+ struct eth_shared_mem_msg msg = (struct eth_shared_mem_msg){
+ .type = MSG_TYPE_MEMPOOL_OFFSET,
+ .offset = rte_shm_bus_get_mem_offset(mb_pool),
+ };
+ rte_shm_bus_send_message(&msg, sizeof(msg));
+ msg = (struct eth_shared_mem_msg){
+ .type = MSG_TYPE_RX_RING_OFFSET,
+ .offset = rte_shm_bus_get_mem_offset(priv->rx),
+ };
+ rte_shm_bus_send_message(&msg, sizeof(msg));
+ rx_mp = mb_pool;
+ return 0;
+}
+
+static int
+shm_eth_tx_queue_setup(struct rte_eth_dev *dev, uint16_t tx_queue_id,
+ uint16_t nb_tx_desc,
+ unsigned int socket_id,
+ const struct rte_eth_txconf *tx_conf)
+{
+ RTE_SET_USED(tx_conf);
+
+ struct shm_eth_private *priv = dev->data->dev_private;
+ char ring_name[32];
+
+ snprintf(ring_name, sizeof(ring_name), "shm_eth_txr%u", tx_queue_id);
+ priv->tx = rte_ring_create(ring_name, nb_tx_desc, socket_id, RING_F_SP_ENQ | RING_F_SC_DEQ);
+ if (priv->tx == NULL)
+ return -1;
+ SHM_ETH_DEBUG("TX ring @ %p\n", priv->tx);
+ if (rte_shm_bus_get_mem_offset(priv->tx) == (uintptr_t)-1) {
+ SHM_ETH_ERR("TX ring not on shared memory");
+ return -1;
+ }
+ dev->data->tx_queues[tx_queue_id] = priv;
+
+ struct eth_shared_mem_msg msg = (struct eth_shared_mem_msg){
+ .type = MSG_TYPE_TX_RING_OFFSET,
+ .offset = rte_shm_bus_get_mem_offset(priv->tx),
+ };
+ rte_shm_bus_send_message(&msg, sizeof(msg));
+
+ return 0;
+}
+
+static int
+shm_eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
+{
+ struct shm_eth_private *priv = dev->data->dev_private;
+ stats->ibytes = priv->stats.rx_bytes;
+ stats->ipackets = priv->stats.rx_pkts;
+ stats->obytes = priv->stats.tx_bytes;
+ stats->opackets = priv->stats.tx_pkts;
+ return 0;
+}
+
+static const struct eth_dev_ops ops = {
+ .dev_configure = shm_eth_configure,
+ .dev_start = shm_eth_start,
+ .dev_stop = shm_eth_stop,
+ .dev_infos_get = shm_eth_infos_get,
+ .mtu_set = shm_eth_mtu_set,
+ .rx_queue_setup = shm_eth_rx_queue_setup,
+ .tx_queue_setup = shm_eth_tx_queue_setup,
+ .link_update = shm_eth_link_update,
+ .stats_get = shm_eth_stats_get,
+};
+
+static uint16_t
+shm_eth_rx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+ void *deq_vals[nb_bufs];
+ struct shm_eth_private *priv = queue;
+ struct rte_ring *rxr = priv->rx;
+ uintptr_t offset = (uintptr_t)rte_shm_bus_get_mem_ptr(0);
+
+ int nb_rx = rte_ring_dequeue_burst(rxr, deq_vals, nb_bufs, NULL);
+ if (nb_rx == 0)
+ return 0;
+
+ uint64_t bytes = 0;
+ for (int i = 0; i < nb_rx; i++) {
+ bufs[i] = RTE_PTR_ADD(deq_vals[i], offset);
+ bufs[i]->pool = rx_mp;
+ bufs[i]->buf_addr = RTE_PTR_ADD(bufs[i]->buf_addr, offset);
+ bytes += bufs[i]->pkt_len;
+ }
+ priv->stats.rx_pkts += nb_rx;
+ priv->stats.rx_bytes += bytes;
+ return nb_rx;
+}
+
+static uint16_t
+shm_eth_tx_burst(void *queue, struct rte_mbuf **bufs, uint16_t nb_bufs)
+{
+ void *enq_vals[nb_bufs];
+ struct shm_eth_private *priv = queue;
+ struct rte_ring *txr = priv->tx;
+ uintptr_t offset = (uintptr_t)rte_shm_bus_get_mem_ptr(0);
+ uint64_t bytes = 0;
+
+ for (int i = 0; i < nb_bufs; i++) {
+ bufs[i]->buf_addr = RTE_PTR_SUB(bufs[i]->buf_addr, offset);
+ bytes += bufs[i]->pkt_len;
+ rte_cldemote(bufs[i]);
+ enq_vals[i] = RTE_PTR_SUB(bufs[i], offset);
+ }
+ uint16_t nb_enq = rte_ring_enqueue_burst(txr, enq_vals, nb_bufs, NULL);
+ if (nb_enq != nb_bufs) {
+ /* restore original buffer settings */
+ for (int i = nb_enq; i < nb_bufs; i++) {
+ bufs[i]->buf_addr = RTE_PTR_ADD(bufs[i]->buf_addr, offset);
+ bytes -= bufs[i]->pkt_len;
+ }
+ }
+ priv->stats.tx_pkts += nb_enq;
+ priv->stats.tx_bytes += bytes;
+ return nb_enq;
+}
+
+static int
+ethdev_init(struct rte_eth_dev *ethdev, void *init_params __rte_unused)
+{
+ struct shm_eth_private *priv = ethdev->data->dev_private;
+ ethdev->dev_ops = &ops;
+ ethdev->data->mac_addrs = &priv->addr;
+ ethdev->rx_pkt_burst = shm_eth_rx_burst;
+ ethdev->tx_pkt_burst = shm_eth_tx_burst;
+
+ struct eth_shared_mem_msg msg = (struct eth_shared_mem_msg){
+ .type = MSG_TYPE_GET_MAC,
+ };
+ rte_shm_bus_send_message(&msg, sizeof(msg));
+
+ rte_shm_bus_recv_message(&msg, sizeof(msg));
+ if (msg.type != MSG_TYPE_REPORT_MAC) {
+ SHM_ETH_ERR("Didn't get mac address from host\n");
+ return -1;
+ }
+ rte_ether_addr_copy(&msg.ethaddr, &priv->addr);
+
+ return 0;
+}
+
+static int
+shm_eth_probe(struct shared_mem_drv *drv, struct rte_device *dev)
+{
+ SHM_ETH_INFO("Probing device %p on driver %s", dev, drv->driver.name);
+ int ret = rte_eth_dev_create(dev, "shared_mem_ethdev", sizeof(struct shm_eth_private),
+ NULL, NULL,
+ ethdev_init, NULL);
+ if (ret != 0)
+ goto out;
+
+ SHM_ETH_DEBUG("Ethdev created ok\n");
+out:
+ return ret;
+}
+
+struct shared_mem_drv shm_drv = {
+ .probe = shm_eth_probe,
+};
+
+
+RTE_PMD_REGISTER_SHMEM_DRV(shm_eth, shm_drv);