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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [s390/] [block/] [xpram.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
 
2
/*
3
 * Xpram.c -- the S/390 expanded memory RAM-disk
4
 *
5
 * significant parts of this code are based on
6
 * the sbull device driver presented in
7
 * A. Rubini: Linux Device Drivers
8
 *
9
 * Author of XPRAM specific coding: Reinhard Buendgen
10
 *                                  buendgen@de.ibm.com
11
 *
12
 * External interfaces:
13
 *   Interfaces to linux kernel
14
 *        xpram_setup: read kernel parameters   (see init/main.c)
15
 *        xpram_init:  initialize device driver (see drivers/block/ll_rw_blk.c)
16
 *   Module interfaces
17
 *        init_module
18
 *        cleanup_module
19
 *   Device specific file operations
20
 *        xpram_iotcl
21
 *        xpram_open
22
 *        xpram_release
23
 *
24
 * "ad-hoc" partitioning:
25
 *    the expanded memory can be partitioned among several devices
26
 *    (with different minors). The partitioning set up can be
27
 *    set by kernel or module parameters (int devs & int sizes[])
28
 *
29
 *    module parameters: devs= and sizes=
30
 *    kernel parameters: xpram_parts=
31
 *      note: I did not succeed in parsing numbers
32
 *            for module parameters of type string "s" ?!?
33
 *
34
 * Other kenel files/modules affected(gerp for "xpram" or "XPRAM":
35
 *    drivers/s390/Config.in
36
 *    drivers/s390/block/Makefile
37
 *    include/linux/blk.h
38
 *    include/linux/major.h
39
 *    init/main.c
40
 *    drivers/block//ll_rw_blk.c
41
 *
42
 *
43
 * Potential future improvements:
44
 *   request clustering: first coding started not yet tested or integrated
45
 *                       I doubt that it really pays off
46
 *   generic hard disk support to replace ad-hoc partitioning
47
 *
48
 * Tested with 2.2.14 (under VM)
49
 */
50
 
51
#ifdef MODULE
52
#  ifndef __KERNEL__
53
#    define __KERNEL__
54
#  endif
55
#  define __NO_VERSION__ /* don't define kernel_version in module.h */
56
#endif /* MODULE */
57
 
58
#include <linux/module.h>
59
#include <linux/version.h>
60
 
61
#ifdef MODULE
62
char kernel_version [] = UTS_RELEASE;
63
#endif
64
 
65
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
66
#  define XPRAM_VERSION 24
67
#else
68
#  define XPRAM_VERSION 22
69
#endif 
70
 
71
#if (XPRAM_VERSION == 24)
72
#  include <linux/config.h>
73
#  include <linux/init.h>
74
#endif /* V24 */
75
#include <linux/sched.h>
76
#include <linux/kernel.h> /* printk() */
77
#include <linux/slab.h> /* kmalloc() */
78
#if (XPRAM_VERSION == 24)
79
#  include <linux/devfs_fs_kernel.h>
80
#endif /* V24 */
81
#include <linux/fs.h>     /* everything... */
82
#include <linux/errno.h>  /* error codes */
83
#include <linux/timer.h>
84
#include <linux/types.h>  /* size_t */
85
#include <linux/ctype.h>  /* isdigit, isxdigit */
86
#include <linux/fcntl.h>  /* O_ACCMODE */
87
#include <linux/hdreg.h>  /* HDIO_GETGEO */
88
 
89
#include <asm/system.h>   /* cli(), *_flags */
90
#include <asm/uaccess.h>  /* put_user */
91
 
92
#if (XPRAM_VERSION == 24)
93
#define MAJOR_NR xpram_major /* force definitions on in blk.h */
94
int xpram_major;   /* must be declared before including blk.h */
95
devfs_handle_t xpram_devfs_handle;
96
 
97
#define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
98
#define DEVICE_NAME "xpram"               /* name for messaging */
99
#define DEVICE_INTR xpram_intrptr         /* pointer to the bottom half */
100
#define DEVICE_NO_RANDOM                  /* no entropy to contribute */
101
#define DEVICE_OFF(d)                     /* do-nothing */
102
 
103
#include <linux/blk.h>
104
 
105
#include "xpram.h"        /* local definitions */
106
 
107
__setup("xpram_parts=", xpram_setup);
108
#endif /* V24 */
109
 
110
/*
111
   define the debug levels:
112
   - 0 No debugging output to console or syslog
113
   - 1 Log internal errors to syslog, ignore check conditions
114
   - 2 Log internal errors and check conditions to syslog
115
   - 3 Log internal errors to console, log check conditions to syslog
116
   - 4 Log internal errors and check conditions to console
117
   - 5 panic on internal errors, log check conditions to console
118
   - 6 panic on both, internal errors and check conditions
119
 */
120
#define XPRAM_DEBUG 4
121
 
122
#define PRINTK_HEADER XPRAM_NAME
123
 
124
#if XPRAM_DEBUG > 0
125
#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x )
126
#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER "info:" x )
127
#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER "warning:" x )
128
#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER "error:" x )
129
#define PRINT_FATAL(x...) panic ( PRINTK_HEADER "panic:"x )
130
#else
131
#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:"  x )
132
#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER "info:" x )
133
#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER "warning:" x )
134
#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER "error:" x )
135
#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER "panic:" x )
136
#endif  
137
 
138
#if (XPRAM_VERSION == 22)
139
#define MAJOR_NR xpram_major /* force definitions on in blk.h */
140
int xpram_major;   /* must be declared before including blk.h */
141
 
142
#define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
143
#define DEVICE_NAME "xpram"               /* name for messaging */
144
#define DEVICE_INTR xpram_intrptr         /* pointer to the bottom half */
145
#define DEVICE_NO_RANDOM                  /* no entropy to contribute */
146
 
147
 
148
#define DEVICE_OFF(d) /* do-nothing */
149
 
150
#define DEVICE_REQUEST *xpram_dummy_device_request  /* dummy function variable 
151
                                                     * to prevent warnings
152
                                                     */#include <linux/blk.h>
153
 
154
#include "xpram.h"        /* local definitions */
155
#endif /* V22 */
156
 
157
/*
158
 * Non-prefixed symbols are static. They are meant to be assigned at
159
 * load time. Prefixed symbols are not static, so they can be used in
160
 * debugging. They are hidden anyways by register_symtab() unless
161
 * XPRAM_DEBUG is defined.
162
 */
163
 
164
static int major    = XPRAM_MAJOR;
165
static int devs     = XPRAM_DEVS;
166
static int rahead   = XPRAM_RAHEAD;
167
static int sizes[XPRAM_MAX_DEVS] = { 0, };
168
static int blksize  = XPRAM_BLKSIZE;
169
static int hardsect = XPRAM_HARDSECT;
170
 
171
int xpram_devs, xpram_rahead;
172
int xpram_blksize, xpram_hardsect;
173
int xpram_mem_avail = 0;
174
unsigned int xpram_sizes[XPRAM_MAX_DEVS];
175
 
176
 
177
MODULE_PARM(devs,"i");
178
MODULE_PARM(sizes,"1-" __MODULE_STRING(XPRAM_MAX_DEVS) "i");
179
 
180
MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \
181
                 "the default is " __MODULE_STRING(XPRAM_DEVS) "\n");
