/************************************************************************** ** ** $Id: pci.c,v 2.0.0.1 94/07/19 19:06:44 wolf Exp $ ** ** General subroutines for the PCI bus on 80*86 systems. ** pci_configure () ** **------------------------------------------------------------------------- ** ** Copyright (c) 1994 Wolfgang Stanglmeier, Koeln, Germany ** ** ** This is a beta version - use with care. ** **------------------------------------------------------------------------- ** ** $Log: pci.c,v $ ** Revision 2.0.0.1 94/07/19 19:06:44 wolf ** New vendor entry: MATROX ** ** Revision 2.0 94/07/10 15:53:29 wolf ** FreeBSD release. ** ** Revision 1.0 94/06/07 20:02:19 wolf ** Beta release. ** *************************************************************************** */ #include #if NPCI > 0 /*======================================================== ** ** Configuration ** **======================================================== */ /* ** maximum number of devices which share one interrupt line */ #define PCI_MAX_DPI 1 /* ** there may be up to 255 busses on pci. ** don't probe them all :-) */ #define FIRST_BUS 0 #define LAST_BUS 0 /* ** there may be up to 32 devices per bus. ** do probe them all ;-) */ #define FIRST_DEVICE 0 #define LAST_DEVICE 31 /*======================================================== ** ** #includes and declarations ** **======================================================== */ #include #include #include #include #include #include #include #include #include #include #include #include static char ident[] = "\n$Id: pci.c,v 2.0.0.1 94/07/19 19:06:44 wolf Exp $\n" "Copyright (c) 1994, Wolfgang Stanglmeier\n"; /* ** Function prototypes missing in system headers */ extern int printf(); extern int ffs(); extern pmap_t pmap_kernel(void); /* ** function prototypes */ int pci_map_mem (pcici_t tag, u_long reg, u_long *va, vm_offset_t *pa); int pci_map_port (pcici_t tag, u_long reg, u_short* pa); void pci_configure (void); /*======================================================== ** ** Autoconfiguration (of isa bus) (Free/386) ** **======================================================== */ /* ** per device (interrupt) data structure. */ static struct { u_short number; u_short isanum; struct { int (*proc)(int dev); dev_t unit; } vector[PCI_MAX_DPI]; } pcidata [NPCI]; #ifndef __NetBSD__ /* ** check device ready */ static int pciprobe (struct isa_device *dev) { if (dev->id_unit >= NPCI) return (0); if (!pci_conf_mode()) return (0); return (1); } /* ** initialize the driver structure */ static int pciattach (struct isa_device *isdp) { pcidata[isdp->id_unit].number = 0; pcidata[isdp->id_unit].isanum = ffs(isdp->id_irq)-1; return (1); } /* ** ISA driver structure */ struct isa_driver pcidriver = { pciprobe, pciattach, "pci" }; /*======================================================== ** ** Interrupt forward from isa to pci devices. ** **======================================================== */ void pciintr (int unit) { u_short i; if (unit >= NPCI) return; #if defined (GENERICAH) || defined (GENERICBT) || defined (GENERICNCR) \ || defined (GENERICAHA) || defined (GENERICISA) for (unit=0; unit < NPCI; unit++) #endif for (i=0; ipd_driver; dvp++) { if (drp->device_id == type) break; }; if (!drp) { /* ** not found */ switch (type & 0xffff) { case 0x1002: printf ("ATI TECHNOLOGIES INC"); break; case 0x101A: printf ("NCR"); break; case 0x102B: printf ("MATROX"); break; case 0x1045: printf ("OPTI"); break; case 0x8086: printf ("INTEL CORPORATION"); break; default: printf ("vendor=%x", type & 0xffff); }; switch (type) { case 0x04848086: printf (" 82378IB pci-isa bridge"); break; case 0x04838086: printf (" 82424ZX cache dram controller"); break; case 0x04828086: printf (" 82375EB pci-eisa bridge"); break; case 0x04A38086: printf (" 82434LX pci cache memory controller"); break; default: printf (", device=%x", type >> 16); }; printf (" [not supported]\n"); for (reg=0x10; reg<=0x20; reg+=4) { data = pci_conf_read (tag, reg); if (!data) continue; switch (data&7) { case 1: case 5: printf (" map(%x): io(%x)\n", reg, data & ~3); break; case 0: printf (" map(%x): mem32(%x)\n", reg, data & ~7); break; case 2: printf (" map(%x): mem20(%x)\n", reg, data & ~7); break; case 4: printf (" map(%x): mem64(%x)\n", reg, data & ~7); break; }; }; continue; }; /* ** found it. ** probe returns the device unit. */ printf ("<%s>", drp -> vendor); unit = (*drp->probe) (tag); if (unit<0) { printf (" probe failed.\n"); continue; }; /* ** install interrupts */ intpin = (pci_conf_read (tag, 0x3c) >> 8) & 0xff; if (intpin) { printf (" irq %c", 0x60+intpin); intpin--; if (intpin < NPCI) { u_short entry = pcidata[intpin].number; if (entry < PCI_MAX_DPI) { pcidata[intpin].vector[entry].proc = drp->intr; pcidata[intpin].vector[entry].unit = unit; entry++; }; printf (" isa=%d [%d]",pcidata[intpin].isanum, entry); pcidata[intpin].number=entry; } else printf (" not installed"); }; /* ** enable memory access */ data = pci_conf_read (tag, 0x04) & 0xffff | 0x0002; pci_conf_write (tag, (u_char) 0x04, data); /* ** attach device ** may produce additional log messages, ** i.e. when installing subdevices. */ printf (" as %s%d\n", drp->name,unit); (void) (*drp->attach) (tag); }; printf ("pci uses physical addresses from %x to %x\n", PCI_PMEM_START, pci_paddr); } /*----------------------------------------------------------------------- ** ** Map device into virtual and physical space ** **----------------------------------------------------------------------- */ extern vm_map_t kernel_map; int pci_map_port (pcici_t tag, u_long reg, u_short* pa) { /* ** @MAPIO@ not yet implemented. */ return (ENOSYS); } int pci_map_mem (pcici_t tag, u_long reg, vm_offset_t* va, vm_offset_t* pa) { u_long data, result; vm_size_t vsize; vm_offset_t vaddr; /* ** sanity check */ if (reg <= 0x10 || reg >= 0x20 || (reg & 3)) return (EINVAL); /* ** get size and type of memory */ pci_conf_write (tag, reg, 0xfffffffful); data = pci_conf_read (tag, reg); switch (data & 0x0f) { case 0x0: /* 32 bit non cachable */ break; default: /* unknown */ return (EINVAL); }; vsize = round_page (-(data & 0xfffffff0)); printf (" memory size=0x%x", vsize); if (!vsize) return (EINVAL); /* ** try to map device to virtual space */ vaddr = vm_map_min (kernel_map); result = vm_map_find (kernel_map, (void*)0, (vm_offset_t) 0, &vaddr, vsize, TRUE); if (result != KERN_SUCCESS) { printf (" vm_map_find failed(%d)\n", result); return (ENOMEM); }; /* ** align physical address to virtual size */ if (data = pci_paddr % vsize) pci_paddr += vsize - data; /* ** display values. */ printf (" virtual=0x%x physical=0x%x\n", vaddr, pci_paddr); *va = vaddr; *pa = pci_paddr; /* ** set device address */ pci_conf_write (tag, reg, pci_paddr); /* ** map physical */ while (vsize >= NBPG) { pmap_enter (pmap_kernel(), vaddr, pci_paddr, VM_PROT_READ|VM_PROT_WRITE, TRUE); vaddr += NBPG; pci_paddr += NBPG; vsize -= NBPG; }; return (0); } #endif