Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * This file is based on code from OCTEON SDK by Cavium Networks.
0004  *
0005  * Copyright (c) 2003-2010 Cavium Networks
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/netdevice.h>
0010 #include <linux/slab.h>
0011 
0012 #include "octeon-ethernet.h"
0013 #include "ethernet-mem.h"
0014 #include "ethernet-defines.h"
0015 
0016 /**
0017  * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
0018  * @pool:     Pool to allocate an skbuff for
0019  * @size:     Size of the buffer needed for the pool
0020  * @elements: Number of buffers to allocate
0021  *
0022  * Returns the actual number of buffers allocated.
0023  */
0024 static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
0025 {
0026     int freed = elements;
0027 
0028     while (freed) {
0029         struct sk_buff *skb = dev_alloc_skb(size + 256);
0030 
0031         if (unlikely(!skb))
0032             break;
0033         skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
0034         *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
0035         cvmx_fpa_free(skb->data, pool, size / 128);
0036         freed--;
0037     }
0038     return elements - freed;
0039 }
0040 
0041 /**
0042  * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
0043  * @pool:     Pool to allocate an skbuff for
0044  * @size:     Size of the buffer needed for the pool
0045  * @elements: Number of buffers to allocate
0046  */
0047 static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
0048 {
0049     char *memory;
0050 
0051     do {
0052         memory = cvmx_fpa_alloc(pool);
0053         if (memory) {
0054             struct sk_buff *skb =
0055                 *(struct sk_buff **)(memory - sizeof(void *));
0056             elements--;
0057             dev_kfree_skb(skb);
0058         }
0059     } while (memory);
0060 
0061     if (elements < 0)
0062         pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
0063             pool, elements);
0064     else if (elements > 0)
0065         pr_warn("Freeing of pool %u is missing %d skbuffs\n",
0066             pool, elements);
0067 }
0068 
0069 /**
0070  * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
0071  * @pool:     Pool to populate
0072  * @size:     Size of each buffer in the pool
0073  * @elements: Number of buffers to allocate
0074  *
0075  * Returns the actual number of buffers allocated.
0076  */
0077 static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
0078 {
0079     char *memory;
0080     char *fpa;
0081     int freed = elements;
0082 
0083     while (freed) {
0084         /*
0085          * FPA memory must be 128 byte aligned.  Since we are
0086          * aligning we need to save the original pointer so we
0087          * can feed it to kfree when the memory is returned to
0088          * the kernel.
0089          *
0090          * We allocate an extra 256 bytes to allow for
0091          * alignment and space for the original pointer saved
0092          * just before the block.
0093          */
0094         memory = kmalloc(size + 256, GFP_ATOMIC);
0095         if (unlikely(!memory)) {
0096             pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
0097                 elements * size, pool);
0098             break;
0099         }
0100         fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
0101         *((char **)fpa - 1) = memory;
0102         cvmx_fpa_free(fpa, pool, 0);
0103         freed--;
0104     }
0105     return elements - freed;
0106 }
0107 
0108 /**
0109  * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
0110  * @pool:     FPA pool to free
0111  * @size:     Size of each buffer in the pool
0112  * @elements: Number of buffers that should be in the pool
0113  */
0114 static void cvm_oct_free_hw_memory(int pool, int size, int elements)
0115 {
0116     char *memory;
0117     char *fpa;
0118 
0119     do {
0120         fpa = cvmx_fpa_alloc(pool);
0121         if (fpa) {
0122             elements--;
0123             fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
0124             memory = *((char **)fpa - 1);
0125             kfree(memory);
0126         }
0127     } while (fpa);
0128 
0129     if (elements < 0)
0130         pr_warn("Freeing of pool %u had too many buffers (%d)\n",
0131             pool, elements);
0132     else if (elements > 0)
0133         pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
0134             pool, elements);
0135 }
0136 
0137 int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
0138 {
0139     int freed;
0140 
0141     if (pool == CVMX_FPA_PACKET_POOL)
0142         freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
0143     else
0144         freed = cvm_oct_fill_hw_memory(pool, size, elements);
0145     return freed;
0146 }
0147 
0148 void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
0149 {
0150     if (pool == CVMX_FPA_PACKET_POOL)
0151         cvm_oct_free_hw_skbuff(pool, size, elements);
0152     else
0153         cvm_oct_free_hw_memory(pool, size, elements);
0154 }