OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [scsi/] [scsi_dma.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  scsi_dma.c Copyright (C) 2000 Eric Youngdale
3
 *
4
 *  mid-level SCSI DMA bounce buffer allocator
5
 *
6
 */
7
 
8
#define __NO_VERSION__
9
#include <linux/config.h>
10
#include <linux/module.h>
11
#include <linux/blk.h>
12
 
13
 
14
#include "scsi.h"
15
#include "hosts.h"
16
#include "constants.h"
17
 
18
#ifdef CONFIG_KMOD
19
#include <linux/kmod.h>
20
#endif
21
 
22
/*
23
 * PAGE_SIZE must be a multiple of the sector size (512).  True
24
 * for all reasonably recent architectures (even the VAX...).
25
 */
26
#define SECTOR_SIZE             512
27
#define SECTORS_PER_PAGE        (PAGE_SIZE/SECTOR_SIZE)
28
 
29
#if SECTORS_PER_PAGE <= 8
30
typedef unsigned char FreeSectorBitmap;
31
#elif SECTORS_PER_PAGE <= 32
32
typedef unsigned int FreeSectorBitmap;
33
#else
34
#error You lose.
35
#endif
36
 
37
/*
38
 * Used for access to internal allocator used for DMA safe buffers.
39
 */
40
static spinlock_t allocator_request_lock = SPIN_LOCK_UNLOCKED;
41
 
42
static FreeSectorBitmap *dma_malloc_freelist = NULL;
43
static int need_isa_bounce_buffers;
44
static unsigned int dma_sectors = 0;
45
unsigned int scsi_dma_free_sectors = 0;
46
unsigned int scsi_need_isa_buffer = 0;
47
static unsigned char **dma_malloc_pages = NULL;
48
 
49
/*
50
 * Function:    scsi_malloc
51
 *
52
 * Purpose:     Allocate memory from the DMA-safe pool.
53
 *
54
 * Arguments:   len       - amount of memory we need.
55
 *
56
 * Lock status: No locks assumed to be held.  This function is SMP-safe.
57
 *
58
 * Returns:     Pointer to memory block.
59
 *
60
 * Notes:       Prior to the new queue code, this function was not SMP-safe.
61
 *              This function can only allocate in units of sectors
62
 *              (i.e. 512 bytes).
63
 *
64
 *              We cannot use the normal system allocator becuase we need
65
 *              to be able to guarantee that we can process a complete disk
66
 *              I/O request without touching the system allocator.  Think
67
 *              about it - if the system were heavily swapping, and tried to
68
 *              write out a block of memory to disk, and the SCSI code needed
69
 *              to allocate more memory in order to be able to write the
70
 *              data to disk, you would wedge the system.
71
 */
72
void *scsi_malloc(unsigned int len)
73
{
74
        unsigned int nbits, mask;
75
        unsigned long flags;
76
 
77
        int i, j;
78
        if (len % SECTOR_SIZE != 0 || len > PAGE_SIZE)
79
                return NULL;
80
 
81
        nbits = len >> 9;
82
        mask = (1 << nbits) - 1;
83
 
84
        spin_lock_irqsave(&allocator_request_lock, flags);
85
 
86
        for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
87
                for (j = 0; j <= SECTORS_PER_PAGE - nbits; j++) {
88
                        if ((dma_malloc_freelist[i] & (mask << j)) == 0) {
89
                                dma_malloc_freelist[i] |= (mask << j);
90
                                scsi_dma_free_sectors -= nbits;
91
#ifdef DEBUG
92
                                SCSI_LOG_MLQUEUE(3, printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9)));
93
                                printk("SMalloc: %d %p [From:%p]\n", len, dma_malloc_pages[i] + (j << 9));
94
#endif
95
                                spin_unlock_irqrestore(&allocator_request_lock, flags);
96
                                return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
97
                        }
98
                }
99
        spin_unlock_irqrestore(&allocator_request_lock, flags);
100
        return NULL;            /* Nope.  No more */
101
}
102
 
103
/*
104
 * Function:    scsi_free
105
 *
106
 * Purpose:     Free memory into the DMA-safe pool.
107
 *
108
 * Arguments:   ptr       - data block we are freeing.
109
 *              len       - size of block we are freeing.
110
 *
111
 * Lock status: No locks assumed to be held.  This function is SMP-safe.
112
 *
113
 * Returns:     Nothing
114
 *
115
 * Notes:       This function *must* only be used to free memory
116
 *              allocated from scsi_malloc().
117
 *
118
 *              Prior to the new queue code, this function was not SMP-safe.
119
 *              This function can only allocate in units of sectors
120
 *              (i.e. 512 bytes).
121
 */
