Implement XSK NDOs (setup, wakeup) and create XSK
Rx and Tx queues. xsk_qid stores the queue id for
a given port which has been registered for zero copy
AF_XDP and used to acquire UMEM pointer if registered.

Signed-off-by: Meghana Malladi <m-mall...@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_common.c |   2 +-
 drivers/net/ethernet/ti/icssg/icssg_prueth.c | 133 +++++++++++++++++++
 drivers/net/ethernet/ti/icssg/icssg_prueth.h |   7 +
 3 files changed, 141 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c 
b/drivers/net/ethernet/ti/icssg/icssg_common.c
index 5d31873492b6..8a0ebe011960 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -752,7 +752,7 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 
flow_id, u32 *xdp_state)
        }
 
        pa = page_address(page);
-       if (emac->xdp_prog) {
+       if (prueth_xdp_is_enabled(emac)) {
                xdp_init_buff(&xdp, PAGE_SIZE, &rx_chn->xdp_rxq);
                xdp_prepare_buff(&xdp, pa, PRUETH_HEADROOM, pkt_len, false);
 
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c 
b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 687249402c38..d70f0400cfd4 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -47,6 +47,9 @@
                                                 NETIF_F_HW_HSR_TAG_INS | \
                                                 NETIF_F_HW_HSR_TAG_RM)
 
+#define PRUETH_RX_DMA_ATTR                     (DMA_ATTR_SKIP_CPU_SYNC |\
+                                                DMA_ATTR_WEAK_ORDERING)
+
 /* CTRLMMR_ICSSG_RGMII_CTRL register bits */
 #define ICSSG_CTRL_RGMII_ID_MODE                BIT(24)
 
@@ -1167,6 +1170,111 @@ static int emac_xdp_setup(struct prueth_emac *emac, 
struct netdev_bpf *bpf)
        return 0;
 }
 