182
MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \
183
                 "the defaults are 0s \n" \
184
                 "All devices with size 0 equally partition the "
185
                 "remaining space on the expanded strorage not "
186
                 "claimed by explicit sizes\n");
187
MODULE_LICENSE("GPL");
188
 
189
 
190
/* The following items are obtained through kmalloc() in init_module() */
191
 
192
Xpram_Dev *xpram_devices = NULL;
193
int *xpram_blksizes = NULL;
194
int *xpram_hardsects = NULL;
195
int *xpram_offsets = NULL;   /* partition offsets */
196
 
197
#define MIN(x,y) ((x) < (y) ? (x) : (y))
198
#define MAX(x,y) ((x) > (y) ? (x) : (y))
199
 
200
/*
201
 *              compute nearest multiple of 4 , argument must be non-negative
202
 *              the macros used depends on XPRAM_KB_IN_PG = 4
203
 */
204
 
205
#define NEXT4(x) ((x & 0x3) ? (x+4-(x &0x3)) : (x))   /* increment if needed */
206
#define LAST4(x) ((x & 0x3) ? (x-4+(x & 0x3)) : (x))  /* decrement if needed */
207
 
208
#if 0               /* this is probably not faster than the previous code */
209
#define NEXT4(x)   ((((x-1)>>2)>>2)+4)             /* increment if needed */
210
#define LAST4(x)   (((x+3)>>2)<<2)                 /* decrement if needed */
211
#endif
212
 
213
/* integer formats */
214
#define XPRAM_INVALF -1    /* invalid     */
215
#define XPRAM_HEXF    0    /* hexadecimal */
216
#define XPRAM_DECF    1    /* decimal     */
217
 
218
/*
219
 *    parsing operations (needed for kernel parameter parsing)
220
 */
221
 
222
/* -------------------------------------------------------------------------
223
 * sets the string pointer after the next comma
224
 *
225
 * argument:    strptr pointer to string
226
 * side effect: strptr points to endof string or to position of the next
227
 *              comma
228
 * ------------------------------------------------------------------------*/
229
static void
230
xpram_scan_to_next_comma (char **strptr)
231
{
232
        while ( ((**strptr) != ',') && (**strptr) )
233
                (*strptr)++;
234
}
235
 
236
/* -------------------------------------------------------------------------
237
 * interpret character as hex-digit
238
 *
239
 * argument: c charcter
240
 * result: c interpreted as hex-digit
241
 * note: can be used to read digits for any base <= 16
242
 * ------------------------------------------------------------------------*/
243
static int
244
xpram_get_hexdigit (char c)
245
{
246
        if ((c >= '0') && (c <= '9'))
247
                return c - '0';
248
        if ((c >= 'a') && (c <= 'f'))
249
                return c + 10 - 'a';
250
        if ((c >= 'A') && (c <= 'F'))
251
                return c + 10 - 'A';
252
        return -1;
253
}
254
 
255
/*--------------------------------------------------------------------------
256
 * Check format of unsigned integer
257
 *
258
 * Argument: strptr pointer to string
259
 * result:   -1 if strptr does not start with a digit
260
 *                (does not start an integer)
261
 *           0  if strptr starts a positive hex-integer with "0x"
262
 *           1  if strptr start a positive decimal integer
263
 *
264
 * side effect: if strptr start a positive hex-integer then strptr is
265
 *              set to the character after the "0x"
266
 *-------------------------------------------------------------------------*/
267
static int
268
xpram_int_format(char **strptr)
269
{
270
        if ( !isdigit(**strptr) )
271
                return XPRAM_INVALF;
272
        if ( (**strptr == '0')
273
             && ( (*((*strptr)+1) == 'x') || (*((*strptr) +1) == 'X') )
274
             && isxdigit(*((*strptr)+2)) ) {
275
                *strptr=(*strptr)+2;
276
                return XPRAM_HEXF;
277
        } else return XPRAM_DECF;
278
}
279
 
280
/*--------------------------------------------------------------------------
281
 * Read non-negative decimal integer
282
 *
283
 * Argument: strptr pointer to string starting with a non-negative integer
284
 *           in decimal format
285
 * result:   the value of theinitial integer pointed to by strptr
286
 *
287
 * side effect: strptr is set to the first character following the integer
288
 *-------------------------------------------------------------------------*/
289
 
290
static int
291
xpram_read_decint (char ** strptr)
292
{
293
        int res=0;
294
        while ( isdigit(**strptr) ) {
295
                res = (res*10) + xpram_get_hexdigit(**strptr);
296
                (*strptr)++;
297
        }
298
        return res;
299
}
300
 
301
/*--------------------------------------------------------------------------
302
 * Read non-negative hex-integer
303
 *
304
 * Argument: strptr pointer to string starting with a non-negative integer
305
 *           in hexformat (without "0x" prefix)
306
 * result:   the value of the initial integer pointed to by strptr
307
 *
308
 * side effect: strptr is set to the first character following the integer
309
 *-------------------------------------------------------------------------*/
310
 
311
static int
312
xpram_read_hexint (char ** strptr)
313
{
314
        int res=0;
315
        while ( isxdigit(**strptr) ) {
316
                res = (res<<4) + xpram_get_hexdigit(**strptr);
317
                (*strptr)++;
318
        }
319
        return res;
320
}
321
/*--------------------------------------------------------------------------
322
 * Read non-negative integer
323
 *
324
 * Argument: strptr pointer to string starting with a non-negative integer
325
             (either in decimal- or in hex-format
326
 * result:   the value of the initial integer pointed to by strptr
327
 *           in case of a parsing error the result is -EINVAL
328
 *
329
 * side effect: strptr is set to the first character following the integer
330
 *-------------------------------------------------------------------------*/
