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-2010 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/slab.h> 30 31#include <asm/octeon/octeon.h> 32 33#include "ethernet-mem.h" 34#include "ethernet-defines.h" 35 36#include <asm/octeon/cvmx-fpa.h> 37 38/** 39 * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs 40 * @pool: Pool to allocate an skbuff for 41 * @size: Size of the buffer needed for the pool 42 * @elements: Number of buffers to allocate 43 * 44 * Returns the actual number of buffers allocated. 45 */ 46static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements) 47{ 48 int freed = elements; 49 50 while (freed) { 51 struct sk_buff *skb = dev_alloc_skb(size + 256); 52 53 if (unlikely(skb == NULL)) 54 break; 55 skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f)); 56 *(struct sk_buff **)(skb->data - sizeof(void *)) = skb; 57 cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128)); 58 freed--; 59 } 60 return elements - freed; 61} 62 63/** 64 * cvm_oct_free_hw_skbuff- free hardware pool skbuffs 65 * @pool: Pool to allocate an skbuff for 66 * @size: Size of the buffer needed for the pool 67 * @elements: Number of buffers to allocate 68 */ 69static void cvm_oct_free_hw_skbuff(int pool, int size, int elements) 70{ 71 char *memory; 72 73 do { 74 memory = cvmx_fpa_alloc(pool); 75 if (memory) { 76 struct sk_buff *skb = 77 *(struct sk_buff **)(memory - sizeof(void *)); 78 elements--; 79 dev_kfree_skb(skb); 80 } 81 } while (memory); 82 83 if (elements < 0) 84 pr_warn("Freeing of pool %u had too many skbuffs (%d)\n", 85 pool, elements); 86 else if (elements > 0) 87 pr_warn("Freeing of pool %u is missing %d skbuffs\n", 88 pool, elements); 89} 90 91/** 92 * cvm_oct_fill_hw_memory - fill a hardware pool with memory. 93 * @pool: Pool to populate 94 * @size: Size of each buffer in the pool 95 * @elements: Number of buffers to allocate 96 * 97 * Returns the actual number of buffers allocated. 98 */ 99static int cvm_oct_fill_hw_memory(int pool, int size, int elements) 100{ 101 char *memory; 102 char *fpa; 103 int freed = elements; 104 105 while (freed) { 106 /* 107 * FPA memory must be 128 byte aligned. Since we are 108 * aligning we need to save the original pointer so we 109 * can feed it to kfree when the memory is returned to 110 * the kernel. 111 * 112 * We allocate an extra 256 bytes to allow for 113 * alignment and space for the original pointer saved 114 * just before the block. 115 */ 116 memory = kmalloc(size + 256, GFP_ATOMIC); 117 if (unlikely(memory == NULL)) { 118 pr_warn("Unable to allocate %u bytes for FPA pool %d\n", 119 elements * size, pool); 120 break; 121 } 122 fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL); 123 *((char **)fpa - 1) = memory; 124 cvmx_fpa_free(fpa, pool, 0); 125 freed--; 126 } 127 return elements - freed; 128} 129 130/** 131 * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory 132 * @pool: FPA pool to free 133 * @size: Size of each buffer in the pool 134 * @elements: Number of buffers that should be in the pool 135 */ 136static void cvm_oct_free_hw_memory(int pool, int size, int elements) 137{ 138 char *memory; 139 char *fpa; 140 141 do { 142 fpa = cvmx_fpa_alloc(pool); 143 if (fpa) { 144 elements--; 145 fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa)); 146 memory = *((char **)fpa - 1); 147 kfree(memory); 148 } 149 } while (fpa); 150 151 if (elements < 0) 152 pr_warn("Freeing of pool %u had too many buffers (%d)\n", 153 pool, elements); 154 else if (elements > 0) 155 pr_warn("Warning: Freeing of pool %u is missing %d buffers\n", 156 pool, elements); 157} 158 159int cvm_oct_mem_fill_fpa(int pool, int size, int elements) 160{ 161 int freed; 162 163 if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL) 164 freed = cvm_oct_fill_hw_skbuff(pool, size, elements); 165 else 166 freed = cvm_oct_fill_hw_memory(pool, size, elements); 167 return freed; 168} 169 170void cvm_oct_mem_empty_fpa(int pool, int size, int elements) 171{ 172 if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL) 173 cvm_oct_free_hw_skbuff(pool, size, elements); 174 else 175 cvm_oct_free_hw_memory(pool, size, elements); 176} 177