cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

io.c (9992B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * arch/parisc/lib/io.c
      4 *
      5 * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
      6 * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
      7 *
      8 * IO accessing functions which shouldn't be inlined because they're too big
      9 */
     10
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <asm/io.h>
     14
     15/* Copies a block of memory to a device in an efficient manner.
     16 * Assumes the device can cope with 32-bit transfers.  If it can't,
     17 * don't use this function.
     18 */
     19void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
     20{
     21	if (((unsigned long)dst & 3) != ((unsigned long)src & 3))
     22		goto bytecopy;
     23	while ((unsigned long)dst & 3) {
     24		writeb(*(char *)src, dst++);
     25		src++;
     26		count--;
     27	}
     28	while (count > 3) {
     29		__raw_writel(*(u32 *)src, dst);
     30		src += 4;
     31		dst += 4;
     32		count -= 4;
     33	}
     34 bytecopy:
     35	while (count--) {
     36		writeb(*(char *)src, dst++);
     37		src++;
     38	}
     39}
     40
     41/*
     42** Copies a block of memory from a device in an efficient manner.
     43** Assumes the device can cope with 32-bit transfers.  If it can't,
     44** don't use this function.
     45**
     46** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
     47**	27341/64    = 427 cyc per int
     48**	61311/128   = 478 cyc per short
     49**	122637/256  = 479 cyc per byte
     50** Ergo bus latencies dominant (not transfer size).
     51**      Minimize total number of transfers at cost of CPU cycles.
     52**	TODO: only look at src alignment and adjust the stores to dest.
     53*/
     54void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
     55{
     56	/* first compare alignment of src/dst */ 
     57	if ( (((unsigned long)dst ^ (unsigned long)src) & 1) || (count < 2) )
     58		goto bytecopy;
     59
     60	if ( (((unsigned long)dst ^ (unsigned long)src) & 2) || (count < 4) )
     61		goto shortcopy;
     62
     63	/* Then check for misaligned start address */
     64	if ((unsigned long)src & 1) {
     65		*(u8 *)dst = readb(src);
     66		src++;
     67		dst++;
     68		count--;
     69		if (count < 2) goto bytecopy;
     70	}
     71
     72	if ((unsigned long)src & 2) {
     73		*(u16 *)dst = __raw_readw(src);
     74		src += 2;
     75		dst += 2;
     76		count -= 2;
     77	}
     78
     79	while (count > 3) {
     80		*(u32 *)dst = __raw_readl(src);
     81		dst += 4;
     82		src += 4;
     83		count -= 4;
     84	}
     85
     86 shortcopy:
     87	while (count > 1) {
     88		*(u16 *)dst = __raw_readw(src);
     89		src += 2;
     90		dst += 2;
     91		count -= 2;
     92	}
     93
     94 bytecopy:
     95	while (count--) {
     96		*(char *)dst = readb(src);
     97		src++;
     98		dst++;
     99	}
    100}
    101
    102/* Sets a block of memory on a device to a given value.
    103 * Assumes the device can cope with 32-bit transfers.  If it can't,
    104 * don't use this function.
    105 */
    106void memset_io(volatile void __iomem *addr, unsigned char val, int count)
    107{
    108	u32 val32 = (val << 24) | (val << 16) | (val << 8) | val;
    109	while ((unsigned long)addr & 3) {
    110		writeb(val, addr++);
    111		count--;
    112	}
    113	while (count > 3) {
    114		__raw_writel(val32, addr);
    115		addr += 4;
    116		count -= 4;
    117	}
    118	while (count--) {
    119		writeb(val, addr++);
    120	}
    121}
    122
    123/*
    124 * Read COUNT 8-bit bytes from port PORT into memory starting at
    125 * SRC.
    126 */
    127void insb (unsigned long port, void *dst, unsigned long count)
    128{
    129	unsigned char *p;
    130
    131	p = (unsigned char *)dst;
    132
    133	while (((unsigned long)p) & 0x3) {
    134		if (!count)
    135			return;
    136		count--;
    137		*p = inb(port);
    138		p++;
    139	}
    140
    141	while (count >= 4) {
    142		unsigned int w;
    143		count -= 4;
    144		w = inb(port) << 24;
    145		w |= inb(port) << 16;
    146		w |= inb(port) << 8;
    147		w |= inb(port);
    148		*(unsigned int *) p = w;
    149		p += 4;
    150	}
    151
    152	while (count) {
    153		--count;
    154		*p = inb(port);
    155		p++;
    156	}
    157}
    158
    159
    160/*
    161 * Read COUNT 16-bit words from port PORT into memory starting at
    162 * SRC.  SRC must be at least short aligned.  This is used by the
    163 * IDE driver to read disk sectors.  Performance is important, but
    164 * the interfaces seems to be slow: just using the inlined version
    165 * of the inw() breaks things.
    166 */
    167void insw (unsigned long port, void *dst, unsigned long count)
    168{
    169	unsigned int l = 0, l2;
    170	unsigned char *p;
    171
    172	p = (unsigned char *)dst;
    173	
    174	if (!count)
    175		return;
    176	
    177	switch (((unsigned long)p) & 0x3)
    178	{
    179	 case 0x00:			/* Buffer 32-bit aligned */
    180		while (count>=2) {
    181			
    182			count -= 2;
    183			l = cpu_to_le16(inw(port)) << 16;
    184			l |= cpu_to_le16(inw(port));
    185			*(unsigned int *)p = l;
    186			p += 4;
    187		}
    188		if (count) {
    189			*(unsigned short *)p = cpu_to_le16(inw(port));
    190		}
    191		break;
    192	
    193	 case 0x02:			/* Buffer 16-bit aligned */
    194		*(unsigned short *)p = cpu_to_le16(inw(port));
    195		p += 2;
    196		count--;
    197		while (count>=2) {
    198			
    199			count -= 2;
    200			l = cpu_to_le16(inw(port)) << 16;
    201			l |= cpu_to_le16(inw(port));
    202			*(unsigned int *)p = l;
    203			p += 4;
    204		}
    205		if (count) {
    206			*(unsigned short *)p = cpu_to_le16(inw(port));
    207		}
    208		break;
    209		
    210	 case 0x01:			/* Buffer 8-bit aligned */
    211	 case 0x03:
    212		/* I don't bother with 32bit transfers
    213		 * in this case, 16bit will have to do -- DE */
    214		--count;
    215		
    216		l = cpu_to_le16(inw(port));
    217		*p = l >> 8;
    218		p++;
    219		while (count--)
    220		{
    221			l2 = cpu_to_le16(inw(port));
    222			*(unsigned short *)p = (l & 0xff) << 8 | (l2 >> 8);
    223			p += 2;
    224			l = l2;
    225		}
    226		*p = l & 0xff;
    227		break;
    228	}
    229}
    230
    231
    232
    233/*
    234 * Read COUNT 32-bit words from port PORT into memory starting at
    235 * SRC. Now works with any alignment in SRC. Performance is important,
    236 * but the interfaces seems to be slow: just using the inlined version
    237 * of the inl() breaks things.
    238 */
    239void insl (unsigned long port, void *dst, unsigned long count)
    240{
    241	unsigned int l = 0, l2;
    242	unsigned char *p;
    243
    244	p = (unsigned char *)dst;
    245	
    246	if (!count)
    247		return;
    248	
    249	switch (((unsigned long) dst) & 0x3)
    250	{
    251	 case 0x00:			/* Buffer 32-bit aligned */
    252		while (count--)
    253		{
    254			*(unsigned int *)p = cpu_to_le32(inl(port));
    255			p += 4;
    256		}
    257		break;
    258	
    259	 case 0x02:			/* Buffer 16-bit aligned */
    260		--count;
    261		
    262		l = cpu_to_le32(inl(port));
    263		*(unsigned short *)p = l >> 16;
    264		p += 2;
    265		
    266		while (count--)
    267		{
    268			l2 = cpu_to_le32(inl(port));
    269			*(unsigned int *)p = (l & 0xffff) << 16 | (l2 >> 16);
    270			p += 4;
    271			l = l2;
    272		}
    273		*(unsigned short *)p = l & 0xffff;
    274		break;
    275	 case 0x01:			/* Buffer 8-bit aligned */
    276		--count;
    277		
    278		l = cpu_to_le32(inl(port));
    279		*(unsigned char *)p = l >> 24;
    280		p++;
    281		*(unsigned short *)p = (l >> 8) & 0xffff;
    282		p += 2;
    283		while (count--)
    284		{
    285			l2 = cpu_to_le32(inl(port));
    286			*(unsigned int *)p = (l & 0xff) << 24 | (l2 >> 8);
    287			p += 4;
    288			l = l2;
    289		}
    290		*p = l & 0xff;
    291		break;
    292	 case 0x03:			/* Buffer 8-bit aligned */
    293		--count;
    294		
    295		l = cpu_to_le32(inl(port));
    296		*p = l >> 24;
    297		p++;
    298		while (count--)
    299		{
    300			l2 = cpu_to_le32(inl(port));
    301			*(unsigned int *)p = (l & 0xffffff) << 8 | l2 >> 24;
    302			p += 4;
    303			l = l2;
    304		}
    305		*(unsigned short *)p = (l >> 8) & 0xffff;
    306		p += 2;
    307		*p = l & 0xff;
    308		break;
    309	}
    310}
    311
    312
    313/*
    314 * Like insb but in the opposite direction.
    315 * Don't worry as much about doing aligned memory transfers:
    316 * doing byte reads the "slow" way isn't nearly as slow as
    317 * doing byte writes the slow way (no r-m-w cycle).
    318 */
    319void outsb(unsigned long port, const void * src, unsigned long count)
    320{
    321	const unsigned char *p;
    322
    323	p = (const unsigned char *)src;
    324	while (count) {
    325		count--;
    326		outb(*p, port);
    327		p++;
    328	}
    329}
    330
    331/*
    332 * Like insw but in the opposite direction.  This is used by the IDE
    333 * driver to write disk sectors.  Performance is important, but the
    334 * interfaces seems to be slow: just using the inlined version of the
    335 * outw() breaks things.
    336 */
    337void outsw (unsigned long port, const void *src, unsigned long count)
    338{
    339	unsigned int l = 0, l2;
    340	const unsigned char *p;
    341
    342	p = (const unsigned char *)src;
    343	
    344	if (!count)
    345		return;
    346	
    347	switch (((unsigned long)p) & 0x3)
    348	{
    349	 case 0x00:			/* Buffer 32-bit aligned */
    350		while (count>=2) {
    351			count -= 2;
    352			l = *(unsigned int *)p;
    353			p += 4;
    354			outw(le16_to_cpu(l >> 16), port);
    355			outw(le16_to_cpu(l & 0xffff), port);
    356		}
    357		if (count) {
    358			outw(le16_to_cpu(*(unsigned short*)p), port);
    359		}
    360		break;
    361	
    362	 case 0x02:			/* Buffer 16-bit aligned */
    363		
    364		outw(le16_to_cpu(*(unsigned short*)p), port);
    365		p += 2;
    366		count--;
    367		
    368		while (count>=2) {
    369			count -= 2;
    370			l = *(unsigned int *)p;
    371			p += 4;
    372			outw(le16_to_cpu(l >> 16), port);
    373			outw(le16_to_cpu(l & 0xffff), port);
    374		}
    375		if (count) {
    376			outw(le16_to_cpu(*(unsigned short *)p), port);
    377		}
    378		break;
    379		
    380	 case 0x01:			/* Buffer 8-bit aligned */	
    381		/* I don't bother with 32bit transfers
    382		 * in this case, 16bit will have to do -- DE */
    383		
    384		l  = *p << 8;
    385		p++;
    386		count--;
    387		while (count)
    388		{
    389			count--;
    390			l2 = *(unsigned short *)p;
    391			p += 2;
    392			outw(le16_to_cpu(l | l2 >> 8), port);
    393		        l = l2 << 8;
    394		}
    395		l2 = *(unsigned char *)p;
    396		outw (le16_to_cpu(l | l2>>8), port);
    397		break;
    398	
    399	}
    400}
    401
    402
    403/*
    404 * Like insl but in the opposite direction.  This is used by the IDE
    405 * driver to write disk sectors.  Works with any alignment in SRC.
    406 *  Performance is important, but the interfaces seems to be slow:
    407 * just using the inlined version of the outl() breaks things.
    408 */
    409void outsl (unsigned long port, const void *src, unsigned long count)
    410{
    411	unsigned int l = 0, l2;
    412	const unsigned char *p;
    413
    414	p = (const unsigned char *)src;
    415	
    416	if (!count)
    417		return;
    418	
    419	switch (((unsigned long)p) & 0x3)
    420	{
    421	 case 0x00:			/* Buffer 32-bit aligned */
    422		while (count--)
    423		{
    424			outl(le32_to_cpu(*(unsigned int *)p), port);
    425			p += 4;
    426		}
    427		break;
    428	
    429	 case 0x02:			/* Buffer 16-bit aligned */
    430		--count;
    431		
    432		l = *(unsigned short *)p;
    433		p += 2;
    434		
    435		while (count--)
    436		{
    437			l2 = *(unsigned int *)p;
    438			p += 4;
    439			outl (le32_to_cpu(l << 16 | l2 >> 16), port);
    440			l = l2;
    441		}
    442		l2 = *(unsigned short *)p;
    443		outl (le32_to_cpu(l << 16 | l2), port);
    444		break;
    445	 case 0x01:			/* Buffer 8-bit aligned */
    446		--count;
    447
    448		l = *p << 24;
    449		p++;
    450		l |= *(unsigned short *)p << 8;
    451		p += 2;
    452
    453		while (count--)
    454		{
    455			l2 = *(unsigned int *)p;
    456			p += 4;
    457			outl (le32_to_cpu(l | l2 >> 24), port);
    458			l = l2 << 8;
    459		}
    460		l2 = *p;
    461		outl (le32_to_cpu(l | l2), port);
    462		break;
    463	 case 0x03:			/* Buffer 8-bit aligned */
    464		--count;
    465		
    466		l = *p << 24;
    467		p++;
    468
    469		while (count--)
    470		{
    471			l2 = *(unsigned int *)p;
    472			p += 4;
    473			outl (le32_to_cpu(l | l2 >> 8), port);
    474			l = l2 << 24;
    475		}
    476		l2 = *(unsigned short *)p << 16;
    477		p += 2;
    478		l2 |= *p;
    479		outl (le32_to_cpu(l | l2), port);
    480		break;
    481	}
    482}
    483
    484EXPORT_SYMBOL(insb);
    485EXPORT_SYMBOL(insw);
    486EXPORT_SYMBOL(insl);
    487EXPORT_SYMBOL(outsb);
    488EXPORT_SYMBOL(outsw);
    489EXPORT_SYMBOL(outsl);