122
int scsi_free(void *obj, unsigned int len)
123
{
124
        unsigned int page, sector, nbits, mask;
125
        unsigned long flags;
126
 
127
#ifdef DEBUG
128
        unsigned long ret = 0;
129
 
130
#ifdef __mips__
131
        __asm__ __volatile__("move\t%0,$31":"=r"(ret));
132
#else
133
        ret = __builtin_return_address(0);
134
#endif
135
        printk("scsi_free %p %d\n", obj, len);
136
        SCSI_LOG_MLQUEUE(3, printk("SFree: %p %d\n", obj, len));
137
#endif
138
 
139
        spin_lock_irqsave(&allocator_request_lock, flags);
140
 
141
        for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
142
                unsigned long page_addr = (unsigned long) dma_malloc_pages[page];
143
                if ((unsigned long) obj >= page_addr &&
144
                    (unsigned long) obj < page_addr + PAGE_SIZE) {
145
                        sector = (((unsigned long) obj) - page_addr) >> 9;
146
 
147
                        nbits = len >> 9;
148
                        mask = (1 << nbits) - 1;
149
 
150
                        if (sector + nbits > SECTORS_PER_PAGE)
151
                                panic("scsi_free:Bad memory alignment");
152
 
153
                        if ((dma_malloc_freelist[page] &
154
                             (mask << sector)) != (mask << sector)) {
155
#ifdef DEBUG
156
                                printk("scsi_free(obj=%p, len=%d) called from %08lx\n",
157
                                       obj, len, ret);
158
#endif
159
                                panic("scsi_free:Trying to free unused memory");
160
                        }
161
                        scsi_dma_free_sectors += nbits;
162
                        dma_malloc_freelist[page] &= ~(mask << sector);
163
                        spin_unlock_irqrestore(&allocator_request_lock, flags);
164
                        return 0;
165
                }
166
        }
167
        panic("scsi_free:Bad offset");
168
}
169
 
170
 
171
/*
172
 * Function:    scsi_resize_dma_pool
173
 *
174
 * Purpose:     Ensure that the DMA pool is sufficiently large to be
175
 *              able to guarantee that we can always process I/O requests
176
 *              without calling the system allocator.
177
 *
178
 * Arguments:   None.
179
 *
180
 * Lock status: No locks assumed to be held.  This function is SMP-safe.
181
 *
182
 * Returns:     Nothing
183
 *
184
 * Notes:       Prior to the new queue code, this function was not SMP-safe.
185
 *              Go through the device list and recompute the most appropriate
186
 *              size for the dma pool.  Then grab more memory (as required).
187
 */
188
void scsi_resize_dma_pool(void)
189
{
190
        int i, k;
191
        unsigned long size;
192
        unsigned long flags;
193
        struct Scsi_Host *shpnt;
194
        struct Scsi_Host *host = NULL;
195
        Scsi_Device *SDpnt;
196
        FreeSectorBitmap *new_dma_malloc_freelist = NULL;
197
        unsigned int new_dma_sectors = 0;
198
        unsigned int new_need_isa_buffer = 0;
199
        unsigned char **new_dma_malloc_pages = NULL;
200
        int out_of_space = 0;
201
 
202
        spin_lock_irqsave(&allocator_request_lock, flags);
203
 
204
        if (!scsi_hostlist) {
205
                /*
206
                 * Free up the DMA pool.
207
                 */
208
                if (scsi_dma_free_sectors != dma_sectors)
209
                        panic("SCSI DMA pool memory leak %d %d\n", scsi_dma_free_sectors, dma_sectors);
210
 
211
                for (i = 0; i < dma_sectors / SECTORS_PER_PAGE; i++)
212
                        free_pages((unsigned long) dma_malloc_pages[i], 0);
213
                if (dma_malloc_pages)
214
                        kfree((char *) dma_malloc_pages);
215
                dma_malloc_pages = NULL;
216
                if (dma_malloc_freelist)
217
                        kfree((char *) dma_malloc_freelist);
218
                dma_malloc_freelist = NULL;
219
                dma_sectors = 0;
220
                scsi_dma_free_sectors = 0;
221
                spin_unlock_irqrestore(&allocator_request_lock, flags);
222
                return;
223
        }
224
        /* Next, check to see if we need to extend the DMA buffer pool */
225
 
226
        new_dma_sectors = 2 * SECTORS_PER_PAGE;         /* Base value we use */
227
 
228
        if (__pa(high_memory) - 1 > ISA_DMA_THRESHOLD)
229
                need_isa_bounce_buffers = 1;
230
        else
231
                need_isa_bounce_buffers = 0;
232
 
233
        if (scsi_devicelist)
234
                for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
235
                        new_dma_sectors += SECTORS_PER_PAGE;    /* Increment for each host */
236
 
237
        for (host = scsi_hostlist; host; host = host->next) {
238
                for (SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next) {
239
                        /*
240
                         * sd and sr drivers allocate scatterlists.
241
                         * sr drivers may allocate for each command 1x2048 or 2x1024 extra
242
                         * buffers for 2k sector size and 1k fs.
243
                         * sg driver allocates buffers < 4k.
244
                         * st driver does not need buffers from the dma pool.
245
                         * estimate 4k buffer/command for devices of unknown type (should panic).
246
                         */
247
                        if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
248
                            SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
249
                                int nents = host->sg_tablesize;
250
#ifdef DMA_CHUNK_SIZE
251
                                /* If the architecture does DMA sg merging, make sure
252
                                   we count with at least 64 entries even for HBAs
253
                                   which handle very few sg entries.  */
254
                                if (nents < 64) nents = 64;
255
#endif
256
                                new_dma_sectors += ((nents *
257
                                sizeof(struct scatterlist) + 511) >> 9) *
258
                                 SDpnt->queue_depth;
259
                                if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
260
                                        new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
261
                        } else if (SDpnt->type == TYPE_SCANNER ||
262
                                   SDpnt->type == TYPE_PRINTER ||
263
                                   SDpnt->type == TYPE_PROCESSOR ||
264
                                   SDpnt->type == TYPE_COMM ||
265
                                   SDpnt->type == TYPE_MEDIUM_CHANGER ||
266
                                   SDpnt->type == TYPE_ENCLOSURE) {
267
                                new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
268
                        } else {
269
                                if (SDpnt->type != TYPE_TAPE) {
270
                                        printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
271
                                        new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
272
                                }
273
                        }
274
 
275
                        if (host->unchecked_isa_dma &&
276
                            need_isa_bounce_buffers &&
277
                            SDpnt->type != TYPE_TAPE) {
278
                                new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
279
                                    SDpnt->queue_depth;
280
                                new_need_isa_buffer++;
281
                        }
282
                }
283
        }