331
 
332
static int
333
xpram_read_int (char ** strptr)
334
{
335
        switch (  xpram_int_format(strptr) ) {
336
        case XPRAM_INVALF: return -EINVAL;
337
        case XPRAM_HEXF:   return xpram_read_hexint(strptr);
338
        case XPRAM_DECF:   return xpram_read_decint(strptr);
339
        default: return -EINVAL;
340
        }
341
}
342
 
343
/*--------------------------------------------------------------------------
344
 * Read size
345
 *
346
 * Argument: strptr pointer to string starting with a non-negative integer
347
 *           followed optionally by a size modifier:
348
 *             k or K for kilo (default),
349
 *             m or M for mega
350
 *             g or G for giga
351
 * result:   the value of the initial integer pointed to by strptr
352
 *           multiplied by the modifier value devided by 1024
353
 *           in case of a parsing error the result is -EINVAL
354
 *
355
 * side effect: strptr is set to the first character following the size
356
 *-------------------------------------------------------------------------*/
357
 
358
static int
359
xpram_read_size (char ** strptr)
360
{
361
        int res;
362
 
363
        res=xpram_read_int(strptr);
364
        if ( res < 0 )return res;
365
        switch ( **strptr ) {
366
        case 'g':
367
        case 'G': res=res*1024;
368
        case 'm':
369
        case 'M': res=res*1024;
370
        case 'k' :
371
        case 'K' : (* strptr)++;
372
        }
373
 
374
        return res;
375
}
376
 
377
 
378
/*--------------------------------------------------------------------------
379
 * Read tail of comma separated size list  ",i1,i2,...,in"
380
 *
381
 * Arguments:strptr pointer to string. It is assumed that the string has
382
 *                  the format (","<size>)*
383
 *           maxl integer describing the maximal number of elements in the
384
                  list pointed to by strptr, max must be > 0.
385
 *           ilist array of dimension >= maxl of integers to be modified
386
 *
387
 * result:   -EINVAL if the list is longer than maxl
388
 *           0 otherwise
389
 *
390
 * side effects: for j=1,...,n ilist[ij] is set to the value of ij if it is
391
 *               a valid non-negative integer and to -EINVAL otherwise
392
 *               if no comma is found where it is expected an entry in
393
 *               ilist is set to -EINVAL
394
 *-------------------------------------------------------------------------*/
395
static int
396
xpram_read_size_list_tail (char ** strptr, int maxl, int * ilist)
397
{
398
        int i=0;
399
        char *str = *strptr;
400
        int res=0;
401
 
402
        while ( (*str == ',') && (i < maxl) ) {
403
                str++;
404
                ilist[i] = xpram_read_size(&str);
405
                if ( ilist[i] == -EINVAL ) {
406
                        xpram_scan_to_next_comma(&str);
407
                        res = -EINVAL;
408
                }
409
                i++;
410
        }
411
        return res;
412
#if 0  /* be lenient about trailing stuff */
413
        if ( *str != 0 && *str != ' ' ) {
414
                ilist[MAX(i-1,0)] = -EINVAL;
415
                return -EINVAL;
416
        } else return 0;
417
#endif
418
}
419
 
420
 
421
/*
422
 *   expanded memory operations
423
 */
424
 
425
 
426
/*--------------------------------------------------------------------*/
427
/* Copy expanded memory page (4kB) into main memory                   */
428
/* Arguments                                                          */
429
/*           page_addr:    address of target page                     */
430
/*           xpage_index:  index of expandeded memory page            */
431
/* Return value                                                       */
432
/*           0:            if operation succeeds                      */
433
/*           non-0:       otherwise                                   */
434
/*--------------------------------------------------------------------*/
435
long xpram_page_in (unsigned long page_addr, unsigned long xpage_index)
436
{
437
        int cc=0;
438
        unsigned long real_page_addr = __pa(page_addr);
439
#ifndef CONFIG_ARCH_S390X
440
        __asm__ __volatile__ (
441
                "   lr  1,%1         \n"   /* r1 = real_page_addr            */
442
                "   lr  2,%2         \n"   /* r2 = xpage_index               */
443
                "   .long 0xb22e0012 \n"   /* pgin r1,r2                     */
444
                /* copy page from expanded memory */
445
                "0: ipm  %0          \n"   /* save status (cc & program mask */
446
                "   srl  %0,28       \n"   /* cc into least significant bits */
447
                "1:                  \n"   /* we are done                    */
448
                ".section .fixup,\"ax\"\n" /* start of fix up section        */
449
                "2: lhi    %0,2      \n"   /* return unused condition code 2 */
450
                "   bras 1,3f        \n"   /* safe label 1: in r1 and goto 3 */
451
                "   .long 1b         \n"   /* literal containing label 1     */
452
                "3: l    1,0(1)      \n"   /* load label 1 address into r1   */
453
                "   br   1           \n"   /* goto label 1 (across sections) */
454
                ".previous           \n"   /* back in text section           */
455
                ".section __ex_table,\"a\"\n" /* start __extable             */
456
                "   .align 4         \n"
457
                "   .long 0b,2b      \n"   /* failure point 0, fixup code 2  */
458
                ".previous           \n"
459
                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
460
                );
461
#else /* CONFIG_ARCH_S390X */
462
        __asm__ __volatile__ (
463
                "   lgr  1,%1        \n"   /* r1 = real_page_addr            */
464
                "   lgr  2,%2        \n"   /* r2 = xpage_index               */
465
                "   .long 0xb22e0012 \n"   /* pgin r1,r2                     */
466
                /* copy page from expanded memory */
467
                "0: ipm  %0          \n"   /* save status (cc & program mask */
468
                "   srl  %0,28       \n"   /* cc into least significant bits */
469
                "1:                  \n"   /* we are done                    */
470
                ".section .fixup,\"ax\"\n" /* start of fix up section        */
471
                "2: lghi %0,2        \n"   /* return unused condition code 2 */
472
                "   jg   1b          \n"   /* goto label 1 above             */
473
                ".previous           \n"   /* back in text section           */
474
                ".section __ex_table,\"a\"\n" /* start __extable             */
475
                "   .align 8         \n"
476
                "   .quad 0b,2b      \n"   /* failure point 0, fixup code 2  */
477
                ".previous           \n"
478
                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
479
                );
480
#endif /* CONFIG_ARCH_S390X */
481
        switch (cc) {
482
        case 0: return 0;
483
        case 1: return -EIO;
484
        case 2: return -ENXIO;
485
        case 3: return -ENXIO;
486
        default: return -EIO;  /* should not happen */
487
        };
488
}
489
 
