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 */ 19 void 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 */ 54 void 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 */ 106 void 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 */ 127 void 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 */ 167 void 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 */ 239 void 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 */ 319 void 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 */ 337 void 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 */ 409 void 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 484 EXPORT_SYMBOL(insb); 485 EXPORT_SYMBOL(insw); 486 EXPORT_SYMBOL(insl); 487 EXPORT_SYMBOL(outsb); 488 EXPORT_SYMBOL(outsw); 489 EXPORT_SYMBOL(outsl); 490
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.