ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / parisc / lib / io.c
1 /*
2  * arch/parisc/lib/io.c
3  *
4  * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
5  * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
6  *
7  * IO accessing functions which shouldn't be inlined because they're too big
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <asm/io.h>
13
14 /* Copies a block of memory to a device in an efficient manner.
15  * Assumes the device can cope with 32-bit transfers.  If it can't,
16  * don't use this function.
17  */
18 void __memcpy_toio(unsigned long dest, unsigned long src, int count)
19 {
20         if ((dest & 3) != (src & 3))
21                 goto bytecopy;
22         while (dest & 3) {
23                 writeb(*(char *)src, dest++);
24                 ((char *)src)++;
25                 count--;
26         }
27         while (count > 3) {
28                 __raw_writel(*(u32 *)src, dest);
29                 src += 4;
30                 dest += 4;
31                 count -= 4;
32         }
33  bytecopy:
34         while (count--) {
35                 writeb(*(char *)src, dest++);
36                 ((char *)src)++;
37         }
38 }
39
40 /*
41 ** Copies a block of memory from a device in an efficient manner.
42 ** Assumes the device can cope with 32-bit transfers.  If it can't,
43 ** don't use this function.
44 **
45 ** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
46 **      27341/64    = 427 cyc per int
47 **      61311/128   = 478 cyc per short
48 **      122637/256  = 479 cyc per byte
49 ** Ergo bus latencies dominant (not transfer size).
50 **      Minimize total number of transfers at cost of CPU cycles.
51 **      TODO: only look at src alignment and adjust the stores to dest.
52 */
53 void __memcpy_fromio(unsigned long dest, unsigned long src, int count)
54 {
55         /* first compare alignment of src/dst */ 
56         if ( ((dest ^ src) & 1) || (count < 2) )
57                 goto bytecopy;
58
59         if ( ((dest ^ src) & 2) || (count < 4) )
60                 goto shortcopy;
61
62         /* Then check for misaligned start address */
63         if (src & 1) {
64                 *(u8 *)dest = readb(src);
65                 ((u8 *)src)++;
66                 ((u8 *)dest)++;
67                 count--;
68                 if (count < 2) goto bytecopy;
69         }
70
71         if (src & 2) {
72                 *(u16 *)dest = __raw_readw(src);
73                 ((u16 *)src)++;
74                 ((u16 *)dest)++;
75                 count-=2;
76         }
77
78         while (count > 3) {
79                 *(u32 *)dest = __raw_readl(src);
80                 dest += 4;
81                 src += 4;
82                 count -= 4;
83         }
84
85  shortcopy:
86         while (count > 1) {
87                 *(u16 *)dest = __raw_readw(src);
88                 ((u16 *)src)++;
89                 ((u16 *)dest)++;
90                 count-=2;
91         }
92
93  bytecopy:
94         while (count--) {
95                 *(char *)dest = readb(src);
96                 ((char *)src)++;
97                 ((char *)dest)++;
98         }
99 }
100
101 /* Sets a block of memory on a device to a given value.
102  * Assumes the device can cope with 32-bit transfers.  If it can't,
103  * don't use this function.
104  */
105 void __memset_io(unsigned long dest, char fill, int count)
106 {
107         u32 fill32 = (fill << 24) | (fill << 16) | (fill << 8) | fill;
108         while (dest & 3) {
109                 writeb(fill, dest++);
110                 count--;
111         }
112         while (count > 3) {
113                 __raw_writel(fill32, dest);
114                 dest += 4;
115                 count -= 4;
116         }
117         while (count--) {
118                 writeb(fill, dest++);
119         }
120 }
121
122 /*
123  * Read COUNT 8-bit bytes from port PORT into memory starting at
124  * SRC.
125  */
126 void insb (unsigned long port, void *dst, unsigned long count)
127 {
128         while (((unsigned long)dst) & 0x3) {
129                 if (!count)
130                         return;
131                 count--;
132                 *(unsigned char *) dst = inb(port);
133                 ((unsigned char *) dst)++;
134         }
135
136         while (count >= 4) {
137                 unsigned int w;
138                 count -= 4;
139                 w = inb(port) << 24;
140                 w |= inb(port) << 16;
141                 w |= inb(port) << 8;
142                 w |= inb(port);
143                 *(unsigned int *) dst = w;
144                 ((unsigned int *) dst)++;
145         }
146
147         while (count) {
148                 --count;
149                 *(unsigned char *) dst = inb(port);
150                 ((unsigned char *) dst)++;
151         }
152 }
153
154
155 /*
156  * Read COUNT 16-bit words from port PORT into memory starting at
157  * SRC.  SRC must be at least short aligned.  This is used by the
158  * IDE driver to read disk sectors.  Performance is important, but
159  * the interfaces seems to be slow: just using the inlined version
160  * of the inw() breaks things.
161  */
162 void insw (unsigned long port, void *dst, unsigned long count)
163 {
164         unsigned int l = 0, l2;
165         
166         if (!count)
167                 return;
168         
169         switch (((unsigned long) dst) & 0x3)
170         {
171          case 0x00:                     /* Buffer 32-bit aligned */
172                 while (count>=2) {
173                         
174                         count -= 2;
175                         l = cpu_to_le16(inw(port)) << 16;
176                         l |= cpu_to_le16(inw(port));
177                         *(unsigned int *) dst = l;
178                         ((unsigned int *) dst)++;
179                 }
180                 if (count) {
181                         *(unsigned short *) dst = cpu_to_le16(inw(port));
182                 }
183                 break;
184         
185          case 0x02:                     /* Buffer 16-bit aligned */
186                 *(unsigned short *) dst = cpu_to_le16(inw(port));
187                 ((unsigned short *) dst)++;
188                 count--;
189                 while (count>=2) {
190                         
191                         count -= 2;
192                         l = cpu_to_le16(inw(port)) << 16;
193                         l |= cpu_to_le16(inw(port));
194                         *(unsigned int *) dst = l;
195                         ((unsigned int *) dst)++;
196                 }
197                 if (count) {
198                         *(unsigned short *) dst = cpu_to_le16(inw(port));
199                 }
200                 break;
201                 
202          case 0x01:                     /* Buffer 8-bit aligned */
203          case 0x03:
204                 /* I don't bother with 32bit transfers
205                  * in this case, 16bit will have to do -- DE */
206                 --count;
207                 
208                 l = cpu_to_le16(inw(port));
209                 *(unsigned char *) dst = l >> 8;
210                 ((unsigned char *) dst)++;
211                 while (count--)
212                 {
213                         l2 = cpu_to_le16(inw(port));
214                         *(unsigned short *) dst = (l & 0xff) << 8 | (l2 >> 8);
215                         ((unsigned short *) dst)++;
216                         l = l2;
217                 }
218                 *(unsigned char *) dst = l & 0xff;
219                 break;
220         }
221 }
222
223
224
225 /*
226  * Read COUNT 32-bit words from port PORT into memory starting at
227  * SRC. Now works with any alignment in SRC. Performance is important,
228  * but the interfaces seems to be slow: just using the inlined version
229  * of the inl() breaks things.
230  */
231 void insl (unsigned long port, void *dst, unsigned long count)
232 {
233         unsigned int l = 0, l2;
234         
235         if (!count)
236                 return;
237         
238         switch (((unsigned long) dst) & 0x3)
239         {
240          case 0x00:                     /* Buffer 32-bit aligned */
241                 while (count--)
242                 {
243                         *(unsigned int *) dst = cpu_to_le32(inl(port));
244                         ((unsigned int *) dst)++;
245                 }
246                 break;
247         
248          case 0x02:                     /* Buffer 16-bit aligned */
249                 --count;
250                 
251                 l = cpu_to_le32(inl(port));
252                 *(unsigned short *) dst = l >> 16;
253                 ((unsigned short *) dst)++;
254                 
255                 while (count--)
256                 {
257                         l2 = cpu_to_le32(inl(port));
258                         *(unsigned int *) dst = (l & 0xffff) << 16 | (l2 >> 16);
259                         ((unsigned int *) dst)++;
260                         l = l2;
261                 }
262                 *(unsigned short *) dst = l & 0xffff;
263                 break;
264          case 0x01:                     /* Buffer 8-bit aligned */
265                 --count;
266                 
267                 l = cpu_to_le32(inl(port));
268                 *(unsigned char *) dst = l >> 24;
269                 ((unsigned char *) dst)++;
270                 *(unsigned short *) dst = (l >> 8) & 0xffff;
271                 ((unsigned short *) dst)++;
272                 while (count--)
273                 {
274                         l2 = cpu_to_le32(inl(port));
275                         *(unsigned int *) dst = (l & 0xff) << 24 | (l2 >> 8);
276                         ((unsigned int *) dst)++;
277                         l = l2;
278                 }
279                 *(unsigned char *) dst = l & 0xff;
280                 break;
281          case 0x03:                     /* Buffer 8-bit aligned */
282                 --count;
283                 
284                 l = cpu_to_le32(inl(port));
285                 *(unsigned char *) dst = l >> 24;
286                 ((unsigned char *) dst)++;
287                 while (count--)
288                 {
289                         l2 = cpu_to_le32(inl(port));
290                         *(unsigned int *) dst = (l & 0xffffff) << 8 | l2 >> 24;
291                         ((unsigned int *) dst)++;
292                         l = l2;
293                 }
294                 *(unsigned short *) dst = (l >> 8) & 0xffff;
295                 ((unsigned short *) dst)++;
296                 *(unsigned char *) dst = l & 0xff;
297                 break;
298         }
299 }
300
301
302 /*
303  * Like insb but in the opposite direction.
304  * Don't worry as much about doing aligned memory transfers:
305  * doing byte reads the "slow" way isn't nearly as slow as
306  * doing byte writes the slow way (no r-m-w cycle).
307  */
308 void outsb(unsigned long port, const void * src, unsigned long count)
309 {
310         while (count) {
311                 count--;
312                 outb(*(char *)src, port);
313                 ((char *) src)++;
314         }
315 }
316
317 /*
318  * Like insw but in the opposite direction.  This is used by the IDE
319  * driver to write disk sectors.  Performance is important, but the
320  * interfaces seems to be slow: just using the inlined version of the
321  * outw() breaks things.
322  */
323 void outsw (unsigned long port, const void *src, unsigned long count)
324 {
325         unsigned int l = 0, l2;
326         
327         if (!count)
328                 return;
329         
330         switch (((unsigned long) src) & 0x3)
331         {
332          case 0x00:                     /* Buffer 32-bit aligned */
333                 while (count>=2) {
334                         count -= 2;
335                         l = *(unsigned int *) src;
336                         ((unsigned int *) src)++;
337                         outw(le16_to_cpu(l >> 16), port);
338                         outw(le16_to_cpu(l & 0xffff), port);
339                 }
340                 if (count) {
341                         outw(le16_to_cpu(*(unsigned short*)src), port);
342                 }
343                 break;
344         
345          case 0x02:                     /* Buffer 16-bit aligned */
346                 
347                 outw(le16_to_cpu(*(unsigned short*)src), port);
348                 ((unsigned short *) src)++;
349                 count--;
350                 
351                 while (count>=2) {
352                         count -= 2;
353                         l = *(unsigned int *) src;
354                         ((unsigned int *) src)++;
355                         outw(le16_to_cpu(l >> 16), port);
356                         outw(le16_to_cpu(l & 0xffff), port);
357                 }
358                 if (count) {
359                         outw(le16_to_cpu(*(unsigned short*)src), port);
360                 }
361                 break;
362                 
363          case 0x01:                     /* Buffer 8-bit aligned */      
364                 /* I don't bother with 32bit transfers
365                  * in this case, 16bit will have to do -- DE */
366                 
367                 l  = *(unsigned char *) src << 8;
368                 ((unsigned char *) src)++;
369                 count--;
370                 while (count)
371                 {
372                         count--;
373                         l2 = *(unsigned short *) src;
374                         ((unsigned short *) src)++;
375                         outw(le16_to_cpu(l | l2 >> 8), port);
376                         l = l2 << 8;
377                 }
378                 l2 = *(unsigned char *) src;
379                 outw (le16_to_cpu(l | l2>>8), port);
380                 break;
381         
382         }
383 }
384
385
386 /*
387  * Like insl but in the opposite direction.  This is used by the IDE
388  * driver to write disk sectors.  Works with any alignment in SRC.
389  *  Performance is important, but the interfaces seems to be slow:
390  * just using the inlined version of the outl() breaks things.
391  */
392 void outsl (unsigned long port, const void *src, unsigned long count)
393 {
394         unsigned int l = 0, l2;
395         
396         if (!count)
397                 return;
398         
399         switch (((unsigned long) src) & 0x3)
400         {
401          case 0x00:                     /* Buffer 32-bit aligned */
402                 while (count--)
403                 {
404                         outl(le32_to_cpu(*(unsigned int *) src), port);
405                         ((unsigned int *) src)++;
406                 }
407                 break;
408         
409          case 0x02:                     /* Buffer 16-bit aligned */
410                 --count;
411                 
412                 l = *(unsigned short *) src;
413                 ((unsigned short *) src)++;
414                 
415                 while (count--)
416                 {
417                         l2 = *(unsigned int *) src;
418                         ((unsigned int *) src)++;
419                         outl (le32_to_cpu(l << 16 | l2 >> 16), port);
420                         l = l2;
421                 }
422                 l2 = *(unsigned short *) src;
423                 outl (le32_to_cpu(l << 16 | l2), port);
424                 break;
425          case 0x01:                     /* Buffer 8-bit aligned */
426                 --count;
427                 
428                 l  = *(unsigned char *) src << 24;
429                 ((unsigned char *) src)++;
430                 l |= *(unsigned short *) src << 8;
431                 ((unsigned short *) src)++;
432                 while (count--)
433                 {
434                         l2 = *(unsigned int *) src;
435                         ((unsigned int *) src)++;
436                         outl (le32_to_cpu(l | l2 >> 24), port);
437                         l = l2 << 8;
438                 }
439                 l2 = *(unsigned char *) src;
440                       outl (le32_to_cpu(l | l2), port);
441                 break;
442          case 0x03:                     /* Buffer 8-bit aligned */
443                 --count;
444                 
445                 l  = *(unsigned char *) src << 24;
446                 ((unsigned char *) src)++;
447                 while (count--)
448                 {
449                         l2 = *(unsigned int *) src;
450                         ((unsigned int *) src)++;
451                         outl (le32_to_cpu(l | l2 >> 8), port);
452                         l = l2 << 24;
453                 }
454                 l2  = *(unsigned short *) src << 16;
455                 ((unsigned short *) src)++;
456                 l2 |= *(unsigned char *) src;
457                 outl (le32_to_cpu(l | l2), port);
458                 break;
459         }
460 }
461
462 EXPORT_SYMBOL(insb);
463 EXPORT_SYMBOL(insw);
464 EXPORT_SYMBOL(insl);
465 EXPORT_SYMBOL(outsb);
466 EXPORT_SYMBOL(outsw);
467 EXPORT_SYMBOL(outsl);