490
/*--------------------------------------------------------------------*/
491
/* Copy a 4kB page of main memory to an expanded memory page          */
492
/* Arguments                                                          */
493
/*           page_addr:    address of source page                     */
494
/*           xpage_index:  index of expandeded memory page            */
495
/* Return value                                                       */
496
/*           0:            if operation succeeds                      */
497
/*           non-0:        otherwise                                  */
498
/*--------------------------------------------------------------------*/
499
long xpram_page_out (unsigned long page_addr, unsigned long xpage_index)
500
{
501
        int cc=0;
502
        unsigned long real_page_addr = __pa(page_addr);
503
#ifndef CONFIG_ARCH_S390X
504
        __asm__ __volatile__ (
505
                "  lr  1,%1        \n"   /* r1 = mem_page                  */
506
                "  lr  2,%2        \n"   /* r2 = rpi                       */
507
                " .long 0xb22f0012 \n"   /* pgout r1,r2                    */
508
                                /* copy page from expanded memory */
509
                "0: ipm  %0        \n"   /* save status (cc & program mask */
510
                " srl  %0,28       \n"   /* cc into least significant bits */
511
                "1:                  \n"   /* we are done                    */
512
                ".section .fixup,\"ax\"\n" /* start of fix up section        */
513
                "2: lhi   %0,2       \n"   /* return unused condition code 2 */
514
                "   bras 1,3f        \n"   /* safe label 1: in r1 and goto 3 */
515
                "   .long 1b         \n"   /* literal containing label 1     */
516
                "3: l    1,0(1)      \n"   /* load label 1 address into r1   */
517
                "   br   1           \n"   /* goto label 1 (across sections) */
518
                ".previous           \n"   /* back in text section           */
519
                ".section __ex_table,\"a\"\n" /* start __extable             */
520
                "   .align 4         \n"
521
                "   .long 0b,2b      \n"   /* failure point 0, fixup code 2  */
522
                ".previous           \n"
523
                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
524
                );
525
#else /* CONFIG_ARCH_S390X */
526
        __asm__ __volatile__ (
527
                "  lgr  1,%1       \n"   /* r1 = mem_page                  */
528
                "  lgr  2,%2       \n"   /* r2 = rpi                       */
529
                " .long 0xb22f0012 \n"   /* pgout r1,r2                    */
530
                                         /* copy page from expanded memory */
531
                "0: ipm  %0        \n"   /* save status (cc & program mask */
532
                "  srl  %0,28      \n"   /* cc into least significant bits */
533
                "1:                \n"   /* we are done                    */
534
                ".section .fixup,\"ax\"\n" /* start of fix up section      */
535
                "2: lghi %0,2      \n"   /* return unused condition code 2 */
536
                "   jg   1b        \n"   /* goto label 1 above             */
537
                ".previous         \n"   /* back in text section           */
538
                ".section __ex_table,\"a\"\n" /* start __extable           */
539
                "   .align 8       \n"
540
                "   .quad 0b,2b    \n"   /* failure point 0, fixup code 2  */
541
                ".previous         \n"
542
                : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
543
                );
544
#endif  /* CONFIG_ARCH_S390X */
545
        switch (cc) {
546
        case 0: return 0;
547
        case 1: return -EIO;
548
        case 2: { PRINT_ERR("expanded storage lost!\n"); return -ENXIO; }
549
        case 3: return -ENXIO;
550
        default: return -EIO;  /* should not happen */
551
        }
552
}
553
 
554
/*--------------------------------------------------------------------*/
555
/* Measure expanded memory                                            */
556
/* Return value                                                       */
557
/*           size of expanded memory in kB (must be a multipe of 4)   */
558
/*--------------------------------------------------------------------*/
559
int xpram_size(void)
560
{
561
        int cc=0;
562
        unsigned long base=0;
563
        unsigned long po, pi, rpi;   /* page index order, page index */
564
 
565
        unsigned long mem_page = __get_free_page(GFP_KERNEL);
566
 
567
        /* for po=0,1,2,... try to move in page number base+(2^po)-1 */
568
        pi=1;
569
        for (po=0; po <= 32; po++) { /* pi = 2^po */
570
                cc=xpram_page_in(mem_page,base+pi-1);
571
                if ( cc ) break;
572
                pi <<= 1;
573
        }
574
        if ( cc && (po < 31 ) ) {
575
                pi >>=1;
576
                base += pi;
577
                pi >>=1;
578
                for ( ; pi > 0; pi >>= 1) {
579
                        rpi = pi - 1;
580
                        cc=xpram_page_in(mem_page,base+rpi);
581
                        if ( !cc ) base += pi;
582
                }
583
        }
584
 
585
        free_page (mem_page);
586
 
587
        if ( cc && (po < 31) )
588
                return (XPRAM_KB_IN_PG * base);
589
        else          /* return maximal value possible */
590
                return INT_MAX;
591
}
592
 
593
/*
594
 * Open and close
595
 */
596
 
597
int xpram_open (struct inode *inode, struct file *filp)
598
{
599
        Xpram_Dev *dev; /* device information */
600
        int num = MINOR(inode->i_rdev);
601
 
602
 
603
        if (num >= xpram_devs) return -ENODEV;
604
        dev = xpram_devices + num;
605
 
606
        PRINT_DEBUG("calling xpram_open for device %d\n",num);
607
        PRINT_DEBUG("  size %dkB, name %s, usage: %d\n",
608
                     dev->size,dev->device_name, atomic_read(&(dev->usage)));
609
 
610
        atomic_inc(&(dev->usage));
611
        return 0;          /* success */
612
}
613
 
614
int xpram_release (struct inode *inode, struct file *filp)
615
{
616
        Xpram_Dev *dev = xpram_devices + MINOR(inode->i_rdev);
617
 
618
        PRINT_DEBUG("calling xpram_release for device %d (size %dkB, usage: %d)\n",MINOR(inode->i_rdev) ,dev->size,atomic_read(&(dev->usage)));
619
 
620
        /*
621
         * If the device is closed for the last time, start a timer
622
         * to release RAM in half a minute. The function and argument
623
         * for the timer have been setup in init_module()
624
         */
625
        if (!atomic_dec_return(&(dev->usage))) {
626
                /* but flush it right now */
627
                /* Everything is already flushed by caller -- AV */
628
        }
629
        return(0);
630
}
631
 
