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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * File...........: linux/drivers/s390/ccwcache.c
3
 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4
 *                  Martin Schiwdefsky <schwidefsky@de.ibm.com>
5
 * Bugreports.to..: <Linux390@de.ibm.com>
6
 * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a
7
 
8
 * History of changes
9
 * 11/14/00 redesign by Martin Schwidefsky
10
 */
11
 
12
#include <linux/module.h>
13
#include <linux/slab.h>
14
#include <linux/version.h>
15
 
16
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
17
#include <linux/spinlock.h>
18
#else
19
#include <asm/spinlock.h>
20
#endif
21
 
22
#include <asm/debug.h>
23
#include <asm/ccwcache.h>
24
#include <asm/ebcdic.h>
25
 
26
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
27
#define CCW_CACHE_SLAB_TYPE (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA)
28
#define CCW_CACHE_TYPE (GFP_ATOMIC | GFP_DMA)
29
#else
30
#define CCW_CACHE_SLAB_TYPE (SLAB_HWCACHE_ALIGN)
31
#define CCW_CACHE_TYPE (GFP_ATOMIC)
32
#define kmem_cache_destroy(x) do {} while(0)
33
#endif
34
 
35
#undef PRINTK_HEADER
36
#define PRINTK_HEADER "ccwcache"
37
 
38
/* pointer to list of allocated requests */
39
static ccw_req_t *ccwreq_actual = NULL;
40
static spinlock_t ccwchain_lock;
41
 
42
/* pointer to debug area */
43
static debug_info_t *debug_area = NULL;
44
 
45
/* SECTION: Handling of the dynamically allocated kmem slabs */
46
 
47
/* a name template for the cache-names */
48
static char ccw_name_template[] = "ccwcache-\0\0\0\0"; /* fill name with zeroes! */
49
/* the cache's names */
50
static char ccw_cache_name[CCW_NUMBER_CACHES][sizeof(ccw_name_template)+1];
51
/* the caches itself*/
52
static kmem_cache_t *ccw_cache[CCW_NUMBER_CACHES];
53
 
54
/* SECTION: (de)allocation of ccw_req_t */
55
 
56
/*
57
 * void enchain ( ccw_req_t *request )
58
 * enchains the request to the ringbuffer
59
 */
60
static inline void
61
enchain ( ccw_req_t *request )
62
{
63
        unsigned long flags;
64
 
65
        /* Sanity checks */
66
        if ( request == NULL )
67
                BUG();
68
        spin_lock_irqsave(&ccwchain_lock,flags);
69
        if ( ccwreq_actual == NULL ) { /* queue empty */
70
                ccwreq_actual = request;
71
                request->int_prev = ccwreq_actual;
72
                request->int_next = ccwreq_actual;
73
        } else {
74
                request->int_next = ccwreq_actual;
75
                request->int_prev = ccwreq_actual->int_prev;
76
                request->int_prev->int_next = request;
77
                request->int_next->int_prev = request;
78
        }
79
        spin_unlock_irqrestore(&ccwchain_lock,flags);
80
}
81
 
82
/*
83
 * void dechain ( ccw_req_t *request )
84
 * dechains the request from the ringbuffer
85
 */
86
static inline void
87
dechain ( ccw_req_t *request )
88
{
89
        unsigned long flags;
90
 
91
        /* Sanity checks */
92
        if ( request == NULL ||
93
             request->int_next == NULL ||
94
             request->int_prev == NULL)
95
                BUG();
96
        /* first deallocate request from list of allocates requests */
97
        spin_lock_irqsave(&ccwchain_lock,flags);
98
        if ( request -> int_next == request -> int_prev ) {
99
                ccwreq_actual = NULL;
100
        } else {
101
                if ( ccwreq_actual == request ) {
102
                        ccwreq_actual = request->int_next;
103
                }
104
                request->int_prev->int_next = request->int_next;
105
                request->int_next->int_prev = request->int_prev;
106
        }
107
        spin_unlock_irqrestore(&ccwchain_lock,flags);
108
}
109
 
