ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / scsi / sym53c8xx_2 / sym_malloc.c
1 /*
2  * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
3  * of PCI-SCSI IO processors.
4  *
5  * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
6  *
7  * This driver is derived from the Linux sym53c8xx driver.
8  * Copyright (C) 1998-2000  Gerard Roudier
9  *
10  * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
11  * a port of the FreeBSD ncr driver to Linux-1.2.13.
12  *
13  * The original ncr driver has been written for 386bsd and FreeBSD by
14  *         Wolfgang Stanglmeier        <wolf@cologne.de>
15  *         Stefan Esser                <se@mi.Uni-Koeln.de>
16  * Copyright (C) 1994  Wolfgang Stanglmeier
17  *
18  * Other major contributions:
19  *
20  * NVRAM detection and reading.
21  * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
22  *
23  *-----------------------------------------------------------------------------
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  * 1. Redistributions of source code must retain the above copyright
29  *    notice, this list of conditions and the following disclaimer.
30  * 2. The name of the author may not be used to endorse or promote products
31  *    derived from this software without specific prior written permission.
32  *
33  * Where this Software is combined with software released under the terms of 
34  * the GNU Public License ("GPL") and the terms of the GPL would require the 
35  * combined work to also be released under the terms of the GPL, the terms
36  * and conditions of this License will apply in addition to those of the
37  * GPL with the exception of any terms or conditions of this License that
38  * conflict with, or are expressly prohibited by, the GPL.
39  *
40  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
44  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50  * SUCH DAMAGE.
51  */
52
53 #ifdef __FreeBSD__
54 #include <dev/sym/sym_glue.h>
55 #else
56 #include "sym_glue.h"
57 #endif
58
59 /*
60  *  Simple power of two buddy-like generic allocator.
61  *  Provides naturally aligned memory chunks.
62  *
63  *  This simple code is not intended to be fast, but to 
64  *  provide power of 2 aligned memory allocations.
65  *  Since the SCRIPTS processor only supplies 8 bit arithmetic, 
66  *  this allocator allows simple and fast address calculations  
67  *  from the SCRIPTS code. In addition, cache line alignment 
68  *  is guaranteed for power of 2 cache line size.
69  *
70  *  This allocator has been developped for the Linux sym53c8xx  
71  *  driver, since this O/S does not provide naturally aligned 
72  *  allocations.
73  *  It has the advantage of allowing the driver to use private 
74  *  pages of memory that will be useful if we ever need to deal 
75  *  with IO MMUs for PCI.
76  */
77 static void *___sym_malloc(m_pool_p mp, int size)
78 {
79         int i = 0;
80         int s = (1 << SYM_MEM_SHIFT);
81         int j;
82         m_addr_t a;
83         m_link_p h = mp->h;
84
85         if (size > SYM_MEM_CLUSTER_SIZE)
86                 return 0;
87
88         while (size > s) {
89                 s <<= 1;
90                 ++i;
91         }
92
93         j = i;
94         while (!h[j].next) {
95                 if (s == SYM_MEM_CLUSTER_SIZE) {
96                         h[j].next = (m_link_p) M_GET_MEM_CLUSTER();
97                         if (h[j].next)
98                                 h[j].next->next = 0;
99                         break;
100                 }
101                 ++j;
102                 s <<= 1;
103         }
104         a = (m_addr_t) h[j].next;
105         if (a) {
106                 h[j].next = h[j].next->next;
107                 while (j > i) {
108                         j -= 1;
109                         s >>= 1;
110                         h[j].next = (m_link_p) (a+s);
111                         h[j].next->next = 0;
112                 }
113         }
114 #ifdef DEBUG
115         printf("___sym_malloc(%d) = %p\n", size, (void *) a);
116 #endif
117         return (void *) a;
118 }
119
120 /*
121  *  Counter-part of the generic allocator.
122  */
123 static void ___sym_mfree(m_pool_p mp, void *ptr, int size)
124 {
125         int i = 0;
126         int s = (1 << SYM_MEM_SHIFT);
127         m_link_p q;
128         m_addr_t a, b;
129         m_link_p h = mp->h;
130
131 #ifdef DEBUG
132         printf("___sym_mfree(%p, %d)\n", ptr, size);
133 #endif
134
135         if (size > SYM_MEM_CLUSTER_SIZE)
136                 return;
137
138         while (size > s) {
139                 s <<= 1;
140                 ++i;
141         }
142
143         a = (m_addr_t) ptr;
144
145         while (1) {
146                 if (s == SYM_MEM_CLUSTER_SIZE) {
147 #ifdef SYM_MEM_FREE_UNUSED
148                         M_FREE_MEM_CLUSTER(a);
149 #else
150                         ((m_link_p) a)->next = h[i].next;
151                         h[i].next = (m_link_p) a;
152 #endif
153                         break;
154                 }
155                 b = a ^ s;
156                 q = &h[i];
157                 while (q->next && q->next != (m_link_p) b) {
158                         q = q->next;
159                 }
160                 if (!q->next) {
161                         ((m_link_p) a)->next = h[i].next;
162                         h[i].next = (m_link_p) a;
163                         break;
164                 }
165                 q->next = q->next->next;
166                 a = a & b;
167                 s <<= 1;
168                 ++i;
169         }
170 }
171
172 /*
173  *  Verbose and zeroing allocator that wrapps to the generic allocator.
174  */
175 static void *__sym_calloc2(m_pool_p mp, int size, char *name, int uflags)
176 {
177         void *p;
178
179         p = ___sym_malloc(mp, size);
180
181         if (DEBUG_FLAGS & DEBUG_ALLOC) {
182                 printf ("new %-10s[%4d] @%p.\n", name, size, p);
183         }
184
185         if (p)
186                 bzero(p, size);
187         else if (uflags & SYM_MEM_WARN)
188                 printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size);
189         return p;
190 }
191 #define __sym_calloc(mp, s, n)  __sym_calloc2(mp, s, n, SYM_MEM_WARN)
192
193 /*
194  *  Its counter-part.
195  */
196 static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name)
197 {
198         if (DEBUG_FLAGS & DEBUG_ALLOC)
199                 printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
200
201         ___sym_mfree(mp, ptr, size);
202 }
203
204 /*
205  *  Default memory pool we donnot need to involve in DMA.
206  *
207  *  With DMA abstraction, we use functions (methods), to 
208  *  distinguish between non DMAable memory and DMAable memory.
209  */
210 static m_addr_t ___mp0_get_mem_cluster(m_pool_p mp)
211 {
212         m_addr_t m = (m_addr_t) sym_get_mem_cluster();
213         if (m)
214                 ++mp->nump;
215         return m;
216 }
217
218 #ifdef  SYM_MEM_FREE_UNUSED
219 static void ___mp0_free_mem_cluster(m_pool_p mp, m_addr_t m)
220 {
221         sym_free_mem_cluster(m);
222         --mp->nump;
223 }
224 #endif
225
226 #ifdef  SYM_MEM_FREE_UNUSED
227 static struct sym_m_pool mp0 =
228         {0, ___mp0_get_mem_cluster, ___mp0_free_mem_cluster};
229 #else
230 static struct sym_m_pool mp0 =
231         {0, ___mp0_get_mem_cluster};
232 #endif
233
234 /*
235  * Actual memory allocation routine for non-DMAed memory.
236  */
237 void *sym_calloc_unlocked(int size, char *name)
238 {
239         void *m;
240         m = __sym_calloc(&mp0, size, name);
241         return m;
242 }
243
244 /*
245  *  Its counter-part.
246  */
247 void sym_mfree_unlocked(void *ptr, int size, char *name)
248 {
249         __sym_mfree(&mp0, ptr, size, name);
250 }
251
252 /*
253  *  Methods that maintains DMAable pools according to user allocations.
254  *  New pools are created on the fly when a new pool id is provided.
255  *  They are deleted on the fly when they get emptied.
256  */
257 /* Get a memory cluster that matches the DMA contraints of a given pool */
258 static m_addr_t ___get_dma_mem_cluster(m_pool_p mp)
259 {
260         m_vtob_p vbp;
261         m_addr_t vaddr;
262
263         vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
264         if (!vbp)
265                 goto out_err;
266
267         vaddr = sym_m_get_dma_mem_cluster(mp, vbp);
268         if (vaddr) {
269                 int hc = VTOB_HASH_CODE(vaddr);
270                 vbp->next = mp->vtob[hc];
271                 mp->vtob[hc] = vbp;
272                 ++mp->nump;
273                 return (m_addr_t) vaddr;
274         }
275         return vaddr;
276 out_err:
277         return 0;
278 }
279
280 #ifdef  SYM_MEM_FREE_UNUSED
281 /* Free a memory cluster and associated resources for DMA */
282 static void ___free_dma_mem_cluster(m_pool_p mp, m_addr_t m)
283 {
284         m_vtob_p *vbpp, vbp;
285         int hc = VTOB_HASH_CODE(m);
286
287         vbpp = &mp->vtob[hc];
288         while (*vbpp && (*vbpp)->vaddr != m)
289                 vbpp = &(*vbpp)->next;
290         if (*vbpp) {
291                 vbp = *vbpp;
292                 *vbpp = (*vbpp)->next;
293                 sym_m_free_dma_mem_cluster(mp, vbp);
294                 __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB");
295                 --mp->nump;
296         }
297 }
298 #endif
299
300 /* Fetch the memory pool for a given pool id (i.e. DMA constraints) */
301 static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
302 {
303         m_pool_p mp;
304         for (mp = mp0.next;
305                 mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat);
306                         mp = mp->next);
307         return mp;
308 }
309
310 /* Create a new memory DMAable pool (when fetch failed) */
311 static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
312 {
313         m_pool_p mp = 0;
314
315         mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
316         if (mp) {
317                 mp->dev_dmat = dev_dmat;
318                 if (!sym_m_create_dma_mem_tag(mp)) {
319                         mp->get_mem_cluster = ___get_dma_mem_cluster;
320 #ifdef  SYM_MEM_FREE_UNUSED
321                         mp->free_mem_cluster = ___free_dma_mem_cluster;
322 #endif
323                         mp->next = mp0.next;
324                         mp0.next = mp;
325                         return mp;
326                 }
327         }
328         if (mp)
329                 __sym_mfree(&mp0, mp, sizeof(*mp), "MPOOL");
330         return 0;
331 }
332
333 #ifdef  SYM_MEM_FREE_UNUSED
334 /* Destroy a DMAable memory pool (when got emptied) */
335 static void ___del_dma_pool(m_pool_p p)
336 {
337         m_pool_p *pp = &mp0.next;
338
339         while (*pp && *pp != p)
340                 pp = &(*pp)->next;
341         if (*pp) {
342                 *pp = (*pp)->next;
343                 sym_m_delete_dma_mem_tag(p);
344                 __sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
345         }
346 }
347 #endif
348
349 /*
350  *  Actual allocator for DMAable memory.
351  */
352 void *__sym_calloc_dma_unlocked(m_pool_ident_t dev_dmat, int size, char *name)
353 {
354         m_pool_p mp;
355         void *m = 0;
356
357         mp = ___get_dma_pool(dev_dmat);
358         if (!mp)
359                 mp = ___cre_dma_pool(dev_dmat);
360         if (mp)
361                 m = __sym_calloc(mp, size, name);
362 #ifdef  SYM_MEM_FREE_UNUSED
363         if (mp && !mp->nump)
364                 ___del_dma_pool(mp);
365 #endif
366
367         return m;
368 }
369
370 /*
371  *  Its counter-part.
372  */
373 void 
374 __sym_mfree_dma_unlocked(m_pool_ident_t dev_dmat, void *m, int size, char *name)
375 {
376         m_pool_p mp;
377
378         mp = ___get_dma_pool(dev_dmat);
379         if (mp)
380                 __sym_mfree(mp, m, size, name);
381 #ifdef  SYM_MEM_FREE_UNUSED
382         if (mp && !mp->nump)
383                 ___del_dma_pool(mp);
384 #endif
385 }
386
387 /*
388  *  Actual virtual to bus physical address translator 
389  *  for 32 bit addressable DMAable memory.
390  */
391 u32 __vtobus_unlocked(m_pool_ident_t dev_dmat, void *m)
392 {
393         m_pool_p mp;
394         int hc = VTOB_HASH_CODE(m);
395         m_vtob_p vp = 0;
396         m_addr_t a = ((m_addr_t) m) & ~SYM_MEM_CLUSTER_MASK;
397
398         mp = ___get_dma_pool(dev_dmat);
399         if (mp) {
400                 vp = mp->vtob[hc];
401                 while (vp && (m_addr_t) vp->vaddr != a)
402                         vp = vp->next;
403         }
404         if (!vp)
405                 panic("sym: VTOBUS FAILED!\n");
406         return (u32)(vp ? vp->baddr + (((m_addr_t) m) - a) : 0);
407 }