632
 
633
/*
634
 * The ioctl() implementation
635
 */
636
 
637
int xpram_ioctl (struct inode *inode, struct file *filp,
638
                 unsigned int cmd, unsigned long arg)
639
{
640
        int err, size;
641
        struct hd_geometry *geo = (struct hd_geometry *)arg;
642
 
643
        PRINT_DEBUG("ioctl 0x%x 0x%lx\n", cmd, arg);
644
        switch(cmd) {
645
 
646
        case BLKGETSIZE:  /* 0x1260 */
647
                /* Return the device size, expressed in sectors */
648
                return put_user( 1024* xpram_sizes[MINOR(inode->i_rdev)]
649
                           / XPRAM_SOFTSECT,
650
                           (unsigned long *) arg);
651
 
652
        case BLKGETSIZE64:
653
                return put_user( (u64)(1024* xpram_sizes[MINOR(inode->i_rdev)]
654
                           / XPRAM_SOFTSECT) << 9,
655
                           (u64 *) arg);
656
 
657
        case BLKFLSBUF: /* flush, 0x1261 */
658
                fsync_dev(inode->i_rdev);
659
                if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
660
                return 0;
661
 
662
        case BLKRAGET: /* return the readahead value, 0x1263 */
663
                if (!arg)  return -EINVAL;
664
                err = 0; /* verify_area_20(VERIFY_WRITE, (long *) arg, sizeof(long));
665
                          * if (err) return err;
666
                          */
667
                put_user(read_ahead[MAJOR(inode->i_rdev)], (long *)arg);
668
 
669
                return 0;
670
 
671
        case BLKRASET: /* set the readahead value, 0x1262 */
672
                if (!capable(CAP_SYS_ADMIN)) return -EACCES;
673
                if (arg > 0xff) return -EINVAL; /* limit it */
674
                read_ahead[MAJOR(inode->i_rdev)] = arg;
675
                atomic_eieio();
676
                return 0;
677
 
678
        case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */
679
                return -EINVAL;
680
 
681
 
682
#if (XPRAM_VERSION == 22)
683
                RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations
684
                                                * BLKROSET
685
                                                * BLKROGET
686
                                                */
687
#endif /* V22 */
688
 
689
        case HDIO_GETGEO:
690
                /*
691
                 * get geometry: we have to fake one...  trim the size to a
692
                 * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
693
                 * whatever cylinders. Tell also that data starts at sector. 4.
694
                 */
695
                size = xpram_mem_avail * 1024 / XPRAM_SOFTSECT;
696
                /* size = xpram_mem_avail * 1024 / xpram_hardsect; */
697
                size &= ~0x3f; /* multiple of 64 */
698
                if (geo==NULL) return -EINVAL;
699
                /*
700
                 * err=verify_area_20(VERIFY_WRITE, geo, sizeof(*geo));
701
                 * if (err) return err;
702
                 */
703
 
704
                put_user(size >> 6, &geo->cylinders);
705
                put_user(        4, &geo->heads);
706
                put_user(       16, &geo->sectors);
707
                put_user(        4, &geo->start);
708
 
709
                return 0;
710
        }
711
 
712
        return -EINVAL; /* unknown command */
713
}
714
 
715
/*
716
 * The file operations
717
 */
718
 
719
#if (XPRAM_VERSION == 22)
720
struct file_operations xpram_fops = {
721
        NULL,          /* lseek: default */
722
        block_read,
723
        block_write,
724
        NULL,          /* xpram_readdir */
725
        NULL,          /* xpram_select */
726
        xpram_ioctl,
727
        NULL,          /* xpram_mmap */
728
        xpram_open,
729
        NULL,          /* flush */
730
        xpram_release,
731
        block_fsync,
732
        NULL,          /* xpram_fasync */
733
        NULL,
734
        NULL
735
};
736
#endif /* V22 */
737
 
738
#if (XPRAM_VERSION == 24)
739
struct block_device_operations xpram_devops =
740
{
741
        owner:   THIS_MODULE,
742
        ioctl:   xpram_ioctl,
743
        open:    xpram_open,
744
        release: xpram_release,
745
};
746
#endif /* V24 */
747
 
748
/*
749
 * Block-driver specific functions
750
 */
751
 
