0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/netdevice.h>
0010 #include <linux/slab.h>
0011
0012 #include "octeon-ethernet.h"
0013 #include "ethernet-mem.h"
0014 #include "ethernet-defines.h"
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
0025 {
0026 int freed = elements;
0027
0028 while (freed) {
0029 struct sk_buff *skb = dev_alloc_skb(size + 256);
0030
0031 if (unlikely(!skb))
0032 break;
0033 skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
0034 *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
0035 cvmx_fpa_free(skb->data, pool, size / 128);
0036 freed--;
0037 }
0038 return elements - freed;
0039 }
0040
0041
0042
0043
0044
0045
0046
0047 static void cvm_oct_free_hw_skbuff(int pool, int size, int elements)
0048 {
0049 char *memory;
0050
0051 do {
0052 memory = cvmx_fpa_alloc(pool);
0053 if (memory) {
0054 struct sk_buff *skb =
0055 *(struct sk_buff **)(memory - sizeof(void *));
0056 elements--;
0057 dev_kfree_skb(skb);
0058 }
0059 } while (memory);
0060
0061 if (elements < 0)
0062 pr_warn("Freeing of pool %u had too many skbuffs (%d)\n",
0063 pool, elements);
0064 else if (elements > 0)
0065 pr_warn("Freeing of pool %u is missing %d skbuffs\n",
0066 pool, elements);
0067 }
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 static int cvm_oct_fill_hw_memory(int pool, int size, int elements)
0078 {
0079 char *memory;
0080 char *fpa;
0081 int freed = elements;
0082
0083 while (freed) {
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094 memory = kmalloc(size + 256, GFP_ATOMIC);
0095 if (unlikely(!memory)) {
0096 pr_warn("Unable to allocate %u bytes for FPA pool %d\n",
0097 elements * size, pool);
0098 break;
0099 }
0100 fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL);
0101 *((char **)fpa - 1) = memory;
0102 cvmx_fpa_free(fpa, pool, 0);
0103 freed--;
0104 }
0105 return elements - freed;
0106 }
0107
0108
0109
0110
0111
0112
0113
0114 static void cvm_oct_free_hw_memory(int pool, int size, int elements)
0115 {
0116 char *memory;
0117 char *fpa;
0118
0119 do {
0120 fpa = cvmx_fpa_alloc(pool);
0121 if (fpa) {
0122 elements--;
0123 fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa));
0124 memory = *((char **)fpa - 1);
0125 kfree(memory);
0126 }
0127 } while (fpa);
0128
0129 if (elements < 0)
0130 pr_warn("Freeing of pool %u had too many buffers (%d)\n",
0131 pool, elements);
0132 else if (elements > 0)
0133 pr_warn("Warning: Freeing of pool %u is missing %d buffers\n",
0134 pool, elements);
0135 }
0136
0137 int cvm_oct_mem_fill_fpa(int pool, int size, int elements)
0138 {
0139 int freed;
0140
0141 if (pool == CVMX_FPA_PACKET_POOL)
0142 freed = cvm_oct_fill_hw_skbuff(pool, size, elements);
0143 else
0144 freed = cvm_oct_fill_hw_memory(pool, size, elements);
0145 return freed;
0146 }
0147
0148 void cvm_oct_mem_empty_fpa(int pool, int size, int elements)
0149 {
0150 if (pool == CVMX_FPA_PACKET_POOL)
0151 cvm_oct_free_hw_skbuff(pool, size, elements);
0152 else
0153 cvm_oct_free_hw_memory(pool, size, elements);
0154 }