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