Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8cb2d8bf authored by Gregory CLEMENT's avatar Gregory CLEMENT Committed by David S. Miller
Browse files

net: add a hardware buffer management helper API



This basic implementation allows to share code between driver using
hardware buffer management. As the code is hardware agnostic, there is
few helpers, most of the optimization brought by the an HW BM has to be
done at driver level.

Tested-by: default avatarSebastian Careba <nitroshift@yahoo.com>
Signed-off-by: default avatarGregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dc35a10f
Loading
Loading
Loading
Loading

include/net/hwbm.h

0 → 100644
+28 −0
Original line number Diff line number Diff line
#ifndef _HWBM_H
#define _HWBM_H

struct hwbm_pool {
	/* Capacity of the pool */
	int size;
	/* Size of the buffers managed */
	int frag_size;
	/* Number of buffers currently used by this pool */
	int buf_num;
	/* constructor called during alocation */
	int (*construct)(struct hwbm_pool *bm_pool, void *buf);
	/* protect acces to the buffer counter*/
	spinlock_t lock;
	/* private data */
	void *priv;
};
#ifdef CONFIG_HWBM
void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf);
int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp);
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp);
#else
void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf) {}
int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp) { return 0; }
int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
{ return 0; }
#endif /* CONFIG_HWBM */
#endif /* _HWBM_H */
+3 −0
Original line number Diff line number Diff line
@@ -253,6 +253,9 @@ config XPS
	depends on SMP
	default y

config HWBM
       bool

config SOCK_CGROUP_DATA
	bool
	default n
+1 −0
Original line number Diff line number Diff line
@@ -25,4 +25,5 @@ obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o
obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o
obj-$(CONFIG_LWTUNNEL) += lwtunnel.o
obj-$(CONFIG_DST_CACHE) += dst_cache.o
obj-$(CONFIG_HWBM) += hwbm.o
obj-$(CONFIG_NET_DEVLINK) += devlink.o

net/core/hwbm.c

0 → 100644
+87 −0
Original line number Diff line number Diff line
/* Support for hardware buffer manager.
 *
 * Copyright (C) 2016 Marvell
 *
 * Gregory CLEMENT <gregory.clement@free-electrons.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 */
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/skbuff.h>
#include <net/hwbm.h>

void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf)
{
	if (likely(bm_pool->frag_size <= PAGE_SIZE))
		skb_free_frag(buf);
	else
		kfree(buf);
}
EXPORT_SYMBOL_GPL(hwbm_buf_free);

/* Refill processing for HW buffer management */
int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp)
{
	int frag_size = bm_pool->frag_size;
	void *buf;

	if (likely(frag_size <= PAGE_SIZE))
		buf = netdev_alloc_frag(frag_size);
	else
		buf = kmalloc(frag_size, gfp);

	if (!buf)
		return -ENOMEM;

	if (bm_pool->construct)
		if (bm_pool->construct(bm_pool, buf)) {
			hwbm_buf_free(bm_pool, buf);
			return -ENOMEM;
		}

	return 0;
}
EXPORT_SYMBOL_GPL(hwbm_pool_refill);

int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num, gfp_t gfp)
{
	int err, i;
	unsigned long flags;

	spin_lock_irqsave(&bm_pool->lock, flags);
	if (bm_pool->buf_num == bm_pool->size) {
		pr_warn("pool already filled\n");
		return bm_pool->buf_num;
	}

	if (buf_num + bm_pool->buf_num > bm_pool->size) {
		pr_warn("cannot allocate %d buffers for pool\n",
			buf_num);
		return 0;
	}

	if ((buf_num + bm_pool->buf_num) < bm_pool->buf_num) {
		pr_warn("Adding %d buffers to the %d current buffers will overflow\n",
			buf_num,  bm_pool->buf_num);
		return 0;
	}

	for (i = 0; i < buf_num; i++) {
		err = hwbm_pool_refill(bm_pool, gfp);
		if (err < 0)
			break;
	}

	/* Update BM driver with number of buffers added to pool */
	bm_pool->buf_num += i;

	pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);
	spin_unlock_irqrestore(&bm_pool->lock, flags);

	return i;
}
EXPORT_SYMBOL_GPL(hwbm_pool_add);