1 : /*
2 : * TIPC Linux kernel implementation
3 : * Copyright (c) 2001-2003 Ericsson Research Canada
4 : * Copyright (c) 2003 OSDL, Inc.
5 : *
6 : * This file is based on the source code done by Jon Maloy
7 : * (jon.maloy@ericsson.com) for TIPC version 0.96, available from
8 : * http://tipc.sourceforge.net
9 : ***************************************************************************
10 : * This program is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License as published by
12 : * the Free Software Foundation; either version 2 of the License, or
13 : * (at your option) any later version.
14 : *
15 : * This program is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU General Public License
21 : * along with this program; if not, write to the Free Software
22 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 : ***************************************************************************
24 : * Alphabetical list of people who have worked on this file:
25 : * - Mark Haverkamp (markh@osdl.org)
26 : * - Mika Kukkonen (mika@osdl.org)
27 : * - Rusty Lynch (rusty@linux.intel.com)
28 : */
29 :
30 : #include "debug.h"
31 : #include "msg_buf.h"
32 :
33 : #define KMALLOC_MAX_SIZE (128 * 1024)
34 :
35 : typedef struct mblock {
36 : uint pages_order;
37 : char data[4];
38 : } mblock;
39 :
40 : #define SMALL_POOL_MSG_SIZE 340u
41 : #define MEDIUM_POOL_MSG_SIZE 1530u
42 :
43 : struct sk_buff *smallPoolHead = 0;
44 : struct sk_buff *mediumPoolHead = 0;
45 :
46 : struct sk_buff *
47 : acquireBuffers(uint size, uint num, struct sk_buff **pool)
48 68523 : {
49 68523 : struct sk_buff *crs = NULL;
50 68523 : uint i;
51 68523 : uint sz = (size + BUF_HEADROOM + 15) & ~15; /* Eth header + alignment */
52 :
53 68523 : if (!pool)
54 : assert(num == 1);
55 137163 : for (i = 0; i < num; i++) {
56 68640 : crs = (struct sk_buff *) alloc_skb(sz, GFP_ATOMIC);
57 : assert(crs);
58 68640 : crs->protocol = __constant_htons(0x807);
59 68640 : skb_reserve(crs, BUF_HEADROOM);
60 68640 : crs->nh.raw = crs->data; /* Please the device layer */
61 68640 : UD(crs)->data = crs->data;
62 68640 : UD(crs)->pool = pool;
63 68640 : UD(crs)->next = (pool ? *pool : (struct sk_buff *) 0);
64 68640 : if (pool)
65 120 : *pool = crs;
66 : }
67 68523 : if (pool)
68 3 : *pool = UD(crs)->next;
69 68523 : UD(crs)->next = 0;
70 68523 : return crs;
71 : }
72 :
73 : struct sk_buff *
74 : buf_acquire(uint size)
75 479979 : {
76 479979 : struct sk_buff *b;
77 :
78 479979 : if (size <= SMALL_POOL_MSG_SIZE) {
79 231 : b = smallPoolHead;
80 231 : if (b) {
81 230 : smallPoolHead = UD(b)->next;
82 230 : return b;
83 : }
84 1 : return acquireBuffers(SMALL_POOL_MSG_SIZE, 40, &smallPoolHead);
85 479748 : } else if (size <= MEDIUM_POOL_MSG_SIZE) {
86 411228 : b = mediumPoolHead;
87 411228 : if (b) {
88 411226 : mediumPoolHead = UD(b)->next;
89 411226 : return b;
90 : }
91 2 : return acquireBuffers(MEDIUM_POOL_MSG_SIZE, 40,
92 : &mediumPoolHead);
93 : }
94 68520 : return acquireBuffers(size, 1, 0);
95 : }
96 :
97 : char *
98 : os_malloc(uint size)
99 27 : {
100 27 : mblock *m;
101 27 : uint allocate = size + sizeof (int);
102 :
103 27 : if (allocate <= KMALLOC_MAX_SIZE) {
104 27 : m = kmalloc(allocate, GFP_ATOMIC);
105 27 : if (!m) {
106 : assert(!"TIPC: kmalloc(GFP_ATOMIC) failed");
107 : }
108 27 : m->pages_order = 0;
109 : } else {
110 0 : uint order = 1;
111 :
112 0 : while ((PAGE_SIZE << order) < allocate)
113 0 : order++;
114 0 : m = (mblock *) __get_free_pages(GFP_ATOMIC, order);
115 0 : if (!m) {
116 : assert(!"TIPC: __get_free_pages(GFP_ATOMIOC) failed");
117 : }
118 0 : m->pages_order = order;
119 : }
120 27 : return (char *) &m->data;
121 : }
122 :
123 : void
124 : os_free(char *m)
125 8 : {
126 8 : mblock *b;
127 8 : b = (mblock *) (m - sizeof (int));
128 : assert(b);
129 : assert(((PAGE_SIZE << b->pages_order) / PAGE_SIZE) < num_physpages);
130 8 : if (b->pages_order)
131 0 : free_pages((unsigned long) b, b->pages_order);
132 : else
133 8 : kfree(b);
134 : }
135 :
136 : /* ///////////////////////////////////////////////////////////////// */
137 : /* Memory management: */
138 : /* These calls do not need to be particularly efficient,since they */
139 : /* will be called infrequenctly. Only multiple pages are requested. */
140 :
141 : typedef struct MemoryBlock {
142 : struct MemoryBlock *next;
143 : struct MemoryBlock *prev;
144 : char mem[4];
145 : } MemoryBlock;
146 :
147 : struct MemoryBlock *memRoot = 0;
148 :
149 : char *
150 : mem_alloc(uint size)
151 27 : {
152 27 : struct MemoryBlock *block;
153 27 : uint sz = size + (2 * sizeof (MemoryBlock *));
154 :
155 27 : block = (MemoryBlock *) os_malloc(sz);
156 27 : if (!block) {
157 0 : warn("TIPC: Failed to allocate %i bytes\n", sz);
158 0 : return NULL;
159 : }
160 27 : block->prev = 0;
161 27 : block->next = memRoot;
162 27 : if (block->next)
163 26 : block->next->prev = block;
164 27 : memRoot = block;
165 27 : return block->mem;
166 : }
167 :
168 : void
169 : mem_free(char *b)
170 8 : {
171 8 : struct MemoryBlock *block;
172 :
173 8 : block = (MemoryBlock *) (b - 2 * sizeof (MemoryBlock *));
174 8 : if (block->next)
175 8 : block->next->prev = block->prev;
176 8 : if (block->prev)
177 4 : block->prev->next = block->next;
178 : else
179 4 : memRoot = block->next;
180 8 : os_free((char *) block);
181 : }
182 :
183 : /*
184 : * Clean up TIPC memory
185 : */
186 : void
187 : tipc_release_msg_buf(void)
188 0 : {
189 0 : MemoryBlock *block;
190 0 : struct sk_buff *obuf;
191 :
192 : /*
193 : * Release sk_buffs from buf_acquire()
194 : */
195 0 : obuf = smallPoolHead;
196 0 : while (obuf) {
197 0 : struct sk_buff *next = UD(obuf)->next;
198 :
199 0 : kfree_skb(obuf);
200 0 : obuf = next;
201 : }
202 0 : obuf = mediumPoolHead;
203 0 : while (obuf) {
204 0 : struct sk_buff *next = UD(obuf)->next;
205 :
206 0 : kfree_skb(obuf);
207 0 : obuf = next;
208 : }
209 :
210 : /*
211 : * Release memory from mem_alloc()
212 : */
213 0 : block = memRoot;
214 0 : while (block) {
215 0 : MemoryBlock *nx = block->next;
216 :
217 : dbg("Releasing memory block\n");
218 0 : os_free((char *) block);
219 0 : block = nx;
220 : }
221 : }
|