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