xref: /openbmc/linux/net/core/hwbm.c (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28cb2d8bfSGregory CLEMENT /* Support for hardware buffer manager.
38cb2d8bfSGregory CLEMENT  *
48cb2d8bfSGregory CLEMENT  * Copyright (C) 2016 Marvell
58cb2d8bfSGregory CLEMENT  *
68cb2d8bfSGregory CLEMENT  * Gregory CLEMENT <gregory.clement@free-electrons.com>
78cb2d8bfSGregory CLEMENT  */
88cb2d8bfSGregory CLEMENT #include <linux/kernel.h>
98cb2d8bfSGregory CLEMENT #include <linux/printk.h>
108cb2d8bfSGregory CLEMENT #include <linux/skbuff.h>
118cb2d8bfSGregory CLEMENT #include <net/hwbm.h>
128cb2d8bfSGregory CLEMENT 
hwbm_buf_free(struct hwbm_pool * bm_pool,void * buf)138cb2d8bfSGregory CLEMENT void hwbm_buf_free(struct hwbm_pool *bm_pool, void *buf)
148cb2d8bfSGregory CLEMENT {
158cb2d8bfSGregory CLEMENT 	if (likely(bm_pool->frag_size <= PAGE_SIZE))
168cb2d8bfSGregory CLEMENT 		skb_free_frag(buf);
178cb2d8bfSGregory CLEMENT 	else
188cb2d8bfSGregory CLEMENT 		kfree(buf);
198cb2d8bfSGregory CLEMENT }
208cb2d8bfSGregory CLEMENT EXPORT_SYMBOL_GPL(hwbm_buf_free);
218cb2d8bfSGregory CLEMENT 
228cb2d8bfSGregory CLEMENT /* Refill processing for HW buffer management */
hwbm_pool_refill(struct hwbm_pool * bm_pool,gfp_t gfp)238cb2d8bfSGregory CLEMENT int hwbm_pool_refill(struct hwbm_pool *bm_pool, gfp_t gfp)
248cb2d8bfSGregory CLEMENT {
258cb2d8bfSGregory CLEMENT 	int frag_size = bm_pool->frag_size;
268cb2d8bfSGregory CLEMENT 	void *buf;
278cb2d8bfSGregory CLEMENT 
288cb2d8bfSGregory CLEMENT 	if (likely(frag_size <= PAGE_SIZE))
298cb2d8bfSGregory CLEMENT 		buf = netdev_alloc_frag(frag_size);
308cb2d8bfSGregory CLEMENT 	else
318cb2d8bfSGregory CLEMENT 		buf = kmalloc(frag_size, gfp);
328cb2d8bfSGregory CLEMENT 
338cb2d8bfSGregory CLEMENT 	if (!buf)
348cb2d8bfSGregory CLEMENT 		return -ENOMEM;
358cb2d8bfSGregory CLEMENT 
368cb2d8bfSGregory CLEMENT 	if (bm_pool->construct)
378cb2d8bfSGregory CLEMENT 		if (bm_pool->construct(bm_pool, buf)) {
388cb2d8bfSGregory CLEMENT 			hwbm_buf_free(bm_pool, buf);
398cb2d8bfSGregory CLEMENT 			return -ENOMEM;
408cb2d8bfSGregory CLEMENT 		}
418cb2d8bfSGregory CLEMENT 
428cb2d8bfSGregory CLEMENT 	return 0;
438cb2d8bfSGregory CLEMENT }
448cb2d8bfSGregory CLEMENT EXPORT_SYMBOL_GPL(hwbm_pool_refill);
458cb2d8bfSGregory CLEMENT 
hwbm_pool_add(struct hwbm_pool * bm_pool,unsigned int buf_num)46*6dcdd884SSebastian Andrzej Siewior int hwbm_pool_add(struct hwbm_pool *bm_pool, unsigned int buf_num)
478cb2d8bfSGregory CLEMENT {
488cb2d8bfSGregory CLEMENT 	int err, i;
498cb2d8bfSGregory CLEMENT 
50*6dcdd884SSebastian Andrzej Siewior 	mutex_lock(&bm_pool->buf_lock);
518cb2d8bfSGregory CLEMENT 	if (bm_pool->buf_num == bm_pool->size) {
528cb2d8bfSGregory CLEMENT 		pr_warn("pool already filled\n");
53*6dcdd884SSebastian Andrzej Siewior 		mutex_unlock(&bm_pool->buf_lock);
548cb2d8bfSGregory CLEMENT 		return bm_pool->buf_num;
558cb2d8bfSGregory CLEMENT 	}
568cb2d8bfSGregory CLEMENT 
578cb2d8bfSGregory CLEMENT 	if (buf_num + bm_pool->buf_num > bm_pool->size) {
588cb2d8bfSGregory CLEMENT 		pr_warn("cannot allocate %d buffers for pool\n",
598cb2d8bfSGregory CLEMENT 			buf_num);
60*6dcdd884SSebastian Andrzej Siewior 		mutex_unlock(&bm_pool->buf_lock);
618cb2d8bfSGregory CLEMENT 		return 0;
628cb2d8bfSGregory CLEMENT 	}
638cb2d8bfSGregory CLEMENT 
648cb2d8bfSGregory CLEMENT 	if ((buf_num + bm_pool->buf_num) < bm_pool->buf_num) {
658cb2d8bfSGregory CLEMENT 		pr_warn("Adding %d buffers to the %d current buffers will overflow\n",
668cb2d8bfSGregory CLEMENT 			buf_num,  bm_pool->buf_num);
67*6dcdd884SSebastian Andrzej Siewior 		mutex_unlock(&bm_pool->buf_lock);
688cb2d8bfSGregory CLEMENT 		return 0;
698cb2d8bfSGregory CLEMENT 	}
708cb2d8bfSGregory CLEMENT 
718cb2d8bfSGregory CLEMENT 	for (i = 0; i < buf_num; i++) {
72*6dcdd884SSebastian Andrzej Siewior 		err = hwbm_pool_refill(bm_pool, GFP_KERNEL);
738cb2d8bfSGregory CLEMENT 		if (err < 0)
748cb2d8bfSGregory CLEMENT 			break;
758cb2d8bfSGregory CLEMENT 	}
768cb2d8bfSGregory CLEMENT 
778cb2d8bfSGregory CLEMENT 	/* Update BM driver with number of buffers added to pool */
788cb2d8bfSGregory CLEMENT 	bm_pool->buf_num += i;
798cb2d8bfSGregory CLEMENT 
808cb2d8bfSGregory CLEMENT 	pr_debug("hwpm pool: %d of %d buffers added\n", i, buf_num);
81*6dcdd884SSebastian Andrzej Siewior 	mutex_unlock(&bm_pool->buf_lock);
828cb2d8bfSGregory CLEMENT 
838cb2d8bfSGregory CLEMENT 	return i;
848cb2d8bfSGregory CLEMENT }
858cb2d8bfSGregory CLEMENT EXPORT_SYMBOL_GPL(hwbm_pool_add);
86