PageRenderTime 45ms CodeModel.GetById 13ms app.highlight 28ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/alpha/kernel/io.c

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