linux/arch/m68knommu/kernel/comempci.c
<<
>>
Prefs
   1/*****************************************************************************/
   2
   3/*
   4 *      comemlite.c -- PCI access code for embedded CO-MEM Lite PCI controller.
   5 *
   6 *      (C) Copyright 1999-2003, Greg Ungerer (gerg@snapgear.com).
   7 *      (C) Copyright 2000, Lineo (www.lineo.com)
   8 */
   9
  10/*****************************************************************************/
  11
  12#include <linux/kernel.h>
  13#include <linux/types.h>
  14#include <linux/pci.h>
  15#include <linux/ptrace.h>
  16#include <linux/spinlock.h>
  17#include <linux/interrupt.h>
  18#include <linux/sched.h>
  19#include <asm/coldfire.h>
  20#include <asm/mcfsim.h>
  21#include <asm/irq.h>
  22#include <asm/anchor.h>
  23
  24#ifdef CONFIG_eLIA
  25#include <asm/elia.h>
  26#endif
  27
  28/*****************************************************************************/
  29
  30/*
  31 *      Debug configuration defines. DEBUGRES sets debugging output for
  32 *      the resource allocation phase. DEBUGPCI traces on pcibios_ function
  33 *      calls, and DEBUGIO traces all accesses to devices on the PCI bus.
  34 */
  35/*#define       DEBUGRES        1*/
  36/*#define       DEBUGPCI        1*/
  37/*#define       DEBUGIO         1*/
  38
  39/*****************************************************************************/
  40
  41/*
  42 *      PCI markers for bus present and active slots.
  43 */
  44int             pci_bus_is_present = 0;
  45unsigned long   pci_slotmask = 0;
  46
  47/*
  48 *      We may or may not need to swap the bytes of PCI bus tranfers.
  49 *      The endianess is re-roder automatically by the CO-MEM, but it
  50 *      will get the wrong byte order for a pure data stream.
  51 */
  52#define pci_byteswap    0
  53
  54
  55/*
  56 *      Resource tracking. The CO-MEM part creates a virtual address
  57 *      space that all the PCI devices live in - it is not in any way
  58 *      directly mapped into the ColdFire address space. So we can
  59 *      really assign any resources we like to devices, as long as
  60 *      they do not clash with other PCI devices.
  61 */
  62unsigned int    pci_iobase = PCIBIOS_MIN_IO;    /* Arbitrary start address */
  63unsigned int    pci_membase = PCIBIOS_MIN_MEM;  /* Arbitrary start address */
  64
  65#define PCI_MINIO       0x100                   /* 256 byte minimum I/O */
  66#define PCI_MINMEM      0x00010000              /* 64k minimum chunk */
  67
  68/*
  69 *      The CO-MEM's shared memory segment is visible inside the PCI
  70 *      memory address space. We need to keep track of the address that
  71 *      this is mapped at, to setup the bus masters pointers.
  72 */
  73unsigned int    pci_shmemaddr;
  74
  75/*****************************************************************************/
  76
  77void    pci_interrupt(int irq, void *id, struct pt_regs *fp);
  78
  79/*****************************************************************************/
  80
  81/*
  82 *      Some platforms have custom ways of reseting the PCI bus.
  83 */
  84
  85void pci_resetbus(void)
  86{
  87#ifdef CONFIG_eLIA
  88        int     i;
  89
  90#ifdef DEBUGPCI
  91        printk(KERN_DEBUG "pci_resetbus()\n");
  92#endif
  93
  94        *((volatile unsigned short *) (MCF_MBAR+MCFSIM_PADDR)) |= eLIA_PCIRESET;
  95        for (i = 0; (i < 1000); i++) {
  96                *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = 
  97                        (ppdata | eLIA_PCIRESET);
  98        }
  99
 100
 101        *((volatile unsigned short *) (MCF_MBAR + MCFSIM_PADAT)) = ppdata;
 102#endif
 103}
 104
 105/*****************************************************************************/
 106
 107int pcibios_assign_resource_slot(int slot)
 108{
 109        volatile unsigned long  *rp;
 110        volatile unsigned char  *ip;
 111        unsigned int            idsel, addr, val, align, i;
 112        int                     bar;
 113
 114#ifdef DEBUGPCI
 115        printk(KERN_INFO "pcibios_assign_resource_slot(slot=%x)\n", slot);
 116#endif
 117
 118        rp = (volatile unsigned long *) COMEM_BASE;
 119        idsel = COMEM_DA_ADDR(0x1 << (slot + 16));
 120
 121        /* Try to assign resource to each BAR */
 122        for (bar = 0; (bar < 6); bar++) {
 123                addr = COMEM_PCIBUS + PCI_BASE_ADDRESS_0 + (bar * 4);
 124                rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
 125                val = rp[LREG(addr)];
 126#ifdef DEBUGRES
 127                printk(KERN_DEBUG "-----------------------------------"
 128                        "-------------------------------------\n");
 129                printk(KERN_DEBUG "BAR[%d]: read=%08x ", bar, val);
 130#endif
 131
 132                rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
 133                rp[LREG(addr)] = 0xffffffff;
 134
 135                rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
 136                val = rp[LREG(addr)];
 137#ifdef DEBUGRES
 138                printk(KERN_DEBUG "write=%08x ", val);
 139#endif
 140                if (val == 0) {
 141#ifdef DEBUGRES
 142                        printk(KERN_DEBUG "\n");
 143#endif
 144                        continue;
 145                }
 146
 147                /* Determine space required by BAR */
 148                /* FIXME: this should go backwords from 0x80000000... */
 149                for (i = 0; (i < 32); i++) {
 150                        if ((0x1 << i) & (val & 0xfffffffc))
 151                                break;
 152                }
 153
 154#ifdef DEBUGRES
 155                printk(KERN_DEBUG "size=%08x(%d)\n", (0x1 << i), i);
 156#endif
 157                i = 0x1 << i;
 158
 159                /* Assign a resource */
 160                if (val & PCI_BASE_ADDRESS_SPACE_IO) {
 161                        if (i < PCI_MINIO)
 162                                i = PCI_MINIO;
 163#ifdef DEBUGRES
 164                        printk(KERN_DEBUG "BAR[%d]: IO size=%08x iobase=%08x\n",
 165                                bar, i, pci_iobase);
 166#endif
 167                        if (i > 0xffff) {
 168                                /* Invalid size?? */
 169                                val = 0 | PCI_BASE_ADDRESS_SPACE_IO;
 170#ifdef DEBUGRES
 171                                printk(KERN_DEBUG "BAR[%d]: too big for IO??\n", bar);
 172#endif
 173                        } else {
 174                                /* Check for un-alignment */
 175                                if ((align = pci_iobase % i))
 176                                        pci_iobase += (i - align);
 177                                val = pci_iobase | PCI_BASE_ADDRESS_SPACE_IO;
 178                                pci_iobase += i;
 179                        }
 180                } else {
 181                        if (i < PCI_MINMEM)
 182                                i = PCI_MINMEM;
 183#ifdef DEBUGRES
 184                        printk(KERN_DEBUG "BAR[%d]: MEMORY size=%08x membase=%08x\n",
 185                                bar, i, pci_membase);
 186#endif
 187                        /* Check for un-alignment */
 188                        if ((align = pci_membase % i))
 189                                pci_membase += (i - align);
 190                        val = pci_membase | PCI_BASE_ADDRESS_SPACE_MEMORY;
 191                        pci_membase += i;
 192                }
 193
 194                /* Write resource back into BAR register */
 195                rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
 196                rp[LREG(addr)] = val;
 197#ifdef DEBUGRES
 198                printk(KERN_DEBUG "BAR[%d]: assigned bar=%08x\n", bar, val);
 199#endif
 200        }
 201
 202#ifdef DEBUGRES
 203        printk(KERN_DEBUG "-----------------------------------"
 204                        "-------------------------------------\n");
 205#endif
 206
 207        /* Assign IRQ if one is wanted... */
 208        ip = (volatile unsigned char *) (COMEM_BASE + COMEM_PCIBUS);
 209        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
 210
 211        addr = (PCI_INTERRUPT_PIN & 0xfc) + (~PCI_INTERRUPT_PIN & 0x03);
 212        if (ip[addr]) {
 213                rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
 214                addr = (PCI_INTERRUPT_LINE & 0xfc)+(~PCI_INTERRUPT_LINE & 0x03);
 215                ip[addr] = 25;
 216#ifdef DEBUGRES
 217                printk(KERN_DEBUG "IRQ LINE=25\n");
 218#endif
 219        }
 220
 221        return(0);
 222}
 223
 224/*****************************************************************************/
 225
 226int pcibios_enable_slot(int slot)
 227{
 228        volatile unsigned long  *rp;
 229        volatile unsigned short *wp;
 230        unsigned int            idsel, addr;
 231        unsigned short          cmd;
 232
 233#ifdef DEBUGPCI
 234        printk(KERN_DEBUG "pcibios_enbale_slot(slot=%x)\n", slot);
 235#endif
 236
 237        rp = (volatile unsigned long *) COMEM_BASE;
 238        wp = (volatile unsigned short *) COMEM_BASE;
 239        idsel = COMEM_DA_ADDR(0x1 << (slot + 16));
 240
 241        /* Get current command settings */
 242        addr = COMEM_PCIBUS + PCI_COMMAND;
 243        addr = (addr & ~0x3) + (~addr & 0x02);
 244        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGRD | idsel;
 245        cmd = wp[WREG(addr)];
 246        /*val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);*/
 247
 248        /* Enable I/O and memory accesses to this device */
 249        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_CFGWR | idsel;
 250        cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
 251        wp[WREG(addr)] = cmd;
 252
 253        return(0);
 254}
 255
 256/*****************************************************************************/
 257
 258void pcibios_assign_resources(void)
 259{
 260        volatile unsigned long  *rp;
 261        unsigned long           sel, id;
 262        int                     slot;
 263
 264        rp = (volatile unsigned long *) COMEM_BASE;
 265
 266        /*
 267         *      Do a quick scan of the PCI bus and see what is here.
 268         */
 269        for (slot = COMEM_MINDEV; (slot <= COMEM_MAXDEV); slot++) {
 270                sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16));
 271                rp[LREG(COMEM_DAHBASE)] = sel;
 272                rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */
 273                id = rp[LREG(COMEM_PCIBUS)];
 274                if ((id != 0) && ((id & 0xffff0000) != (sel & 0xffff0000))) {
 275                        printk(KERN_INFO "PCI: slot=%d id=%08x\n", slot, (int) id);
 276                        pci_slotmask |= 0x1 << slot;
 277                        pcibios_assign_resource_slot(slot);
 278                        pcibios_enable_slot(slot);
 279                }
 280        }
 281}
 282
 283/*****************************************************************************/
 284
 285int pcibios_init(void)
 286{
 287        volatile unsigned long  *rp;
 288        unsigned long           sel, id;
 289        int                     slot;
 290
 291#ifdef DEBUGPCI
 292        printk(KERN_DEBUG "pcibios_init()\n");
 293#endif
 294
 295        pci_resetbus();
 296
 297        /*
 298         *      Do some sort of basic check to see if the CO-MEM part
 299         *      is present... This works ok, but I think we really need
 300         *      something better...
 301         */
 302        rp = (volatile unsigned long *) COMEM_BASE;
 303        if ((rp[LREG(COMEM_LBUSCFG)] & 0xff) != 0x50) {
 304                printk(KERN_INFO "PCI: no PCI bus present\n");
 305                return(0);
 306        }
 307
 308#ifdef COMEM_BRIDGEDEV
 309        /*
 310         *      Setup the PCI bridge device first. It needs resources too,
 311         *      so that bus masters can get to its shared memory.
 312         */
 313        slot = COMEM_BRIDGEDEV;
 314        sel = COMEM_DA_CFGRD | COMEM_DA_ADDR(0x1 << (slot + 16));
 315        rp[LREG(COMEM_DAHBASE)] = sel;
 316        rp[LREG(COMEM_PCIBUS)] = 0; /* Clear bus */
 317        id = rp[LREG(COMEM_PCIBUS)];
 318        if ((id == 0) || ((id & 0xffff0000) == (sel & 0xffff0000))) {
 319                printk(KERN_INFO "PCI: no PCI bus bridge present\n");
 320                return(0);
 321        }
 322
 323        printk(KERN_INFO "PCI: bridge device at slot=%d id=%08x\n", slot, (int) id);
 324        pci_slotmask |= 0x1 << slot;
 325        pci_shmemaddr = pci_membase;
 326        pcibios_assign_resource_slot(slot);
 327        pcibios_enable_slot(slot);
 328#endif
 329
 330        pci_bus_is_present = 1;
 331
 332        /* Get PCI irq for local vectoring */
 333        if (request_irq(COMEM_IRQ, pci_interrupt, 0, "PCI bridge", NULL)) {
 334                printk(KERN_WARNING "PCI: failed to acquire interrupt %d\n", COMEM_IRQ);
 335        } else {
 336                mcf_autovector(COMEM_IRQ);
 337        }
 338
 339        pcibios_assign_resources();
 340
 341        return(0);
 342}
 343
 344/*****************************************************************************/
 345
 346char *pcibios_setup(char *option)
 347{
 348        /* Nothing for us to handle. */
 349        return(option);
 350}
 351/*****************************************************************************/
 352
 353void pcibios_fixup_bus(struct pci_bus *b)
 354{
 355}
 356
 357/*****************************************************************************/
 358
 359void pcibios_align_resource(void *data, struct resource *res,
 360                                resource_size_t size, resource_size_t align)
 361{
 362}
 363
 364/*****************************************************************************/
 365
 366int pcibios_enable_device(struct pci_dev *dev, int mask)
 367{
 368        int slot;
 369
 370        slot = PCI_SLOT(dev->devfn);
 371        if ((dev->bus == 0) && (pci_slotmask & (1 << slot)))
 372                pcibios_enable_slot(slot);
 373        return(0);
 374}
 375
 376/*****************************************************************************/
 377
 378void pcibios_update_resource(struct pci_dev *dev, struct resource *root, struct resource *r, int resource)
 379{
 380        printk(KERN_WARNING "%s(%d): no support for changing PCI resources...\n",
 381                __FILE__, __LINE__);
 382}
 383
 384
 385/*****************************************************************************/
 386
 387/*
 388 *      Local routines to interrcept the standard I/O and vector handling
 389 *      code. Don't include this 'till now - initialization code above needs
 390 *      access to the real code too.
 391 */
 392#include <asm/mcfpci.h>
 393
 394/*****************************************************************************/
 395
 396void pci_outb(unsigned char val, unsigned int addr)
 397{
 398        volatile unsigned long  *rp;
 399        volatile unsigned char  *bp;
 400
 401#ifdef DEBUGIO
 402        printk(KERN_DEBUG "pci_outb(val=%02x,addr=%x)\n", val, addr);
 403#endif
 404
 405        rp = (volatile unsigned long *) COMEM_BASE;
 406        bp = (volatile unsigned char *) COMEM_BASE;
 407        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);
 408        addr = (addr & ~0x3) + (~addr & 0x03);
 409        bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;
 410}
 411
 412/*****************************************************************************/
 413
 414void pci_outw(unsigned short val, unsigned int addr)
 415{
 416        volatile unsigned long  *rp;
 417        volatile unsigned short *sp;
 418
 419#ifdef DEBUGIO
 420        printk(KERN_DEBUG "pci_outw(val=%04x,addr=%x)\n", val, addr);
 421#endif
 422
 423        rp = (volatile unsigned long *) COMEM_BASE;
 424        sp = (volatile unsigned short *) COMEM_BASE;
 425        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);
 426        addr = (addr & ~0x3) + (~addr & 0x02);
 427        if (pci_byteswap)
 428                val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);
 429        sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;
 430}
 431
 432/*****************************************************************************/
 433
 434void pci_outl(unsigned int val, unsigned int addr)
 435{
 436        volatile unsigned long  *rp;
 437        volatile unsigned int   *lp;
 438
 439#ifdef DEBUGIO
 440        printk(KERN_DEBUG "pci_outl(val=%08x,addr=%x)\n", val, addr);
 441#endif
 442
 443        rp = (volatile unsigned long *) COMEM_BASE;
 444        lp = (volatile unsigned int *) COMEM_BASE;
 445        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(addr);
 446
 447        if (pci_byteswap)
 448                val = (val << 24) | ((val & 0x0000ff00) << 8) |
 449                        ((val & 0x00ff0000) >> 8) | (val >> 24);
 450
 451        lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))] = val;
 452}
 453
 454/*****************************************************************************/
 455
 456unsigned long   pci_blmask[] = {
 457        0x000000e0,
 458        0x000000d0,
 459        0x000000b0,
 460        0x00000070
 461};
 462
 463unsigned char pci_inb(unsigned int addr)
 464{
 465        volatile unsigned long  *rp;
 466        volatile unsigned char  *bp;
 467        unsigned long           r;
 468        unsigned char           val;
 469
 470#ifdef DEBUGIO
 471        printk(KERN_DEBUG "pci_inb(addr=%x)\n", addr);
 472#endif
 473
 474        rp = (volatile unsigned long *) COMEM_BASE;
 475        bp = (volatile unsigned char *) COMEM_BASE;
 476
 477        r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_blmask[(addr & 0x3)];
 478        rp[LREG(COMEM_DAHBASE)] = r;
 479
 480        addr = (addr & ~0x3) + (~addr & 0x3);
 481        val = bp[(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];
 482        return(val);
 483}
 484
 485/*****************************************************************************/
 486
 487unsigned long   pci_bwmask[] = {
 488        0x000000c0,
 489        0x000000c0,
 490        0x00000030,
 491        0x00000030
 492};
 493
 494unsigned short pci_inw(unsigned int addr)
 495{
 496        volatile unsigned long  *rp;
 497        volatile unsigned short *sp;
 498        unsigned long           r;
 499        unsigned short          val;
 500
 501#ifdef DEBUGIO
 502        printk(KERN_DEBUG "pci_inw(addr=%x)", addr);
 503#endif
 504
 505        rp = (volatile unsigned long *) COMEM_BASE;
 506        r = COMEM_DA_IORD | COMEM_DA_ADDR(addr) | pci_bwmask[(addr & 0x3)];
 507        rp[LREG(COMEM_DAHBASE)] = r;
 508
 509        sp = (volatile unsigned short *) COMEM_BASE;
 510        addr = (addr & ~0x3) + (~addr & 0x02);
 511        val = sp[WREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];
 512        if (pci_byteswap)
 513                val = ((val & 0xff) << 8) | ((val >> 8) & 0xff);
 514#ifdef DEBUGIO
 515        printk(KERN_DEBUG "=%04x\n", val);
 516#endif
 517        return(val);
 518}
 519
 520/*****************************************************************************/
 521
 522unsigned int pci_inl(unsigned int addr)
 523{
 524        volatile unsigned long  *rp;
 525        volatile unsigned int   *lp;
 526        unsigned int            val;
 527
 528#ifdef DEBUGIO
 529        printk(KERN_DEBUG "pci_inl(addr=%x)", addr);
 530#endif
 531
 532        rp = (volatile unsigned long *) COMEM_BASE;
 533        lp = (volatile unsigned int *) COMEM_BASE;
 534        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(addr);
 535        val = lp[LREG(COMEM_PCIBUS + COMEM_DA_OFFSET(addr))];
 536
 537        if (pci_byteswap)
 538                val = (val << 24) | ((val & 0x0000ff00) << 8) |
 539                        ((val & 0x00ff0000) >> 8) | (val >> 24);
 540
 541#ifdef DEBUGIO
 542        printk(KERN_DEBUG "=%08x\n", val);
 543#endif
 544        return(val);
 545}
 546
 547/*****************************************************************************/
 548
 549void pci_outsb(void *addr, void *buf, int len)
 550{
 551        volatile unsigned long  *rp;
 552        volatile unsigned char  *bp;
 553        unsigned char           *dp = (unsigned char *) buf;
 554        unsigned int            a = (unsigned int) addr;
 555
 556#ifdef DEBUGIO
 557        printk(KERN_DEBUG "pci_outsb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
 558#endif
 559
 560        rp = (volatile unsigned long *) COMEM_BASE;
 561        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a);
 562
 563        a = (a & ~0x3) + (~a & 0x03);
 564        bp = (volatile unsigned char *)
 565                (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
 566
 567        while (len--)
 568                *bp = *dp++;
 569}
 570
 571/*****************************************************************************/
 572
 573void pci_outsw(void *addr, void *buf, int len)
 574{
 575        volatile unsigned long  *rp;
 576        volatile unsigned short *wp;
 577        unsigned short          w, *dp = (unsigned short *) buf;
 578        unsigned int            a = (unsigned int) addr;
 579
 580#ifdef DEBUGIO
 581        printk(KERN_DEBUG "pci_outsw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
 582#endif
 583
 584        rp = (volatile unsigned long *) COMEM_BASE;
 585        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a);
 586
 587        a = (a & ~0x3) + (~a & 0x2);
 588        wp = (volatile unsigned short *)
 589                (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
 590
 591        while (len--) {
 592                w = *dp++;
 593                if (pci_byteswap)
 594                        w = ((w & 0xff) << 8) | ((w >> 8) & 0xff);
 595                *wp = w;
 596        }
 597}
 598
 599/*****************************************************************************/
 600
 601void pci_outsl(void *addr, void *buf, int len)
 602{
 603        volatile unsigned long  *rp;
 604        volatile unsigned long  *lp;
 605        unsigned long           l, *dp = (unsigned long *) buf;
 606        unsigned int            a = (unsigned int) addr;
 607
 608#ifdef DEBUGIO
 609        printk(KERN_DEBUG "pci_outsl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
 610#endif
 611
 612        rp = (volatile unsigned long *) COMEM_BASE;
 613        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IOWR | COMEM_DA_ADDR(a);
 614
 615        lp = (volatile unsigned long *)
 616                (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
 617
 618        while (len--) {
 619                l = *dp++;
 620                if (pci_byteswap)
 621                        l = (l << 24) | ((l & 0x0000ff00) << 8) |
 622                                ((l & 0x00ff0000) >> 8) | (l >> 24);
 623                *lp = l;
 624        }
 625}
 626
 627/*****************************************************************************/
 628
 629void pci_insb(void *addr, void *buf, int len)
 630{
 631        volatile unsigned long  *rp;
 632        volatile unsigned char  *bp;
 633        unsigned char           *dp = (unsigned char *) buf;
 634        unsigned int            a = (unsigned int) addr;
 635
 636#ifdef DEBUGIO
 637        printk(KERN_DEBUG "pci_insb(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
 638#endif
 639
 640        rp = (volatile unsigned long *) COMEM_BASE;
 641        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a);
 642
 643        a = (a & ~0x3) + (~a & 0x03);
 644        bp = (volatile unsigned char *)
 645                (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
 646
 647        while (len--)
 648                *dp++ = *bp;
 649}
 650
 651/*****************************************************************************/
 652
 653void pci_insw(void *addr, void *buf, int len)
 654{
 655        volatile unsigned long  *rp;
 656        volatile unsigned short *wp;
 657        unsigned short          w, *dp = (unsigned short *) buf;
 658        unsigned int            a = (unsigned int) addr;
 659
 660#ifdef DEBUGIO
 661        printk(KERN_DEBUG "pci_insw(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
 662#endif
 663
 664        rp = (volatile unsigned long *) COMEM_BASE;
 665        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a);
 666
 667        a = (a & ~0x3) + (~a & 0x2);
 668        wp = (volatile unsigned short *)
 669                (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
 670
 671        while (len--) {
 672                w = *wp;
 673                if (pci_byteswap)
 674                        w = ((w & 0xff) << 8) | ((w >> 8) & 0xff);
 675                *dp++ = w;
 676        }
 677}
 678
 679/*****************************************************************************/
 680
 681void pci_insl(void *addr, void *buf, int len)
 682{
 683        volatile unsigned long  *rp;
 684        volatile unsigned long  *lp;
 685        unsigned long           l, *dp = (unsigned long *) buf;
 686        unsigned int            a = (unsigned int) addr;
 687
 688#ifdef DEBUGIO
 689        printk(KERN_DEBUG "pci_insl(addr=%x,buf=%x,len=%d)\n", (int)addr, (int)buf, len);
 690#endif
 691
 692        rp = (volatile unsigned long *) COMEM_BASE;
 693        rp[LREG(COMEM_DAHBASE)] = COMEM_DA_IORD | COMEM_DA_ADDR(a);
 694
 695        lp = (volatile unsigned long *)
 696                (COMEM_BASE + COMEM_PCIBUS + COMEM_DA_OFFSET(a));
 697
 698        while (len--) {
 699                l = *lp;
 700                if (pci_byteswap)
 701                        l = (l << 24) | ((l & 0x0000ff00) << 8) |
 702                                ((l & 0x00ff0000) >> 8) | (l >> 24);
 703                *dp++ = l;
 704        }
 705}
 706
 707/*****************************************************************************/
 708
 709struct pci_localirqlist {
 710        void            (*handler)(int, void *, struct pt_regs *);
 711        const char      *device;
 712        void            *dev_id;
 713};
 714
 715struct pci_localirqlist pci_irqlist[COMEM_MAXPCI];
 716
 717/*****************************************************************************/
 718
 719int pci_request_irq(unsigned int irq,
 720        void (*handler)(int, void *, struct pt_regs *),
 721        unsigned long flags, const char *device, void *dev_id)
 722{
 723        int     i;
 724
 725#ifdef DEBUGIO
 726        printk(KERN_DEBUG "pci_request_irq(irq=%d,handler=%x,flags=%x,device=%s,"
 727                "dev_id=%x)\n", irq, (int) handler, (int) flags, device,
 728                (int) dev_id);
 729#endif
 730
 731        /* Check if this interrupt handler is already lodged */
 732        for (i = 0; (i < COMEM_MAXPCI); i++) {
 733                if (pci_irqlist[i].handler == handler)
 734                        return(0);
 735        }
 736
 737        /* Find a free spot to put this handler */
 738        for (i = 0; (i < COMEM_MAXPCI); i++) {
 739                if (pci_irqlist[i].handler == 0) {
 740                        pci_irqlist[i].handler = handler;
 741                        pci_irqlist[i].device = device;
 742                        pci_irqlist[i].dev_id = dev_id;
 743                        return(0);
 744                }
 745        }
 746
 747        /* Couldn't fit?? */
 748        return(1);
 749}
 750
 751/*****************************************************************************/
 752
 753void pci_free_irq(unsigned int irq, void *dev_id)
 754{
 755        int     i;
 756
 757#ifdef DEBUGIO
 758        printk(KERN_DEBUG "pci_free_irq(irq=%d,dev_id=%x)\n", irq, (int) dev_id);
 759#endif
 760
 761        if (dev_id == (void *) NULL)
 762                return;
 763
 764        /* Check if this interrupt handler is lodged */
 765        for (i = 0; (i < COMEM_MAXPCI); i++) {
 766                if (pci_irqlist[i].dev_id == dev_id) {
 767                        pci_irqlist[i].handler = NULL;
 768                        pci_irqlist[i].device = NULL;
 769                        pci_irqlist[i].dev_id = NULL;
 770                        break;
 771                }
 772        }
 773}
 774
 775/*****************************************************************************/
 776
 777void pci_interrupt(int irq, void *id, struct pt_regs *fp)
 778{
 779        int     i;
 780
 781#ifdef DEBUGIO
 782        printk(KERN_DEBUG "pci_interrupt(irq=%d,id=%x,fp=%x)\n", irq, (int) id, (int) fp);
 783#endif
 784
 785        for (i = 0; (i < COMEM_MAXPCI); i++) {
 786                if (pci_irqlist[i].handler)
 787                        (*pci_irqlist[i].handler)(irq,pci_irqlist[i].dev_id,fp);
 788        }
 789}
 790
 791/*****************************************************************************/
 792
 793/*
 794 *      The shared memory region is broken up into contiguous 512 byte
 795 *      regions for easy allocation... This is not an optimal solution
 796 *      but it makes allocation and freeing regions really easy.
 797 */
 798
 799#define PCI_MEMSLOTSIZE         512
 800#define PCI_MEMSLOTS            (COMEM_SHMEMSIZE / PCI_MEMSLOTSIZE)
 801
 802char    pci_shmemmap[PCI_MEMSLOTS];
 803
 804
 805void *pci_bmalloc(int size)
 806{
 807        int     i, j, nrslots;
 808
 809#ifdef DEBUGIO
 810        printk(KERN_DEBUG "pci_bmalloc(size=%d)\n", size);
 811#endif
 812
 813        if (size <= 0)
 814                return((void *) NULL);
 815
 816        nrslots = (size - 1) / PCI_MEMSLOTSIZE;
 817
 818        for (i = 0; (i < (PCI_MEMSLOTS-nrslots)); i++) {
 819                if (pci_shmemmap[i] == 0) {
 820                        for (j = i+1; (j < (i+nrslots)); j++) {
 821                                if (pci_shmemmap[j])
 822                                        goto restart;
 823                        }
 824
 825                        for (j = i; (j <= i+nrslots); j++)
 826                                pci_shmemmap[j] = 1;
 827                        break;
 828                }
 829restart:
 830        }
 831
 832        return((void *) (COMEM_BASE + COMEM_SHMEM + (i * PCI_MEMSLOTSIZE)));
 833}
 834
 835/*****************************************************************************/
 836
 837void pci_bmfree(void *mp, int size)
 838{
 839        int     i, j, nrslots;
 840
 841#ifdef DEBUGIO
 842        printk(KERN_DEBUG "pci_bmfree(mp=%x,size=%d)\n", (int) mp, size);
 843#endif
 844
 845        nrslots = size / PCI_MEMSLOTSIZE;
 846        i = (((unsigned long) mp) - (COMEM_BASE + COMEM_SHMEM)) /
 847                PCI_MEMSLOTSIZE;
 848
 849        for (j = i; (j < (i+nrslots)); j++)
 850                pci_shmemmap[j] = 0;
 851}
 852
 853/*****************************************************************************/
 854
 855unsigned long pci_virt_to_bus(volatile void *address)
 856{
 857        unsigned long   l;
 858
 859#ifdef DEBUGIO
 860        printk(KERN_DEBUG "pci_virt_to_bus(address=%x)", (int) address);
 861#endif
 862
 863        l = ((unsigned long) address) - COMEM_BASE;
 864#ifdef DEBUGIO
 865        printk(KERN_DEBUG "=%x\n", (int) (l+pci_shmemaddr));
 866#endif
 867        return(l + pci_shmemaddr);
 868}
 869
 870/*****************************************************************************/
 871
 872void *pci_bus_to_virt(unsigned long address)
 873{
 874        unsigned long   l;
 875
 876#ifdef DEBUGIO
 877        printk(KERN_DEBUG "pci_bus_to_virt(address=%x)", (int) address);
 878#endif
 879
 880        l = address - pci_shmemaddr;
 881#ifdef DEBUGIO
 882        printk(KERN_DEBUG "=%x\n", (int) (address + COMEM_BASE));
 883#endif
 884        return((void *) (address + COMEM_BASE));
 885}
 886
 887/*****************************************************************************/
 888
 889void pci_bmcpyto(void *dst, void *src, int len)
 890{
 891        unsigned long   *dp, *sp, val;
 892        unsigned char   *dcp, *scp;
 893        int             i, j;
 894
 895#ifdef DEBUGIO
 896        printk(KERN_DEBUG "pci_bmcpyto(dst=%x,src=%x,len=%d)\n", (int)dst, (int)src, len);
 897#endif
 898
 899        dp = (unsigned long *) dst;
 900        sp = (unsigned long *) src;
 901        i = len >> 2;
 902
 903#if 0
 904        printk(KERN_INFO "DATA:");
 905        scp = (unsigned char *) sp;
 906        for (i = 0; (i < len); i++) {
 907                if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i);
 908                printk(KERN_INFO "%02x ", *scp++);
 909        }
 910        printk(KERN_INFO "\n");
 911#endif
 912
 913        for (j = 0; (i >= 0); i--, j++) {
 914                val = *sp++;
 915                val = (val << 24) | ((val & 0x0000ff00) << 8) |
 916                        ((val & 0x00ff0000) >> 8) | (val >> 24);
 917                *dp++ = val;
 918        }
 919
 920        if (len & 0x3) {
 921                dcp = (unsigned char *) dp;
 922                scp = ((unsigned char *) sp) + 3;
 923                for (i = 0; (i < (len & 0x3)); i++)
 924                        *dcp++ = *scp--;
 925        }
 926}
 927
 928/*****************************************************************************/
 929
 930void pci_bmcpyfrom(void *dst, void *src, int len)
 931{
 932        unsigned long   *dp, *sp, val;
 933        unsigned char   *dcp, *scp;
 934        int             i;
 935
 936#ifdef DEBUGIO
 937        printk(KERN_DEBUG "pci_bmcpyfrom(dst=%x,src=%x,len=%d)\n",(int)dst,(int)src,len);
 938#endif
 939
 940        dp = (unsigned long *) dst;
 941        sp = (unsigned long *) src;
 942        i = len >> 2;
 943
 944        for (; (i >= 0); i--) {
 945                val = *sp++;
 946                val = (val << 24) | ((val & 0x0000ff00) << 8) |
 947                        ((val & 0x00ff0000) >> 8) | (val >> 24);
 948                *dp++ = val;
 949        }
 950
 951        if (len & 0x3) {
 952                dcp = ((unsigned char *) dp) + 3;
 953                scp = (unsigned char *) sp;
 954                for (i = 0; (i < (len & 0x3)); i++)
 955                        *dcp++ = *scp--;
 956        }
 957
 958#if 0
 959        printk(KERN_INFO "DATA:");
 960        dcp = (unsigned char *) dst;
 961        for (i = 0; (i < len); i++) {
 962                if ((i % 16) == 0) printk(KERN_INFO "\n%04x: ", i);
 963                printk(KERN_INFO "%02x ", *dcp++);
 964        }
 965        printk(KERN_INFO "\n");
 966#endif
 967}
 968
 969/*****************************************************************************/
 970
 971void *pci_alloc_consistent(struct pci_dev *dev, size_t size, dma_addr_t *dma_addr)
 972{
 973        void *mp;
 974        if ((mp = pci_bmalloc(size)) != NULL) {
 975                dma_addr = mp - (COMEM_BASE + COMEM_SHMEM);
 976                return(mp);
 977        }
 978        *dma_addr = (dma_addr_t) NULL;
 979        return(NULL);
 980}
 981
 982/*****************************************************************************/
 983
 984void pci_free_consistent(struct pci_dev *dev, size_t size, void *cpu_addr, dma_addr_t dma_addr)
 985{
 986        pci_bmfree(cpu_addr, size);
 987}
 988
 989/*****************************************************************************/
 990
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.