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  */
___sym_malloc(m_pool_p mp,int size)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  */
___sym_mfree(m_pool_p mp,void * ptr,int size)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  */
__sym_calloc2(m_pool_p mp,int size,char * name,int uflags)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  */
__sym_mfree(m_pool_p mp,void * ptr,int size,char * name)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  *  If DMA abtraction is not needed, the generic allocator
208  *  calls directly some kernel allocator.
209  *
210  *  With DMA abstraction, we use functions (methods), to
211  *  distinguish between non DMAable memory and DMAable memory.
212  */
213 #ifndef	SYM_OPT_BUS_DMA_ABSTRACTION
214 
215 static struct sym_m_pool mp0;
216 
217 #else
218 
___mp0_get_mem_cluster(m_pool_p mp)219 static m_addr_t ___mp0_get_mem_cluster(m_pool_p mp)
220 {
221 	m_addr_t m = (m_addr_t) sym_get_mem_cluster();
222 	if (m)
223 		++mp->nump;
224 	return m;
225 }
226 
227 #ifdef	SYM_MEM_FREE_UNUSED
___mp0_free_mem_cluster(m_pool_p mp,m_addr_t m)228 static void ___mp0_free_mem_cluster(m_pool_p mp, m_addr_t m)
229 {
230 	sym_free_mem_cluster(m);
231 	--mp->nump;
232 }
233 #endif
234 
235 #ifdef	SYM_MEM_FREE_UNUSED
236 static struct sym_m_pool mp0 =
237 	{0, ___mp0_get_mem_cluster, ___mp0_free_mem_cluster};
238 #else
239 static struct sym_m_pool mp0 =
240 	{0, ___mp0_get_mem_cluster};
241 #endif
242 
243 #endif	/* SYM_OPT_BUS_DMA_ABSTRACTION */
244 
245 /*
246  * Actual memory allocation routine for non-DMAed memory.
247  */
sym_calloc_unlocked(int size,char * name)248 void *sym_calloc_unlocked(int size, char *name)
249 {
250 	void *m;
251 	m = __sym_calloc(&mp0, size, name);
252 	return m;
253 }
254 
255 /*
256  *  Its counter-part.
257  */
sym_mfree_unlocked(void * ptr,int size,char * name)258 void sym_mfree_unlocked(void *ptr, int size, char *name)
259 {
260 	__sym_mfree(&mp0, ptr, size, name);
261 }
262 
263 #ifdef	SYM_OPT_BUS_DMA_ABSTRACTION
264 /*
265  *  Methods that maintains DMAable pools according to user allocations.
266  *  New pools are created on the fly when a new pool id is provided.
267  *  They are deleted on the fly when they get emptied.
268  */
269 /* Get a memory cluster that matches the DMA contraints of a given pool */
___get_dma_mem_cluster(m_pool_p mp)270 static m_addr_t ___get_dma_mem_cluster(m_pool_p mp)
271 {
272 	m_vtob_p vbp;
273 	m_addr_t vaddr;
274 
275 	vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
276 	if (!vbp)
277 		goto out_err;
278 
279 	vaddr = sym_m_get_dma_mem_cluster(mp, vbp);
280 	if (vaddr) {
281 		int hc = VTOB_HASH_CODE(vaddr);
282 		vbp->next = mp->vtob[hc];
283 		mp->vtob[hc] = vbp;
284 		++mp->nump;
285 		return (m_addr_t) vaddr;
286 	}
287 	return vaddr;
288 out_err:
289 	return 0;
290 }
291 
292 #ifdef	SYM_MEM_FREE_UNUSED
293 /* Free a memory cluster and associated resources for DMA */
___free_dma_mem_cluster(m_pool_p mp,m_addr_t m)294 static void ___free_dma_mem_cluster(m_pool_p mp, m_addr_t m)
295 {
296 	m_vtob_p *vbpp, vbp;
297 	int hc = VTOB_HASH_CODE(m);
298 
299 	vbpp = &mp->vtob[hc];
300 	while (*vbpp && (*vbpp)->vaddr != m)
301 		vbpp = &(*vbpp)->next;
302 	if (*vbpp) {
303 		vbp = *vbpp;
304 		*vbpp = (*vbpp)->next;
305 		sym_m_free_dma_mem_cluster(mp, vbp);
306 		__sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB");
307 		--mp->nump;
308 	}
309 }
310 #endif
311 
312 /* Fetch the memory pool for a given pool id (i.e. DMA constraints) */
___get_dma_pool(m_pool_ident_t dev_dmat)313 static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
314 {
315 	m_pool_p mp;
316 	for (mp = mp0.next;
317 		mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat);
318 			mp = mp->next);
319 	return mp;
320 }
321 
322 /* Create a new memory DMAable pool (when fetch failed) */
___cre_dma_pool(m_pool_ident_t dev_dmat)323 static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
324 {
325 	m_pool_p mp = 0;
326 
327 	mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
328 	if (mp) {
329 		mp->dev_dmat = dev_dmat;
330 		if (!sym_m_create_dma_mem_tag(mp)) {
331 			mp->get_mem_cluster = ___get_dma_mem_cluster;
332 #ifdef	SYM_MEM_FREE_UNUSED
333 			mp->free_mem_cluster = ___free_dma_mem_cluster;
334 #endif
335 			mp->next = mp0.next;
336 			mp0.next = mp;
337 			return mp;
338 		}
339 	}
340 	if (mp)
341 		__sym_mfree(&mp0, mp, sizeof(*mp), "MPOOL");
342 	return 0;
343 }
344 
345 #ifdef	SYM_MEM_FREE_UNUSED
346 /* Destroy a DMAable memory pool (when got emptied) */
___del_dma_pool(m_pool_p p)347 static void ___del_dma_pool(m_pool_p p)
348 {
349 	m_pool_p *pp = &mp0.next;
350 
351 	while (*pp && *pp != p)
352 		pp = &(*pp)->next;
353 	if (*pp) {
354 		*pp = (*pp)->next;
355 		sym_m_delete_dma_mem_tag(p);
356 		__sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
357 	}
358 }
359 #endif
360 
361 /*
362  *  Actual allocator for DMAable memory.
363  */
__sym_calloc_dma_unlocked(m_pool_ident_t dev_dmat,int size,char * name)364 void *__sym_calloc_dma_unlocked(m_pool_ident_t dev_dmat, int size, char *name)
365 {
366 	m_pool_p mp;
367 	void *m = 0;
368 
369 	mp = ___get_dma_pool(dev_dmat);
370 	if (!mp)
371 		mp = ___cre_dma_pool(dev_dmat);
372 	if (mp)
373 		m = __sym_calloc(mp, size, name);
374 #ifdef	SYM_MEM_FREE_UNUSED
375 	if (mp && !mp->nump)
376 		___del_dma_pool(mp);
377 #endif
378 
379 	return m;
380 }
381 
382 /*
383  *  Its counter-part.
384  */
385 void
__sym_mfree_dma_unlocked(m_pool_ident_t dev_dmat,void * m,int size,char * name)386 __sym_mfree_dma_unlocked(m_pool_ident_t dev_dmat, void *m, int size, char *name)
387 {
388 	m_pool_p mp;
389 
390 	mp = ___get_dma_pool(dev_dmat);
391 	if (mp)
392 		__sym_mfree(mp, m, size, name);
393 #ifdef	SYM_MEM_FREE_UNUSED
394 	if (mp && !mp->nump)
395 		___del_dma_pool(mp);
396 #endif
397 }
398 
399 /*
400  *  Actual virtual to bus physical address translator
401  *  for 32 bit addressable DMAable memory.
402  */
__vtobus_unlocked(m_pool_ident_t dev_dmat,void * m)403 u32 __vtobus_unlocked(m_pool_ident_t dev_dmat, void *m)
404 {
405 	m_pool_p mp;
406 	int hc = VTOB_HASH_CODE(m);
407 	m_vtob_p vp = 0;
408 	m_addr_t a = ((m_addr_t) m) & ~SYM_MEM_CLUSTER_MASK;
409 
410 	mp = ___get_dma_pool(dev_dmat);
411 	if (mp) {
412 		vp = mp->vtob[hc];
413 		while (vp && (m_addr_t) vp->vaddr != a)
414 			vp = vp->next;
415 	}
416 	if (!vp)
417 		panic("sym: VTOBUS FAILED!\n");
418 	return (u32)(vp ? vp->baddr + (((m_addr_t) m) - a) : 0);
419 }
420 
421 #endif	/* SYM_OPT_BUS_DMA_ABSTRACTION */
422