Merge branch 'linux-next' of git://git.infradead.org/ubifs-2.6
[linux-2.6] / drivers / staging / octeon / ethernet-mem.c
1 /**********************************************************************
2  * Author: Cavium Networks
3  *
4  * Contact: support@caviumnetworks.com
5  * This file is part of the OCTEON SDK
6  *
7  * Copyright (c) 2003-2007 Cavium Networks
8  *
9  * This file is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License, Version 2, as
11  * published by the Free Software Foundation.
12  *
13  * This file is distributed in the hope that it will be useful, but
14  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16  * NONINFRINGEMENT.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this file; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  * or visit http://www.gnu.org/licenses/.
23  *
24  * This file may also be available under a different license from Cavium.
25  * Contact Cavium Networks for more information
26 **********************************************************************/
27 #include <linux/kernel.h>
28 #include <linux/netdevice.h>
29 #include <linux/mii.h>
30 #include <net/dst.h>
31
32 #include <asm/octeon/octeon.h>
33
34 #include "ethernet-defines.h"
35
36 #include "cvmx-fpa.h"
37
38 /**
39  * Fill the supplied hardware pool with skbuffs
40  *
41  * @pool:     Pool to allocate an skbuff for
42  * @size:     Size of the buffer needed for the pool
43  * @elements: Number of buffers to allocate
44  */
45 static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
46 {
47         int freed = elements;
48         while (freed) {
49
50                 struct sk_buff *skb = dev_alloc_skb(size + 128);
51                 if (unlikely(skb == NULL)) {
52                         pr_warning
53                             ("Failed to allocate skb for hardware pool %d\n",
54                              pool);
55                         break;
56                 }
57
58                 skb_reserve(skb, 128 - (((unsigned long)skb->data) & 0x7f));
59                 *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
60                 cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128));
61                 freed--;
62         }
63         return elements - freed;
64 }
65
66 /**
67  * Free the supplied hardware pool of skbuffs
68  *
69  * @pool:     Pool to allocate an skbuff for
70  * @size:     Size of the buffer needed for the pool
71  * @elements: Number of buffers to allocate
72  */
73 static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
74 {
75         char *memory;
76
77         do {
78                 memory = cvmx_fpa_alloc(pool);
79                 if (memory) {
80                         struct sk_buff *skb =
81                             *(struct sk_buff **)(memory - sizeof(void *));
82                         elements--;
83                         dev_kfree_skb(skb);
84                 }
85         } while (memory);
86
87         if (elements < 0)
88                 pr_warning("Freeing of pool %u had too many skbuffs (%d)\n",
89                      pool, elements);
90         else if (elements > 0)
91                 pr_warning("Freeing of pool %u is missing %d skbuffs\n",
92                        pool, elements);
93 }
94
95 /**
96  * This function fills a hardware pool with memory. Depending
97  * on the config defines, this memory might come from the
98  * kernel or global 32bit memory allocated with
99  * cvmx_bootmem_alloc.
100  *
101  * @pool:     Pool to populate
102  * @size:     Size of each buffer in the pool
103  * @elements: Number of buffers to allocate
104  */
105 static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
106 {
107         char *memory;
108         int freed = elements;
109
110         if (USE_32BIT_SHARED) {
111                 extern uint64_t octeon_reserve32_memory;
112
113                 memory =
114                     cvmx_bootmem_alloc_range(elements * size, 128,
115                                              octeon_reserve32_memory,
116                                              octeon_reserve32_memory +
117                                              (CONFIG_CAVIUM_RESERVE32 << 20) -
118                                              1);
119                 if (memory == NULL)
120                         panic("Unable to allocate %u bytes for FPA pool %d\n",
121                               elements * size, pool);
122
123                 pr_notice("Memory range %p - %p reserved for "
124                           "hardware\n", memory,
125                           memory + elements * size - 1);
126
127                 while (freed) {
128                         cvmx_fpa_free(memory, pool, 0);
129                         memory += size;
130                         freed--;
131                 }
132         } else {
133                 while (freed) {
134                         /* We need to force alignment to 128 bytes here */
135                         memory = kmalloc(size + 127, GFP_ATOMIC);
136                         if (unlikely(memory == NULL)) {
137                                 pr_warning("Unable to allocate %u bytes for "
138                                            "FPA pool %d\n",
139                                      elements * size, pool);
140                                 break;
141                         }
142                         memory = (char *)(((unsigned long)memory + 127) & -128);
143                         cvmx_fpa_free(memory, pool, 0);
144                         freed--;
145                 }
146         }
147         return elements - freed;
148 }
149
150 /**
151  * Free memory previously allocated with cvm_oct_fill_hw_memory
152  *
153  * @pool:     FPA pool to free
154  * @size:     Size of each buffer in the pool
155  * @elements: Number of buffers that should be in the pool
156  */
157 static void cvm_oct_free_hw_memory(int pool, int size, int elements)
158 {
159         if (USE_32BIT_SHARED) {
160                 pr_warning("Warning: 32 shared memory is not freeable\n");
161         } else {
162                 char *memory;
163                 do {
164                         memory = cvmx_fpa_alloc(pool);
165                         if (memory) {
166                                 elements--;
167                                 kfree(phys_to_virt(cvmx_ptr_to_phys(memory)));
168                         }
169                 } while (memory);
170
171                 if (elements < 0)
172                         pr_warning("Freeing of pool %u had too many "
173                                    "buffers (%d)\n",
174                                pool, elements);
175                 else if (elements > 0)
176                         pr_warning("Warning: Freeing of pool %u is "
177                                 "missing %d buffers\n",
178                              pool, elements);
179         }
180 }
181
182 int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
183 {
184         int freed;
185         if (USE_SKBUFFS_IN_HW)
186                 freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
187         else
188                 freed = cvm_oct_fill_hw_memory(pool, size, elements);
189         return freed;
190 }
191
192 void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
193 {
194         if (USE_SKBUFFS_IN_HW)
195                 cvm_oct_free_hw_skbuff(pool, size, elements);
196         else
197                 cvm_oct_free_hw_memory(pool, size, elements);
198 }