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