1 // SPDX-License-Identifier: GPL-2.0-only !! 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * Based on arch/arm/kernel/io.c !! 3 * Alpha IO and memory functions. 4 * << 5 * Copyright (C) 2012 ARM Ltd. << 6 */ 4 */ 7 5 8 #include <linux/export.h> !! 6 #include <linux/kernel.h> 9 #include <linux/types.h> 7 #include <linux/types.h> 10 #include <linux/io.h> !! 8 #include <linux/string.h> >> 9 #include <linux/module.h> >> 10 #include <asm/io.h> >> 11 >> 12 /* Out-of-line versions of the i/o routines that redirect into the >> 13 platform-specific version. Note that "platform-specific" may mean >> 14 "generic", which bumps through the machine vector. */ >> 15 >> 16 unsigned int >> 17 ioread8(const void __iomem *addr) >> 18 { >> 19 unsigned int ret; >> 20 mb(); >> 21 ret = IO_CONCAT(__IO_PREFIX,ioread8)(addr); >> 22 mb(); >> 23 return ret; >> 24 } >> 25 >> 26 unsigned int ioread16(const void __iomem *addr) >> 27 { >> 28 unsigned int ret; >> 29 mb(); >> 30 ret = IO_CONCAT(__IO_PREFIX,ioread16)(addr); >> 31 mb(); >> 32 return ret; >> 33 } >> 34 >> 35 unsigned int ioread32(const void __iomem *addr) >> 36 { >> 37 unsigned int ret; >> 38 mb(); >> 39 ret = IO_CONCAT(__IO_PREFIX,ioread32)(addr); >> 40 mb(); >> 41 return ret; >> 42 } >> 43 >> 44 u64 ioread64(const void __iomem *addr) >> 45 { >> 46 unsigned int ret; >> 47 mb(); >> 48 ret = IO_CONCAT(__IO_PREFIX,ioread64)(addr); >> 49 mb(); >> 50 return ret; >> 51 } >> 52 >> 53 void iowrite8(u8 b, void __iomem *addr) >> 54 { >> 55 mb(); >> 56 IO_CONCAT(__IO_PREFIX,iowrite8)(b, addr); >> 57 } >> 58 >> 59 void iowrite16(u16 b, void __iomem *addr) >> 60 { >> 61 mb(); >> 62 IO_CONCAT(__IO_PREFIX,iowrite16)(b, addr); >> 63 } >> 64 >> 65 void iowrite32(u32 b, void __iomem *addr) >> 66 { >> 67 mb(); >> 68 IO_CONCAT(__IO_PREFIX,iowrite32)(b, addr); >> 69 } >> 70 >> 71 void iowrite64(u64 b, void __iomem *addr) >> 72 { >> 73 mb(); >> 74 IO_CONCAT(__IO_PREFIX,iowrite64)(b, addr); >> 75 } >> 76 >> 77 EXPORT_SYMBOL(ioread8); >> 78 EXPORT_SYMBOL(ioread16); >> 79 EXPORT_SYMBOL(ioread32); >> 80 EXPORT_SYMBOL(ioread64); >> 81 EXPORT_SYMBOL(iowrite8); >> 82 EXPORT_SYMBOL(iowrite16); >> 83 EXPORT_SYMBOL(iowrite32); >> 84 EXPORT_SYMBOL(iowrite64); >> 85 >> 86 u8 inb(unsigned long port) >> 87 { >> 88 return ioread8(ioport_map(port, 1)); >> 89 } >> 90 >> 91 u16 inw(unsigned long port) >> 92 { >> 93 return ioread16(ioport_map(port, 2)); >> 94 } >> 95 >> 96 u32 inl(unsigned long port) >> 97 { >> 98 return ioread32(ioport_map(port, 4)); >> 99 } >> 100 >> 101 void outb(u8 b, unsigned long port) >> 102 { >> 103 iowrite8(b, ioport_map(port, 1)); >> 104 } >> 105 >> 106 void outw(u16 b, unsigned long port) >> 107 { >> 108 iowrite16(b, ioport_map(port, 2)); >> 109 } >> 110 >> 111 void outl(u32 b, unsigned long port) >> 112 { >> 113 iowrite32(b, ioport_map(port, 4)); >> 114 } >> 115 >> 116 EXPORT_SYMBOL(inb); >> 117 EXPORT_SYMBOL(inw); >> 118 EXPORT_SYMBOL(inl); >> 119 EXPORT_SYMBOL(outb); >> 120 EXPORT_SYMBOL(outw); >> 121 EXPORT_SYMBOL(outl); >> 122 >> 123 u8 __raw_readb(const volatile void __iomem *addr) >> 124 { >> 125 return IO_CONCAT(__IO_PREFIX,readb)(addr); >> 126 } >> 127 >> 128 u16 __raw_readw(const volatile void __iomem *addr) >> 129 { >> 130 return IO_CONCAT(__IO_PREFIX,readw)(addr); >> 131 } >> 132 >> 133 u32 __raw_readl(const volatile void __iomem *addr) >> 134 { >> 135 return IO_CONCAT(__IO_PREFIX,readl)(addr); >> 136 } >> 137 >> 138 u64 __raw_readq(const volatile void __iomem *addr) >> 139 { >> 140 return IO_CONCAT(__IO_PREFIX,readq)(addr); >> 141 } >> 142 >> 143 void __raw_writeb(u8 b, volatile void __iomem *addr) >> 144 { >> 145 IO_CONCAT(__IO_PREFIX,writeb)(b, addr); >> 146 } >> 147 >> 148 void __raw_writew(u16 b, volatile void __iomem *addr) >> 149 { >> 150 IO_CONCAT(__IO_PREFIX,writew)(b, addr); >> 151 } >> 152 >> 153 void __raw_writel(u32 b, volatile void __iomem *addr) >> 154 { >> 155 IO_CONCAT(__IO_PREFIX,writel)(b, addr); >> 156 } >> 157 >> 158 void __raw_writeq(u64 b, volatile void __iomem *addr) >> 159 { >> 160 IO_CONCAT(__IO_PREFIX,writeq)(b, addr); >> 161 } >> 162 >> 163 EXPORT_SYMBOL(__raw_readb); >> 164 EXPORT_SYMBOL(__raw_readw); >> 165 EXPORT_SYMBOL(__raw_readl); >> 166 EXPORT_SYMBOL(__raw_readq); >> 167 EXPORT_SYMBOL(__raw_writeb); >> 168 EXPORT_SYMBOL(__raw_writew); >> 169 EXPORT_SYMBOL(__raw_writel); >> 170 EXPORT_SYMBOL(__raw_writeq); >> 171 >> 172 u8 readb(const volatile void __iomem *addr) >> 173 { >> 174 u8 ret; >> 175 mb(); >> 176 ret = __raw_readb(addr); >> 177 mb(); >> 178 return ret; >> 179 } >> 180 >> 181 u16 readw(const volatile void __iomem *addr) >> 182 { >> 183 u16 ret; >> 184 mb(); >> 185 ret = __raw_readw(addr); >> 186 mb(); >> 187 return ret; >> 188 } >> 189 >> 190 u32 readl(const volatile void __iomem *addr) >> 191 { >> 192 u32 ret; >> 193 mb(); >> 194 ret = __raw_readl(addr); >> 195 mb(); >> 196 return ret; >> 197 } >> 198 >> 199 u64 readq(const volatile void __iomem *addr) >> 200 { >> 201 u64 ret; >> 202 mb(); >> 203 ret = __raw_readq(addr); >> 204 mb(); >> 205 return ret; >> 206 } >> 207 >> 208 void writeb(u8 b, volatile void __iomem *addr) >> 209 { >> 210 mb(); >> 211 __raw_writeb(b, addr); >> 212 } >> 213 >> 214 void writew(u16 b, volatile void __iomem *addr) >> 215 { >> 216 mb(); >> 217 __raw_writew(b, addr); >> 218 } >> 219 >> 220 void writel(u32 b, volatile void __iomem *addr) >> 221 { >> 222 mb(); >> 223 __raw_writel(b, addr); >> 224 } >> 225 >> 226 void writeq(u64 b, volatile void __iomem *addr) >> 227 { >> 228 mb(); >> 229 __raw_writeq(b, addr); >> 230 } >> 231 >> 232 EXPORT_SYMBOL(readb); >> 233 EXPORT_SYMBOL(readw); >> 234 EXPORT_SYMBOL(readl); >> 235 EXPORT_SYMBOL(readq); >> 236 EXPORT_SYMBOL(writeb); >> 237 EXPORT_SYMBOL(writew); >> 238 EXPORT_SYMBOL(writel); >> 239 EXPORT_SYMBOL(writeq); 11 240 12 /* 241 /* 13 * Copy data from IO memory space to "real" me !! 242 * The _relaxed functions must be ordered w.r.t. each other, but they don't >> 243 * have to be ordered w.r.t. other memory accesses. 14 */ 244 */ 15 void __memcpy_fromio(void *to, const volatile !! 245 u8 readb_relaxed(const volatile void __iomem *addr) 16 { 246 { 17 while (count && !IS_ALIGNED((unsigned !! 247 mb(); 18 *(u8 *)to = __raw_readb(from); !! 248 return __raw_readb(addr); 19 from++; !! 249 } 20 to++; !! 250 >> 251 u16 readw_relaxed(const volatile void __iomem *addr) >> 252 { >> 253 mb(); >> 254 return __raw_readw(addr); >> 255 } >> 256 >> 257 u32 readl_relaxed(const volatile void __iomem *addr) >> 258 { >> 259 mb(); >> 260 return __raw_readl(addr); >> 261 } >> 262 >> 263 u64 readq_relaxed(const volatile void __iomem *addr) >> 264 { >> 265 mb(); >> 266 return __raw_readq(addr); >> 267 } >> 268 >> 269 EXPORT_SYMBOL(readb_relaxed); >> 270 EXPORT_SYMBOL(readw_relaxed); >> 271 EXPORT_SYMBOL(readl_relaxed); >> 272 EXPORT_SYMBOL(readq_relaxed); >> 273 >> 274 /* >> 275 * Read COUNT 8-bit bytes from port PORT into memory starting at SRC. >> 276 */ >> 277 void ioread8_rep(const void __iomem *port, void *dst, unsigned long count) >> 278 { >> 279 while ((unsigned long)dst & 0x3) { >> 280 if (!count) >> 281 return; 21 count--; 282 count--; >> 283 *(unsigned char *)dst = ioread8(port); >> 284 dst += 1; 22 } 285 } 23 286 24 while (count >= 8) { !! 287 while (count >= 4) { 25 *(u64 *)to = __raw_readq(from) !! 288 unsigned int w; 26 from += 8; !! 289 count -= 4; 27 to += 8; !! 290 w = ioread8(port); 28 count -= 8; !! 291 w |= ioread8(port) << 8; >> 292 w |= ioread8(port) << 16; >> 293 w |= ioread8(port) << 24; >> 294 *(unsigned int *)dst = w; >> 295 dst += 4; 29 } 296 } 30 297 31 while (count) { 298 while (count) { 32 *(u8 *)to = __raw_readb(from); !! 299 --count; 33 from++; !! 300 *(unsigned char *)dst = ioread8(port); 34 to++; !! 301 dst += 1; >> 302 } >> 303 } >> 304 >> 305 void insb(unsigned long port, void *dst, unsigned long count) >> 306 { >> 307 ioread8_rep(ioport_map(port, 1), dst, count); >> 308 } >> 309 >> 310 EXPORT_SYMBOL(ioread8_rep); >> 311 EXPORT_SYMBOL(insb); >> 312 >> 313 /* >> 314 * Read COUNT 16-bit words from port PORT into memory starting at >> 315 * SRC. SRC must be at least short aligned. This is used by the >> 316 * IDE driver to read disk sectors. Performance is important, but >> 317 * the interfaces seems to be slow: just using the inlined version >> 318 * of the inw() breaks things. >> 319 */ >> 320 void ioread16_rep(const void __iomem *port, void *dst, unsigned long count) >> 321 { >> 322 if (unlikely((unsigned long)dst & 0x3)) { >> 323 if (!count) >> 324 return; >> 325 BUG_ON((unsigned long)dst & 0x1); 35 count--; 326 count--; >> 327 *(unsigned short *)dst = ioread16(port); >> 328 dst += 2; >> 329 } >> 330 >> 331 while (count >= 2) { >> 332 unsigned int w; >> 333 count -= 2; >> 334 w = ioread16(port); >> 335 w |= ioread16(port) << 16; >> 336 *(unsigned int *)dst = w; >> 337 dst += 4; 36 } 338 } >> 339 >> 340 if (count) { >> 341 *(unsigned short*)dst = ioread16(port); >> 342 } >> 343 } >> 344 >> 345 void insw(unsigned long port, void *dst, unsigned long count) >> 346 { >> 347 ioread16_rep(ioport_map(port, 2), dst, count); 37 } 348 } 38 EXPORT_SYMBOL(__memcpy_fromio); !! 349 >> 350 EXPORT_SYMBOL(ioread16_rep); >> 351 EXPORT_SYMBOL(insw); >> 352 39 353 40 /* 354 /* 41 * This generates a memcpy that works on a fro !! 355 * Read COUNT 32-bit words from port PORT into memory starting at 42 * bits. Count is in terms of the number of bi !! 356 * SRC. Now works with any alignment in SRC. Performance is important, 43 * optimizes to use the STR groupings when pos !! 357 * but the interfaces seems to be slow: just using the inlined version 44 */ !! 358 * of the inl() breaks things. 45 #define memcpy_toio_aligned(to, from, count, b !! 359 */ 46 ({ !! 360 void ioread32_rep(const void __iomem *port, void *dst, unsigned long count) 47 volatile u##bits __iomem *_to !! 361 { 48 const u##bits *_from = from; !! 362 if (unlikely((unsigned long)dst & 0x3)) { 49 size_t _count = count; !! 363 while (count--) { 50 const u##bits *_end_from = _fr !! 364 struct S { int x __attribute__((packed)); }; 51 !! 365 ((struct S *)dst)->x = ioread32(port); 52 for (; _from < _end_from; _fro !! 366 dst += 4; 53 __const_memcpy_toio_al !! 367 } 54 if ((_count % 8) >= 4) { !! 368 } else { 55 __const_memcpy_toio_al !! 369 /* Buffer 32-bit aligned. */ 56 _from += 4; !! 370 while (count--) { 57 _to += 4; !! 371 *(unsigned int *)dst = ioread32(port); 58 } !! 372 dst += 4; 59 if ((_count % 4) >= 2) { !! 373 } 60 __const_memcpy_toio_al !! 374 } 61 _from += 2; << 62 _to += 2; << 63 } << 64 if (_count % 2) << 65 __const_memcpy_toio_al << 66 }) << 67 << 68 void __iowrite64_copy_full(void __iomem *to, c << 69 { << 70 memcpy_toio_aligned(to, from, count, 6 << 71 dgh(); << 72 } 375 } 73 EXPORT_SYMBOL(__iowrite64_copy_full); << 74 376 75 void __iowrite32_copy_full(void __iomem *to, c !! 377 void insl(unsigned long port, void *dst, unsigned long count) 76 { 378 { 77 memcpy_toio_aligned(to, from, count, 3 !! 379 ioread32_rep(ioport_map(port, 4), dst, count); 78 dgh(); << 79 } 380 } 80 EXPORT_SYMBOL(__iowrite32_copy_full); !! 381 >> 382 EXPORT_SYMBOL(ioread32_rep); >> 383 EXPORT_SYMBOL(insl); >> 384 81 385 82 /* 386 /* 83 * Copy data from "real" memory space to IO me !! 387 * Like insb but in the opposite direction. >> 388 * Don't worry as much about doing aligned memory transfers: >> 389 * doing byte reads the "slow" way isn't nearly as slow as >> 390 * doing byte writes the slow way (no r-m-w cycle). 84 */ 391 */ 85 void __memcpy_toio(volatile void __iomem *to, !! 392 void iowrite8_rep(void __iomem *port, const void *xsrc, unsigned long count) 86 { 393 { 87 while (count && !IS_ALIGNED((unsigned !! 394 const unsigned char *src = xsrc; 88 __raw_writeb(*(u8 *)from, to); !! 395 while (count--) 89 from++; !! 396 iowrite8(*src++, port); 90 to++; !! 397 } 91 count--; !! 398 >> 399 void outsb(unsigned long port, const void *src, unsigned long count) >> 400 { >> 401 iowrite8_rep(ioport_map(port, 1), src, count); >> 402 } >> 403 >> 404 EXPORT_SYMBOL(iowrite8_rep); >> 405 EXPORT_SYMBOL(outsb); >> 406 >> 407 >> 408 /* >> 409 * Like insw but in the opposite direction. This is used by the IDE >> 410 * driver to write disk sectors. Performance is important, but the >> 411 * interfaces seems to be slow: just using the inlined version of the >> 412 * outw() breaks things. >> 413 */ >> 414 void iowrite16_rep(void __iomem *port, const void *src, unsigned long count) >> 415 { >> 416 if (unlikely((unsigned long)src & 0x3)) { >> 417 if (!count) >> 418 return; >> 419 BUG_ON((unsigned long)src & 0x1); >> 420 iowrite16(*(unsigned short *)src, port); >> 421 src += 2; >> 422 --count; >> 423 } >> 424 >> 425 while (count >= 2) { >> 426 unsigned int w; >> 427 count -= 2; >> 428 w = *(unsigned int *)src; >> 429 src += 4; >> 430 iowrite16(w >> 0, port); >> 431 iowrite16(w >> 16, port); >> 432 } >> 433 >> 434 if (count) { >> 435 iowrite16(*(unsigned short *)src, port); >> 436 } >> 437 } >> 438 >> 439 void outsw(unsigned long port, const void *src, unsigned long count) >> 440 { >> 441 iowrite16_rep(ioport_map(port, 2), src, count); >> 442 } >> 443 >> 444 EXPORT_SYMBOL(iowrite16_rep); >> 445 EXPORT_SYMBOL(outsw); >> 446 >> 447 >> 448 /* >> 449 * Like insl but in the opposite direction. This is used by the IDE >> 450 * driver to write disk sectors. Works with any alignment in SRC. >> 451 * Performance is important, but the interfaces seems to be slow: >> 452 * just using the inlined version of the outl() breaks things. >> 453 */ >> 454 void iowrite32_rep(void __iomem *port, const void *src, unsigned long count) >> 455 { >> 456 if (unlikely((unsigned long)src & 0x3)) { >> 457 while (count--) { >> 458 struct S { int x __attribute__((packed)); }; >> 459 iowrite32(((struct S *)src)->x, port); >> 460 src += 4; >> 461 } >> 462 } else { >> 463 /* Buffer 32-bit aligned. */ >> 464 while (count--) { >> 465 iowrite32(*(unsigned int *)src, port); >> 466 src += 4; >> 467 } 92 } 468 } >> 469 } >> 470 >> 471 void outsl(unsigned long port, const void *src, unsigned long count) >> 472 { >> 473 iowrite32_rep(ioport_map(port, 4), src, count); >> 474 } >> 475 >> 476 EXPORT_SYMBOL(iowrite32_rep); >> 477 EXPORT_SYMBOL(outsl); 93 478 94 while (count >= 8) { !! 479 95 __raw_writeq(*(u64 *)from, to) !! 480 /* 96 from += 8; !! 481 * Copy data from IO memory space to "real" memory space. 97 to += 8; !! 482 * This needs to be optimized. >> 483 */ >> 484 void memcpy_fromio(void *to, const volatile void __iomem *from, long count) >> 485 { >> 486 /* Optimize co-aligned transfers. Everything else gets handled >> 487 a byte at a time. */ >> 488 >> 489 if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) { 98 count -= 8; 490 count -= 8; >> 491 do { >> 492 *(u64 *)to = __raw_readq(from); >> 493 count -= 8; >> 494 to += 8; >> 495 from += 8; >> 496 } while (count >= 0); >> 497 count += 8; 99 } 498 } 100 499 101 while (count) { !! 500 if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) { 102 __raw_writeb(*(u8 *)from, to); !! 501 count -= 4; 103 from++; !! 502 do { >> 503 *(u32 *)to = __raw_readl(from); >> 504 count -= 4; >> 505 to += 4; >> 506 from += 4; >> 507 } while (count >= 0); >> 508 count += 4; >> 509 } >> 510 >> 511 if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) { >> 512 count -= 2; >> 513 do { >> 514 *(u16 *)to = __raw_readw(from); >> 515 count -= 2; >> 516 to += 2; >> 517 from += 2; >> 518 } while (count >= 0); >> 519 count += 2; >> 520 } >> 521 >> 522 while (count > 0) { >> 523 *(u8 *) to = __raw_readb(from); >> 524 count--; 104 to++; 525 to++; >> 526 from++; >> 527 } >> 528 mb(); >> 529 } >> 530 >> 531 EXPORT_SYMBOL(memcpy_fromio); >> 532 >> 533 >> 534 /* >> 535 * Copy data from "real" memory space to IO memory space. >> 536 * This needs to be optimized. >> 537 */ >> 538 void memcpy_toio(volatile void __iomem *to, const void *from, long count) >> 539 { >> 540 /* Optimize co-aligned transfers. Everything else gets handled >> 541 a byte at a time. */ >> 542 /* FIXME -- align FROM. */ >> 543 >> 544 if (count >= 8 && ((u64)to & 7) == ((u64)from & 7)) { >> 545 count -= 8; >> 546 do { >> 547 __raw_writeq(*(const u64 *)from, to); >> 548 count -= 8; >> 549 to += 8; >> 550 from += 8; >> 551 } while (count >= 0); >> 552 count += 8; >> 553 } >> 554 >> 555 if (count >= 4 && ((u64)to & 3) == ((u64)from & 3)) { >> 556 count -= 4; >> 557 do { >> 558 __raw_writel(*(const u32 *)from, to); >> 559 count -= 4; >> 560 to += 4; >> 561 from += 4; >> 562 } while (count >= 0); >> 563 count += 4; >> 564 } >> 565 >> 566 if (count >= 2 && ((u64)to & 1) == ((u64)from & 1)) { >> 567 count -= 2; >> 568 do { >> 569 __raw_writew(*(const u16 *)from, to); >> 570 count -= 2; >> 571 to += 2; >> 572 from += 2; >> 573 } while (count >= 0); >> 574 count += 2; >> 575 } >> 576 >> 577 while (count > 0) { >> 578 __raw_writeb(*(const u8 *) from, to); 105 count--; 579 count--; >> 580 to++; >> 581 from++; 106 } 582 } >> 583 mb(); 107 } 584 } 108 EXPORT_SYMBOL(__memcpy_toio); !! 585 >> 586 EXPORT_SYMBOL(memcpy_toio); >> 587 109 588 110 /* 589 /* 111 * "memset" on IO memory space. 590 * "memset" on IO memory space. 112 */ 591 */ 113 void __memset_io(volatile void __iomem *dst, i !! 592 void _memset_c_io(volatile void __iomem *to, unsigned long c, long count) 114 { 593 { 115 u64 qc = (u8)c; !! 594 /* Handle any initial odd byte */ >> 595 if (count > 0 && ((u64)to & 1)) { >> 596 __raw_writeb(c, to); >> 597 to++; >> 598 count--; >> 599 } 116 600 117 qc |= qc << 8; !! 601 /* Handle any initial odd halfword */ 118 qc |= qc << 16; !! 602 if (count >= 2 && ((u64)to & 2)) { 119 qc |= qc << 32; !! 603 __raw_writew(c, to); >> 604 to += 2; >> 605 count -= 2; >> 606 } 120 607 121 while (count && !IS_ALIGNED((unsigned !! 608 /* Handle any initial odd word */ 122 __raw_writeb(c, dst); !! 609 if (count >= 4 && ((u64)to & 4)) { 123 dst++; !! 610 __raw_writel(c, to); 124 count--; !! 611 to += 4; >> 612 count -= 4; 125 } 613 } 126 614 127 while (count >= 8) { !! 615 /* Handle all full-sized quadwords: we're aligned 128 __raw_writeq(qc, dst); !! 616 (or have a small count) */ 129 dst += 8; !! 617 count -= 8; 130 count -= 8; !! 618 if (count >= 0) { >> 619 do { >> 620 __raw_writeq(c, to); >> 621 to += 8; >> 622 count -= 8; >> 623 } while (count >= 0); 131 } 624 } >> 625 count += 8; 132 626 133 while (count) { !! 627 /* The tail is word-aligned if we still have count >= 4 */ 134 __raw_writeb(c, dst); !! 628 if (count >= 4) { 135 dst++; !! 629 __raw_writel(c, to); 136 count--; !! 630 to += 4; >> 631 count -= 4; >> 632 } >> 633 >> 634 /* The tail is half-word aligned if we have count >= 2 */ >> 635 if (count >= 2) { >> 636 __raw_writew(c, to); >> 637 to += 2; >> 638 count -= 2; >> 639 } >> 640 >> 641 /* And finally, one last byte.. */ >> 642 if (count) { >> 643 __raw_writeb(c, to); >> 644 } >> 645 mb(); >> 646 } >> 647 >> 648 EXPORT_SYMBOL(_memset_c_io); >> 649 >> 650 #if IS_ENABLED(CONFIG_VGA_CONSOLE) || IS_ENABLED(CONFIG_MDA_CONSOLE) >> 651 >> 652 #include <asm/vga.h> >> 653 >> 654 /* A version of memcpy used by the vga console routines to move data around >> 655 arbitrarily between screen and main memory. */ >> 656 >> 657 void >> 658 scr_memcpyw(u16 *d, const u16 *s, unsigned int count) >> 659 { >> 660 const u16 __iomem *ios = (const u16 __iomem *) s; >> 661 u16 __iomem *iod = (u16 __iomem *) d; >> 662 int s_isio = __is_ioaddr(s); >> 663 int d_isio = __is_ioaddr(d); >> 664 >> 665 if (s_isio) { >> 666 if (d_isio) { >> 667 /* FIXME: Should handle unaligned ops and >> 668 operation widening. */ >> 669 >> 670 count /= 2; >> 671 while (count--) { >> 672 u16 tmp = __raw_readw(ios++); >> 673 __raw_writew(tmp, iod++); >> 674 } >> 675 } >> 676 else >> 677 memcpy_fromio(d, ios, count); >> 678 } else { >> 679 if (d_isio) >> 680 memcpy_toio(iod, s, count); >> 681 else >> 682 memcpy(d, s, count); >> 683 } >> 684 } >> 685 >> 686 EXPORT_SYMBOL(scr_memcpyw); >> 687 >> 688 void scr_memmovew(u16 *d, const u16 *s, unsigned int count) >> 689 { >> 690 if (d < s) >> 691 scr_memcpyw(d, s, count); >> 692 else { >> 693 count /= 2; >> 694 d += count; >> 695 s += count; >> 696 while (count--) >> 697 scr_writew(scr_readw(--s), --d); 137 } 698 } 138 } 699 } 139 EXPORT_SYMBOL(__memset_io); !! 700 EXPORT_SYMBOL(scr_memmovew); >> 701 #endif >> 702 >> 703 void __iomem *ioport_map(unsigned long port, unsigned int size) >> 704 { >> 705 return IO_CONCAT(__IO_PREFIX,ioportmap) (port); >> 706 } >> 707 >> 708 void ioport_unmap(void __iomem *addr) >> 709 { >> 710 } >> 711 >> 712 EXPORT_SYMBOL(ioport_map); >> 713 EXPORT_SYMBOL(ioport_unmap); 140 714
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.