110
/*
111
 * ccw_req_t *ccw_alloc_request ( int cplength, int datasize )
112
 * allocates a ccw_req_t, that
113
 * - can hold a CP of cplength CCWS
114
 * - can hold additional data up to datasize
115
 */
116
ccw_req_t *
117
ccw_alloc_request ( char *magic, int cplength, int datasize )
118
{
119
        ccw_req_t * request = NULL;
120
        int size_needed;
121
        int data_offset, ccw_offset;
122
        int cachind;
123
 
124
        /* Sanity checks */
125
        if ( magic == NULL || datasize > PAGE_SIZE ||
126
             cplength == 0 || (cplength*sizeof(ccw1_t)) > PAGE_SIZE)
127
                BUG();
128
        debug_text_event ( debug_area, 1, "ALLC");
129
        debug_text_event ( debug_area, 1, magic);
130
        debug_int_event ( debug_area, 1, cplength);
131
        debug_int_event ( debug_area, 1, datasize);
132
 
133
        /* We try to keep things together in memory */
134
        size_needed = (sizeof (ccw_req_t) + 7) & -8;
135
        data_offset = ccw_offset = 0;
136
        if (size_needed + datasize <= PAGE_SIZE) {
137
                /* Keep data with the request */
138
                data_offset = size_needed;
139
                size_needed += (datasize + 7) & -8;
140
        }
141
        if (size_needed + cplength*sizeof(ccw1_t) <= PAGE_SIZE) {
142
                /* Keep CCWs with request */
143
                ccw_offset = size_needed;
144
                size_needed += cplength*sizeof(ccw1_t);
145
        }
146
 
147
        /* determine cache index for the requested size */
148
        for (cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ )
149
           if ( size_needed <= (SMALLEST_SLAB << cachind) )
150
                        break;
151
 
152
        /* Try to fulfill the request from a cache */
153
        if ( ccw_cache[cachind] == NULL )
154
                BUG();
155
        request = kmem_cache_alloc ( ccw_cache[cachind], CCW_CACHE_TYPE );
156
        if (request == NULL)
157
                return NULL;
158
        memset ( request, 0, (SMALLEST_SLAB << cachind));
159
        request->cache = ccw_cache[cachind];
160
 
161
        /* Allocate memory for the extra data */
162
        if (data_offset == 0) {
163
                /* Allocated memory for extra data with kmalloc */
164
            request->data = (void *) kmalloc(datasize, CCW_CACHE_TYPE );
165
                if (request->data == NULL) {
166
                        printk(KERN_WARNING PRINTK_HEADER
167
                               "Couldn't allocate data area\n");
168
                        kmem_cache_free(request->cache, request);
169
                        return NULL;
170
                }
171
        } else
172
                /* Extra data already allocated with the request */
173
                request->data = (void *) ((addr_t) request + data_offset);
174
 
175
        /* Allocate memory for the channel program */
176
        if (ccw_offset == 0) {
177
                /* Allocated memory for the channel program with kmalloc */
178
                request->cpaddr = (ccw1_t *) kmalloc(cplength*sizeof(ccw1_t),
179
                                                     CCW_CACHE_TYPE);
180
                if (request->cpaddr == NULL) {
181
                        printk (KERN_DEBUG PRINTK_HEADER
182
                                "Couldn't allocate ccw area\n");
183
                        if (data_offset == 0)
184
                                kfree(request->data);
185
                        kmem_cache_free(request->cache, request);
186
                        return NULL;
187
                }
188
        } else
189
                /* Channel program already allocated with the request */
190
                request->cpaddr = (ccw1_t *) ((addr_t) request + ccw_offset);
191
 
192
        memset ( request->data, 0, datasize );
193
        memset ( request->cpaddr, 0, cplength*sizeof(ccw1_t) );
194
        strncpy ( (char *)(&request->magic), magic, 4);
195
 
196
        ASCEBC((char *)(&request->magic),4);
197
        request -> cplength = cplength;
198
        request -> datasize = datasize;
199
        /* enqueue request to list of allocated requests */
200
        enchain(request);
201
        debug_int_event ( debug_area, 1, (long)request);
202
        return request;
203
}
204
 