284
 
285
#ifdef DEBUG_INIT
286
        printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors);
287
#endif
288
 
289
        /* limit DMA memory to 32MB: */
290
        new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
291
 
292
        /*
293
         * We never shrink the buffers - this leads to
294
         * race conditions that I would rather not even think
295
         * about right now.
296
         */
297
#if 0                           /* Why do this? No gain and risks out_of_space */
298
        if (new_dma_sectors < dma_sectors)
299
                new_dma_sectors = dma_sectors;
300
#endif
301
        if (new_dma_sectors <= dma_sectors) {
302
                spin_unlock_irqrestore(&allocator_request_lock, flags);
303
                return;         /* best to quit while we are in front */
304
        }
305
 
306
        for (k = 0; k < 20; ++k) {       /* just in case */
307
                out_of_space = 0;
308
                size = (new_dma_sectors / SECTORS_PER_PAGE) *
309
                    sizeof(FreeSectorBitmap);
310
                new_dma_malloc_freelist = (FreeSectorBitmap *)
311
                    kmalloc(size, GFP_ATOMIC);
312
                if (new_dma_malloc_freelist) {
313
                        memset(new_dma_malloc_freelist, 0, size);
314
                        size = (new_dma_sectors / SECTORS_PER_PAGE) *
315
                            sizeof(*new_dma_malloc_pages);
316
                        new_dma_malloc_pages = (unsigned char **)
317
                            kmalloc(size, GFP_ATOMIC);
318
                        if (!new_dma_malloc_pages) {
319
                                size = (new_dma_sectors / SECTORS_PER_PAGE) *
320
                                    sizeof(FreeSectorBitmap);
321
                                kfree((char *) new_dma_malloc_freelist);
322
                                out_of_space = 1;
323
                        } else {
324
                                memset(new_dma_malloc_pages, 0, size);
325
                        }
326
                } else
327
                        out_of_space = 1;
328
 
329
                if ((!out_of_space) && (new_dma_sectors > dma_sectors)) {
330
                        for (i = dma_sectors / SECTORS_PER_PAGE;
331
                           i < new_dma_sectors / SECTORS_PER_PAGE; i++) {
332
                                new_dma_malloc_pages[i] = (unsigned char *)
333
                                    __get_free_pages(GFP_ATOMIC | GFP_DMA, 0);
334
                                if (!new_dma_malloc_pages[i])
335
                                        break;
336
                        }
337
                        if (i != new_dma_sectors / SECTORS_PER_PAGE) {  /* clean up */
338
                                int k = i;
339
 
340
                                out_of_space = 1;
341
                                for (i = 0; i < k; ++i)
342
                                        free_pages((unsigned long) new_dma_malloc_pages[i], 0);
343
                        }
344
                }
345
                if (out_of_space) {     /* try scaling down new_dma_sectors request */
346
                        printk("scsi::resize_dma_pool: WARNING, dma_sectors=%u, "
347
                               "wanted=%u, scaling\n", dma_sectors, new_dma_sectors);
348
                        if (new_dma_sectors < (8 * SECTORS_PER_PAGE))
349
                                break;  /* pretty well hopeless ... */
350
                        new_dma_sectors = (new_dma_sectors * 3) / 4;
351
                        new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
352
                        if (new_dma_sectors <= dma_sectors)
353
                                break;  /* stick with what we have got */
354
                } else
355
                        break;  /* found space ... */
356
        }                       /* end of for loop */
