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 } 158