drivers: nrf_wifi: Implement TX zero-copy feature

This uses the network packet as is without the need for a copy all the
way till the packet is handed over to RPU.

Signed-off-by: Chaitanya Tata <Chaitanya.Tata@nordicsemi.no>
This commit is contained in:
Chaitanya Tata 2025-02-08 01:34:48 +05:30 committed by Benjamin Cabé
commit 5119f9c379
4 changed files with 87 additions and 0 deletions

View file

@ -828,4 +828,25 @@ config NRF_WIFI_COEX_DISABLE_PRIORITY_WINDOW_FOR_SCAN
help
Enable this configuration to disable priority window for scan
in the case of coexistence with Short Range radio.
if NETWORKING
config NRF_WIFI_ZERO_COPY_TX
bool "Zero copy Transmit path [EXPERIMENTAL]"
select NET_L2_ETHERNET_RESERVE_HEADER
select EXPERIMENTAL
# 54L has lower RAM
default y if SOC_SERIES_NRF54LX
help
Enable this configuration to use zero copy Transmit path.
The driver will use the network buffer directly for transmission
without copying the data to the driver's buffer. This reduces the
driver heap memory usage without much impact on the performance.
The application should configure the network buffers to ensure that
the whole packet fits in a single buffer, else the driver will fallback
to the normal copy path, but the memory requirements would still match
to the zero copy path and may be sub-optimal for the normal copy path.
endif # NETWORKING
endif # WIFI_NRF70

View file

@ -1002,6 +1002,11 @@ int nrf_wifi_if_get_config_zep(const struct device *dev,
ETHERNET_CHECKSUM_SUPPORT_TCP |
ETHERNET_CHECKSUM_SUPPORT_UDP;
}
#endif
#ifdef CONFIG_NRF_WIFI_ZERO_COPY_TX
if (type == ETHERNET_CONFIG_TYPE_EXTRA_TX_PKT_HEADROOM) {
config->extra_tx_pkt_headroom = NRF_WIFI_EXTRA_TX_HEADROOM;
}
#endif
ret = 0;
unlock:

View file

@ -268,6 +268,9 @@ struct nwb {
void (*cleanup_cb)();
unsigned char priority;
bool chksum_done;
#ifdef CONFIG_NRF_WIFI_ZERO_COPY_TX
struct net_pkt *pkt;
#endif
};
static void *zep_shim_nbuf_alloc(unsigned int size)
@ -301,6 +304,12 @@ static void zep_shim_nbuf_free(void *nbuf)
if (!nbuf) {
return;
}
#ifdef CONFIG_NRF_WIFI_ZERO_COPY_TX
if (((struct nwb *)nbuf)->pkt) {
net_pkt_unref(((struct nwb *)nbuf)->pkt);
((struct nwb *)nbuf)->pkt = NULL;
}
#endif /* CONFIG_NRF_WIFI_ZERO_COPY_TX */
zep_shim_data_mem_free(((struct nwb *)nbuf)->priv);
zep_shim_data_mem_free(nbuf);
@ -387,12 +396,62 @@ static void zep_shim_nbuf_set_chksum_done(void *nbuf, unsigned char chksum_done)
#include <zephyr/net/ethernet.h>
#include <zephyr/net/net_core.h>
#ifdef CONFIG_NRF_WIFI_ZERO_COPY_TX
void *net_pkt_to_nbuf_zc(struct net_pkt *pkt)
{
struct nwb *nbuff;
if (!pkt || !pkt->buffer) {
LOG_DBG("Invalid packet, dropping");
return NULL;
}
/* Check if packet has more than one fragment */
if (pkt->buffer->frags) {
LOG_ERR("Zero-copy only supports single buffer packets");
return NULL;
}
nbuff = zep_shim_nbuf_alloc(NRF_WIFI_EXTRA_TX_HEADROOM); /* Just for headers */
if (!nbuff) {
return NULL;
}
zep_shim_nbuf_headroom_res(nbuff, NRF_WIFI_EXTRA_TX_HEADROOM);
/* Zero-copy: point to the single data buffer */
/* TODO: Use API for proper cursor access? */
nbuff->data = pkt->buffer->data;
nbuff->len = pkt->buffer->len;
nbuff->priority = net_pkt_priority(pkt);
nbuff->chksum_done = (bool)net_pkt_is_chksum_done(pkt);
nbuff->pkt = pkt;
/* Ref the packet so that it is not freed */
net_pkt_ref(pkt);
return nbuff;
}
#endif /* CONFIG_NRF_WIFI_ZERO_COPY_TX */
void *net_pkt_to_nbuf(struct net_pkt *pkt)
{
struct nwb *nbuff;
unsigned char *data;
unsigned int len;
if (!pkt) {
return NULL;
}
#ifdef CONFIG_NRF_WIFI_ZERO_COPY_TX
/* For zero-copy, check if packet has single buffer */
if (pkt->buffer && !pkt->buffer->frags) {
return net_pkt_to_nbuf_zc(pkt);
}
#endif /* CONFIG_NRF_WIFI_ZERO_COPY_TX */
len = net_pkt_get_len(pkt);
nbuff = zep_shim_nbuf_alloc(len + 100);

View file

@ -16,6 +16,8 @@
#include <zephyr/drivers/gpio.h>
#include <zephyr/net/net_pkt.h>
#define NRF_WIFI_EXTRA_TX_HEADROOM 100
/**
* struct zep_shim_bus_qspi_priv - Structure to hold context information for the Linux OS
* shim.