752
void xpram_request(request_queue_t * queue)
753
{
754
        Xpram_Dev *device;
755
        /*     u8 *ptr;          */
756
        /*    int size;          */
757
 
758
        unsigned long page_no;         /* expanded memory page number */
759
        unsigned long sects_to_copy;   /* number of sectors to be copied */
760
        char * buffer;                 /* local pointer into buffer cache */
761
        int dev_no;                    /* device number of request */
762
        int fault;                     /* faulty access to expanded memory */
763
#if ( XPRAM_VERSION == 24 )     
764
        struct request * current_req;      /* working request */
765
#else 
766
#       define current_req CURRENT
767
#endif /* V24 */
768
 
769
        while(1) {
770
                INIT_REQUEST;
771
 
772
                fault=0;
773
#if ( XPRAM_VERSION == 24 )
774
                current_req = blkdev_entry_next_request (&queue->queue_head);
775
#endif /* V24 */
776
                dev_no = DEVICE_NR(current_req->rq_dev);
777
                /* Check if the minor number is in range */
778
                if ( dev_no > xpram_devs ) {
779
                        static int count = 0;
780
                        if (count++ < 5) /* print the message at most five times */
781
                                PRINT_WARN(" request for unknown device\n");
782
                        end_request(0);
783
                        continue;
784
                }
785
 
786
                /* pointer to device structure, from the global array */
787
                device = xpram_devices + dev_no;
788
                sects_to_copy = current_req->current_nr_sectors;
789
                /* does request exceed size of device ? */
790
                if ( XPRAM_SEC2KB(sects_to_copy) > xpram_sizes[dev_no] ) {
791
                        PRINT_WARN(" request past end of device\n");
792
                        end_request(0);
793
                        continue;
794
                }
795
 
796
                /* Does request start at page boundery? -- paranoia */
797
#if 0
798
                PRINT_DEBUG(" req %lx, sect %lx, to copy %lx, buf addr %lx\n", (unsigned long) current_req, current_req->sector, sects_to_copy, (unsigned long) current_req->buffer);
799
#endif
800
                buffer = current_req->buffer;
801
#if XPRAM_SEC_IN_PG != 1
802
                /* Does request start at an expanded storage page boundery? */
803
                if ( current_req->sector &  (XPRAM_SEC_IN_PG - 1) ) {
804
                        PRINT_WARN(" request does not start at an expanded storage page boundery\n");
805
                        PRINT_WARN(" referenced sector: %ld\n",current_req->sector);
806
                        end_request(0);
807
                        continue;
808
                }
809
                /* Does request refere to partial expanded storage pages? */
810
                if ( sects_to_copy & (XPRAM_SEC_IN_PG - 1) ) {
811
                        PRINT_WARN(" request referes to a partial expanded storage page\n");
812
                        end_request(0);
813
                        continue;
814
                }
815
#endif /*  XPRAM_SEC_IN_PG != 1 */
816
                /* Is request buffer aligned with kernel pages? */
817
                if ( ((unsigned long)buffer) & (XPRAM_PGSIZE-1) ) {
818
                        PRINT_WARN(" request buffer is not aligned with kernel pages\n");
819
                        end_request(0);
820
                        continue;
821
                }
822
 
823
                /* which page of expanded storage is affected first? */
824
                page_no = (xpram_offsets[dev_no] >> XPRAM_KB_IN_PG_ORDER)
825
                        + (current_req->sector >> XPRAM_SEC_IN_PG_ORDER);
826
 
827
#if 0 
828
                PRINT_DEBUG("request: %d ( dev %d, copy %d sectors, at page %d ) \n", current_req->cmd,dev_no,sects_to_copy,page_no);
829
#endif
830
 
831
                switch(current_req->cmd) {
832
                case READ:
833
                        do {
834
                                if ( (fault=xpram_page_in((unsigned long)buffer,page_no)) ) {
835
                                        PRINT_WARN("xpram(dev %d): page in failed for page %ld.\n",dev_no,page_no);
836
                                        break;
837
                                }
838
                                sects_to_copy -= XPRAM_SEC_IN_PG;
839
                                buffer += XPRAM_PGSIZE;
840
                                page_no++;
841
                        } while ( sects_to_copy > 0 );
842
                        break;
843
                case WRITE:
844
                        do {
845
                                if ( (fault=xpram_page_out((unsigned long)buffer,page_no))
846
                                        ) {
847
                                        PRINT_WARN("xpram(dev %d): page out failed for page %ld.\n",dev_no,page_no);
848
                                        break;
849
                                }
850
                                sects_to_copy -= XPRAM_SEC_IN_PG;
851
                                buffer += XPRAM_PGSIZE;
852
                                page_no++;
853
                        } while ( sects_to_copy > 0 );
854
                        break;
855
                default:
856
                        /* can't happen */
857
                        end_request(0);
858
                        continue;
859
                }
860
                if ( fault ) end_request(0);
861
                else end_request(1); /* success */
862
        }
863
}
864
 
865
/*
866
 *    Kernel interfaces
867
 */
868
 
869
/*
870
 * Parses the kernel parameters given in the kernel parameter line.
871
 * The expected format is
872
 *           <number_of_partitions>[","<partition_size>]*
873
 * where
874
 *           devices is a positive integer that initializes xpram_devs
875
 *           each size is a non-negative integer possibly followed by a
876
 *           magnitude (k,K,m,M,g,G), the list of sizes initialises
877
 *           xpram_sizes
878
 *
879
 * Arguments
880
 *           str: substring of kernel parameter line that contains xprams
881
 *                kernel parameters.
882
 *           ints: not used -- not in Version > 2.3 any more
883
 *
884
 * Result    0 on success, -EINVAl else -- only for Version > 2.3
885
 *
886
 * Side effects
887
 *           the global variabls devs is set to the value of
888
 *           <number_of_partitions> and sizes[i] is set to the i-th
889
 *           partition size (if provided). A parsing error of a value
890
 *           results in this value being set to -EINVAL.
891
 */
892
#if (XPRAM_VERSION == 22)
893
void xpram_setup (char *str, int *ints)
894
#else 
895
int xpram_setup (char *str)
896
#endif /* V22 */
897
{
898
        devs = xpram_read_int(&str);
899
        if ( devs != -EINVAL )
900
          if ( xpram_read_size_list_tail(&str,devs,sizes) < 0 ) {
901
                        PRINT_ERR("error while reading xpram parameters.\n");
902
#if (XPRAM_VERSION == 24)
903
                        return -EINVAL;
904
#endif /* V24 */
905
                          }
906
#if (XPRAM_VERSION == 24)
907
          else return 0;
908
        else return -EINVAL;
909
#elif (XPRAM_VERSION == 22)
910
        return;
911
#endif /* V24/V22 */
912
}
913
 
914
/*
915
 * initialize xpram device driver
916
 *
917
 * Result: 0 ok
918
 *         negative number: negative error code
919
 */
920
 
