18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* XDP user-space ring structure
38c2ecf20Sopenharmony_ci * Copyright(c) 2018 Intel Corporation.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/log2.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <linux/overflow.h>
98c2ecf20Sopenharmony_ci#include <net/xdp_sock_drv.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "xsk_queue.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic size_t xskq_get_ring_size(struct xsk_queue *q, bool umem_queue)
148c2ecf20Sopenharmony_ci{
158c2ecf20Sopenharmony_ci	struct xdp_umem_ring *umem_ring;
168c2ecf20Sopenharmony_ci	struct xdp_rxtx_ring *rxtx_ring;
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci	if (umem_queue)
198c2ecf20Sopenharmony_ci		return struct_size(umem_ring, desc, q->nentries);
208c2ecf20Sopenharmony_ci	return struct_size(rxtx_ring, desc, q->nentries);
218c2ecf20Sopenharmony_ci}
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistruct xsk_queue *xskq_create(u32 nentries, bool umem_queue)
248c2ecf20Sopenharmony_ci{
258c2ecf20Sopenharmony_ci	struct xsk_queue *q;
268c2ecf20Sopenharmony_ci	gfp_t gfp_flags;
278c2ecf20Sopenharmony_ci	size_t size;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	q = kzalloc(sizeof(*q), GFP_KERNEL);
308c2ecf20Sopenharmony_ci	if (!q)
318c2ecf20Sopenharmony_ci		return NULL;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	q->nentries = nentries;
348c2ecf20Sopenharmony_ci	q->ring_mask = nentries - 1;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	gfp_flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN |
378c2ecf20Sopenharmony_ci		    __GFP_COMP  | __GFP_NORETRY;
388c2ecf20Sopenharmony_ci	size = xskq_get_ring_size(q, umem_queue);
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	q->ring = (struct xdp_ring *)__get_free_pages(gfp_flags,
418c2ecf20Sopenharmony_ci						      get_order(size));
428c2ecf20Sopenharmony_ci	if (!q->ring) {
438c2ecf20Sopenharmony_ci		kfree(q);
448c2ecf20Sopenharmony_ci		return NULL;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	return q;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_civoid xskq_destroy(struct xsk_queue *q)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	if (!q)
538c2ecf20Sopenharmony_ci		return;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	page_frag_free(q->ring);
568c2ecf20Sopenharmony_ci	kfree(q);
578c2ecf20Sopenharmony_ci}
58