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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [include/] [asm-s390x/] [idals.h] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * File...........: linux/include/asm-s390x/idals.h
3
 * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
4
 *                  Martin Schwidefsky <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
 * 07/24/00 new file
10
 * 05/04/02 code restructuring.
11
 */
12
 
13
#ifndef _S390_IDALS_H
14
#define _S390_IDALS_H
15
 
16
#include <linux/config.h>
17
#include <linux/errno.h>
18
#include <linux/types.h>
19
#include <linux/slab.h>
20
#include <asm/irq.h>
21
#include <asm/uaccess.h>
22
 
23
#ifdef CONFIG_ARCH_S390X
24
#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
25
#else
26
#define IDA_SIZE_LOG 11 /* 11 for 2k , 12 for 4k */
27
#endif
28
#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
29
 
30
/*
31
 * Test if an address/length pair needs an idal list.
32
 */
33
static inline int
34
idal_is_needed(void *vaddr, unsigned int length)
35
{
36
#if defined(CONFIG_ARCH_S390X)
37
        return ((__pa(vaddr) + length) >> 31) != 0;
38
#else
39
        return 0;
40
#endif
41
}
42
 
43
 
44
/*
45
 * Return the number of idal words needed for an address/length pair.
46
 */
47
static inline unsigned int
48
idal_nr_words(void *vaddr, unsigned int length)
49
{
50
#if defined(CONFIG_ARCH_S390X)
51
        if (idal_is_needed(vaddr, length))
52
                return ((__pa(vaddr) & (IDA_BLOCK_SIZE-1)) + length +
53
                        (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
54
#endif
55
        return 0;
56
}
57
 
58
/*
59
 * Create the list of idal words for an address/length pair.
60
 */
61
static inline unsigned long *
62
idal_create_words(unsigned long *idaws, void *vaddr, unsigned int length)
63
{
64
#if defined(CONFIG_ARCH_S390X)
65
        unsigned long paddr;
66
        unsigned int cidaw;
67
 
68
        paddr = __pa(vaddr);
69
        cidaw = ((paddr & (IDA_BLOCK_SIZE-1)) + length +
70
                 (IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
71
        *idaws++ = paddr;
72
        paddr &= -IDA_BLOCK_SIZE;
73
        while (--cidaw > 0) {
74
                paddr += IDA_BLOCK_SIZE;
75
                *idaws++ = paddr;
76
        }
77
#endif
78
        return idaws;
79
}
80
 
81
/*
82
 * Sets the address of the data in CCW.
83
 * If necessary it allocates an IDAL and sets the appropriate flags.
84
 */
85
static inline int
86
set_normalized_cda(ccw1_t * ccw, void *vaddr)
87
{
88
#if defined (CONFIG_ARCH_S390X)
89
        unsigned int nridaws;
90
        unsigned long *idal;
91
 
92
        if (ccw->flags & CCW_FLAG_IDA)
93
                return -EINVAL;
94
        nridaws = idal_nr_words(vaddr, ccw->count);
95
        if (nridaws > 0) {
96
                idal = kmalloc(nridaws * sizeof(unsigned long),
97
                               GFP_ATOMIC | GFP_DMA );
98
                if (idal == NULL)
99
                        return -ENOMEM;
100
                idal_create_words(idal, vaddr, ccw->count);
101
                ccw->flags |= CCW_FLAG_IDA;
102
                vaddr = idal;
103
        }
104
#endif
105
        ccw->cda = (__u32)(unsigned long) vaddr;
106
        return 0;
107
}
108
 
109
/*
110
 * Releases any allocated IDAL related to the CCW.
111
 */
112
static inline void
113
clear_normalized_cda(ccw1_t * ccw)
114
{
115
#if defined(CONFIG_ARCH_S390X)
116
        if (ccw->flags & CCW_FLAG_IDA) {
117
                kfree((void *)(unsigned long) ccw->cda);
118
                ccw->flags &= ~CCW_FLAG_IDA;
119
        }
120
#endif
121
        ccw->cda = 0;
122
}
123
 
124
/*
125
 * Idal buffer extension
126
 */
127
struct idal_buffer {
128
        size_t size;
129
        size_t page_order;
130
        void *data[0];
131
};
132
 
133
/*
134
 * Allocate an idal buffer
135
 */
136
static inline struct idal_buffer *
137
idal_buffer_alloc(size_t size, int page_order)
138
{
139
        struct idal_buffer *ib;
140
        int nr_chunks, nr_ptrs, i;
141
 
142
        nr_ptrs = (size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
143
        nr_chunks = (4096 << page_order) >> IDA_SIZE_LOG;
144
        ib = kmalloc(sizeof(struct idal_buffer) + nr_ptrs*sizeof(void *),
145
                     GFP_DMA | GFP_KERNEL);
146
        if (ib == NULL)
147
                return ERR_PTR(-ENOMEM);
148
        ib->size = size;
149
        ib->page_order = page_order;
150
        for (i = 0; i < nr_ptrs; i++) {
151
                if ((i & (nr_chunks - 1)) != 0) {
152
                        ib->data[i] = ib->data[i-1] + IDA_BLOCK_SIZE;
153
                        continue;
154
                }
155
                ib->data[i] = (void *)
156
                        __get_free_pages(GFP_KERNEL, page_order);
157
                if (ib->data[i] != NULL)
158
                        continue;
159
                // Not enough memory
160
                while (i >= nr_chunks) {
161
                        i -= nr_chunks;
162
                        free_pages((unsigned long) ib->data[i],
163
                                   ib->page_order);
164
                }
165
                kfree(ib);
166
                return ERR_PTR(-ENOMEM);
167
        }
168
        return ib;
169
}
170
 
171
/*
172
 * Free an idal buffer.
173
 */
174
static inline void
175
idal_buffer_free(struct idal_buffer *ib)
176
{
177
        int nr_chunks, nr_ptrs, i;
178
 
179
        nr_ptrs = (ib->size + IDA_BLOCK_SIZE - 1) >> IDA_SIZE_LOG;
180
        nr_chunks = (4096 << ib->page_order) >> IDA_SIZE_LOG;
181
        for (i = 0; i < nr_ptrs; i += nr_chunks)
182
                free_pages((unsigned long) ib->data[i], ib->page_order);
183
        kfree(ib);
184
}
185
 
186
/*
187
 * Test if a idal list is really needed.
188
 */
189
static inline int
190
__idal_buffer_is_needed(struct idal_buffer *ib)
191
{
192
#ifdef CONFIG_ARCH_S390X
193
        return ib->size > (4096 << ib->page_order) ||
194
                idal_is_needed(ib->data[0], ib->size);
195
#else
196
        return ib->size > (4096 << ib->page_order);
197
#endif
198
}
199
 
200
/*
201
 * Set channel data address to idal buffer.
202
 */
203
static inline void
204
idal_buffer_set_cda(struct idal_buffer *ib, ccw1_t *ccw)
205
{
206
        if (__idal_buffer_is_needed(ib)) {
207
                // setup idals;
208
                ccw->cda = (u32)(addr_t) ib->data;
209
                ccw->flags |= CCW_FLAG_IDA;
210
        } else
211
                // we do not need idals - use direct addressing
212
                ccw->cda = (u32)(addr_t) ib->data[0];
213
        ccw->count = ib->size;
214
}
215
 
216
/*
217
 * Copy count bytes from an idal buffer to user memory
218
 */
219
static inline size_t
220
idal_buffer_to_user(const struct idal_buffer *ib, void *to, size_t count)
221
{
222
        size_t left;
223
        int i;
224
 
225
        if (count > ib->size)
226
                BUG();
227
        for (i = 0; count > IDA_BLOCK_SIZE; i++) {
228
                left = copy_to_user(to, ib->data[i], IDA_BLOCK_SIZE);
229
                if (left)
230
                        return left + count - IDA_BLOCK_SIZE;
231
                (addr_t) to += IDA_BLOCK_SIZE;
232
                count -= IDA_BLOCK_SIZE;
233
        }
234
        return copy_to_user(to, ib->data[i], count);
235
}
236
 
237
/*
238
 * Copy count bytes from user memory to an idal buffer
239
 */
240
static inline size_t
241
idal_buffer_from_user(struct idal_buffer *ib, const void *from, size_t count)
242
{
243
        size_t left;
244
        int i;
245
 
246
        if (count > ib->size)
247
                BUG();
248
        for (i = 0; count > IDA_BLOCK_SIZE; i++) {
249
                left = copy_from_user(ib->data[i], from, IDA_BLOCK_SIZE);
250
                if (left)
251
                        return left + count - IDA_BLOCK_SIZE;
252
                (addr_t) from += IDA_BLOCK_SIZE;
253
                count -= IDA_BLOCK_SIZE;
254
        }
255
        return copy_from_user(ib->data[i], from, count);
256
}
257
 
258
#endif

powered by: WebSVN 2.1.0

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