@@ -60,6 +60,17 @@ void __io_uring_free(struct task_struct *tsk);
void io_uring_unreg_ringfd(void);
const char *io_uring_get_opcode(u8 opcode);
+struct io_zc_rx_ifq;
+struct io_zc_rx_buf *io_zc_rx_get_buf(struct io_zc_rx_ifq *ifq);
+void io_zc_rx_put_buf(struct io_zc_rx_ifq *ifq, struct io_zc_rx_buf *buf);
+static inline dma_addr_t io_zc_rx_buf_dma(struct io_zc_rx_buf *buf)
+{
+ return buf->dma;
+}
+static inline struct page *io_zc_rx_buf_page(struct io_zc_rx_buf *buf)
+{
+ return buf->page;
+}
static inline void io_uring_files_cancel(void)
{
if (current->io_uring) {
@@ -108,6 +119,13 @@ static inline const char *io_uring_get_opcode(u8 opcode)
{
return "";
}
+static inline struct io_zc_rx_buf *io_zc_rx_get_buf(struct io_zc_rx_ifq *ifq)
+{
+ return NULL;
+}
+void io_zc_rx_put_buf(struct io_zc_rx_ifq *ifq, struct io_zc_rx_buf *buf)
+{
+}
#endif
#endif
@@ -14,6 +14,9 @@
#include "zc_rx.h"
#define POOL_CACHE_SIZE 128
+#define POOL_REFILL_COUNT 64
+#define IO_ZC_RX_UREF 0x10000
+#define IO_ZC_RX_KREF_MASK (IO_ZC_RX_UREF - 1)
struct io_zc_rx_pool {
struct io_zc_rx_ifq *ifq;
@@ -267,6 +270,8 @@ int io_register_zc_rx_ifq(struct io_ring_ctx *ctx,
ifq->rq_entries = reg.rq_entries;
ifq->cq_entries = reg.cq_entries;
+ ifq->cached_rq_head = 0;
+ ifq->cached_cq_tail = 0;
ifq->if_rxq_id = reg.if_rxq_id;
ctx->ifq = ifq;
@@ -309,3 +314,96 @@ int io_unregister_zc_rx_ifq(struct io_ring_ctx *ctx)
return 0;
}
+
+static bool io_zc_rx_put_buf_uref(struct io_zc_rx_buf *buf)
+{
+ if (atomic_read(&buf->refcount) < IO_ZC_RX_UREF)
+ return false;
+
+ return atomic_sub_and_test(IO_ZC_RX_UREF, &buf->refcount);
+}
+
+static void io_zc_rx_refill_cache(struct io_zc_rx_ifq *ifq, int count)
+{
+ unsigned int entries = io_zc_rx_rqring_entries(ifq);
+ unsigned int mask = ifq->rq_entries - 1;
+ struct io_zc_rx_pool *pool = ifq->pool;
+ struct io_uring_rbuf_rqe *rqe;
+ struct io_zc_rx_buf *buf;
+ int i, filled;
+
+ if (!entries)
+ return;
+
+ for (i = 0, filled = 0; i < entries && filled < count; i++) {
+ unsigned int rq_idx = ifq->cached_rq_head++ & mask;
+ u32 pgid;
+
+ rqe = &ifq->rqes[rq_idx];
+ pgid = rqe->off / PAGE_SIZE;
+ buf = &pool->bufs[pgid];
+ if (!io_zc_rx_put_buf_uref(buf))
+ continue;
+ pool->cache[filled++] = pgid;
+ }
+
+ smp_store_release(&ifq->ring->rq.head, ifq->cached_rq_head);
+ pool->cache_count += filled;
+}
+
+struct io_zc_rx_buf *io_zc_rx_get_buf(struct io_zc_rx_ifq *ifq)
+{
+ struct io_zc_rx_pool *pool;
+ struct io_zc_rx_buf *buf;
+ int count;
+ u16 pgid;
+
+ pool = ifq->pool;
+ if (pool->cache_count)
+ goto out;
+
+ io_zc_rx_refill_cache(ifq, POOL_REFILL_COUNT);
+ if (pool->cache_count)
+ goto out;
+
+ spin_lock(&pool->freelist_lock);
+
+ count = min_t(u32, pool->free_count, POOL_CACHE_SIZE);
+ pool->free_count -= count;
+ pool->cache_count += count;
+ memcpy(pool->cache, &pool->freelist[pool->free_count],
+ count * sizeof(u32));
+
+ spin_unlock(&pool->freelist_lock);
+
+ if (pool->cache_count)
+ goto out;
+
+ return NULL;
+out:
+ pgid = pool->cache[--pool->cache_count];
+ buf = &pool->bufs[pgid];
+ atomic_set(&buf->refcount, 1);
+
+ return buf;
+}
+EXPORT_SYMBOL(io_zc_rx_get_buf);
+
+static void io_zc_rx_recycle_buf(struct io_zc_rx_pool *pool,
+ struct io_zc_rx_buf *buf)
+{
+ spin_lock(&pool->freelist_lock);
+ pool->freelist[pool->free_count++] = buf - pool->bufs;
+ spin_unlock(&pool->freelist_lock);
+}
+
+void io_zc_rx_put_buf(struct io_zc_rx_ifq *ifq, struct io_zc_rx_buf *buf)
+{
+ struct io_zc_rx_pool *pool = ifq->pool;
+
+ if (!atomic_dec_and_test(&buf->refcount))
+ return;
+
+ io_zc_rx_recycle_buf(pool, buf);
+}
+EXPORT_SYMBOL(io_zc_rx_put_buf);
@@ -2,6 +2,8 @@
#ifndef IOU_ZC_RX_H
#define IOU_ZC_RX_H
+#include <linux/io_uring_types.h>
+
struct io_zc_rx_ifq {
struct io_ring_ctx *ctx;
struct net_device *dev;
@@ -9,12 +11,23 @@ struct io_zc_rx_ifq {
struct io_uring_rbuf_rqe *rqes;
struct io_uring_rbuf_cqe *cqes;
u32 rq_entries, cq_entries;
+ u32 cached_rq_head;
+ u32 cached_cq_tail;
void *pool;
/* hw rx descriptor ring id */
u32 if_rxq_id;
};
+static inline u32 io_zc_rx_rqring_entries(struct io_zc_rx_ifq *ifq)
+{
+ struct io_rbuf_ring *ring = ifq->ring;
+ u32 entries;
+
+ entries = smp_load_acquire(&ring->rq.tail) - ifq->cached_rq_head;
+ return min(entries, ifq->rq_entries);
+}
+
int io_register_zc_rx_ifq(struct io_ring_ctx *ctx,
struct io_uring_zc_rx_ifq_reg __user *arg);
int io_unregister_zc_rx_ifq(struct io_ring_ctx *ctx);