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