aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/staging/octeon/ethernet-mem.c45
-rw-r--r--drivers/staging/octeon/ethernet-tx.c6
2 files changed, 31 insertions, 20 deletions
diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c
index 7090521471b2..53ed2f7ffdfd 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);
diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c
index a3594bb0a45d..e5695d964d9a 100644
--- a/drivers/staging/octeon/ethernet-tx.c
+++ b/drivers/staging/octeon/ethernet-tx.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
@@ -186,7 +186,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
186 * shown a 25% increase in performance under some loads. 186 * shown a 25% increase in performance under some loads.
187 */ 187 */
188#if REUSE_SKBUFFS_WITHOUT_FREE 188#if REUSE_SKBUFFS_WITHOUT_FREE
189 fpa_head = skb->head + 128 - ((unsigned long)skb->head & 0x7f); 189 fpa_head = skb->head + 256 - ((unsigned long)skb->head & 0x7f);
190 if (unlikely(skb->data < fpa_head)) { 190 if (unlikely(skb->data < fpa_head)) {
191 /* 191 /*
192 * printk("TX buffer beginning can't meet FPA 192 * printk("TX buffer beginning can't meet FPA
@@ -247,7 +247,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev)
247 pko_command.s.reg0 = 0; 247 pko_command.s.reg0 = 0;
248 pko_command.s.dontfree = 0; 248 pko_command.s.dontfree = 0;
249 249
250 hw_buffer.s.back = (skb->data - fpa_head) >> 7; 250 hw_buffer.s.back = ((unsigned long)skb->data >> 7) - ((unsigned long)fpa_head >> 7);
251 *(struct sk_buff **)(fpa_head - sizeof(void *)) = skb; 251 *(struct sk_buff **)(fpa_head - sizeof(void *)) = skb;
252 252
253 /* 253 /*