aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/octeon/ethernet-mem.c
diff options
context:
space:
mode:
authorDavid Daney <ddaney@caviumnetworks.com>2010-01-27 16:22:53 -0500
committerRalf Baechle <ralf@linux-mips.org>2010-02-27 06:53:07 -0500
commit166bdaa9aad9903bf4330ef68feb37f220c9eac8 (patch)
tree2afbf9f99ff30c7276fe3ceb54477216e482bf0b /drivers/staging/octeon/ethernet-mem.c
parent6568a234363978e1aebb5b7c9840ed87eed20362 (diff)
Staging: Octeon Ethernet: Fix memory allocation.
After aligning the blocks returned by kmalloc, we need to save the original pointer so they can be correctly freed. There are no guarantees about the alignment of SKB data, so we need to handle worst case alignment. Since right shifts over subtraction have no distributive property, we need to fix the back pointer calculation. Signed-off-by: David Daney <ddaney@caviumnetworks.com> To: linux-mips@linux-mips.org Patchwork: http://patchwork.linux-mips.org/patch/884/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'drivers/staging/octeon/ethernet-mem.c')
-rw-r--r--drivers/staging/octeon/ethernet-mem.c45
1 files changed, 28 insertions, 17 deletions
diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c
index 7090521471b..53ed2f7ffdf 100644
--- a/drivers/staging/octeon/ethernet-mem.c
+++ b/drivers/staging/octeon/ethernet-mem.c
@@ -4,7 +4,7 @@
4 * Contact: support@caviumnetworks.com 4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK 5 * This file is part of the OCTEON SDK
6 * 6 *
7 * Copyright (c) 2003-2007 Cavium Networks 7 * Copyright (c) 2003-2010 Cavium Networks
8 * 8 *
9 * This file is free software; you can redistribute it and/or modify 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 10 * it under the terms of the GNU General Public License, Version 2, as
@@ -45,7 +45,7 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
45 int freed = elements; 45 int freed = elements;
46 while (freed) { 46 while (freed) {
47 47
48 struct sk_buff *skb = dev_alloc_skb(size + 128); 48 struct sk_buff *skb = dev_alloc_skb(size + 256);
49 if (unlikely(skb == NULL)) { 49 if (unlikely(skb == NULL)) {
50 pr_warning 50 pr_warning
51 ("Failed to allocate skb for hardware pool %d\n", 51 ("Failed to allocate skb for hardware pool %d\n",
@@ -53,7 +53,7 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
53 break; 53 break;
54 } 54 }
55 55
56 skb_reserve(skb, 128 - (((unsigned long)skb->data) & 0x7f)); 56 skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
57 *(struct sk_buff **)(skb->data - sizeof(void *)) = skb; 57 *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
58 cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128)); 58 cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128));
59 freed--; 59 freed--;
@@ -91,10 +91,7 @@ static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
91} 91}
92 92
93/** 93/**
94 * This function fills a hardware pool with memory. Depending 94 * This function fills a hardware pool with memory.
95 * on the config defines, this memory might come from the
96 * kernel or global 32bit memory allocated with
97 * cvmx_bootmem_alloc.
98 * 95 *
99 * @pool: Pool to populate 96 * @pool: Pool to populate
100 * @size: Size of each buffer in the pool 97 * @size: Size of each buffer in the pool
@@ -103,18 +100,29 @@ static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
103static int cvm_oct_fill_hw_memory(int pool, int size, int elements) 100static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
104{ 101{
105 char *memory; 102 char *memory;
103 char *fpa;
106 int freed = elements; 104 int freed = elements;
107 105
108 while (freed) { 106 while (freed) {
109 /* We need to force alignment to 128 bytes here */ 107 /*
110 memory = kmalloc(size + 127, GFP_ATOMIC); 108 * FPA memory must be 128 byte aligned. Since we are
109 * aligning we need to save the original pointer so we
110 * can feed it to kfree when the memory is returned to
111 * the kernel.
112 *
113 * We allocate an extra 256 bytes to allow for
114 * alignment and space for the original pointer saved
115 * just before the block.
116 */
117 memory = kmalloc(size + 256, GFP_ATOMIC);
111 if (unlikely(memory == NULL)) { 118 if (unlikely(memory == NULL)) {
112 pr_warning("Unable to allocate %u bytes for FPA pool %d\n", 119 pr_warning("Unable to allocate %u bytes for FPA pool %d\n",
113 elements * size, pool); 120 elements * size, pool);
114 break; 121 break;
115 } 122 }
116 memory = (char *)(((unsigned long)memory + 127) & -128); 123 fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
117 cvmx_fpa_free(memory, pool, 0); 124 *((char **)fpa - 1) = memory;
125 cvmx_fpa_free(fpa, pool, 0);
118 freed--; 126 freed--;
119 } 127 }
120 return elements - freed; 128 return elements - freed;
@@ -130,13 +138,16 @@ static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
130static void cvm_oct_free_hw_memory(int pool, int size, int elements) 138static void cvm_oct_free_hw_memory(int pool, int size, int elements)
131{ 139{
132 char *memory; 140 char *memory;
141 char *fpa;
133 do { 142 do {
134 memory = cvmx_fpa_alloc(pool); 143 fpa = cvmx_fpa_alloc(pool);
135 if (memory) { 144 if (fpa) {
136 elements--; 145 elements--;
137 kfree(phys_to_virt(cvmx_ptr_to_phys(memory))); 146 fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
147 memory = *((char **)fpa - 1);
148 kfree(memory);
138 } 149 }
139 } while (memory); 150 } while (fpa);
140 151
141 if (elements < 0) 152 if (elements < 0)
142 pr_warning("Freeing of pool %u had too many buffers (%d)\n", 153 pr_warning("Freeing of pool %u had too many buffers (%d)\n",
@@ -149,7 +160,7 @@ static void cvm_oct_free_hw_memory(int pool, int size, int elements)
149int cvm_oct_mem_fill_fpa(int pool, int size, int elements) 160int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
150{ 161{
151 int freed; 162 int freed;
152 if (USE_SKBUFFS_IN_HW) 163 if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL)
153 freed = cvm_oct_fill_hw_skbuff(pool, size, elements); 164 freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
154 else 165 else
155 freed = cvm_oct_fill_hw_memory(pool, size, elements); 166 freed = cvm_oct_fill_hw_memory(pool, size, elements);
@@ -158,7 +169,7 @@ int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
158 169
159void cvm_oct_mem_empty_fpa(int pool, int size, int elements) 170void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
160{ 171{
161 if (USE_SKBUFFS_IN_HW) 172 if (USE_SKBUFFS_IN_HW && pool == CVMX_FPA_PACKET_POOL)
162 cvm_oct_free_hw_skbuff(pool, size, elements); 173 cvm_oct_free_hw_skbuff(pool, size, elements);
163 else 174 else
164 cvm_oct_free_hw_memory(pool, size, elements); 175 cvm_oct_free_hw_memory(pool, size, elements);