921
int xpram_init(void)
922
{
923
        int result, i;
924
        int mem_usable;       /* net size of expanded memory */
925
        int mem_needed=0;     /* size of expanded memory needed to fullfill
926
                               * requirements of non-zero parameters in sizes
927
                               */
928
 
929
        int mem_auto_no=0;    /* number of (implicit) zero parameters in sizes */
930
        int mem_auto;         /* automatically determined device size          */
931
#if (XPRAM_VERSION == 24)
932
        int minor_length;     /* store the length of a minor (w/o '\0') */
933
        int minor_thresh;     /* threshhold for minor lenght            */
934
 
935
        request_queue_t *q;   /* request queue */
936
#endif /* V24 */
937
 
938
                                /*
939
                                 * Copy the (static) cfg variables to public prefixed ones to allow
940
                                 * snoozing with a debugger.
941
                                 */
942
 
943
        xpram_rahead   = rahead;
944
        xpram_blksize  = blksize;
945
        xpram_hardsect = hardsect;
946
 
947
        PRINT_INFO("initializing: %s\n","");
948
                                /* check arguments */
949
        xpram_major    = major;
950
        if ( (devs <= 0) || (devs > XPRAM_MAX_DEVS) ) {
951
                PRINT_ERR("invalid number %d of devices\n",devs);
952
                PRINT_ERR("Giving up xpram\n");
953
                return -EINVAL;
954
        }
955
        xpram_devs     = devs;
956
        for (i=0; i < xpram_devs; i++) {
957
                if ( sizes[i] < 0 ) {
958
                        PRINT_ERR("Invalid partition size %d kB\n",xpram_sizes[i]);
959
                        PRINT_ERR("Giving up xpram\n");
960
                        return -EINVAL;
961
                } else {
962
                  xpram_sizes[i] = NEXT4(sizes[i]);  /* page align */
963
                        if ( sizes[i] ) mem_needed += xpram_sizes[i];
964
                        else mem_auto_no++;
965
                }
966
        }
967
 
968
        PRINT_DEBUG("  major %d \n", xpram_major);
969
        PRINT_INFO("  number of devices (partitions): %d \n", xpram_devs);
970
        for (i=0; i < xpram_devs; i++) {
971
                if ( sizes[i] )
972
                        PRINT_INFO("  size of partition %d: %d kB\n", i, xpram_sizes[i]);
973
                else
974
                        PRINT_INFO("  size of partition %d to be set automatically\n",i);
975
        }
976
        PRINT_DEBUG("  memory needed (for sized partitions): %d kB\n", mem_needed);
977
        PRINT_DEBUG("  partitions to be sized automatically: %d\n", mem_auto_no);
978
 
979
#if 0
980
                                /* Hardsect can't be changed :( */
981
                                /* I try it any way. Yet I must distinguish
982
                                 * between hardsects (to be changed to 4096)
983
                                 * and soft sectors, hard-coded for buffer
984
                                 * sizes within the requests
985
                                 */
986
        if (hardsect != 512) {
987
                PRINT_ERR("Can't change hardsect size\n");
988
                hardsect = xpram_hardsect = 512;
989
        }
990
#endif
991
        PRINT_INFO("  hardsector size: %dB \n",xpram_hardsect);
992
 
993
        /*
994
         * Register your major, and accept a dynamic number
995
         */
996
#if (XPRAM_VERSION == 22)
997
        result = register_blkdev(xpram_major, "xpram", &xpram_fops);
998
#elif (XPRAM_VERSION == 24)
999
        result = devfs_register_blkdev(xpram_major, "xpram", &xpram_devops);
1000
#endif /* V22/V24 */
1001
        if (result < 0) {
1002
                PRINT_ERR("Can't get major %d\n",xpram_major);
1003
                PRINT_ERR("Giving up xpram\n");
1004
                return result;
1005
        }
1006
#if (XPRAM_VERSION == 24)
1007
        xpram_devfs_handle = devfs_mk_dir (NULL, "slram", NULL);
1008
        devfs_register_series (xpram_devfs_handle, "%u", XPRAM_MAX_DEVS,
1009
                               DEVFS_FL_DEFAULT, XPRAM_MAJOR, 0,
1010
                               S_IFBLK | S_IRUSR | S_IWUSR,
1011
                               &xpram_devops, NULL);
1012
#endif /* V22/V24 */
1013
        if (xpram_major == 0) xpram_major = result; /* dynamic */
1014
        major = xpram_major; /* Use `major' later on to save typing */
1015
 
1016
        result = -ENOMEM; /* for the possible errors */
1017
 
1018
        /*
1019
         * measure expanded memory
1020
         */
1021
 
1022
        xpram_mem_avail = xpram_size();
1023
        if (!xpram_mem_avail) {
1024
                PRINT_ERR("No or not enough expanded memory available\n");
1025
                PRINT_ERR("Giving up xpram\n");
1026
                result = -ENODEV;
1027
                goto fail_malloc;
1028
        }
1029
        PRINT_INFO("  %d kB expanded memory found.\n",xpram_mem_avail );
1030
 
1031
        /*
1032
         * Assign the other needed values: request, rahead, size, blksize,
1033
         * hardsect. All the minor devices feature the same value.
1034
         * Note that `xpram' defines all of them to allow testing non-default
1035
         * values. A real device could well avoid setting values in global
1036
         * arrays if it uses the default values.
1037
         */
1038
 
1039
#if (XPRAM_VERSION == 22)
1040
        blk_dev[major].request_fn = xpram_request;
1041
#elif (XPRAM_VERSION == 24)
1042
        q = BLK_DEFAULT_QUEUE (major);
1043
        blk_init_queue (q, xpram_request);
1044
        blk_queue_headactive (BLK_DEFAULT_QUEUE (major), 0);
1045
#endif /* V22/V24 */
1046
        read_ahead[major] = xpram_rahead;
1047
 
1048
        /* we want to have XPRAM_UNUSED blocks security buffer between devices */
1049
        mem_usable=xpram_mem_avail-(XPRAM_UNUSED*(xpram_devs-1));
1050
        if ( mem_needed > mem_usable ) {
1051
                PRINT_ERR("Not enough expanded memory available\n");
1052
                PRINT_ERR("Giving up xpram\n");
1053
                goto fail_malloc;
1054
        }
1055
 
1056
        /*
1057
         * partitioning:
1058
         * xpram_sizes[i] != 0; partition i has size xpram_sizes[i] kB
1059
         * else:             ; all partitions i with xpram_sizesxpram_size[i]
1060
         *                     partition equally the remaining space
1061
         */
1062
 
1063
        if ( mem_auto_no ) {
1064
                mem_auto=LAST4((mem_usable-mem_needed)/mem_auto_no);
1065
                PRINT_INFO("  automatically determined partition size: %d kB\n", mem_auto);
1066
                for (i=0; i < xpram_devs; i++)
1067
                        if (xpram_sizes[i] == 0) xpram_sizes[i] = mem_auto;
1068
        }
1069
        blk_size[major]=xpram_sizes;
1070
 
1071
        xpram_offsets = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
1072
        if (!xpram_offsets) {
1073
                PRINT_ERR("Not enough memory for xpram_offsets\n");
1074
                PRINT_ERR("Giving up xpram\n");
1075
                goto fail_malloc;
1076
        }
1077
        xpram_offsets[0] = 0;
1078
        for (i=1; i < xpram_devs; i++)
1079
                xpram_offsets[i] = xpram_offsets[i-1] + xpram_sizes[i-1] + XPRAM_UNUSED;
1080
 
1081
#if 0
1082
        for (i=0; i < xpram_devs; i++)
1083
                PRINT_DEBUG(" device(%d) offset = %d kB, size = %d kB\n",i, xpram_offsets[i], xpram_sizes[i]);
1084
#endif
1085
 
1086
        xpram_blksizes = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
1087
        if (!xpram_blksizes) {
1088
                PRINT_ERR("Not enough memory for xpram_blksizes\n");
1089
                PRINT_ERR("Giving up xpram\n");
1090
                goto fail_malloc_blksizes;
1091
        }
1092
        for (i=0; i < xpram_devs; i++) /* all the same blocksize */
1093
                xpram_blksizes[i] = xpram_blksize;
1094
        blksize_size[major]=xpram_blksizes;
1095
 
1096
        xpram_hardsects = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
1097
        if (!xpram_hardsects) {
1098
                PRINT_ERR("Not enough memory for xpram_hardsects\n");
1099
                PRINT_ERR("Giving up xpram\n");
1100
                goto fail_malloc_hardsects;
1101
        }
1102
        for (i=0; i < xpram_devs; i++) /* all the same hardsect */
1103
                xpram_hardsects[i] = xpram_hardsect;
1104
        hardsect_size[major]=xpram_hardsects;
1105
 
1106
        /*
1107
         * allocate the devices -- we can't have them static, as the number
1108
         * can be specified at load time
1109
         */
1110
 
1111
        xpram_devices = kmalloc(xpram_devs * sizeof (Xpram_Dev), GFP_KERNEL);
1112
        if (!xpram_devices) {
1113
                PRINT_ERR("Not enough memory for xpram_devices\n");
1114
                PRINT_ERR("Giving up xpram\n");
1115
                goto fail_malloc_devices;
1116
        }
1117
        memset(xpram_devices, 0, xpram_devs * sizeof (Xpram_Dev));
1118
#if (XPRAM_VERSION == 24)
1119
        minor_length = 1;
1120
        minor_thresh = 10;
1121
#endif /* V24 */
1122
        for (i=0; i < xpram_devs; i++) {
1123
                /* data and usage remain zeroed */
1124
                xpram_devices[i].size = xpram_sizes[i];  /* size in kB not in bytes */
1125
                atomic_set(&(xpram_devices[i].usage),0);
1126
#if (XPRAM_VERSION == 24)
1127
                if (i == minor_thresh) {
1128
                  minor_length++;
1129
                  minor_thresh *= 10;
1130
                }
1131
                xpram_devices[i].device_name =
1132
                  kmalloc(1 + strlen(XPRAM_DEVICE_NAME_PREFIX) + minor_length,GFP_KERNEL);
1133
                if ( xpram_devices[i].device_name == NULL ) {
1134
                  PRINT_ERR("Not enough memory for xpram_devices[%d].device_name\n",i);
1135
                  PRINT_ERR("Giving up xpram\n");
1136
                  goto fail_devfs_register;
1137
                }
1138
                sprintf(xpram_devices[i].device_name,XPRAM_DEVICE_NAME_PREFIX "%d",i);
1139
 
1140
        PRINT_DEBUG("initializing xpram_open for device %d\n",i);
1141
        PRINT_DEBUG("  size %dkB, name %s, usage: %d\n",
1142
                     xpram_devices[i].size,xpram_devices[i].device_name, atomic_read(&(xpram_devices[i].usage)));
1143
 
1144
#if 0  /* WHY? */
1145
                xpram_devices[i].devfs_entry =
1146
                  devfs_register(NULL /* devfs root dir */,
1147
                                 xpram_devices[i].device_name, 0,
1148
 
1149
                                 XPRAM_MAJOR,i,
1150
                                 0755 /* access mode */,
1151
 
1152
                                 &xpram_devops,
1153
                                 (void *) &(xpram_devices[i])
1154
                                 );
1155
                if ( xpram_devices[i].devfs_entry == NULL ) {
1156
                  PRINT_ERR("devfs system registry failed\n");
1157
                  PRINT_ERR("Giving up xpram\n");
1158
                  goto fail_devfs_register;
1159
                }
1160
#endif  /* WHY? */
1161
#endif /* V24 */
1162
 
1163
        }
1164
 
1165
        return 0; /* succeed */
1166
 
1167
        /* clean up memory in case of failures */
1168
#if (XPRAM_VERSION == 24)
1169
 fail_devfs_register:
1170
        for (i=0; i < xpram_devs; i++) {
1171
          if ( xpram_devices[i].device_name )
1172
            kfree(xpram_devices[i].device_name);
1173
        }
1174
        kfree(xpram_devices);
1175
#endif /* V24 */
1176
 fail_malloc_blksizes:
1177
        kfree (xpram_offsets);
1178
 fail_malloc_hardsects:
1179
        kfree (xpram_blksizes);
1180
        blksize_size[major] = NULL;
1181
 fail_malloc_devices:
1182
        kfree(xpram_hardsects);
1183
        hardsect_size[major] = NULL;
1184
 fail_malloc:
1185
        read_ahead[major] = 0;
1186
#if (XPRAM_VERSION == 22)
1187
        blk_dev[major].request_fn = NULL;
1188
#endif /* V22 */
1189
        /* ???  unregister_chrdev(major, "xpram"); */
1190
        unregister_blkdev(major, "xpram");
1191
        return result;
1192
}
1193
 
