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