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