kernel: Remove some bogus casts of NULL to something.
[dragonfly.git] / sys / dev / atm / hea / eni_buffer.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/dev/hea/eni_buffer.c,v 1.5 1999/08/28 00:41:43 peter Exp $
27  */
28
29 /*
30  * Efficient ENI Adapter Support
31  * -----------------------------
32  *
33  * Handle adapter memory buffers for ENI adapters
34  *
35  */
36
37 #include <netproto/atm/kern_include.h>
38
39 #include "eni_stats.h"
40 #include "eni.h"
41 #include "eni_var.h"
42
43 static int      eni_test_memory (Eni_unit *);
44
45 /*
46  * The host is going to manage (that is, allocate and free) buffers
47  * in the adapters RAM space. We are going to implement this as a
48  * linked list describing FREE and INUSE memory segments. Initially,
49  * the list contains one element with all memory marked free. As requests
50  * are made, we search the list until we find the first free element
51  * which can satisfy the request. If necessary, we will break the free
52  * element into an INUSE element, and a new FREE element. When freeing
53  * memory, we look at adjacent elements and if one or more are free,
54  * we will combine into a single larger FREE element.
55  */
56
57 /*
58  * This is for testing purposes. Since there are two versions of
59  * the Efficient adapter with different memory sizes, this allows
60  * us to fool an adapter with more memory into thinking it has less.
61  */
62 static int eni_mem_max = MAX_ENI_MEM;   /* Default to all available memory */
63
64 /*
65  * Size and test adapter RAM
66  *
67  * Walk through adapter RAM writing known patterns and reading back
68  * for comparison. We write more than one pattern on the off chance
69  * that we "get lucky" and read what we expected.
70  *
71  * Arguments:
72  *      eup             pointer to device unit structure
73  *
74  * Returns
75  *      size            memory size in bytes
76  */
77 static int
78 eni_test_memory(Eni_unit *eup)
79 {
80         int     ram_size = 0;
81         int     i;
82         Eni_mem mp;
83
84         /*
85          * Walk through to maximum looking for RAM
86          */
87         for ( i = 0; i < MAX_ENI_MEM; i += TEST_STEP ) {
88                 mp = (Eni_mem)((int)eup->eu_ram + i);
89                 /* write pattern */
90                 *mp = (u_long)TEST_PAT;
91                 /* read pattern, match? */
92                 if ( *mp == (u_long)TEST_PAT ) {
93                         /* yes - write inverse pattern */
94                         *mp = (u_long)~TEST_PAT;
95                         /* read pattern, match? */
96                         if ( *mp == (u_long)~TEST_PAT ) {
97                                 /* yes - assume another 1K available */
98                                 ram_size = i + TEST_STEP;
99                         } else
100                             break;
101                 } else
102                         break;
103         }
104         /*
105          * Clear all RAM to initial value of zero.
106          * This makes sure we don't leave anything funny in the
107          * queues.
108          */
109         KM_ZERO ( eup->eu_ram, ram_size );
110
111         /*
112          * If we'd like to claim to have less memory, here's where
113          * we do so. We take the minimum of what we'd like and what
114          * we really found on the adapter.
115          */
116         ram_size = MIN ( ram_size, eni_mem_max ); 
117
118         return ( ram_size );
119
120 }
121
122 /*
123  * Initialize our memory allocator.
124  *
125  * Arguments:
126  *      eup             Pointer to per unit structure
127  *
128  * Returns:
129  *      size            Physical RAM size
130  *      -1              failed to initialize memory
131  *
132  */
133 int
134 eni_init_memory(Eni_unit *eup)
135 {
136
137         /*
138          * Have we (somehow) been called before?
139          */
140         if ( eup->eu_memmap != NULL )
141         {
142                 /* Oops  - it's already been initialized */
143                 return -1;
144         }
145
146         /*
147          * Allocate initial element which will hold all of memory
148          */
149         eup->eu_memmap = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_WAITOK);
150
151         /*
152          * Test and size memory
153          */
154         eup->eu_ramsize = eni_test_memory ( eup );
155
156         /*
157          * Initialize a one element list which contains
158          * all buffer memory
159          */
160         eup->eu_memmap->prev = eup->eu_memmap->next = NULL;
161         eup->eu_memmap->base = (caddr_t)SEGBUF_BASE;
162         eup->eu_memmap->size = eup->eu_ramsize - SEGBUF_BASE;
163         eup->eu_memmap->state = MEM_FREE;
164
165         return ( eup->eu_ramsize );
166 }
167
168 /*
169  * Allocate a buffer from adapter RAM. Due to constraints on the card,
170  * we may roundup the size request to the next largest chunksize. Note
171  * also that we must pay attention to address alignment within adapter
172  * memory as well.
173  *
174  * Arguments:
175  *      eup             pointer to per unit structure
176  *      size            pointer to requested size - in bytes
177  *
178  * Returns:
179  *      addr            address relative to adapter of allocated memory
180  *      size            modified to reflect actual size of buffer
181  *
182  */
183 caddr_t
184 eni_allocate_buffer(Eni_unit *eup, u_long *size)
185 {
186         int     nsize;
187         int     nclicks;
188         Mbd     *eptr = eup->eu_memmap;
189
190         /*
191          * Initial size requested
192          */
193         nsize = *size;
194
195         /*
196          * Find the buffer size which will hold this request. There
197          * are 8 possible sizes, each a power of two up, starting at
198          * 256 words or 1024 bytes.
199          */
200         for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ )
201                 if ( ( 1 << nclicks ) * ENI_BUF_PGSZ >= nsize )
202                         break;
203
204         /*
205          * Request was for larger then the card supports
206          */
207         if ( nclicks >= ENI_BUF_NBIT ) {
208                 eup->eu_stats.eni_st_drv.drv_mm_toobig++;
209                 /* Indicate 0 bytes allocated */
210                 *size = 0;
211                 /* Return NULL buffer */
212                 return ( NULL );
213         }
214
215         /*
216          * New size will be buffer size
217          */
218         nsize = ( 1 << nclicks ) * ENI_BUF_PGSZ;
219
220         /*
221          * Look through memory for a segment large enough to
222          * hold request
223          */
224         while ( eptr ) {
225             /*
226              * State must be FREE and size must hold request
227              */
228             if ( eptr->state == MEM_FREE && eptr->size >= nsize )
229             {
230                 /*
231                  * Request will fit - now check if the
232                  * alignment needs fixing
233                  */
234                 if ( ((u_int)eptr->base & (nsize-1)) != 0 )
235                 {
236                     caddr_t     nbase;
237
238                     /*
239                      * Calculate where the buffer would have to
240                      * fall to be aligned.
241                      */
242                     nbase = (caddr_t)((u_int)( eptr->base + nsize ) &
243                         ~(nsize-1));
244                     /*
245                      * If we use this alignment, will it still fit?
246                      */
247                     if ( (eptr->size - (nbase - eptr->base)) >= 0 )
248                     {
249                         Mbd     *etmp;
250
251                         /* Yep - create a new segment */
252                         etmp = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_WAITOK);
253                         /* Place it in the list */
254                         etmp->next = eptr->next;
255                         if ( etmp->next )
256                             etmp->next->prev = etmp;
257                         etmp->prev = eptr;
258                         eptr->next = etmp;
259                         /* Fill in new base and size */
260                         etmp->base = nbase;
261                         etmp->size = eptr->size - ( nbase - eptr->base );
262                         /* Adjust old size */
263                         eptr->size -= etmp->size;
264                         /* Mark its state */
265                         etmp->state = MEM_FREE;
266                         eptr = etmp;
267                         /* Done - outa here */
268                         break;
269                     }
270                 } else
271                     break;              /* Alignment is okay  - we're done */
272             }
273             /* Haven't found anything yet - keep looking */
274             eptr = eptr->next;
275         }
276
277         if ( eptr != NULL )
278         {
279             /* Found a usable segment - grab what we need */
280             /* Exact fit? */
281             if ( eptr->size == nsize )
282                 /* Mark it as INUSE */
283                 eptr->state = MEM_INUSE;
284             else
285             {
286                 Mbd     *etmp;
287                 /* larger then we need - split it */
288
289                 etmp = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_WAITOK);
290                 /* Place new element in list */
291                 etmp->next = eptr->next;
292                 if ( etmp->next )
293                     etmp->next->prev = etmp;
294                 etmp->prev = eptr;
295                 eptr->next = etmp;
296                 /* Set new base, size and state */
297                 etmp->base = eptr->base + nsize;
298                 etmp->size = eptr->size - nsize;
299                 etmp->state = MEM_FREE;
300                 /* Adjust size and state of element we intend to use */
301                 eptr->size = nsize;
302                 eptr->state = MEM_INUSE;
303             }
304         }
305
306         /* After all that, did we find a usable buffer? */
307         if ( eptr )
308         {
309                 /* Record another inuse buffer of this size */
310                 if ( eptr->base )
311                         eup->eu_memclicks[nclicks]++;
312
313                 /*
314                  * Return true size of allocated buffer
315                  */
316                 *size = eptr->size;
317                 /*
318                  * Make address relative to start of RAM since
319                  * its (the address) for use by the adapter, not
320                  * the host.
321                  */
322                 return ((caddr_t)eptr->base);
323         } else {
324                 eup->eu_stats.eni_st_drv.drv_mm_nobuf++;
325                 /* No buffer to return - indicate zero length */
326                 *size = 0;
327                 /* Return NULL buffer */
328                 return ( NULL );
329         }
330 }
331
332 /*
333  * Procedure to release a buffer previously allocated from adapter
334  * RAM. When possible, we'll compact memory.
335  *
336  * Arguments:
337  *      eup             pointer to per unit structure
338  *      base            base adapter address of buffer to be freed
339  *
340  * Returns:
341  *      none
342  *
343  */
344 void
345 eni_free_buffer(Eni_unit *eup, caddr_t base)
346 {
347         Mbd     *eptr = eup->eu_memmap;
348         int     nclicks;
349
350         /* Look through entire list */
351         while ( eptr )
352         {
353                 /* Is this the buffer to be freed? */
354                 if ( eptr->base == base )
355                 {
356                         /*
357                          * We're probably asking for trouble but,
358                          * assume this is it.
359                          */
360                         if ( eptr->state != MEM_INUSE )
361                         {
362                                 eup->eu_stats.eni_st_drv.drv_mm_notuse++;
363                                 /* Huh? Something's wrong */
364                                 return;
365                         }
366                         /* Reset state to FREE */
367                         eptr->state = MEM_FREE;
368
369                         /* Determine size for stats info */
370                         for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ )
371                             if ( ( 1 << nclicks ) * ENI_BUF_PGSZ == eptr->size )
372                                 break;
373
374                         /* Valid size? Yes - decrement inuse count */
375                         if ( nclicks < ENI_BUF_NBIT )
376                                 eup->eu_memclicks[nclicks]--;
377
378                         /* Try to compact neighbors */
379                         /* with previous */
380                         if ( eptr->prev )
381                             if ( eptr->prev->state == MEM_FREE )
382                             {
383                                 Mbd     *etmp = eptr;
384                                 /* Add to previous block */
385                                 eptr->prev->size += eptr->size;
386                                 /* Set prev block to skip this one */
387                                 eptr->prev->next = eptr->next;
388                                 /* Set next block to skip this one */
389                                 if ( eptr->next )
390                                         eptr->next->prev = eptr->prev;
391                                 /* Reset to where we want to be */
392                                 eptr = eptr->prev;
393                                 /* and free this element */
394                                 (void)KM_FREE(etmp, etmp->size, M_DEVBUF);
395                             }
396                         /* with next */
397                         if ( eptr->next )
398                             if ( eptr->next->state == MEM_FREE )
399                             {
400                                 Mbd     *etmp = eptr->next;
401
402                                 /* add following block in */
403                                 eptr->size += etmp->size;
404                                 /* set next next block to skip next block */
405                                 if ( etmp->next )
406                                         etmp->next->prev = eptr;
407                                 /* skip next block */
408                                 eptr->next = etmp->next;
409                                 /* and free next element */
410                                 (void)KM_FREE(etmp, etmp->size, M_DEVBUF);
411                             }
412                         /*
413                          * We've freed the buffer and done any compaction,
414                          * we needn't look any further...
415                          */
416                         return;
417                 }
418                 eptr = eptr->next;
419         }
420
421         if ( eptr == NULL )
422         {
423                 /* Oops - failed to find the buffer. This is BAD */
424                 eup->eu_stats.eni_st_drv.drv_mm_notfnd++;
425         }
426
427 }
428