ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / alpha / lib / io.c
1 /*
2  * Alpha IO and memory functions.. Just expand the inlines in the header
3  * files..
4  */
5
6 #include <linux/kernel.h>
7 #include <linux/types.h>
8 #include <linux/string.h>
9
10 #include <asm/io.h>
11
12 u8 _inb(unsigned long addr)
13 {
14         return __inb(addr);
15 }
16
17 u16 _inw(unsigned long addr)
18 {
19         return __inw(addr);
20 }
21
22 u32 _inl(unsigned long addr)
23 {
24         return __inl(addr);
25 }
26
27
28 void _outb(u8 b, unsigned long addr)
29 {
30         __outb(b, addr);
31 }
32
33 void _outw(u16 b, unsigned long addr)
34 {
35         __outw(b, addr);
36 }
37
38 void _outl(u32 b, unsigned long addr)
39 {
40         __outl(b, addr);
41 }
42
43 u8 ___raw_readb(unsigned long addr)
44 {
45         return __readb(addr);
46 }
47
48 u16 ___raw_readw(unsigned long addr)
49 {
50         return __readw(addr);
51 }
52
53 u32 ___raw_readl(unsigned long addr)
54 {
55         return __readl(addr);
56 }
57
58 u64 ___raw_readq(unsigned long addr)
59 {
60         return __readq(addr);
61 }
62
63 u8 _readb(unsigned long addr)
64 {
65         unsigned long r = __readb(addr);
66         mb();
67         return r;
68 }
69
70 u16 _readw(unsigned long addr)
71 {
72         unsigned long r = __readw(addr);
73         mb();
74         return r;
75 }
76
77 u32 _readl(unsigned long addr)
78 {
79         unsigned long r = __readl(addr);
80         mb();
81         return r;
82 }
83
84 u64 _readq(unsigned long addr)
85 {
86         unsigned long r = __readq(addr);
87         mb();
88         return r;
89 }
90
91 void ___raw_writeb(u8 b, unsigned long addr)
92 {
93         __writeb(b, addr);
94 }
95
96 void ___raw_writew(u16 b, unsigned long addr)
97 {
98         __writew(b, addr);
99 }
100
101 void ___raw_writel(u32 b, unsigned long addr)
102 {
103         __writel(b, addr);
104 }
105
106 void ___raw_writeq(u64 b, unsigned long addr)
107 {
108         __writeq(b, addr);
109 }
110
111 void _writeb(u8 b, unsigned long addr)
112 {
113         __writeb(b, addr);
114         mb();
115 }
116
117 void _writew(u16 b, unsigned long addr)
118 {
119         __writew(b, addr);
120         mb();
121 }
122
123 void _writel(u32 b, unsigned long addr)
124 {
125         __writel(b, addr);
126         mb();
127 }
128
129 void _writeq(u64 b, unsigned long addr)
130 {
131         __writeq(b, addr);
132         mb();
133 }
134
135 /*
136  * Read COUNT 8-bit bytes from port PORT into memory starting at
137  * SRC.
138  */
139 void insb (unsigned long port, void *dst, unsigned long count)
140 {
141         while (((unsigned long)dst) & 0x3) {
142                 if (!count)
143                         return;
144                 count--;
145                 *(unsigned char *) dst = inb(port);
146                 dst += 1;
147         }
148
149         while (count >= 4) {
150                 unsigned int w;
151                 count -= 4;
152                 w = inb(port);
153                 w |= inb(port) << 8;
154                 w |= inb(port) << 16;
155                 w |= inb(port) << 24;
156                 *(unsigned int *) dst = w;
157                 dst += 4;
158         }
159
160         while (count) {
161                 --count;
162                 *(unsigned char *) dst = inb(port);
163                 dst += 1;
164         }
165 }
166
167
168 /*
169  * Read COUNT 16-bit words from port PORT into memory starting at
170  * SRC.  SRC must be at least short aligned.  This is used by the
171  * IDE driver to read disk sectors.  Performance is important, but
172  * the interfaces seems to be slow: just using the inlined version
173  * of the inw() breaks things.
174  */
175 void insw (unsigned long port, void *dst, unsigned long count)
176 {
177         if (((unsigned long)dst) & 0x3) {
178                 if (((unsigned long)dst) & 0x1) {
179                         panic("insw: memory not short aligned");
180                 }
181                 if (!count)
182                         return;
183                 count--;
184                 *(unsigned short *) dst = inw(port);
185                 dst += 2;
186         }
187
188         while (count >= 2) {
189                 unsigned int w;
190                 count -= 2;
191                 w = inw(port);
192                 w |= inw(port) << 16;
193                 *(unsigned int *) dst = w;
194                 dst += 4;
195         }
196
197         if (count) {
198                 *(unsigned short*) dst = inw(port);
199         }
200 }
201
202
203 /*
204  * Read COUNT 32-bit words from port PORT into memory starting at
205  * SRC. Now works with any alignment in SRC. Performance is important,
206  * but the interfaces seems to be slow: just using the inlined version
207  * of the inl() breaks things.
208  */
209 void insl (unsigned long port, void *dst, unsigned long count)
210 {
211         unsigned int l = 0, l2;
212
213         if (!count)
214                 return;
215
216         switch (((unsigned long) dst) & 0x3)
217         {
218          case 0x00:                     /* Buffer 32-bit aligned */
219                 while (count--)
220                 {
221                         *(unsigned int *) dst = inl(port);
222                         dst += 4;
223                 }
224                 break;
225
226         /* Assuming little endian Alphas in cases 0x01 -- 0x03 ... */
227
228          case 0x02:                     /* Buffer 16-bit aligned */
229                 --count;
230
231                 l = inl(port);
232                 *(unsigned short *) dst = l;
233                 dst += 2;
234
235                 while (count--)
236                 {
237                         l2 = inl(port);
238                         *(unsigned int *) dst = l >> 16 | l2 << 16;
239                         dst += 4;
240                         l = l2;
241                 }
242                 *(unsigned short *) dst = l >> 16;
243                 break;
244
245          case 0x01:                     /* Buffer 8-bit aligned */
246                 --count;
247
248                 l = inl(port);
249                 *(unsigned char *) dst = l;
250                 dst += 1;
251                 *(unsigned short *) dst = l >> 8;
252                 dst += 2;
253                 while (count--)
254                 {
255                         l2 = inl(port);
256                         *(unsigned int *) dst = l >> 24 | l2 << 8;
257                         dst += 4;
258                         l = l2;
259                 }
260                 *(unsigned char *) dst = l >> 24;
261                 break;
262
263          case 0x03:                     /* Buffer 8-bit aligned */
264                 --count;
265
266                 l = inl(port);
267                 *(unsigned char *) dst = l;
268                 dst += 1;
269                 while (count--)
270                 {
271                         l2 = inl(port);
272                         *(unsigned int *) dst = l << 24 | l2 >> 8;
273                         dst += 4;
274                         l = l2;
275                 }
276                 *(unsigned short *) dst = l >> 8;
277                 dst += 2;
278                 *(unsigned char *) dst = l >> 24;
279                 break;
280         }
281 }
282
283
284 /*
285  * Like insb but in the opposite direction.
286  * Don't worry as much about doing aligned memory transfers:
287  * doing byte reads the "slow" way isn't nearly as slow as
288  * doing byte writes the slow way (no r-m-w cycle).
289  */
290 void outsb(unsigned long port, const void * src, unsigned long count)
291 {
292         while (count) {
293                 count--;
294                 outb(*(char *)src, port);
295                 src += 1;
296         }
297 }
298
299 /*
300  * Like insw but in the opposite direction.  This is used by the IDE
301  * driver to write disk sectors.  Performance is important, but the
302  * interfaces seems to be slow: just using the inlined version of the
303  * outw() breaks things.
304  */
305 void outsw (unsigned long port, const void *src, unsigned long count)
306 {
307         if (((unsigned long)src) & 0x3) {
308                 if (((unsigned long)src) & 0x1) {
309                         panic("outsw: memory not short aligned");
310                 }
311                 outw(*(unsigned short*)src, port);
312                 src += 2;
313                 --count;
314         }
315
316         while (count >= 2) {
317                 unsigned int w;
318                 count -= 2;
319                 w = *(unsigned int *) src;
320                 src += 4;
321                 outw(w >>  0, port);
322                 outw(w >> 16, port);
323         }
324
325         if (count) {
326                 outw(*(unsigned short *) src, port);
327         }
328 }
329
330
331 /*
332  * Like insl but in the opposite direction.  This is used by the IDE
333  * driver to write disk sectors.  Works with any alignment in SRC.
334  *  Performance is important, but the interfaces seems to be slow:
335  * just using the inlined version of the outl() breaks things.
336  */
337 void outsl (unsigned long port, const void *src, unsigned long count)
338 {
339         unsigned int l = 0, l2;
340
341         if (!count)
342                 return;
343
344         switch (((unsigned long) src) & 0x3)
345         {
346          case 0x00:                     /* Buffer 32-bit aligned */
347                 while (count--)
348                 {
349                         outl(*(unsigned int *) src, port);
350                         src += 4;
351                 }
352                 break;
353
354          case 0x02:                     /* Buffer 16-bit aligned */
355                 --count;
356
357                 l = *(unsigned short *) src << 16;
358                 src += 2;
359
360                 while (count--)
361                 {
362                         l2 = *(unsigned int *) src;
363                         src += 4;
364                         outl (l >> 16 | l2 << 16, port);
365                         l = l2;
366                 }
367                 l2 = *(unsigned short *) src;
368                 outl (l >> 16 | l2 << 16, port);
369                 break;
370
371          case 0x01:                     /* Buffer 8-bit aligned */
372                 --count;
373
374                 l  = *(unsigned char *) src << 8;
375                 src += 1;
376                 l |= *(unsigned short *) src << 16;
377                 src += 2;
378                 while (count--)
379                 {
380                         l2 = *(unsigned int *) src;
381                         src += 4;
382                         outl (l >> 8 | l2 << 24, port);
383                         l = l2;
384                 }
385                 l2 = *(unsigned char *) src;
386                 outl (l >> 8 | l2 << 24, port);
387                 break;
388
389          case 0x03:                     /* Buffer 8-bit aligned */
390                 --count;
391
392                 l  = *(unsigned char *) src << 24;
393                 src += 1;
394                 while (count--)
395                 {
396                         l2 = *(unsigned int *) src;
397                         src += 4;
398                         outl (l >> 24 | l2 << 8, port);
399                         l = l2;
400                 }
401                 l2  = *(unsigned short *) src;
402                 src += 2;
403                 l2 |= *(unsigned char *) src << 16;
404                 outl (l >> 24 | l2 << 8, port);
405                 break;
406         }
407 }
408
409
410 /*
411  * Copy data from IO memory space to "real" memory space.
412  * This needs to be optimized.
413  */
414 void _memcpy_fromio(void * to, unsigned long from, long count)
415 {
416         /* Optimize co-aligned transfers.  Everything else gets handled
417            a byte at a time. */
418
419         if (count >= 8 && ((unsigned long)to & 7) == (from & 7)) {
420                 count -= 8;
421                 do {
422                         *(u64 *)to = __raw_readq(from);
423                         count -= 8;
424                         to += 8;
425                         from += 8;
426                 } while (count >= 0);
427                 count += 8;
428         }
429
430         if (count >= 4 && ((unsigned long)to & 3) == (from & 3)) {
431                 count -= 4;
432                 do {
433                         *(u32 *)to = __raw_readl(from);
434                         count -= 4;
435                         to += 4;
436                         from += 4;
437                 } while (count >= 0);
438                 count += 4;
439         }
440
441         if (count >= 2 && ((unsigned long)to & 1) == (from & 1)) {
442                 count -= 2;
443                 do {
444                         *(u16 *)to = __raw_readw(from);
445                         count -= 2;
446                         to += 2;
447                         from += 2;
448                 } while (count >= 0);
449                 count += 2;
450         }
451
452         while (count > 0) {
453                 *(u8 *) to = __raw_readb(from);
454                 count--;
455                 to++;
456                 from++;
457         }
458 }
459
460 /*
461  * Copy data from "real" memory space to IO memory space.
462  * This needs to be optimized.
463  */
464 void _memcpy_toio(unsigned long to, const void * from, long count)
465 {
466         /* Optimize co-aligned transfers.  Everything else gets handled
467            a byte at a time. */
468         /* FIXME -- align FROM.  */
469
470         if (count >= 8 && (to & 7) == ((unsigned long)from & 7)) {
471                 count -= 8;
472                 do {
473                         __raw_writeq(*(const u64 *)from, to);
474                         count -= 8;
475                         to += 8;
476                         from += 8;
477                 } while (count >= 0);
478                 count += 8;
479         }
480
481         if (count >= 4 && (to & 3) == ((unsigned long)from & 3)) {
482                 count -= 4;
483                 do {
484                         __raw_writel(*(const u32 *)from, to);
485                         count -= 4;
486                         to += 4;
487                         from += 4;
488                 } while (count >= 0);
489                 count += 4;
490         }
491
492         if (count >= 2 && (to & 1) == ((unsigned long)from & 1)) {
493                 count -= 2;
494                 do {
495                         __raw_writew(*(const u16 *)from, to);
496                         count -= 2;
497                         to += 2;
498                         from += 2;
499                 } while (count >= 0);
500                 count += 2;
501         }
502
503         while (count > 0) {
504                 __raw_writeb(*(const u8 *) from, to);
505                 count--;
506                 to++;
507                 from++;
508         }
509         mb();
510 }
511
512 /*
513  * "memset" on IO memory space.
514  */
515 void _memset_c_io(unsigned long to, unsigned long c, long count)
516 {
517         /* Handle any initial odd byte */
518         if (count > 0 && (to & 1)) {
519                 __raw_writeb(c, to);
520                 to++;
521                 count--;
522         }
523
524         /* Handle any initial odd halfword */
525         if (count >= 2 && (to & 2)) {
526                 __raw_writew(c, to);
527                 to += 2;
528                 count -= 2;
529         }
530
531         /* Handle any initial odd word */
532         if (count >= 4 && (to & 4)) {
533                 __raw_writel(c, to);
534                 to += 4;
535                 count -= 4;
536         }
537
538         /* Handle all full-sized quadwords: we're aligned
539            (or have a small count) */
540         count -= 8;
541         if (count >= 0) {
542                 do {
543                         __raw_writeq(c, to);
544                         to += 8;
545                         count -= 8;
546                 } while (count >= 0);
547         }
548         count += 8;
549
550         /* The tail is word-aligned if we still have count >= 4 */
551         if (count >= 4) {
552                 __raw_writel(c, to);
553                 to += 4;
554                 count -= 4;
555         }
556
557         /* The tail is half-word aligned if we have count >= 2 */
558         if (count >= 2) {
559                 __raw_writew(c, to);
560                 to += 2;
561                 count -= 2;
562         }
563
564         /* And finally, one last byte.. */
565         if (count) {
566                 __raw_writeb(c, to);
567         }
568         mb();
569 }
570
571 void
572 scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
573 {
574         if (! __is_ioaddr((unsigned long) s)) {
575                 /* Source is memory.  */
576                 if (! __is_ioaddr((unsigned long) d))
577                         memcpy(d, s, count);
578                 else
579                         memcpy_toio(d, s, count);
580         } else {
581                 /* Source is screen.  */
582                 if (! __is_ioaddr((unsigned long) d))
583                         memcpy_fromio(d, s, count);
584                 else {
585                         /* FIXME: Should handle unaligned ops and
586                            operation widening.  */
587                         count /= 2;
588                         while (count--) {
589                                 u16 tmp = __raw_readw((unsigned long)(s++));
590                                 __raw_writew(tmp, (unsigned long)(d++));
591                         }
592                 }
593         }
594 }