Aaro Koskinen | 6762098 | 2015-04-04 22:51:21 +0300 | [diff] [blame] | 1 | /* |
| 2 | * This file is based on code from OCTEON SDK by Cavium Networks. |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 3 | * |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 4 | * Copyright (c) 2003-2010 Cavium Networks |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 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. |
Aaro Koskinen | 6762098 | 2015-04-04 22:51:21 +0300 | [diff] [blame] | 9 | */ |
| 10 | |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 11 | #include <linux/kernel.h> |
| 12 | #include <linux/netdevice.h> |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 13 | #include <linux/slab.h> |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 14 | |
| 15 | #include <asm/octeon/octeon.h> |
| 16 | |
Aaro Koskinen | 5c2f26d | 2014-03-02 00:09:09 +0200 | [diff] [blame] | 17 | #include "ethernet-mem.h" |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 18 | #include "ethernet-defines.h" |
| 19 | |
David Daney | af86649 | 2011-11-22 14:47:00 +0000 | [diff] [blame] | 20 | #include <asm/octeon/cvmx-fpa.h> |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 21 | |
| 22 | /** |
David Daney | ec977c5 | 2010-02-16 17:25:32 -0800 | [diff] [blame] | 23 | * cvm_oct_fill_hw_skbuff - fill the supplied hardware pool with skbuffs |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 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 |
David Daney | ec977c5 | 2010-02-16 17:25:32 -0800 | [diff] [blame] | 27 | * |
| 28 | * Returns the actual number of buffers allocated. |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 29 | */ |
| 30 | static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements) |
| 31 | { |
| 32 | int freed = elements; |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 33 | |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 34 | while (freed) { |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 35 | struct sk_buff *skb = dev_alloc_skb(size + 256); |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 36 | |
Aaro Koskinen | a5de43c | 2013-09-05 21:44:00 +0300 | [diff] [blame] | 37 | if (unlikely(skb == NULL)) |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 38 | break; |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 39 | skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f)); |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 40 | *(struct sk_buff **)(skb->data - sizeof(void *)) = skb; |
Aaro Koskinen | c93b0e7 | 2015-04-04 22:51:19 +0300 | [diff] [blame] | 41 | cvmx_fpa_free(skb->data, pool, size / 128); |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 42 | freed--; |
| 43 | } |
| 44 | return elements - freed; |
| 45 | } |
| 46 | |
| 47 | /** |
David Daney | ec977c5 | 2010-02-16 17:25:32 -0800 | [diff] [blame] | 48 | * cvm_oct_free_hw_skbuff- free hardware pool skbuffs |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 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 | */ |
| 53 | static 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) |
Himangi Saraogi | 8a125b0 | 2014-03-03 06:33:54 +0530 | [diff] [blame] | 68 | pr_warn("Freeing of pool %u had too many skbuffs (%d)\n", |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 69 | pool, elements); |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 70 | else if (elements > 0) |
Himangi Saraogi | 8a125b0 | 2014-03-03 06:33:54 +0530 | [diff] [blame] | 71 | pr_warn("Freeing of pool %u is missing %d skbuffs\n", |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 72 | pool, elements); |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | /** |
David Daney | ec977c5 | 2010-02-16 17:25:32 -0800 | [diff] [blame] | 76 | * cvm_oct_fill_hw_memory - fill a hardware pool with memory. |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 77 | * @pool: Pool to populate |
| 78 | * @size: Size of each buffer in the pool |
| 79 | * @elements: Number of buffers to allocate |
David Daney | ec977c5 | 2010-02-16 17:25:32 -0800 | [diff] [blame] | 80 | * |
| 81 | * Returns the actual number of buffers allocated. |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 82 | */ |
| 83 | static int cvm_oct_fill_hw_memory(int pool, int size, int elements) |
| 84 | { |
| 85 | char *memory; |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 86 | char *fpa; |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 87 | int freed = elements; |
| 88 | |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 89 | while (freed) { |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 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); |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 101 | if (unlikely(memory == NULL)) { |
Himangi Saraogi | 8a125b0 | 2014-03-03 06:33:54 +0530 | [diff] [blame] | 102 | pr_warn("Unable to allocate %u bytes for FPA pool %d\n", |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 103 | elements * size, pool); |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 104 | break; |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 105 | } |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 106 | fpa = (char *)(((unsigned long)memory + 256) & ~0x7fUL); |
| 107 | *((char **)fpa - 1) = memory; |
| 108 | cvmx_fpa_free(fpa, pool, 0); |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 109 | freed--; |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 110 | } |
| 111 | return elements - freed; |
| 112 | } |
| 113 | |
| 114 | /** |
David Daney | ec977c5 | 2010-02-16 17:25:32 -0800 | [diff] [blame] | 115 | * cvm_oct_free_hw_memory - Free memory allocated by cvm_oct_fill_hw_memory |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 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 | */ |
| 120 | static void cvm_oct_free_hw_memory(int pool, int size, int elements) |
| 121 | { |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 122 | char *memory; |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 123 | char *fpa; |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 124 | |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 125 | do { |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 126 | fpa = cvmx_fpa_alloc(pool); |
| 127 | if (fpa) { |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 128 | elements--; |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 129 | fpa = (char *)phys_to_virt(cvmx_ptr_to_phys(fpa)); |
| 130 | memory = *((char **)fpa - 1); |
| 131 | kfree(memory); |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 132 | } |
David Daney | 166bdaa | 2010-01-27 13:22:53 -0800 | [diff] [blame] | 133 | } while (fpa); |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 134 | |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 135 | if (elements < 0) |
Himangi Saraogi | 8a125b0 | 2014-03-03 06:33:54 +0530 | [diff] [blame] | 136 | pr_warn("Freeing of pool %u had too many buffers (%d)\n", |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 137 | pool, elements); |
| 138 | else if (elements > 0) |
Himangi Saraogi | 8a125b0 | 2014-03-03 06:33:54 +0530 | [diff] [blame] | 139 | pr_warn("Warning: Freeing of pool %u is missing %d buffers\n", |
David Daney | 6568a23 | 2010-01-07 11:05:01 -0800 | [diff] [blame] | 140 | pool, elements); |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 141 | } |
| 142 | |
| 143 | int cvm_oct_mem_fill_fpa(int pool, int size, int elements) |
| 144 | { |
| 145 | int freed; |
Nicolas Koch | 883d29e | 2014-06-03 21:56:31 +0200 | [diff] [blame] | 146 | |
Aaro Koskinen | 3a990f3 | 2015-04-04 22:51:17 +0300 | [diff] [blame] | 147 | if (pool == CVMX_FPA_PACKET_POOL) |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 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 | |
| 154 | void cvm_oct_mem_empty_fpa(int pool, int size, int elements) |
| 155 | { |
Aaro Koskinen | 3a990f3 | 2015-04-04 22:51:17 +0300 | [diff] [blame] | 156 | if (pool == CVMX_FPA_PACKET_POOL) |
David Daney | 80ff0fd | 2009-05-05 17:35:21 -0700 | [diff] [blame] | 157 | cvm_oct_free_hw_skbuff(pool, size, elements); |
| 158 | else |
| 159 | cvm_oct_free_hw_memory(pool, size, elements); |
| 160 | } |