1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * arch/parisc/lib/io.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
61da177e4SLinus Torvalds * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * IO accessing functions which shouldn't be inlined because they're too big
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/module.h>
131da177e4SLinus Torvalds #include <asm/io.h>
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds /* Copies a block of memory to a device in an efficient manner.
161da177e4SLinus Torvalds * Assumes the device can cope with 32-bit transfers. If it can't,
171da177e4SLinus Torvalds * don't use this function.
181da177e4SLinus Torvalds */
memcpy_toio(volatile void __iomem * dst,const void * src,int count)191da177e4SLinus Torvalds void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
201da177e4SLinus Torvalds {
211da177e4SLinus Torvalds if (((unsigned long)dst & 3) != ((unsigned long)src & 3))
221da177e4SLinus Torvalds goto bytecopy;
231da177e4SLinus Torvalds while ((unsigned long)dst & 3) {
241da177e4SLinus Torvalds writeb(*(char *)src, dst++);
251da177e4SLinus Torvalds src++;
261da177e4SLinus Torvalds count--;
271da177e4SLinus Torvalds }
281da177e4SLinus Torvalds while (count > 3) {
291da177e4SLinus Torvalds __raw_writel(*(u32 *)src, dst);
301da177e4SLinus Torvalds src += 4;
311da177e4SLinus Torvalds dst += 4;
321da177e4SLinus Torvalds count -= 4;
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds bytecopy:
351da177e4SLinus Torvalds while (count--) {
361da177e4SLinus Torvalds writeb(*(char *)src, dst++);
371da177e4SLinus Torvalds src++;
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds /*
421da177e4SLinus Torvalds ** Copies a block of memory from a device in an efficient manner.
431da177e4SLinus Torvalds ** Assumes the device can cope with 32-bit transfers. If it can't,
441da177e4SLinus Torvalds ** don't use this function.
451da177e4SLinus Torvalds **
461da177e4SLinus Torvalds ** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
471da177e4SLinus Torvalds ** 27341/64 = 427 cyc per int
481da177e4SLinus Torvalds ** 61311/128 = 478 cyc per short
491da177e4SLinus Torvalds ** 122637/256 = 479 cyc per byte
501da177e4SLinus Torvalds ** Ergo bus latencies dominant (not transfer size).
511da177e4SLinus Torvalds ** Minimize total number of transfers at cost of CPU cycles.
521da177e4SLinus Torvalds ** TODO: only look at src alignment and adjust the stores to dest.
531da177e4SLinus Torvalds */
memcpy_fromio(void * dst,const volatile void __iomem * src,int count)541da177e4SLinus Torvalds void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
551da177e4SLinus Torvalds {
561da177e4SLinus Torvalds /* first compare alignment of src/dst */
571da177e4SLinus Torvalds if ( (((unsigned long)dst ^ (unsigned long)src) & 1) || (count < 2) )
581da177e4SLinus Torvalds goto bytecopy;
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds if ( (((unsigned long)dst ^ (unsigned long)src) & 2) || (count < 4) )
611da177e4SLinus Torvalds goto shortcopy;
621da177e4SLinus Torvalds
631da177e4SLinus Torvalds /* Then check for misaligned start address */
641da177e4SLinus Torvalds if ((unsigned long)src & 1) {
651da177e4SLinus Torvalds *(u8 *)dst = readb(src);
661da177e4SLinus Torvalds src++;
671da177e4SLinus Torvalds dst++;
681da177e4SLinus Torvalds count--;
691da177e4SLinus Torvalds if (count < 2) goto bytecopy;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds if ((unsigned long)src & 2) {
731da177e4SLinus Torvalds *(u16 *)dst = __raw_readw(src);
741da177e4SLinus Torvalds src += 2;
751da177e4SLinus Torvalds dst += 2;
761da177e4SLinus Torvalds count -= 2;
771da177e4SLinus Torvalds }
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds while (count > 3) {
801da177e4SLinus Torvalds *(u32 *)dst = __raw_readl(src);
811da177e4SLinus Torvalds dst += 4;
821da177e4SLinus Torvalds src += 4;
831da177e4SLinus Torvalds count -= 4;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds shortcopy:
871da177e4SLinus Torvalds while (count > 1) {
881da177e4SLinus Torvalds *(u16 *)dst = __raw_readw(src);
891da177e4SLinus Torvalds src += 2;
901da177e4SLinus Torvalds dst += 2;
911da177e4SLinus Torvalds count -= 2;
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds bytecopy:
951da177e4SLinus Torvalds while (count--) {
961da177e4SLinus Torvalds *(char *)dst = readb(src);
971da177e4SLinus Torvalds src++;
981da177e4SLinus Torvalds dst++;
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds }
1011da177e4SLinus Torvalds
1021da177e4SLinus Torvalds /* Sets a block of memory on a device to a given value.
1031da177e4SLinus Torvalds * Assumes the device can cope with 32-bit transfers. If it can't,
1041da177e4SLinus Torvalds * don't use this function.
1051da177e4SLinus Torvalds */
memset_io(volatile void __iomem * addr,unsigned char val,int count)1061da177e4SLinus Torvalds void memset_io(volatile void __iomem *addr, unsigned char val, int count)
1071da177e4SLinus Torvalds {
1081da177e4SLinus Torvalds u32 val32 = (val << 24) | (val << 16) | (val << 8) | val;
1091da177e4SLinus Torvalds while ((unsigned long)addr & 3) {
1101da177e4SLinus Torvalds writeb(val, addr++);
1111da177e4SLinus Torvalds count--;
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds while (count > 3) {
1141da177e4SLinus Torvalds __raw_writel(val32, addr);
1151da177e4SLinus Torvalds addr += 4;
1161da177e4SLinus Torvalds count -= 4;
1171da177e4SLinus Torvalds }
1181da177e4SLinus Torvalds while (count--) {
1191da177e4SLinus Torvalds writeb(val, addr++);
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds /*
1241da177e4SLinus Torvalds * Read COUNT 8-bit bytes from port PORT into memory starting at
1251da177e4SLinus Torvalds * SRC.
1261da177e4SLinus Torvalds */
insb(unsigned long port,void * dst,unsigned long count)1271da177e4SLinus Torvalds void insb (unsigned long port, void *dst, unsigned long count)
1281da177e4SLinus Torvalds {
1291da177e4SLinus Torvalds unsigned char *p;
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds p = (unsigned char *)dst;
1321da177e4SLinus Torvalds
1331da177e4SLinus Torvalds while (((unsigned long)p) & 0x3) {
1341da177e4SLinus Torvalds if (!count)
1351da177e4SLinus Torvalds return;
1361da177e4SLinus Torvalds count--;
1371da177e4SLinus Torvalds *p = inb(port);
1381da177e4SLinus Torvalds p++;
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds while (count >= 4) {
1421da177e4SLinus Torvalds unsigned int w;
1431da177e4SLinus Torvalds count -= 4;
1441da177e4SLinus Torvalds w = inb(port) << 24;
1451da177e4SLinus Torvalds w |= inb(port) << 16;
1461da177e4SLinus Torvalds w |= inb(port) << 8;
1471da177e4SLinus Torvalds w |= inb(port);
1481da177e4SLinus Torvalds *(unsigned int *) p = w;
1491da177e4SLinus Torvalds p += 4;
1501da177e4SLinus Torvalds }
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds while (count) {
1531da177e4SLinus Torvalds --count;
1541da177e4SLinus Torvalds *p = inb(port);
1551da177e4SLinus Torvalds p++;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds /*
1611da177e4SLinus Torvalds * Read COUNT 16-bit words from port PORT into memory starting at
1621da177e4SLinus Torvalds * SRC. SRC must be at least short aligned. This is used by the
1631da177e4SLinus Torvalds * IDE driver to read disk sectors. Performance is important, but
1641da177e4SLinus Torvalds * the interfaces seems to be slow: just using the inlined version
1651da177e4SLinus Torvalds * of the inw() breaks things.
1661da177e4SLinus Torvalds */
insw(unsigned long port,void * dst,unsigned long count)1671da177e4SLinus Torvalds void insw (unsigned long port, void *dst, unsigned long count)
1681da177e4SLinus Torvalds {
1691da177e4SLinus Torvalds unsigned int l = 0, l2;
1701da177e4SLinus Torvalds unsigned char *p;
1711da177e4SLinus Torvalds
1721da177e4SLinus Torvalds p = (unsigned char *)dst;
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds if (!count)
1751da177e4SLinus Torvalds return;
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds switch (((unsigned long)p) & 0x3)
1781da177e4SLinus Torvalds {
1791da177e4SLinus Torvalds case 0x00: /* Buffer 32-bit aligned */
1801da177e4SLinus Torvalds while (count>=2) {
1811da177e4SLinus Torvalds
1821da177e4SLinus Torvalds count -= 2;
1831da177e4SLinus Torvalds l = cpu_to_le16(inw(port)) << 16;
1841da177e4SLinus Torvalds l |= cpu_to_le16(inw(port));
1851da177e4SLinus Torvalds *(unsigned int *)p = l;
1861da177e4SLinus Torvalds p += 4;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds if (count) {
1891da177e4SLinus Torvalds *(unsigned short *)p = cpu_to_le16(inw(port));
1901da177e4SLinus Torvalds }
1911da177e4SLinus Torvalds break;
1921da177e4SLinus Torvalds
1931da177e4SLinus Torvalds case 0x02: /* Buffer 16-bit aligned */
1941da177e4SLinus Torvalds *(unsigned short *)p = cpu_to_le16(inw(port));
1951da177e4SLinus Torvalds p += 2;
1961da177e4SLinus Torvalds count--;
1971da177e4SLinus Torvalds while (count>=2) {
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds count -= 2;
2001da177e4SLinus Torvalds l = cpu_to_le16(inw(port)) << 16;
2011da177e4SLinus Torvalds l |= cpu_to_le16(inw(port));
2021da177e4SLinus Torvalds *(unsigned int *)p = l;
2031da177e4SLinus Torvalds p += 4;
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds if (count) {
2061da177e4SLinus Torvalds *(unsigned short *)p = cpu_to_le16(inw(port));
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds break;
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds case 0x01: /* Buffer 8-bit aligned */
2111da177e4SLinus Torvalds case 0x03:
2121da177e4SLinus Torvalds /* I don't bother with 32bit transfers
2131da177e4SLinus Torvalds * in this case, 16bit will have to do -- DE */
2141da177e4SLinus Torvalds --count;
2151da177e4SLinus Torvalds
2161da177e4SLinus Torvalds l = cpu_to_le16(inw(port));
2171da177e4SLinus Torvalds *p = l >> 8;
2181da177e4SLinus Torvalds p++;
2191da177e4SLinus Torvalds while (count--)
2201da177e4SLinus Torvalds {
2211da177e4SLinus Torvalds l2 = cpu_to_le16(inw(port));
2221da177e4SLinus Torvalds *(unsigned short *)p = (l & 0xff) << 8 | (l2 >> 8);
2231da177e4SLinus Torvalds p += 2;
2241da177e4SLinus Torvalds l = l2;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds *p = l & 0xff;
2271da177e4SLinus Torvalds break;
2281da177e4SLinus Torvalds }
2291da177e4SLinus Torvalds }
2301da177e4SLinus Torvalds
2311da177e4SLinus Torvalds
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds /*
2341da177e4SLinus Torvalds * Read COUNT 32-bit words from port PORT into memory starting at
2351da177e4SLinus Torvalds * SRC. Now works with any alignment in SRC. Performance is important,
2361da177e4SLinus Torvalds * but the interfaces seems to be slow: just using the inlined version
2371da177e4SLinus Torvalds * of the inl() breaks things.
2381da177e4SLinus Torvalds */
insl(unsigned long port,void * dst,unsigned long count)2391da177e4SLinus Torvalds void insl (unsigned long port, void *dst, unsigned long count)
2401da177e4SLinus Torvalds {
2411da177e4SLinus Torvalds unsigned int l = 0, l2;
2421da177e4SLinus Torvalds unsigned char *p;
2431da177e4SLinus Torvalds
2441da177e4SLinus Torvalds p = (unsigned char *)dst;
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds if (!count)
2471da177e4SLinus Torvalds return;
2481da177e4SLinus Torvalds
2491da177e4SLinus Torvalds switch (((unsigned long) dst) & 0x3)
2501da177e4SLinus Torvalds {
2511da177e4SLinus Torvalds case 0x00: /* Buffer 32-bit aligned */
2521da177e4SLinus Torvalds while (count--)
2531da177e4SLinus Torvalds {
2541da177e4SLinus Torvalds *(unsigned int *)p = cpu_to_le32(inl(port));
2551da177e4SLinus Torvalds p += 4;
2561da177e4SLinus Torvalds }
2571da177e4SLinus Torvalds break;
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds case 0x02: /* Buffer 16-bit aligned */
2601da177e4SLinus Torvalds --count;
2611da177e4SLinus Torvalds
2621da177e4SLinus Torvalds l = cpu_to_le32(inl(port));
2631da177e4SLinus Torvalds *(unsigned short *)p = l >> 16;
2641da177e4SLinus Torvalds p += 2;
2651da177e4SLinus Torvalds
2661da177e4SLinus Torvalds while (count--)
2671da177e4SLinus Torvalds {
2681da177e4SLinus Torvalds l2 = cpu_to_le32(inl(port));
2691da177e4SLinus Torvalds *(unsigned int *)p = (l & 0xffff) << 16 | (l2 >> 16);
2701da177e4SLinus Torvalds p += 4;
2711da177e4SLinus Torvalds l = l2;
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds *(unsigned short *)p = l & 0xffff;
2741da177e4SLinus Torvalds break;
2751da177e4SLinus Torvalds case 0x01: /* Buffer 8-bit aligned */
2761da177e4SLinus Torvalds --count;
2771da177e4SLinus Torvalds
2781da177e4SLinus Torvalds l = cpu_to_le32(inl(port));
2791da177e4SLinus Torvalds *(unsigned char *)p = l >> 24;
2801da177e4SLinus Torvalds p++;
2811da177e4SLinus Torvalds *(unsigned short *)p = (l >> 8) & 0xffff;
2821da177e4SLinus Torvalds p += 2;
2831da177e4SLinus Torvalds while (count--)
2841da177e4SLinus Torvalds {
2851da177e4SLinus Torvalds l2 = cpu_to_le32(inl(port));
2861da177e4SLinus Torvalds *(unsigned int *)p = (l & 0xff) << 24 | (l2 >> 8);
2871da177e4SLinus Torvalds p += 4;
2881da177e4SLinus Torvalds l = l2;
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds *p = l & 0xff;
2911da177e4SLinus Torvalds break;
2921da177e4SLinus Torvalds case 0x03: /* Buffer 8-bit aligned */
2931da177e4SLinus Torvalds --count;
2941da177e4SLinus Torvalds
2951da177e4SLinus Torvalds l = cpu_to_le32(inl(port));
2961da177e4SLinus Torvalds *p = l >> 24;
2971da177e4SLinus Torvalds p++;
2981da177e4SLinus Torvalds while (count--)
2991da177e4SLinus Torvalds {
3001da177e4SLinus Torvalds l2 = cpu_to_le32(inl(port));
3011da177e4SLinus Torvalds *(unsigned int *)p = (l & 0xffffff) << 8 | l2 >> 24;
3021da177e4SLinus Torvalds p += 4;
3031da177e4SLinus Torvalds l = l2;
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds *(unsigned short *)p = (l >> 8) & 0xffff;
3061da177e4SLinus Torvalds p += 2;
3071da177e4SLinus Torvalds *p = l & 0xff;
3081da177e4SLinus Torvalds break;
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds }
3111da177e4SLinus Torvalds
3121da177e4SLinus Torvalds
3131da177e4SLinus Torvalds /*
3141da177e4SLinus Torvalds * Like insb but in the opposite direction.
3151da177e4SLinus Torvalds * Don't worry as much about doing aligned memory transfers:
3161da177e4SLinus Torvalds * doing byte reads the "slow" way isn't nearly as slow as
3171da177e4SLinus Torvalds * doing byte writes the slow way (no r-m-w cycle).
3181da177e4SLinus Torvalds */
outsb(unsigned long port,const void * src,unsigned long count)3191da177e4SLinus Torvalds void outsb(unsigned long port, const void * src, unsigned long count)
3201da177e4SLinus Torvalds {
3211da177e4SLinus Torvalds const unsigned char *p;
3221da177e4SLinus Torvalds
3231da177e4SLinus Torvalds p = (const unsigned char *)src;
3241da177e4SLinus Torvalds while (count) {
3251da177e4SLinus Torvalds count--;
3261da177e4SLinus Torvalds outb(*p, port);
3271da177e4SLinus Torvalds p++;
3281da177e4SLinus Torvalds }
3291da177e4SLinus Torvalds }
3301da177e4SLinus Torvalds
3311da177e4SLinus Torvalds /*
3321da177e4SLinus Torvalds * Like insw but in the opposite direction. This is used by the IDE
3331da177e4SLinus Torvalds * driver to write disk sectors. Performance is important, but the
3341da177e4SLinus Torvalds * interfaces seems to be slow: just using the inlined version of the
3351da177e4SLinus Torvalds * outw() breaks things.
3361da177e4SLinus Torvalds */
outsw(unsigned long port,const void * src,unsigned long count)3371da177e4SLinus Torvalds void outsw (unsigned long port, const void *src, unsigned long count)
3381da177e4SLinus Torvalds {
3391da177e4SLinus Torvalds unsigned int l = 0, l2;
3401da177e4SLinus Torvalds const unsigned char *p;
3411da177e4SLinus Torvalds
3421da177e4SLinus Torvalds p = (const unsigned char *)src;
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds if (!count)
3451da177e4SLinus Torvalds return;
3461da177e4SLinus Torvalds
3471da177e4SLinus Torvalds switch (((unsigned long)p) & 0x3)
3481da177e4SLinus Torvalds {
3491da177e4SLinus Torvalds case 0x00: /* Buffer 32-bit aligned */
3501da177e4SLinus Torvalds while (count>=2) {
3511da177e4SLinus Torvalds count -= 2;
3521da177e4SLinus Torvalds l = *(unsigned int *)p;
3531da177e4SLinus Torvalds p += 4;
3541da177e4SLinus Torvalds outw(le16_to_cpu(l >> 16), port);
3551da177e4SLinus Torvalds outw(le16_to_cpu(l & 0xffff), port);
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds if (count) {
3581da177e4SLinus Torvalds outw(le16_to_cpu(*(unsigned short*)p), port);
3591da177e4SLinus Torvalds }
3601da177e4SLinus Torvalds break;
3611da177e4SLinus Torvalds
3621da177e4SLinus Torvalds case 0x02: /* Buffer 16-bit aligned */
3631da177e4SLinus Torvalds
3641da177e4SLinus Torvalds outw(le16_to_cpu(*(unsigned short*)p), port);
3651da177e4SLinus Torvalds p += 2;
3661da177e4SLinus Torvalds count--;
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds while (count>=2) {
3691da177e4SLinus Torvalds count -= 2;
3701da177e4SLinus Torvalds l = *(unsigned int *)p;
3711da177e4SLinus Torvalds p += 4;
3721da177e4SLinus Torvalds outw(le16_to_cpu(l >> 16), port);
3731da177e4SLinus Torvalds outw(le16_to_cpu(l & 0xffff), port);
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds if (count) {
3761da177e4SLinus Torvalds outw(le16_to_cpu(*(unsigned short *)p), port);
3771da177e4SLinus Torvalds }
3781da177e4SLinus Torvalds break;
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds case 0x01: /* Buffer 8-bit aligned */
3811da177e4SLinus Torvalds /* I don't bother with 32bit transfers
3821da177e4SLinus Torvalds * in this case, 16bit will have to do -- DE */
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds l = *p << 8;
3851da177e4SLinus Torvalds p++;
3861da177e4SLinus Torvalds count--;
3871da177e4SLinus Torvalds while (count)
3881da177e4SLinus Torvalds {
3891da177e4SLinus Torvalds count--;
3901da177e4SLinus Torvalds l2 = *(unsigned short *)p;
3911da177e4SLinus Torvalds p += 2;
3921da177e4SLinus Torvalds outw(le16_to_cpu(l | l2 >> 8), port);
3931da177e4SLinus Torvalds l = l2 << 8;
3941da177e4SLinus Torvalds }
3951da177e4SLinus Torvalds l2 = *(unsigned char *)p;
3961da177e4SLinus Torvalds outw (le16_to_cpu(l | l2>>8), port);
3971da177e4SLinus Torvalds break;
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds
4021da177e4SLinus Torvalds
4031da177e4SLinus Torvalds /*
4041da177e4SLinus Torvalds * Like insl but in the opposite direction. This is used by the IDE
4051da177e4SLinus Torvalds * driver to write disk sectors. Works with any alignment in SRC.
4061da177e4SLinus Torvalds * Performance is important, but the interfaces seems to be slow:
4071da177e4SLinus Torvalds * just using the inlined version of the outl() breaks things.
4081da177e4SLinus Torvalds */
outsl(unsigned long port,const void * src,unsigned long count)4091da177e4SLinus Torvalds void outsl (unsigned long port, const void *src, unsigned long count)
4101da177e4SLinus Torvalds {
4111da177e4SLinus Torvalds unsigned int l = 0, l2;
4121da177e4SLinus Torvalds const unsigned char *p;
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds p = (const unsigned char *)src;
4151da177e4SLinus Torvalds
4161da177e4SLinus Torvalds if (!count)
4171da177e4SLinus Torvalds return;
4181da177e4SLinus Torvalds
4191da177e4SLinus Torvalds switch (((unsigned long)p) & 0x3)
4201da177e4SLinus Torvalds {
4211da177e4SLinus Torvalds case 0x00: /* Buffer 32-bit aligned */
4221da177e4SLinus Torvalds while (count--)
4231da177e4SLinus Torvalds {
4241da177e4SLinus Torvalds outl(le32_to_cpu(*(unsigned int *)p), port);
4251da177e4SLinus Torvalds p += 4;
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds break;
4281da177e4SLinus Torvalds
4291da177e4SLinus Torvalds case 0x02: /* Buffer 16-bit aligned */
4301da177e4SLinus Torvalds --count;
4311da177e4SLinus Torvalds
4321da177e4SLinus Torvalds l = *(unsigned short *)p;
4331da177e4SLinus Torvalds p += 2;
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds while (count--)
4361da177e4SLinus Torvalds {
4371da177e4SLinus Torvalds l2 = *(unsigned int *)p;
4381da177e4SLinus Torvalds p += 4;
4391da177e4SLinus Torvalds outl (le32_to_cpu(l << 16 | l2 >> 16), port);
4401da177e4SLinus Torvalds l = l2;
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds l2 = *(unsigned short *)p;
4431da177e4SLinus Torvalds outl (le32_to_cpu(l << 16 | l2), port);
4441da177e4SLinus Torvalds break;
4451da177e4SLinus Torvalds case 0x01: /* Buffer 8-bit aligned */
4461da177e4SLinus Torvalds --count;
4471da177e4SLinus Torvalds
4481da177e4SLinus Torvalds l = *p << 24;
4491da177e4SLinus Torvalds p++;
4501da177e4SLinus Torvalds l |= *(unsigned short *)p << 8;
4511da177e4SLinus Torvalds p += 2;
4521da177e4SLinus Torvalds
4531da177e4SLinus Torvalds while (count--)
4541da177e4SLinus Torvalds {
4551da177e4SLinus Torvalds l2 = *(unsigned int *)p;
4561da177e4SLinus Torvalds p += 4;
4571da177e4SLinus Torvalds outl (le32_to_cpu(l | l2 >> 24), port);
4581da177e4SLinus Torvalds l = l2 << 8;
4591da177e4SLinus Torvalds }
4601da177e4SLinus Torvalds l2 = *p;
4611da177e4SLinus Torvalds outl (le32_to_cpu(l | l2), port);
4621da177e4SLinus Torvalds break;
4631da177e4SLinus Torvalds case 0x03: /* Buffer 8-bit aligned */
4641da177e4SLinus Torvalds --count;
4651da177e4SLinus Torvalds
4661da177e4SLinus Torvalds l = *p << 24;
4671da177e4SLinus Torvalds p++;
4681da177e4SLinus Torvalds
4691da177e4SLinus Torvalds while (count--)
4701da177e4SLinus Torvalds {
4711da177e4SLinus Torvalds l2 = *(unsigned int *)p;
4721da177e4SLinus Torvalds p += 4;
4731da177e4SLinus Torvalds outl (le32_to_cpu(l | l2 >> 8), port);
4741da177e4SLinus Torvalds l = l2 << 24;
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds l2 = *(unsigned short *)p << 16;
4771da177e4SLinus Torvalds p += 2;
4781da177e4SLinus Torvalds l2 |= *p;
4791da177e4SLinus Torvalds outl (le32_to_cpu(l | l2), port);
4801da177e4SLinus Torvalds break;
4811da177e4SLinus Torvalds }
4821da177e4SLinus Torvalds }
4831da177e4SLinus Torvalds
4841da177e4SLinus Torvalds EXPORT_SYMBOL(insb);
4851da177e4SLinus Torvalds EXPORT_SYMBOL(insw);
4861da177e4SLinus Torvalds EXPORT_SYMBOL(insl);
4871da177e4SLinus Torvalds EXPORT_SYMBOL(outsb);
4881da177e4SLinus Torvalds EXPORT_SYMBOL(outsw);
4891da177e4SLinus Torvalds EXPORT_SYMBOL(outsl);
490