+static int prueth_xsk_pool_enable(struct prueth_emac *emac,
+                                 struct xsk_buff_pool *pool, u16 queue_id)
+{
+       struct prueth_rx_chn *rx_chn = &emac->rx_chns;
+       bool need_update = false;
+       u32 frame_size;
+       int ret;
+
+       if (queue_id >= PRUETH_MAX_RX_FLOWS ||
+           queue_id >= emac->tx_ch_num) {
+               netdev_err(emac->ndev, "Invalid XSK queue ID %d\n", queue_id);
+               return -EINVAL;
+       }
+
+       frame_size = xsk_pool_get_rx_frame_size(pool);
+       if (frame_size < PRUETH_MAX_PKT_SIZE)
+               return -EOPNOTSUPP;
+
+       ret = xsk_pool_dma_map(pool, rx_chn->dma_dev, PRUETH_RX_DMA_ATTR);
+       if (ret) {
+               netdev_err(emac->ndev, "Failed to map XSK pool: %d\n", ret);
+               return ret;
+       }
+
+       need_update = netif_running(emac->ndev) || prueth_xdp_is_enabled(emac);
+
+       if (need_update) {
+               prueth_destroy_txq(emac);
+               prueth_destroy_rxq(emac);
+       }
+
+       emac->xsk_qid = queue_id;
+
+       if (netif_running(emac->ndev)) {
+               ret = prueth_create_rxq(emac);
+               if (ret) {
+                       netdev_err(emac->ndev, "Failed to create RX queue: 
%d\n", ret);
+                       return ret;
+               }
+
+               ret = prueth_create_txq(emac);
+               if (ret) {
+                       netdev_err(emac->ndev, "Failed to create TX queue: 
%d\n", ret);
+                       prueth_destroy_rxq(emac);
+                       emac->xdp_prog = NULL;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int prueth_xsk_pool_disable(struct prueth_emac *emac, u16 queue_id)
+{
+       struct xsk_buff_pool *pool;
+       bool need_update = false;
+       int ret;
+
+       if (queue_id >= PRUETH_MAX_RX_FLOWS ||
+           queue_id >= emac->tx_ch_num) {
+               netdev_err(emac->ndev, "Invalid XSK queue ID %d\n", queue_id);
+               return -EINVAL;
+       }
+
+       if (emac->xsk_qid != queue_id) {
+               netdev_err(emac->ndev, "XSK queue ID %d not registered\n", 
queue_id);
+               return -EINVAL;
+       }
+
+       pool = xsk_get_pool_from_qid(emac->ndev, queue_id);
+       if (!pool) {
+               netdev_err(emac->ndev, "No XSK pool registered for queue %d\n", 
queue_id);
+               return -EINVAL;
+       }
+
+       need_update = netif_running(emac->ndev) || prueth_xdp_is_enabled(emac);
+
+       if (need_update) {
+               prueth_destroy_txq(emac);
+               prueth_destroy_rxq(emac);
+               synchronize_rcu();
+       }
+
+       xsk_pool_dma_unmap(pool, PRUETH_RX_DMA_ATTR);
+       emac->xsk_qid = -EINVAL;
+
+       if (netif_running(emac->ndev)) {
+               ret = prueth_create_rxq(emac);
+               if (ret) {
+                       netdev_err(emac->ndev, "Failed to create RX queue: 
%d\n", ret);
+                       return ret;
+               }
+
+               ret = prueth_create_txq(emac);
+               if (ret) {
+                       netdev_err(emac->ndev, "Failed to create TX queue: 
%d\n", ret);
+                       prueth_destroy_rxq(emac);
+                       emac->xdp_prog = NULL;
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 /**
  * emac_ndo_bpf - implements ndo_bpf for icssg_prueth
  * @ndev: network adapter device
@@ -1181,11 +1289,35 @@ static int emac_ndo_bpf(struct net_device *ndev, struct 
netdev_bpf *bpf)
        switch (bpf->command) {
        case XDP_SETUP_PROG:
                return emac_xdp_setup(emac, bpf);
+       case XDP_SETUP_XSK_POOL:
+               return bpf->xsk.pool ?
+                       prueth_xsk_pool_enable(emac, bpf->xsk.pool, 
bpf->xsk.queue_id) :
+                       prueth_xsk_pool_disable(emac, bpf->xsk.queue_id);
        default:
                return -EINVAL;
        }
 }
 
+static int prueth_xsk_wakeup(struct net_device *ndev, u32 qid, u32 flags)
+{
+       struct prueth_emac *emac = netdev_priv(ndev);
+
+       if (!netif_running(ndev) || !netif_carrier_ok(ndev))
+               return -ENETDOWN;
+
+       if (!prueth_xdp_is_enabled(emac) || emac->xsk_qid != qid) {
+               netdev_err(ndev, "XSK queue %d not registered or XDP not 
enabled\n", qid);
+               return -EINVAL;
+       }
+
+       if (qid >= PRUETH_MAX_RX_FLOWS || qid >= emac->tx_ch_num) {
+               netdev_err(ndev, "Invalid XSK queue ID %d\n", qid);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct net_device_ops emac_netdev_ops = {
        .ndo_open = emac_ndo_open,
        .ndo_stop = emac_ndo_stop,
@@ -1202,6 +1334,7 @@ static const struct net_device_ops emac_netdev_ops = {
        .ndo_vlan_rx_kill_vid = emac_ndo_vlan_rx_del_vid,
        .ndo_bpf = emac_ndo_bpf,
        .ndo_xdp_xmit = emac_xdp_xmit,
+       .ndo_xsk_wakeup = prueth_xsk_wakeup,
 };
 
 static int prueth_netdev_init(struct prueth *prueth,
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h 
b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index e0dadbfca45a..2f64ec97b454 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -38,6 +38,8 @@
 #include <net/devlink.h>
 #include <net/xdp.h>
 #include <net/page_pool/helpers.h>
+#include <net/xsk_buff_pool.h>
+#include <net/xdp_sock_drv.h>
 
 #include "icssg_config.h"
 #include "icss_iep.h"
@@ -241,6 +243,7 @@ struct prueth_emac {
        struct netdev_hw_addr_list vlan_mcast_list[MAX_VLAN_ID];
        struct bpf_prog *xdp_prog;
        struct xdp_attachment_info xdpi;
+       int xsk_qid;
 };
 
 /* The buf includes headroom compatible with both skb and xdpf */
@@ -499,5 +502,9 @@ u32 emac_xmit_xdp_frame(struct prueth_emac *emac,
                        unsigned int q_idx);
 void prueth_rx_cleanup(void *data, dma_addr_t desc_dma);
 void prueth_tx_cleanup(void *data, dma_addr_t desc_dma);
+static inline bool prueth_xdp_is_enabled(struct prueth_emac *emac)
+{
+       return !!READ_ONCE(emac->xdp_prog);
+}
 
 #endif /* __NET_TI_ICSSG_PRUETH_H */
-- 
2.43.0

Reply via email to