357
        if (out_of_space) {
358
                spin_unlock_irqrestore(&allocator_request_lock, flags);
359
                scsi_need_isa_buffer = new_need_isa_buffer;     /* some useful info */
360
                printk("      WARNING, not enough memory, pool not expanded\n");
361
                return;
362
        }
363
        /* When we dick with the actual DMA list, we need to
364
         * protect things
365
         */
366
        if (dma_malloc_freelist) {
367
                size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
368
                memcpy(new_dma_malloc_freelist, dma_malloc_freelist, size);
369
                kfree((char *) dma_malloc_freelist);
370
        }
371
        dma_malloc_freelist = new_dma_malloc_freelist;
372
 
373
        if (dma_malloc_pages) {
374
                size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages);
375
                memcpy(new_dma_malloc_pages, dma_malloc_pages, size);
376
                kfree((char *) dma_malloc_pages);
377
        }
378
        scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
379
        dma_malloc_pages = new_dma_malloc_pages;
380
        dma_sectors = new_dma_sectors;
381
        scsi_need_isa_buffer = new_need_isa_buffer;
382
 
383
        spin_unlock_irqrestore(&allocator_request_lock, flags);
384
 
385
#ifdef DEBUG_INIT
386
        printk("resize_dma_pool: dma free sectors   = %d\n", scsi_dma_free_sectors);
387
        printk("resize_dma_pool: dma sectors        = %d\n", dma_sectors);
388
        printk("resize_dma_pool: need isa buffers   = %d\n", scsi_need_isa_buffer);
389
#endif
390
}
391
 
392
/*
393
 * Function:    scsi_init_minimal_dma_pool
394
 *
395
 * Purpose:     Allocate a minimal (1-page) DMA pool.
396
 *
397
 * Arguments:   None.
398
 *
399
 * Lock status: No locks assumed to be held.  This function is SMP-safe.
400
 *
401
 * Returns:     Nothing
402
 *
403
 * Notes:
404
 */
405
int scsi_init_minimal_dma_pool(void)
406
{
407
        unsigned long size;
408
        unsigned long flags;
409
        int has_space = 0;
410
 
411
        spin_lock_irqsave(&allocator_request_lock, flags);
412
 
413
        dma_sectors = PAGE_SIZE / SECTOR_SIZE;
414
        scsi_dma_free_sectors = dma_sectors;
415
        /*
416
         * Set up a minimal DMA buffer list - this will be used during scan_scsis
417
         * in some cases.
418
         */
419
 
420
        /* One bit per sector to indicate free/busy */
421
        size = (dma_sectors / SECTORS_PER_PAGE) * sizeof(FreeSectorBitmap);
422
        dma_malloc_freelist = (FreeSectorBitmap *)
423
            kmalloc(size, GFP_ATOMIC);
424
        if (dma_malloc_freelist) {
425
                memset(dma_malloc_freelist, 0, size);
426
                /* One pointer per page for the page list */
427
                dma_malloc_pages = (unsigned char **) kmalloc(
428
                        (dma_sectors / SECTORS_PER_PAGE) * sizeof(*dma_malloc_pages),
429
                                                             GFP_ATOMIC);
430
                if (dma_malloc_pages) {
431
                        memset(dma_malloc_pages, 0, size);
432
                        dma_malloc_pages[0] = (unsigned char *)
433
                            __get_free_pages(GFP_ATOMIC | GFP_DMA, 0);
434
                        if (dma_malloc_pages[0])
435
                                has_space = 1;
436
                }
437
        }
438
        if (!has_space) {
439
                if (dma_malloc_freelist) {
440
                        kfree((char *) dma_malloc_freelist);
441
                        if (dma_malloc_pages)
442
                                kfree((char *) dma_malloc_pages);
443
                }
444
                spin_unlock_irqrestore(&allocator_request_lock, flags);
445
                printk("scsi::init_module: failed, out of memory\n");
446
                return 1;
447
        }
448
 
449
        spin_unlock_irqrestore(&allocator_request_lock, flags);
450
        return 0;
451
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.