205
/*
206
 * void ccw_free_request ( ccw_req_t * )
207
 * deallocates the ccw_req_t, given as argument
208
 */
209
 
210
void
211
ccw_free_request ( ccw_req_t * request )
212
{
213
        int size_needed;
214
 
215
        debug_text_event ( debug_area, 1, "FREE");
216
        debug_int_event ( debug_area, 1, (long)request);
217
 
218
        /* Sanity checks */
219
        if ( request == NULL || request->cache == NULL)
220
                BUG();
221
 
222
        dechain ( request);
223
        /* Free memory allocated with kmalloc
224
         * make the same decisions as in ccw_alloc_requets */
225
        size_needed = (sizeof (ccw_req_t) + 7) & -8;
226
        if (size_needed + request->datasize <= PAGE_SIZE)
227
                /* We kept the data with the request */
228
                size_needed += (request->datasize + 7) & -8;
229
        else
230
                kfree(request->data);
231
        if (size_needed + request->cplength*sizeof(ccw1_t) > PAGE_SIZE)
232
                /* We kept the CCWs with request */
233
                kfree(request->cpaddr);
234
        kmem_cache_free(request -> cache, request);
235
}
236
 
237
/* SECTION: initialization and cleanup functions */
238
 
239
/*
240
 * ccwcache_init
241
 * called as an initializer function for the ccw memory management
242
 */
243
 
244
int
245
ccwcache_init (void)
246
{
247
        int rc = 0;
248
        int cachind;
249
 
250
        /* initialize variables */
251
        spin_lock_init(&ccwchain_lock);
252
 
253
        /* allocate a debug area */
254
        debug_area = debug_register( "ccwcache", 2, 4,sizeof(void*));
255
        if ( debug_area == NULL )
256
                BUG();
257
 
258
        debug_register_view(debug_area,&debug_hex_ascii_view);
259
        debug_register_view(debug_area,&debug_raw_view);
260
        debug_text_event ( debug_area, 0, "INIT");
261
 
262
        /* First allocate the kmem caches */
263
        for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
264
                int slabsize = SMALLEST_SLAB << cachind;
265
                debug_text_event ( debug_area, 1, "allc");
266
                debug_int_event ( debug_area, 1, slabsize);
267
                sprintf ( ccw_cache_name[cachind],
268
                          "%s%d%c", ccw_name_template, slabsize, 0);
269
                ccw_cache[cachind] =
270
                        kmem_cache_create( ccw_cache_name[cachind],
271
                                           slabsize, 0,
272
                                           CCW_CACHE_SLAB_TYPE,
273
                                           NULL, NULL );
274
                debug_int_event ( debug_area, 1, (long)ccw_cache[cachind]);
275
                if (ccw_cache[cachind] == NULL)
276
                        panic ("Allocation of CCW cache failed\n");
277
        }
278
        return rc;
279
}
280
 
281
/*
282
 * ccwcache_cleanup
283
 * called as a cleanup function for the ccw memory management
284
 */
285
 
286
void
287
ccwcache_cleanup (void)
288
{
289
        int cachind;
290
 
291
        /* Shrink the caches, if available */
292
        for ( cachind = 0; cachind < CCW_NUMBER_CACHES; cachind ++ ) {
293
                if ( ccw_cache[cachind] ) {
294
#if 0 /* this is useless and could cause an OOPS in the worst case */
295
                        if ( kmem_cache_shrink(ccw_cache[cachind]) == 0 ) {
296
                                ccw_cache[cachind] = NULL;
297
                        }
298
#endif
299
                        kmem_cache_destroy(ccw_cache[cachind]);
300
                }
301
        }
302
        debug_unregister( debug_area );
303
}
304
 
305
EXPORT_SYMBOL(ccw_alloc_request);
306
EXPORT_SYMBOL(ccw_free_request);
307
 

powered by: WebSVN 2.1.0

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