1194
/*
1195
 * Finally, the module stuff
1196
 */
1197
 
1198
int init_module(void)
1199
{
1200
        int rc = 0;
1201
 
1202
        PRINT_INFO ("trying to load module\n");
1203
        rc = xpram_init ();
1204
        if (rc == 0) {
1205
                PRINT_INFO ("Module loaded successfully\n");
1206
        } else {
1207
                PRINT_WARN ("Module load returned rc=%d\n", rc);
1208
        }
1209
        return rc;
1210
}
1211
 
1212
void cleanup_module(void)
1213
{
1214
        int i;
1215
 
1216
                                /* first of all, flush it all and reset all the data structures */
1217
 
1218
 
1219
        for (i=0; i<xpram_devs; i++)
1220
                fsync_dev(MKDEV(xpram_major, i)); /* flush the devices */
1221
 
1222
#if (XPRAM_VERSION == 22)
1223
        blk_dev[major].request_fn = NULL;
1224
#endif /* V22 */
1225
        read_ahead[major] = 0;
1226
        blk_size[major] = NULL;
1227
        kfree(blksize_size[major]);
1228
        blksize_size[major] = NULL;
1229
        kfree(hardsect_size[major]);
1230
        hardsect_size[major] = NULL;
1231
        kfree(xpram_offsets);
1232
 
1233
                                /* finally, the usual cleanup */
1234
#if (XPRAM_VERSION == 22)
1235
        unregister_blkdev(major, "xpram");
1236
#elif (XPRAM_VERSION == 24)
1237
        devfs_unregister(xpram_devfs_handle);
1238
        if (devfs_unregister_blkdev(MAJOR_NR, "xpram"))
1239
                printk(KERN_WARNING "xpram: cannot unregister blkdev\n");
1240
#endif /* V22/V24 */
1241
        kfree(xpram_devices);
1242
}

powered by: WebSVN 2.1.0

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