Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / staging / octeon / ethernet-mem.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * This file is based on code from OCTEON SDK by Cavium Networks.
4  *
5  * Copyright (c) 2003-2010 Cavium Networks
6  */
7
8 #include <linux/kernel.h>
9 #include <linux/netdevice.h>
10 #include <linux/slab.h>
11
12 #include <asm/octeon/octeon.h>
13
14 #include "ethernet-mem.h"
15 #include "ethernet-defines.h"
16
17 #include <asm/octeon/cvmx-fpa.h>
18
19 /**
20  * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs
21  * @pool:     Pool to allocate an skbuff for
22  * @size:     Size of the buffer needed for the pool
23  * @elements: Number of buffers to allocate
24  *
25  * Returns the actual number of buffers allocated.
26  */
27 static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
28 {
29         int freed = elements;
30
31         while (freed) {
32                 struct sk_buff *skb = dev_alloc_skb(size + 256);
33
34                 if (unlikely(!skb))
35                         break;
36                 skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
37                 *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
38                 cvmx_fpa_free(skb->data, pool, size / 128);
39                 freed--;
40         }
41         return elements - freed;
42 }
43
44 /**
45  * cvm_oct_free_hw_skbuff- free hardware pool skbuffs
46  * @pool:     Pool to allocate an skbuff for
47  * @size:     Size of the buffer needed for the pool
48  * @elements: Number of buffers to allocate
49  */
50 static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
51 {
52         char *memory;
53
54         do {
55                 memory = cvmx_fpa_alloc(pool);
56                 if (memory) {
57                         struct sk_buff *skb =
58                             *(struct sk_buff **)(memory - sizeof(void *));
59                         elements--;
60                         dev_kfree_skb(skb);
61                 }
62         } while (memory);
63
64         if (elements < 0)
65                 pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
66                         pool, elements);
67         else if (elements > 0)
68                 pr_warn("Freeing of pool %u is missing %d skbuffs\n",
69                         pool, elements);
70 }
71
72 /**
73  * cvm_oct_fill_hw_memory - fill a hardware pool with memory.
74  * @pool:     Pool to populate
75  * @size:     Size of each buffer in the pool
76  * @elements: Number of buffers to allocate
77  *
78  * Returns the actual number of buffers allocated.
79  */
80 static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
81 {
82         char *memory;
83         char *fpa;
84         int freed = elements;
85
86         while (freed) {
87                 /*
88                  * FPA memory must be 128 byte aligned.  Since we are
89                  * aligning we need to save the original pointer so we
90                  * can feed it to kfree when the memory is returned to
91                  * the kernel.
92                  *
93                  * We allocate an extra 256 bytes to allow for
94                  * alignment and space for the original pointer saved
95                  * just before the block.
96                  */
97                 memory = kmalloc(size + 256, GFP_ATOMIC);
98                 if (unlikely(!memory)) {
99                         pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
100                                 elements * size, pool);
101                         break;
102                 }
103                 fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
104                 *((char **)fpa - 1) = memory;
105                 cvmx_fpa_free(fpa, pool, 0);
106                 freed--;
107         }
108         return elements - freed;
109 }
110
111 /**
112  * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory
113  * @pool:     FPA pool to free
114  * @size:     Size of each buffer in the pool
115  * @elements: Number of buffers that should be in the pool
116  */
117 static void cvm_oct_free_hw_memory(int pool, int size, int elements)
118 {
119         char *memory;
120         char *fpa;
121
122         do {
123                 fpa = cvmx_fpa_alloc(pool);
124                 if (fpa) {
125                         elements--;
126                         fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
127                         memory = *((char **)fpa - 1);
128                         kfree(memory);
129                 }
130         } while (fpa);
131
132         if (elements < 0)
133                 pr_warn("Freeing of pool %u had too many buffers (%d)\n",
134                         pool, elements);
135         else if (elements > 0)
136                 pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
137                         pool, elements);
138 }
139
140 int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
141 {
142         int freed;
143
144         if (pool == CVMX_FPA_PACKET_POOL)
145                 freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
146         else
147                 freed = cvm_oct_fill_hw_memory(pool, size, elements);
148         return freed;
149 }
150
151 void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
152 {
153         if (pool == CVMX_FPA_PACKET_POOL)
154                 cvm_oct_free_hw_skbuff(pool, size, elements);
155         else
156                 cvm_oct_free_hw_memory(pool, size, elements);
157 }