Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157516139
D21935.id63030.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
D21935.id63030.diff
View Options
Index: sys/dev/ena/ena.h
===================================================================
--- sys/dev/ena/ena.h
+++ sys/dev/ena/ena.h
@@ -252,6 +252,9 @@
struct mbuf *mbuf;
bus_dmamap_t map;
struct ena_com_buf ena_buf;
+#ifdef DEV_NETMAP
+ uint32_t netmap_buf_idx;
+#endif /* DEV_NETMAP */
} __aligned(CACHE_LINE_SIZE);
struct ena_stats_tx {
@@ -351,6 +354,10 @@
/* Used for LLQ */
uint8_t *push_buf_intermediate_buf;
+
+#ifdef DEV_NETMAP
+ bool initialized;
+#endif /* DEV_NETMAP */
} __aligned(CACHE_LINE_SIZE);
struct ena_stats_dev {
@@ -470,5 +477,25 @@
int ena_restore_device(struct ena_adapter *);
void ena_destroy_device(struct ena_adapter *, bool);
int ena_refill_rx_bufs(struct ena_ring *, uint32_t);
+inline int validate_rx_req_id(struct ena_ring *, uint16_t);
+
+inline int
+validate_rx_req_id(struct ena_ring *rx_ring, uint16_t req_id)
+{
+ if (likely(req_id < rx_ring->ring_size))
+ return (0);
+
+ device_printf(rx_ring->adapter->pdev, "Invalid rx req_id: %hu\n",
+ req_id);
+ counter_u64_add(rx_ring->rx_stats.bad_req_id, 1);
+
+ /* Trigger device reset */
+ if (likely(!ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, rx_ring->adapter))) {
+ rx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID;
+ ENA_FLAG_SET_ATOMIC(ENA_FLAG_TRIGGER_RESET, rx_ring->adapter);
+ }
+
+ return (EFAULT);
+}
#endif /* !(ENA_H) */
Index: sys/dev/ena/ena.c
===================================================================
--- sys/dev/ena/ena.c
+++ sys/dev/ena/ena.c
@@ -764,6 +764,11 @@
size = sizeof(struct ena_rx_buffer) * rx_ring->ring_size;
+#ifdef DEV_NETMAP
+ ena_netmap_reset_rx_ring(adapter, qid);
+ rx_ring->initialized = false;
+#endif /* DEV_NETMAP */
+
/*
* Alloc extra element so in rx path
* we can always prefetch rx_info + 1
@@ -1008,8 +1013,12 @@
req_id = rx_ring->free_rx_ids[next_to_use];
rx_info = &rx_ring->rx_buffer_info[req_id];
-
- rc = ena_alloc_rx_mbuf(adapter, rx_ring, rx_info);
+#ifdef DEV_NETMAP
+ if (adapter->ifp->if_capenable & IFCAP_NETMAP)
+ rc = ena_netmap_alloc_rx_slot(adapter, rx_ring, rx_info);
+ else
+#endif /* DEV_NETMAP */
+ rc = ena_alloc_rx_mbuf(adapter, rx_ring, rx_info);
if (unlikely(rc != 0)) {
ena_trace(ENA_WARNING,
"failed to alloc buffer for rx queue %d\n",
@@ -1054,6 +1063,14 @@
if (rx_info->mbuf != NULL)
ena_free_rx_mbuf(adapter, rx_ring, rx_info);
+#ifdef DEV_NETMAP
+ if (((if_getflags(adapter->ifp) & IFF_DYING) == 0) &&
+ (adapter->ifp->if_capenable & IFCAP_NETMAP)) {
+ if (rx_info->netmap_buf_idx != 0)
+ ena_netmap_free_rx_slot(adapter, rx_ring,
+ rx_info);
+ }
+#endif /* DEV_NETMAP */
}
}
@@ -1072,10 +1089,12 @@
rx_ring = &adapter->rx_ring[i];
bufs_num = rx_ring->ring_size - 1;
rc = ena_refill_rx_bufs(rx_ring, bufs_num);
-
if (unlikely(rc != bufs_num))
ena_trace(ENA_WARNING, "refilling Queue %d failed. "
"Allocated %d buffers from: %d\n", i, rc, bufs_num);
+#ifdef DEV_NETMAP
+ rx_ring->initialized = true;
+#endif /* DEV_NETMAP */
}
}
Index: sys/dev/ena/ena_datapath.c
===================================================================
--- sys/dev/ena/ena_datapath.c
+++ sys/dev/ena/ena_datapath.c
@@ -32,6 +32,9 @@
#include "ena.h"
#include "ena_datapath.h"
+#ifdef DEV_NETMAP
+#include "ena_netmap.h"
+#endif /* DEV_NETMAP */
/*********************************************************************
* Static functions prototypes
@@ -40,7 +43,6 @@
static int ena_tx_cleanup(struct ena_ring *);
static int ena_rx_cleanup(struct ena_ring *);
static inline int validate_tx_req_id(struct ena_ring *, uint16_t);
-static inline int validate_rx_req_id(struct ena_ring *, uint16_t);
static void ena_rx_hash_mbuf(struct ena_ring *, struct ena_com_rx_ctx *,
struct mbuf *);
static struct mbuf* ena_rx_mbuf(struct ena_ring *, struct ena_com_rx_buf_info *,
@@ -206,25 +208,6 @@
return (EFAULT);
}
-static inline int
-validate_rx_req_id(struct ena_ring *rx_ring, uint16_t req_id)
-{
- if (likely(req_id < rx_ring->ring_size))
- return (0);
-
- device_printf(rx_ring->adapter->pdev, "Invalid rx req_id: %hu\n",
- req_id);
- counter_u64_add(rx_ring->rx_stats.bad_req_id, 1);
-
- /* Trigger device reset */
- if (likely(!ENA_FLAG_ISSET(ENA_FLAG_TRIGGER_RESET, rx_ring->adapter))) {
- rx_ring->adapter->reset_reason = ENA_REGS_RESET_INV_RX_REQ_ID;
- ENA_FLAG_SET_ATOMIC(ENA_FLAG_TRIGGER_RESET, rx_ring->adapter);
- }
-
- return (EFAULT);
-}
-
/**
* ena_tx_cleanup - clear sent packets and corresponding descriptors
* @tx_ring: ring for which we want to clean packets
@@ -577,6 +560,9 @@
unsigned int qid;
int rc, i;
int budget = RX_BUDGET;
+#ifdef DEV_NETMAP
+ int done;
+#endif /* DEV_NETMAP */
adapter = rx_ring->que->adapter;
ifp = adapter->ifp;
@@ -586,6 +572,11 @@
io_sq = &adapter->ena_dev->io_sq_queues[ena_qid];
next_to_clean = rx_ring->next_to_clean;
+#ifdef DEV_NETMAP
+ if (netmap_rx_irq(adapter->ifp, rx_ring->qid, &done) != NM_IRQ_PASS)
+ return (0);
+#endif /* DEV_NETMAP */
+
ena_trace(ENA_DBG, "rx: qid %d\n", qid);
do {
Index: sys/dev/ena/ena_netmap.h
===================================================================
--- sys/dev/ena/ena_netmap.h
+++ sys/dev/ena/ena_netmap.h
@@ -47,5 +47,10 @@
#include <dev/netmap/netmap_kern.h>
int ena_netmap_attach(struct ena_adapter *);
+int ena_netmap_alloc_rx_slot(struct ena_adapter *, struct ena_ring *,
+ struct ena_rx_buffer *);
+void ena_netmap_free_rx_slot(struct ena_adapter *, struct ena_ring *,
+ struct ena_rx_buffer *);
+void ena_netmap_reset_rx_ring(struct ena_adapter *, int);
#endif /* _ENA_NETMAP_H_ */
Index: sys/dev/ena/ena_netmap.c
===================================================================
--- sys/dev/ena/ena_netmap.c
+++ sys/dev/ena/ena_netmap.c
@@ -35,10 +35,37 @@
#include "ena.h"
#include "ena_netmap.h"
+#define ENA_NETMAP_MORE_FRAMES 1
+#define ENA_NETMAP_NO_MORE_FRAMES 0
+#define ENA_MAX_FRAMES 16384
+
+struct ena_netmap_ctx {
+ struct netmap_kring *kring;
+ struct ena_adapter *adapter;
+ struct netmap_adapter *na;
+ struct netmap_slot *slots;
+ struct ena_ring *ring;
+ struct ena_com_io_cq *io_cq;
+ struct ena_com_io_sq *io_sq;
+ u_int nm_i;
+ uint16_t nt;
+ uint16_t lim;
+};
+
+/* Netmap callbacks */
static int ena_netmap_reg(struct netmap_adapter *, int);
static int ena_netmap_txsync(struct netmap_kring *, int);
static int ena_netmap_rxsync(struct netmap_kring *, int);
+/* Helper functions */
+static int ena_netmap_rx_frames(struct ena_netmap_ctx *);
+static int ena_netmap_rx_frame(struct ena_netmap_ctx *);
+static int ena_netmap_rx_load_desc(struct ena_netmap_ctx *, uint16_t,
+ int *);
+static void ena_netmap_rx_cleanup(struct ena_netmap_ctx *);
+static void ena_netmap_fill_ctx(struct netmap_kring *,
+ struct ena_netmap_ctx *, uint16_t);
+
int
ena_netmap_attach(struct ena_adapter *adapter)
{
@@ -61,6 +88,124 @@
return (netmap_attach(&na));
}
+int
+ena_netmap_alloc_rx_slot(struct ena_adapter *adapter,
+ struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info)
+{
+ struct netmap_adapter *na = NA(adapter->ifp);
+ struct netmap_kring *kring;
+ struct netmap_ring *ring;
+ struct netmap_slot *slot;
+ void *addr;
+ uint64_t paddr;
+ int nm_i, qid, head, lim, rc;
+
+ /* if previously allocated frag is not used */
+ if (unlikely(rx_info->netmap_buf_idx != 0))
+ return (0);
+
+ qid = rx_ring->qid;
+ kring = na->rx_rings[qid];
+ nm_i = kring->nr_hwcur;
+ head = kring->rhead;
+
+ ena_trace(ENA_NETMAP | ENA_DBG, "nr_hwcur: %d, nr_hwtail: %d, "
+ "rhead: %d, rcur: %d, rtail: %d\n", kring->nr_hwcur,
+ kring->nr_hwtail, kring->rhead, kring->rcur, kring->rtail);
+
+ if ((nm_i == head) && rx_ring->initialized) {
+ ena_trace(ENA_NETMAP, "No free slots in netmap ring\n");
+ return (ENOMEM);
+ }
+
+ ring = kring->ring;
+ if (ring == NULL) {
+ device_printf(adapter->pdev, "Rx ring %d is NULL\n", qid);
+ return (EFAULT);
+ }
+ slot = &ring->slot[nm_i];
+
+ addr = PNMB(na, slot, &paddr);
+ if (addr == NETMAP_BUF_BASE(na)) {
+ device_printf(adapter->pdev, "Bad buff in slot\n");
+ return (EFAULT);
+ }
+
+ rc = netmap_load_map(na, adapter->rx_buf_tag, rx_info->map, addr);
+ if (rc != 0) {
+ ena_trace(ENA_WARNING, "DMA mapping error\n");
+ return (rc);
+ }
+ bus_dmamap_sync(adapter->rx_buf_tag, rx_info->map, BUS_DMASYNC_PREREAD);
+
+ rx_info->ena_buf.paddr = paddr;
+ rx_info->ena_buf.len = ring->nr_buf_size;
+ rx_info->mbuf = NULL;
+ rx_info->netmap_buf_idx = slot->buf_idx;
+
+ slot->buf_idx = 0;
+
+ lim = kring->nkr_num_slots - 1;
+ kring->nr_hwcur = nm_next(nm_i, lim);
+
+ return (0);
+}
+
+void
+ena_netmap_free_rx_slot(struct ena_adapter *adapter,
+ struct ena_ring *rx_ring, struct ena_rx_buffer *rx_info)
+{
+ struct netmap_adapter *na;
+ struct netmap_kring *kring;
+ struct netmap_slot *slot;
+ int nm_i, qid, lim;
+
+ na = NA(adapter->ifp);
+ if (na == NULL) {
+ device_printf(adapter->pdev, "netmap adapter is NULL\n");
+ return;
+ }
+
+ if (na->rx_rings == NULL) {
+ device_printf(adapter->pdev, "netmap rings are NULL\n");
+ return;
+ }
+
+ qid = rx_ring->qid;
+ kring = na->rx_rings[qid];
+ if (kring == NULL) {
+ device_printf(adapter->pdev,
+ "netmap kernel ring %d is NULL\n", qid);
+ return;
+ }
+
+ lim = kring->nkr_num_slots - 1;
+ nm_i = nm_prev(kring->nr_hwcur, lim);
+
+ if (kring->nr_mode != NKR_NETMAP_ON)
+ return;
+
+ bus_dmamap_sync(adapter->rx_buf_tag, rx_info->map,
+ BUS_DMASYNC_POSTREAD);
+ netmap_unload_map(na, adapter->rx_buf_tag, rx_info->map);
+
+ slot = &kring->ring->slot[nm_i];
+
+ ENA_ASSERT(slot->buf_idx == 0, "Overwrite slot buf\n");
+ slot->buf_idx = rx_info->netmap_buf_idx;
+ slot->flags = NS_BUF_CHANGED;
+
+ rx_info->netmap_buf_idx = 0;
+ kring->nr_hwcur = nm_i;
+}
+
+void
+ena_netmap_reset_rx_ring(struct ena_adapter *adapter, int qid)
+{
+ if (adapter->ifp->if_capenable & IFCAP_NETMAP)
+ netmap_reset(NA(adapter->ifp), NR_RX, qid, 0);
+}
+
static int
ena_netmap_reg(struct netmap_adapter *na, int onoff)
{
@@ -104,8 +249,192 @@
static int
ena_netmap_rxsync(struct netmap_kring *kring, int flags)
{
- ena_trace(ENA_NETMAP, "netmap rxsync\n");
+ struct ena_netmap_ctx ctx;
+ int rc;
+
+ ena_netmap_fill_ctx(kring, &ctx, ENA_IO_RXQ_IDX(kring->ring_id));
+ ctx.ring = &ctx.adapter->rx_ring[kring->ring_id];
+
+ if (ctx.kring->rhead > ctx.lim) {
+ /* Probably not needed to release slots from RX ring. */
+ return (netmap_ring_reinit(ctx.kring));
+ }
+
+ if (unlikely((if_getdrvflags(ctx.na->ifp) & IFF_DRV_RUNNING) == 0))
+ return (0);
+
+ if (unlikely(!ENA_FLAG_ISSET(ENA_FLAG_LINK_UP, ctx.adapter)))
+ return (0);
+
+ if ((rc = ena_netmap_rx_frames(&ctx)) != 0)
+ return (rc);
+
+ ena_netmap_rx_cleanup(&ctx);
+
+ return (0);
+}
+
+static inline int
+ena_netmap_rx_frames(struct ena_netmap_ctx *ctx)
+{
+ int rc = 0;
+ int frames_counter = 0;
+
+ ctx->nt = ctx->ring->next_to_clean;
+ ctx->nm_i = ctx->kring->nr_hwtail;
+
+ while((rc = ena_netmap_rx_frame(ctx)) == ENA_NETMAP_MORE_FRAMES) {
+ frames_counter++;
+ /* In case of multiple frames, it is not an error. */
+ rc = 0;
+ if (frames_counter > ENA_MAX_FRAMES) {
+ device_printf(ctx->adapter->pdev,
+ "Driver is stuck in the Rx loop\n");
+ break;
+ }
+ };
+
+ ctx->kring->nr_hwtail = ctx->nm_i;
+ ctx->kring->nr_kflags &= ~NKR_PENDINTR;
+ ctx->ring->next_to_clean = ctx->nt;
+
+ return (rc);
+}
+
+static inline int
+ena_netmap_rx_frame(struct ena_netmap_ctx *ctx)
+{
+ struct ena_com_rx_ctx ena_rx_ctx;
+ int rc, len = 0;
+ uint16_t buf, nm;
+
+ ena_rx_ctx.ena_bufs = ctx->ring->ena_bufs;
+ ena_rx_ctx.max_bufs = ctx->adapter->max_rx_sgl_size;
+ bus_dmamap_sync(ctx->io_cq->cdesc_addr.mem_handle.tag,
+ ctx->io_cq->cdesc_addr.mem_handle.map, BUS_DMASYNC_POSTREAD);
+
+ rc = ena_com_rx_pkt(ctx->io_cq, ctx->io_sq, &ena_rx_ctx);
+ if (unlikely(rc != 0)) {
+ ena_trace(ENA_ALERT, "Too many desc from the device.\n");
+ counter_u64_add(ctx->ring->rx_stats.bad_desc_num, 1);
+ ctx->adapter->reset_reason = ENA_REGS_RESET_TOO_MANY_RX_DESCS;
+ ENA_FLAG_SET_ATOMIC(ENA_FLAG_TRIGGER_RESET, ctx->adapter);
+ return (rc);
+ }
+ if (unlikely(ena_rx_ctx.descs == 0))
+ return (ENA_NETMAP_NO_MORE_FRAMES);
+
+ ena_trace(ENA_NETMAP | ENA_DBG, "Rx: q %d got packet from ena. descs #:"
+ " %d l3 proto %d l4 proto %d hash: %x\n", ctx->ring->qid,
+ ena_rx_ctx.descs, ena_rx_ctx.l3_proto, ena_rx_ctx.l4_proto,
+ ena_rx_ctx.hash);
+
+ for (buf = 0; buf < ena_rx_ctx.descs; buf++)
+ if ((rc = ena_netmap_rx_load_desc(ctx, buf, &len)) != 0)
+ break;
+ /*
+ * ena_netmap_rx_load_desc doesn't know the number of descriptors.
+ * It just set flag NS_MOREFRAG to all slots, then here flag of
+ * last slot is cleared.
+ */
+ ctx->slots[nm_prev(ctx->nm_i, ctx->lim)].flags = NS_BUF_CHANGED;
+
+ if (rc != 0) {
+ goto rx_clear_desc;
+ }
+
+ bus_dmamap_sync(ctx->io_cq->cdesc_addr.mem_handle.tag,
+ ctx->io_cq->cdesc_addr.mem_handle.map, BUS_DMASYNC_PREREAD);
+
+ counter_enter();
+ counter_u64_add_protected(ctx->ring->rx_stats.bytes, len);
+ counter_u64_add_protected(ctx->adapter->hw_stats.rx_bytes, len);
+ counter_u64_add_protected(ctx->ring->rx_stats.cnt, 1);
+ counter_u64_add_protected(ctx->adapter->hw_stats.rx_packets, 1);
+ counter_exit();
+
+ return (ENA_NETMAP_MORE_FRAMES);
+
+rx_clear_desc:
+ nm = ctx->nm_i;
+
+ /* Remove failed packet from ring */
+ while(buf--) {
+ ctx->slots[nm].flags = 0;
+ ctx->slots[nm].len = 0;
+ nm = nm_prev(nm, ctx->lim);
+ }
+
+ return (rc);
+}
+
+static inline int
+ena_netmap_rx_load_desc(struct ena_netmap_ctx *ctx, uint16_t buf, int *len)
+{
+ struct ena_rx_buffer *rx_info;
+ uint16_t req_id;
+ int rc;
+
+ req_id = ctx->ring->ena_bufs[buf].req_id;
+ rc = validate_rx_req_id(ctx->ring, req_id);
+ if (unlikely(rc != 0))
+ return (rc);
+
+ rx_info = &ctx->ring->rx_buffer_info[req_id];
+ bus_dmamap_sync(ctx->adapter->rx_buf_tag, rx_info->map,
+ BUS_DMASYNC_POSTREAD);
+ netmap_unload_map(ctx->na, ctx->adapter->rx_buf_tag, rx_info->map);
+
+ ENA_ASSERT(ctx->slots[ctx->nm_i].buf_idx == 0, "Rx idx is not 0.\n");
+
+ ctx->slots[ctx->nm_i].buf_idx = rx_info->netmap_buf_idx;
+ rx_info->netmap_buf_idx = 0;
+ /*
+ * Set NS_MOREFRAG to all slots.
+ * Then ena_netmap_rx_frame clears it from last one.
+ */
+ ctx->slots[ctx->nm_i].flags |= NS_MOREFRAG | NS_BUF_CHANGED;
+ ctx->slots[ctx->nm_i].len = ctx->ring->ena_bufs[buf].len;
+ *len += ctx->slots[ctx->nm_i].len;
+ ctx->ring->free_rx_ids[ctx->nt] = req_id;
+ ena_trace(ENA_DBG, "rx_info %p, buf_idx %d, paddr %jx, nm: %d\n",
+ rx_info, ctx->slots[ctx->nm_i].buf_idx,
+ (uintmax_t)rx_info->ena_buf.paddr, ctx->nm_i);
+
+ ctx->nm_i = nm_next(ctx->nm_i, ctx->lim);
+ ctx->nt = ENA_RX_RING_IDX_NEXT(ctx->nt, ctx->ring->ring_size);
+
return (0);
}
+static inline void
+ena_netmap_rx_cleanup(struct ena_netmap_ctx *ctx)
+{
+ int refill_required;
+
+ refill_required = ctx->kring->rhead - ctx->kring->nr_hwcur;
+ if (ctx->kring->nr_hwcur != ctx->kring->nr_hwtail)
+ refill_required -= 1;
+
+ if (refill_required == 0)
+ return;
+ else if (refill_required < 0)
+ refill_required += ctx->kring->nkr_num_slots;
+
+ ena_refill_rx_bufs(ctx->ring, refill_required);
+}
+
+static inline void
+ena_netmap_fill_ctx(struct netmap_kring *kring, struct ena_netmap_ctx *ctx,
+ uint16_t ena_qid)
+{
+ ctx->kring = kring;
+ ctx->na = kring->na;
+ ctx->adapter = ctx->na->ifp->if_softc;
+ ctx->lim = kring->nkr_num_slots - 1;
+ ctx->io_cq = &ctx->adapter->ena_dev->io_cq_queues[ena_qid];
+ ctx->io_sq = &ctx->adapter->ena_dev->io_sq_queues[ena_qid];
+ ctx->slots = kring->ring->slot;
+}
+
#endif /* DEV_NETMAP */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, May 23, 7:23 AM (12 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33443162
Default Alt Text
D21935.id63030.diff (15 KB)
Attached To
Mode
D21935: Support for ENA NETMAP Rx
Attached
Detach File
Event Timeline
Log In to Comment