^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * I/O string operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2006 IBM Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Largely rewritten by Cort Dougan (cort@cs.nmt.edu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * and Paul Mackerras.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Rewritten in C by Stephen Rothwell.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/bug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /* See definition in io.h */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) bool isa_io_special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) void _insb(const volatile u8 __iomem *port, void *buf, long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u8 *tbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u8 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) if (unlikely(count <= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) tmp = *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) eieio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *tbuf++ = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) } while (--count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) EXPORT_SYMBOL(_insb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) void _outsb(volatile u8 __iomem *port, const void *buf, long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) const u8 *tbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (unlikely(count <= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) *port = *tbuf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) } while (--count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) EXPORT_SYMBOL(_outsb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) void _insw_ns(const volatile u16 __iomem *port, void *buf, long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) u16 *tbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) u16 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (unlikely(count <= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) tmp = *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) eieio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) *tbuf++ = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) } while (--count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) EXPORT_SYMBOL(_insw_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) void _outsw_ns(volatile u16 __iomem *port, const void *buf, long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) const u16 *tbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) if (unlikely(count <= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) *port = *tbuf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) } while (--count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) EXPORT_SYMBOL(_outsw_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) void _insl_ns(const volatile u32 __iomem *port, void *buf, long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u32 *tbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) u32 tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (unlikely(count <= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) tmp = *port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) eieio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) *tbuf++ = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) } while (--count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) asm volatile("twi 0,%0,0; isync" : : "r" (tmp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) EXPORT_SYMBOL(_insl_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) void _outsl_ns(volatile u32 __iomem *port, const void *buf, long count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) const u32 *tbuf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (unlikely(count <= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) *port = *tbuf++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) } while (--count != 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) asm volatile("sync");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) EXPORT_SYMBOL(_outsl_ns);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) notrace void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) _memset_io(volatile void __iomem *addr, int c, unsigned long n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) void *p = (void __force *)addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) u32 lc = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) lc |= lc << 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) lc |= lc << 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) __asm__ __volatile__ ("sync" : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) while(n && !IO_CHECK_ALIGN(p, 4)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) *((volatile u8 *)p) = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) n--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) while(n >= 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) *((volatile u32 *)p) = lc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) p += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) n -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) while(n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) *((volatile u8 *)p) = c;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) n--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) __asm__ __volatile__ ("sync" : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) EXPORT_SYMBOL(_memset_io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) void _memcpy_fromio(void *dest, const volatile void __iomem *src,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) unsigned long n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) void *vsrc = (void __force *) src;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) __asm__ __volatile__ ("sync" : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) while(n && (!IO_CHECK_ALIGN(vsrc, 4) || !IO_CHECK_ALIGN(dest, 4))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) *((u8 *)dest) = *((volatile u8 *)vsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) eieio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) vsrc++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) dest++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) n--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) while(n >= 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) *((u32 *)dest) = *((volatile u32 *)vsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) eieio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) vsrc += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) dest += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) n -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) while(n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) *((u8 *)dest) = *((volatile u8 *)vsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) eieio();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) vsrc++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) dest++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) n--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) __asm__ __volatile__ ("sync" : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) EXPORT_SYMBOL(_memcpy_fromio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) void _memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) void *vdest = (void __force *) dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) __asm__ __volatile__ ("sync" : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) while(n && (!IO_CHECK_ALIGN(vdest, 4) || !IO_CHECK_ALIGN(src, 4))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) *((volatile u8 *)vdest) = *((u8 *)src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) src++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) vdest++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) n--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) while(n >= 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) *((volatile u32 *)vdest) = *((volatile u32 *)src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) src += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) vdest += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) n-=4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) while(n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) *((volatile u8 *)vdest) = *((u8 *)src);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) src++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) vdest++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) n--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) __asm__ __volatile__ ("sync" : : : "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) EXPORT_SYMBOL(_memcpy_toio);