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
_inb(unsigned long addr)12 u8 _inb(unsigned long addr)
13 {
14 return __inb(addr);
15 }
16
_inw(unsigned long addr)17 u16 _inw(unsigned long addr)
18 {
19 return __inw(addr);
20 }
21
_inl(unsigned long addr)22 u32 _inl(unsigned long addr)
23 {
24 return __inl(addr);
25 }
26
27
_outb(u8 b,unsigned long addr)28 void _outb(u8 b, unsigned long addr)
29 {
30 __outb(b, addr);
31 }
32
_outw(u16 b,unsigned long addr)33 void _outw(u16 b, unsigned long addr)
34 {
35 __outw(b, addr);
36 }
37
_outl(u32 b,unsigned long addr)38 void _outl(u32 b, unsigned long addr)
39 {
40 __outl(b, addr);
41 }
42
___raw_readb(unsigned long addr)43 u8 ___raw_readb(unsigned long addr)
44 {
45 return __readb(addr);
46 }
47
___raw_readw(unsigned long addr)48 u16 ___raw_readw(unsigned long addr)
49 {
50 return __readw(addr);
51 }
52
___raw_readl(unsigned long addr)53 u32 ___raw_readl(unsigned long addr)
54 {
55 return __readl(addr);
56 }
57
___raw_readq(unsigned long addr)58 u64 ___raw_readq(unsigned long addr)
59 {
60 return __readq(addr);
61 }
62
_readb(unsigned long addr)63 u8 _readb(unsigned long addr)
64 {
65 unsigned long r = __readb(addr);
66 mb();
67 return r;
68 }
69
_readw(unsigned long addr)70 u16 _readw(unsigned long addr)
71 {
72 unsigned long r = __readw(addr);
73 mb();
74 return r;
75 }
76
_readl(unsigned long addr)77 u32 _readl(unsigned long addr)
78 {
79 unsigned long r = __readl(addr);
80 mb();
81 return r;
82 }
83
_readq(unsigned long addr)84 u64 _readq(unsigned long addr)
85 {
86 unsigned long r = __readq(addr);
87 mb();
88 return r;
89 }
90
___raw_writeb(u8 b,unsigned long addr)91 void ___raw_writeb(u8 b, unsigned long addr)
92 {
93 __writeb(b, addr);
94 }
95
___raw_writew(u16 b,unsigned long addr)96 void ___raw_writew(u16 b, unsigned long addr)
97 {
98 __writew(b, addr);
99 }
100
___raw_writel(u32 b,unsigned long addr)101 void ___raw_writel(u32 b, unsigned long addr)
102 {
103 __writel(b, addr);
104 }
105
___raw_writeq(u64 b,unsigned long addr)106 void ___raw_writeq(u64 b, unsigned long addr)
107 {
108 __writeq(b, addr);
109 }
110
_writeb(u8 b,unsigned long addr)111 void _writeb(u8 b, unsigned long addr)
112 {
113 __writeb(b, addr);
114 mb();
115 }
116
_writew(u16 b,unsigned long addr)117 void _writew(u16 b, unsigned long addr)
118 {
119 __writew(b, addr);
120 mb();
121 }
122
_writel(u32 b,unsigned long addr)123 void _writel(u32 b, unsigned long addr)
124 {
125 __writel(b, addr);
126 mb();
127 }
128
_writeq(u64 b,unsigned long addr)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 */
insb(unsigned long port,void * dst,unsigned long count)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 = (unsigned char *)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 = (unsigned int *)dst + 1;
158 }
159
160 while (count) {
161 --count;
162 *(unsigned char *) dst = inb(port);
163 dst = (unsigned char *)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 */
insw(unsigned long port,void * dst,unsigned long count)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 = (unsigned short *)dst + 1;
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 = (unsigned int *)dst + 1;
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 */
insl(unsigned long port,void * dst,unsigned long count)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 = (unsigned int *)dst + 1;
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 = (unsigned short *)dst + 1;
234
235 while (count--)
236 {
237 l2 = inl(port);
238 *(unsigned int *) dst = l >> 16 | l2 << 16;
239 dst = (unsigned int *)dst + 1;
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 dst = (unsigned char *)dst + 1;
250 *(unsigned short *) dst = l >> 8;
251 dst = (unsigned short *)dst + 1;
252 while (count--)
253 {
254 l2 = inl(port);
255 *(unsigned int *) dst = l >> 24 | l2 << 8;
256 dst = (unsigned int *)dst + 1;
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 dst = (unsigned char *)dst + 1;
267 while (count--)
268 {
269 l2 = inl(port);
270 *(unsigned int *) dst = l << 24 | l2 >> 8;
271 dst = (unsigned int *)dst + 1;
272 l = l2;
273 }
274 *(unsigned short *) dst = l >> 8;
275 dst = (unsigned short *)dst + 1;
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 */
outsb(unsigned long port,const void * src,unsigned long count)288 void outsb(unsigned long port, const void * src, unsigned long count)
289 {
290 while (count) {
291 count--;
292 outb(*(char *)src, port);
293 src = (char *)src + 1;
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 */
outsw(unsigned long port,const void * src,unsigned long count)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 src = (unsigned short *)src + 1;
311 --count;
312 }
313
314 while (count >= 2) {
315 unsigned int w;
316 count -= 2;
317 w = *(unsigned int *) src;
318 src = (unsigned int *)src + 1;
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 */
outsl(unsigned long port,const void * src,unsigned long count)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 src = (unsigned int *)src + 1;
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 src = (unsigned short *)src + 1;
359
360 while (count--)
361 {
362 l2 = *(unsigned int *) src;
363 src = (unsigned int *)src + 1;
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 src = (unsigned char *)src + 1;
375 l |= *(unsigned short *) src << 16;
376 src = (unsigned short *)src + 1;
377 while (count--)
378 {
379 l2 = *(unsigned int *) src;
380 src = (unsigned int *)src + 1;
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 src = (unsigned char *)src + 1;
392 while (count--)
393 {
394 l2 = *(unsigned int *) src;
395 src = (unsigned int *)src + 1;
396 outl (l >> 24 | l2 << 8, port);
397 l = l2;
398 }
399 l2 = *(unsigned short *) src;
400 src = (unsigned short *)src + 1;
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 */
_memcpy_fromio(void * to,unsigned long from,long count)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 */
_memcpy_toio(unsigned long to,const void * from,long count)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 */
_memset_c_io(unsigned long to,unsigned long c,long count)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
scr_memcpyw(u16 * d,const u16 * s,unsigned int count)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 }
593