OSDN Git Service

46e7892398656a0ed3a481f30fe914b6593c3648
[linux-kernel-docs/linux-2.4.36.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                 ((unsigned char *) dst)++;
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                 ((unsigned int *) dst)++;
158         }
159
160         while (count) {
161                 --count;
162                 *(unsigned char *) dst = inb(port);
163                 ((unsigned char *) dst)++;
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                 ((unsigned short *) dst)++;
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                 ((unsigned int *) dst)++;
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                         ((unsigned int *) dst)++;
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                 ((unsigned short *) dst)++;
234                 
235                 while (count--)
236                 {
237                         l2 = inl(port);
238                         *(unsigned int *) dst = l >> 16 | l2 << 16;
239                         ((unsigned int *) dst)++;
240                         l = l2;
241                 }
242                 *(unsigned short *) dst = l >> 16;
243                 break;
244          case 0x01:                     /* Buffer 8-bit aligned */
245                 --count;
246                 
247                 l = inl(port);
248                 *(unsigned char *) dst = l;
249                 ((unsigned char *) dst)++;
250                 *(unsigned short *) dst = l >> 8;
251                 ((unsigned short *) dst)++;
252                 while (count--)
253                 {
254                         l2 = inl(port);
255                         *(unsigned int *) dst = l >> 24 | l2 << 8;
256                         ((unsigned int *) dst)++;
257                         l = l2;
258                 }
259                 *(unsigned char *) dst = l >> 24;
260                 break;
261          case 0x03:                     /* Buffer 8-bit aligned */
262                 --count;
263                 
264                 l = inl(port);
265                 *(unsigned char *) dst = l;
266                 ((unsigned char *) dst)++;
267                 while (count--)
268                 {
269                         l2 = inl(port);
270                         *(unsigned int *) dst = l << 24 | l2 >> 8;
271                         ((unsigned int *) dst)++;
272                         l = l2;
273                 }
274                 *(unsigned short *) dst = l >> 8;
275                 ((unsigned short *) dst)++;
276                 *(unsigned char *) dst = l >> 24;
277                 break;
278         }
279 }
280
281
282 /*
283  * Like insb but in the opposite direction.
284  * Don't worry as much about doing aligned memory transfers:
285  * doing byte reads the "slow" way isn't nearly as slow as
286  * doing byte writes the slow way (no r-m-w cycle).
287  */
288 void outsb(unsigned long port, const void * src, unsigned long count)
289 {
290         while (count) {
291                 count--;
292                 outb(*(char *)src, port);
293                 ((char *) src)++;
294         }
295 }
296
297 /*
298  * Like insw but in the opposite direction.  This is used by the IDE
299  * driver to write disk sectors.  Performance is important, but the
300  * interfaces seems to be slow: just using the inlined version of the
301  * outw() breaks things.
302  */
303 void outsw (unsigned long port, const void *src, unsigned long count)
304 {
305         if (((unsigned long)src) & 0x3) {
306                 if (((unsigned long)src) & 0x1) {
307                         panic("outsw: memory not short aligned");
308                 }
309                 outw(*(unsigned short*)src, port);
310                 ((unsigned short *) src)++;
311                 --count;
312         }
313
314         while (count >= 2) {
315                 unsigned int w;
316                 count -= 2;
317                 w = *(unsigned int *) src;
318                 ((unsigned int *) src)++;
319                 outw(w >>  0, port);
320                 outw(w >> 16, port);
321         }
322
323         if (count) {
324                 outw(*(unsigned short *) src, port);
325         }
326 }
327
328
329 /*
330  * Like insl but in the opposite direction.  This is used by the IDE
331  * driver to write disk sectors.  Works with any alignment in SRC.
332  *  Performance is important, but the interfaces seems to be slow:
333  * just using the inlined version of the outl() breaks things.
334  */
335 void outsl (unsigned long port, const void *src, unsigned long count)
336 {
337         unsigned int l = 0, l2;
338         
339         if (!count)
340                 return;
341         
342         switch (((unsigned long) src) & 0x3)
343         {
344          case 0x00:                     /* Buffer 32-bit aligned */
345                 while (count--)
346                 {
347                         outl(*(unsigned int *) src, port);
348                         ((unsigned int *) src)++;
349                 }
350                 break;
351         
352         /* Assuming little endian Alphas in cases 0x01 -- 0x03 ... */
353         
354          case 0x02:                     /* Buffer 16-bit aligned */
355                 --count;
356                 
357                 l = *(unsigned short *) src << 16;
358                 ((unsigned short *) src)++;
359                 
360                 while (count--)
361                 {
362                         l2 = *(unsigned int *) src;
363                         ((unsigned int *) src)++;
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          case 0x01:                     /* Buffer 8-bit aligned */
371                 --count;
372                 
373                 l  = *(unsigned char *) src << 8;
374                 ((unsigned char *) src)++;
375                 l |= *(unsigned short *) src << 16;
376                 ((unsigned short *) src)++;
377                 while (count--)
378                 {
379                         l2 = *(unsigned int *) src;
380                         ((unsigned int *) src)++;
381                         outl (l >> 8 | l2 << 24, port);
382                         l = l2;
383                 }
384                 l2 = *(unsigned char *) src;
385                 outl (l >> 8 | l2 << 24, port);
386                 break;
387          case 0x03:                     /* Buffer 8-bit aligned */
388                 --count;
389                 
390                 l  = *(unsigned char *) src << 24;
391                 ((unsigned char *) src)++;
392                 while (count--)
393                 {
394                         l2 = *(unsigned int *) src;
395                         ((unsigned int *) src)++;
396                         outl (l >> 24 | l2 << 8, port);
397                         l = l2;
398                 }
399                 l2  = *(unsigned short *) src;
400                 ((unsigned short *) src)++;
401                 l2 |= *(unsigned char *) src << 16;
402                 outl (l >> 24 | l2 << 8, port);
403                 break;
404         }
405 }
406
407
408 /*
409  * Copy data from IO memory space to "real" memory space.
410  * This needs to be optimized.
411  */
412 void _memcpy_fromio(void * to, unsigned long from, long count)
413 {
414         /* Optimize co-aligned transfers.  Everything else gets handled
415            a byte at a time. */
416
417         if (count >= 8 && ((long)to & 7) == (from & 7)) {
418                 count -= 8;
419                 do {
420                         *(u64 *)to = __raw_readq(from);
421                         count -= 8;
422                         to += 8;
423                         from += 8;
424                 } while (count >= 0);
425                 count += 8;
426         }
427
428         if (count >= 4 && ((long)to & 3) == (from & 3)) {
429                 count -= 4;
430                 do {
431                         *(u32 *)to = __raw_readl(from);
432                         count -= 4;
433                         to += 4;
434                         from += 4;
435                 } while (count >= 0);
436                 count += 4;
437         }
438                 
439         if (count >= 2 && ((long)to & 1) == (from & 1)) {
440                 count -= 2;
441                 do {
442                         *(u16 *)to = __raw_readw(from);
443                         count -= 2;
444                         to += 2;
445                         from += 2;
446                 } while (count >= 0);
447                 count += 2;
448         }
449
450         while (count > 0) {
451                 *(u8 *) to = __raw_readb(from);
452                 count--;
453                 to++;
454                 from++;
455         }
456 }
457
458 /*
459  * Copy data from "real" memory space to IO memory space.
460  * This needs to be optimized.
461  */
462 void _memcpy_toio(unsigned long to, const void * from, long count)
463 {
464         /* Optimize co-aligned transfers.  Everything else gets handled
465            a byte at a time. */
466         /* FIXME -- align FROM.  */
467
468         if (count >= 8 && (to & 7) == ((long)from & 7)) {
469                 count -= 8;
470                 do {
471                         __raw_writeq(*(const u64 *)from, to);
472                         count -= 8;
473                         to += 8;
474                         from += 8;
475                 } while (count >= 0);
476                 count += 8;
477         }
478
479         if (count >= 4 && (to & 3) == ((long)from & 3)) {
480                 count -= 4;
481                 do {
482                         __raw_writel(*(const u32 *)from, to);
483                         count -= 4;
484                         to += 4;
485                         from += 4;
486                 } while (count >= 0);
487                 count += 4;
488         }
489                 
490         if (count >= 2 && (to & 1) == ((long)from & 1)) {
491                 count -= 2;
492                 do {
493                         __raw_writew(*(const u16 *)from, to);
494                         count -= 2;
495                         to += 2;
496                         from += 2;
497                 } while (count >= 0);
498                 count += 2;
499         }
500
501         while (count > 0) {
502                 __raw_writeb(*(const u8 *) from, to);
503                 count--;
504                 to++;
505                 from++;
506         }
507         mb();
508 }
509
510 /*
511  * "memset" on IO memory space.
512  */
513 void _memset_c_io(unsigned long to, unsigned long c, long count)
514 {
515         /* Handle any initial odd byte */
516         if (count > 0 && (to & 1)) {
517                 __raw_writeb(c, to);
518                 to++;
519                 count--;
520         }
521
522         /* Handle any initial odd halfword */
523         if (count >= 2 && (to & 2)) {
524                 __raw_writew(c, to);
525                 to += 2;
526                 count -= 2;
527         }
528
529         /* Handle any initial odd word */
530         if (count >= 4 && (to & 4)) {
531                 __raw_writel(c, to);
532                 to += 4;
533                 count -= 4;
534         }
535
536         /* Handle all full-sized quadwords: we're aligned
537            (or have a small count) */
538         count -= 8;
539         if (count >= 0) {
540                 do {
541                         __raw_writeq(c, to);
542                         to += 8;
543                         count -= 8;
544                 } while (count >= 0);
545         }
546         count += 8;
547
548         /* The tail is word-aligned if we still have count >= 4 */
549         if (count >= 4) {
550                 __raw_writel(c, to);
551                 to += 4;
552                 count -= 4;
553         }
554
555         /* The tail is half-word aligned if we have count >= 2 */
556         if (count >= 2) {
557                 __raw_writew(c, to);
558                 to += 2;
559                 count -= 2;
560         }
561
562         /* And finally, one last byte.. */
563         if (count) {
564                 __raw_writeb(c, to);
565         }
566         mb();
567 }
568
569 void
570 scr_memcpyw(u16 *d, const u16 *s, unsigned int count)
571 {
572         if (! __is_ioaddr((unsigned long) s)) {
573                 /* Source is memory.  */
574                 if (! __is_ioaddr((unsigned long) d))
575                         memcpy(d, s, count);
576                 else
577                         memcpy_toio(d, s, count);
578         } else {
579                 /* Source is screen.  */
580                 if (! __is_ioaddr((unsigned long) d))
581                         memcpy_fromio(d, s, count);
582                 else {
583                         /* FIXME: Should handle unaligned ops and
584                            operation widening.  */
585                         count /= 2;
586                         while (count--) {
587                                 u16 tmp = __raw_readw((unsigned long)(s++));
588                                 __raw_writew(tmp, (unsigned long)(d++));
589                         }
590                 }
591         }
592 }