| /* |
| * Copyright 1999 Egbert Eich |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that |
| * copyright notice and this permission notice appear in supporting |
| * documentation, and that the name of the authors not be used in |
| * advertising or publicity pertaining to distribution of the software without |
| * specific, written prior permission. The authors makes no representations |
| * about the suitability of this software for any purpose. It is provided |
| * "as is" without express or implied warranty. |
| * |
| * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| #include "debug.h" |
| #include <fcntl.h> |
| #include <unistd.h> |
| #include <malloc.h> |
| #include <stdio.h> |
| #include <sys/mman.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <string.h> |
| #if defined (__alpha__) || defined (__ia64__) |
| #include <sys/io.h> |
| #endif |
| #include "AsmMacros.h" |
| |
| #include "pci.h" |
| |
| /* |
| * I'm rather simple mindend - therefore I do a poor man's |
| * pci scan without all the fancy stuff that is done in |
| * scanpci. However that's all we need. |
| */ |
| |
| PciStructPtr PciStruct = NULL; |
| PciBusPtr PciBuses = NULL; |
| PciStructPtr CurrentPci = NULL; |
| PciStructPtr PciList = NULL; |
| PciStructPtr BootBios = NULL; |
| int pciMaxBus = 0; |
| |
| static CARD32 PciCfg1Addr; |
| |
| static void readConfigSpaceCfg1(CARD32 bus, CARD32 dev, CARD32 func, |
| CARD32 *reg); |
| static int checkSlotCfg1(CARD32 bus, CARD32 dev, CARD32 func); |
| static int checkSlotCfg2(CARD32 bus, int dev); |
| static void readConfigSpaceCfg2(CARD32 bus, int dev, CARD32 *reg); |
| static CARD8 interpretConfigSpace(CARD32 *reg, int busidx, |
| CARD8 dev, CARD8 func); |
| static CARD32 findBIOSMap(PciStructPtr pciP, CARD32 *biosSize); |
| static void restoreMem(PciStructPtr pciP); |
| |
| |
| #ifdef __alpha__ |
| #define PCI_BUS_FROM_TAG(tag) (((tag) & 0x00ff0000) >> 16) |
| #define PCI_DFN_FROM_TAG(tag) (((tag) & 0x0000ff00) >> 8) |
| |
| #include <asm/unistd.h> |
| |
| CARD32 |
| axpPciCfgRead(CARD32 tag) |
| { |
| int bus, dfn; |
| CARD32 val = 0xffffffff; |
| |
| bus = PCI_BUS_FROM_TAG(tag); |
| dfn = PCI_DFN_FROM_TAG(tag); |
| |
| syscall(__NR_pciconfig_read, bus, dfn, tag & 0xff, 4, &val); |
| return(val); |
| } |
| |
| void |
| axpPciCfgWrite(CARD32 tag, CARD32 val) |
| { |
| int bus, dfn; |
| |
| bus = PCI_BUS_FROM_TAG(tag); |
| dfn = PCI_DFN_FROM_TAG(tag); |
| |
| syscall(__NR_pciconfig_write, bus, dfn, tag & 0xff, 4, &val); |
| } |
| |
| static CARD32 (*readPci)(CARD32 reg) = axpPciCfgRead; |
| static void (*writePci)(CARD32 reg, CARD32 val) = axpPciCfgWrite; |
| #else |
| static CARD32 readPciCfg1(CARD32 reg); |
| static void writePciCfg1(CARD32 reg, CARD32 val); |
| static CARD32 readPciCfg2(CARD32 reg); |
| static void writePciCfg2(CARD32 reg, CARD32 val); |
| |
| static CARD32 (*readPci)(CARD32 reg) = readPciCfg1; |
| static void (*writePci)(CARD32 reg, CARD32 val) = writePciCfg1; |
| #endif |
| |
| #if defined(__alpha__) || defined(__sparc__) |
| #define PCI_EN 0x00000000 |
| #else |
| #define PCI_EN 0x80000000 |
| #endif |
| |
| |
| static int numbus; |
| static int hostbridges = 1; |
| static unsigned long pciMinMemReg = ~0; |
| |
| |
| void |
| scan_pci(void) |
| { |
| unsigned short configtype; |
| |
| CARD32 reg[64]; |
| int busidx; |
| CARD8 cardnum; |
| CARD8 func; |
| int idx; |
| |
| int i; |
| PciStructPtr pci1; |
| PciBusPtr pci_b1,pci_b2; |
| |
| #if defined(__alpha__) || defined(__powerpc__) || defined(__sparc__) || defined(__ia64__) |
| configtype = 1; |
| #else |
| CARD8 tmp1, tmp2; |
| CARD32 tmp32_1, tmp32_2; |
| outb(PCI_MODE2_ENABLE_REG, 0x00); |
| outb(PCI_MODE2_FORWARD_REG, 0x00); |
| tmp1 = inb(PCI_MODE2_ENABLE_REG); |
| tmp2 = inb(PCI_MODE2_FORWARD_REG); |
| if ((tmp1 == 0x00) && (tmp2 == 0x00)) { |
| configtype = 2; |
| readPci = readPciCfg2; |
| writePci = writePciCfg2; |
| P_printf("PCI says configuration type 2\n"); |
| } else { |
| tmp32_1 = inl(PCI_MODE1_ADDRESS_REG); |
| outl(PCI_MODE1_ADDRESS_REG, PCI_EN); |
| tmp32_2 = inl(PCI_MODE1_ADDRESS_REG); |
| outl(PCI_MODE1_ADDRESS_REG, tmp32_1); |
| if (tmp32_2 == PCI_EN) { |
| configtype = 1; |
| P_printf("PCI says configuration type 1\n"); |
| } else { |
| P_printf("No PCI !\n"); |
| return; |
| } |
| } |
| #endif |
| |
| if (configtype == 1) { |
| P_printf("PCI probing configuration type 1\n"); |
| busidx = 0; |
| numbus = 1; |
| idx = 0; |
| do { |
| P_printf("\nProbing for devices on PCI bus %d:\n", busidx); |
| for (cardnum = 0; cardnum < MAX_DEV_PER_VENDOR_CFG1; cardnum++) { |
| func = 0; |
| do { |
| /* loop over the different functions, if present */ |
| if (!checkSlotCfg1(busidx,cardnum,func)) |
| break; |
| readConfigSpaceCfg1(busidx,cardnum,func,reg); |
| |
| func = interpretConfigSpace(reg,busidx, |
| cardnum,func); |
| |
| if (idx++ > MAX_PCI_DEVICES) |
| continue; |
| } while (func < 8); |
| } |
| } while (++busidx < PCI_MAXBUS); |
| #if defined(__alpha__) || defined(__powerpc__) || defined(__sparc__) || defined(__ia64__) |
| /* don't use outl() ;-) */ |
| #else |
| outl(PCI_MODE1_ADDRESS_REG, 0); |
| #endif |
| } else { |
| int slot; |
| |
| P_printf("PCI probing configuration type 2\n"); |
| busidx = 0; |
| numbus = 1; |
| idx = 0; |
| do { |
| for (slot=0xc0; slot<0xd0; i++) { |
| if (!checkSlotCfg2(busidx,slot)) |
| break; |
| readConfigSpaceCfg2(busidx,slot,reg); |
| |
| interpretConfigSpace(reg,busidx, |
| slot,0); |
| if (idx++ > MAX_PCI_DEVICES) |
| continue; |
| } |
| } while (++busidx < PCI_MAXBUS); |
| } |
| |
| |
| pciMaxBus = numbus - 1; |
| P_printf("Number of buses in system: %i\n",pciMaxBus + 1); |
| P_printf("Min PCI mem address: 0x%lx\n",pciMinMemReg); |
| |
| /* link buses */ |
| pci_b1 = PciBuses; |
| while (pci_b1) { |
| pci_b2 = PciBuses; |
| pci_b1->pBus = NULL; |
| while (pci_b2) { |
| if (pci_b1->primary == pci_b2->secondary) |
| pci_b1->pBus = pci_b2; |
| pci_b2 = pci_b2->next; |
| } |
| pci_b1 = pci_b1->next; |
| } |
| pci1 = PciStruct; |
| while (pci1) { |
| pci_b2 = PciBuses; |
| pci1->pBus = NULL; |
| while (pci_b2) { |
| if (pci1->bus == pci_b2->secondary) |
| pci1->pBus = pci_b2; |
| pci_b2 = pci_b2->next; |
| } |
| pci1 = pci1->next; |
| } |
| if (RESORT) { |
| PciStructPtr tmp = PciStruct, tmp1; |
| PciStruct = NULL; |
| while (tmp) { |
| tmp1 = tmp->next; |
| tmp->next = PciStruct; |
| PciStruct = tmp; |
| tmp = tmp1; |
| } |
| } |
| PciList = CurrentPci = PciStruct; |
| } |
| |
| #ifndef __alpha__ |
| static CARD32 |
| readPciCfg1(CARD32 reg) |
| { |
| CARD32 val; |
| |
| outl(PCI_MODE1_ADDRESS_REG, reg); |
| val = inl(PCI_MODE1_DATA_REG); |
| outl(PCI_MODE1_ADDRESS_REG, 0); |
| P_printf("reading: 0x%x from 0x%x\n",val,reg); |
| return val; |
| } |
| |
| static void |
| writePciCfg1(CARD32 reg, CARD32 val) |
| { |
| P_printf("writing: 0x%x to 0x%x\n",val,reg); |
| outl(PCI_MODE1_ADDRESS_REG, reg); |
| outl(PCI_MODE1_DATA_REG,val); |
| outl(PCI_MODE1_ADDRESS_REG, 0); |
| } |
| |
| static CARD32 |
| readPciCfg2(CARD32 reg) |
| { |
| CARD32 val; |
| CARD8 bus = (reg >> 16) & 0xff; |
| CARD8 dev = (reg >> 11) & 0x1f; |
| CARD8 num = reg & 0xff; |
| |
| outb(PCI_MODE2_ENABLE_REG, 0xF1); |
| outb(PCI_MODE2_FORWARD_REG, bus); |
| val = inl((dev << 8) + num); |
| outb(PCI_MODE2_ENABLE_REG, 0x00); |
| P_printf("reading: 0x%x from 0x%x\n",val,reg); |
| return val; |
| } |
| |
| static void |
| writePciCfg2(CARD32 reg, CARD32 val) |
| { |
| CARD8 bus = (reg >> 16) & 0xff; |
| CARD8 dev = (reg >> 11) & 0x1f; |
| CARD8 num = reg & 0xff; |
| |
| P_printf("writing: 0x%x to 0x%x\n",val,reg); |
| outb(PCI_MODE2_ENABLE_REG, 0xF1); |
| outb(PCI_MODE2_FORWARD_REG, bus); |
| outl((dev << 8) + num,val); |
| outb(PCI_MODE2_ENABLE_REG, 0x00); |
| } |
| #endif |
| |
| void |
| pciVideoDisable(void) |
| { |
| /* disable VGA routing on bridges */ |
| PciBusPtr pbp = PciBuses; |
| PciStructPtr pcp = PciStruct; |
| |
| while (pbp) { |
| writePci(pbp->Slot.l | 0x3c, pbp->bctl & ~(CARD32)(8<<16)); |
| pbp = pbp->next; |
| } |
| /* disable display devices */ |
| while (pcp) { |
| writePci(pcp->Slot.l | 0x04, pcp->cmd_st & ~(CARD32)3); |
| writePci(pcp->Slot.l | 0x30, pcp->RomBase & ~(CARD32)1); |
| pcp = pcp->next; |
| } |
| } |
| |
| void |
| pciVideoRestore(void) |
| { |
| /* disable VGA routing on bridges */ |
| PciBusPtr pbp = PciBuses; |
| PciStructPtr pcp = PciStruct; |
| |
| while (pbp) { |
| writePci(pbp->Slot.l | 0x3c, pbp->bctl); |
| pbp = pbp->next; |
| } |
| /* disable display devices */ |
| while (pcp) { |
| writePci(pcp->Slot.l | 0x04, pcp->cmd_st); |
| writePci(pcp->Slot.l | 0x30, pcp->RomBase); |
| pcp = pcp->next; |
| } |
| } |
| |
| void |
| EnableCurrent() |
| { |
| PciBusPtr pbp; |
| PciStructPtr pcp = CurrentPci; |
| |
| pciVideoDisable(); |
| |
| pbp = pcp->pBus; |
| while (pbp) { /* enable bridges */ |
| writePci(pbp->Slot.l | 0x3c, pbp->bctl | (CARD32)(8<<16)); |
| pbp = pbp->pBus; |
| } |
| writePci(pcp->Slot.l | 0x04, pcp->cmd_st | (CARD32)3); |
| writePci(pcp->Slot.l | 0x30, pcp->RomBase | (CARD32)1); |
| } |
| |
| CARD8 |
| PciRead8(int offset, CARD32 Slot) |
| { |
| int shift = offset & 0x3; |
| offset = offset & 0xFC; |
| return ((readPci(Slot | offset) >> (shift << 3)) & 0xff); |
| } |
| |
| CARD16 |
| PciRead16(int offset, CARD32 Slot) |
| { |
| int shift = offset & 0x2; |
| offset = offset & 0xFC; |
| return ((readPci(Slot | offset) >> (shift << 3)) & 0xffff); |
| } |
| |
| CARD32 |
| PciRead32(int offset, CARD32 Slot) |
| { |
| offset = offset & 0xFC; |
| return (readPci(Slot | offset)); |
| } |
| |
| void |
| PciWrite8(int offset, CARD8 byte, CARD32 Slot) |
| { |
| CARD32 val; |
| int shift = offset & 0x3; |
| offset = offset & 0xFC; |
| val = readPci(Slot | offset); |
| val &= ~(CARD32)(0xff << (shift << 3)); |
| val |= byte << (shift << 3); |
| writePci(Slot | offset, val); |
| } |
| |
| void |
| PciWrite16(int offset, CARD16 word, CARD32 Slot) |
| { |
| CARD32 val; |
| int shift = offset & 0x2; |
| offset = offset & 0xFC; |
| val = readPci(Slot | offset); |
| val &= ~(CARD32)(0xffff << (shift << 3)); |
| val |= word << (shift << 3); |
| writePci(Slot | offset, val); |
| } |
| |
| void |
| PciWrite32(int offset, CARD32 lg, CARD32 Slot) |
| { |
| offset = offset & 0xFC; |
| writePci(Slot | offset, lg); |
| } |
| |
| int |
| mapPciRom(PciStructPtr pciP) |
| { |
| unsigned long RomBase = 0; |
| int mem_fd; |
| unsigned char *mem, *ptr; |
| unsigned char *scratch = NULL; |
| int length = 0; |
| CARD32 biosSize = 0x1000000; |
| CARD32 enablePci; |
| |
| if (!pciP) |
| pciP = CurrentPci; |
| |
| if (FIX_ROM) { |
| RomBase = findBIOSMap(pciP, &biosSize); |
| if (!RomBase) { |
| fprintf(stderr,"Cannot remap BIOS of %i:%i:%i " |
| "- trying preset address\n",pciP->bus,pciP->dev, |
| pciP->func); |
| RomBase = pciP->RomBase & ~(CARD32)0xFF; |
| } |
| } else { |
| RomBase = pciP->RomBase & ~(CARD32)0xFF; |
| if (~RomBase + 1 < biosSize || !RomBase) |
| RomBase = findBIOSMap(pciP, &biosSize); |
| } |
| |
| P_printf("RomBase: 0x%lx\n",RomBase); |
| |
| if ((mem_fd = open(MEM_FILE,O_RDONLY))<0) { |
| perror("opening memory"); |
| restoreMem(pciP); |
| return (0); |
| } |
| |
| PciWrite32(0x30,RomBase | 1,pciP->Slot.l); |
| |
| #ifdef __alpha__ |
| mem = ptr = (unsigned char *)mmap(0, biosSize, PROT_READ, |
| MAP_SHARED, mem_fd, RomBase | _bus_base()); |
| #else |
| mem = ptr = (unsigned char *)mmap(0, biosSize, PROT_READ, |
| MAP_SHARED, mem_fd, RomBase); |
| #endif |
| if (pciP != CurrentPci) { |
| enablePci = PciRead32(0x4,pciP->Slot.l); |
| PciWrite32(0x4,enablePci | 0x2,pciP->Slot.l); |
| } |
| |
| #ifdef PRINT_PCI |
| dprint((unsigned long)ptr,0x30); |
| #endif |
| while ( *ptr == 0x55 && *(ptr+1) == 0xAA) { |
| unsigned short data_off = *(ptr+0x18) | (*(ptr+0x19)<< 8); |
| unsigned char *data = ptr + data_off; |
| unsigned char type; |
| int i; |
| |
| if (*data!='P' || *(data+1)!='C' || *(data+2)!='I' || *(data+3)!='R') { |
| break; |
| } |
| type = *(data + 0x14); |
| P_printf("data segment in BIOS: 0x%x, type: 0x%x ",data_off,type); |
| |
| if (type != 0) { /* not PC-AT image: find next one */ |
| unsigned int image_length; |
| unsigned char indicator = *(data + 0x15); |
| if (indicator & 0x80) /* last image */ |
| break; |
| image_length = (*(data + 0x10) |
| | (*(data + 0x11) << 8)) << 9; |
| P_printf("data image length: 0x%x, ind: 0x%x\n", |
| image_length,indicator); |
| ptr = ptr + image_length; |
| continue; |
| } |
| /* OK, we have a PC Image */ |
| length = (*(ptr + 2) << 9); |
| P_printf("BIOS length: 0x%x\n",length); |
| scratch = (unsigned char *)malloc(length); |
| /* don't use memcpy() here: Reading from bus! */ |
| for (i=0;i<length;i++) |
| *(scratch + i)=*(ptr + i); |
| break; |
| } |
| |
| if (pciP != CurrentPci) |
| PciWrite32(0x4,enablePci,pciP->Slot.l); |
| |
| /* unmap/close/disable PCI bios mem */ |
| munmap(mem, biosSize); |
| close(mem_fd); |
| /* disable and restore mapping */ |
| writePci(pciP->Slot.l | 0x30, pciP->RomBase & ~(CARD32)1); |
| |
| if (scratch && length) { |
| memcpy((unsigned char *)V_BIOS, scratch, length); |
| free(scratch); |
| } |
| |
| restoreMem(pciP); |
| return length; |
| } |
| |
| CARD32 |
| findPci(CARD16 slotBX) |
| { |
| CARD32 slot = slotBX << 8; |
| |
| if (slot == (CurrentPci->Slot.l & ~PCI_EN)) |
| return (CurrentPci->Slot.l | PCI_EN); |
| else { |
| #if !SHOW_ALL_DEV |
| PciBusPtr pBus = CurrentPci->pBus; |
| while (pBus) { |
| /* fprintf(stderr,"slot: 0x%x bridge: 0x%x\n",slot, pBus->Slot.l); */ |
| if (slot == (pBus->Slot.l & ~PCI_EN)) |
| return pBus->Slot.l | PCI_EN; |
| pBus = pBus->next; |
| } |
| #else |
| PciStructPtr pPci = PciStruct; |
| while (pPci) { |
| /*fprintf(stderr,"slot: 0x%x bridge: 0x%x\n",slot, pPci->Slot.l); */ |
| if (slot == (pPci->Slot.l & ~PCI_EN)) |
| return pPci->Slot.l | PCI_EN; |
| pPci = pPci->next; |
| } |
| #endif |
| } |
| return 0; |
| } |
| |
| CARD16 |
| pciSlotBX(PciStructPtr pPci) |
| { |
| return (CARD16)((pPci->Slot.l >> 8) & 0xFFFF); |
| } |
| |
| PciStructPtr |
| findPciDevice(CARD16 vendorID, CARD16 deviceID, char n) |
| { |
| PciStructPtr pPci = CurrentPci; |
| n++; |
| |
| while (pPci) { |
| if ((pPci->VendorID == vendorID) && (pPci->DeviceID == deviceID)) { |
| if (!(--n)) break; |
| } |
| pPci = pPci->next; |
| } |
| return pPci; |
| } |
| |
| PciStructPtr |
| findPciClass(CARD8 intf, CARD8 subClass, CARD16 class, char n) |
| { |
| PciStructPtr pPci = CurrentPci; |
| n++; |
| |
| while (pPci) { |
| if ((pPci->Interface == intf) && (pPci->SubClass == subClass) |
| && (pPci->BaseClass == class)) { |
| if (!(--n)) break; |
| } |
| pPci = pPci->next; |
| } |
| return pPci; |
| } |
| |
| static void |
| readConfigSpaceCfg1(CARD32 bus, CARD32 dev, CARD32 func, CARD32 *reg) |
| { |
| CARD32 config_cmd = PCI_EN | (bus<<16) | |
| (dev<<11) | (func<<8); |
| int i; |
| |
| for (i = 0; i<64;i+=4) { |
| #ifdef __alpha__ |
| reg[i] = axpPciCfgRead(config_cmd | i); |
| #else |
| outl(PCI_MODE1_ADDRESS_REG, config_cmd | i); |
| reg[i] = inl(PCI_MODE1_DATA_REG); |
| #endif |
| |
| #ifdef V86BIOS_DEBUG |
| P_printf("0x%lx\n",reg[i]); |
| #endif |
| } |
| } |
| |
| static int |
| checkSlotCfg1(CARD32 bus, CARD32 dev, CARD32 func) |
| { |
| CARD32 config_cmd = PCI_EN | (bus<<16) | |
| (dev<<11) | (func<<8); |
| CARD32 reg; |
| #ifdef __alpha__ |
| reg = axpPciCfgRead(config_cmd); |
| #else |
| outl(PCI_MODE1_ADDRESS_REG, config_cmd); |
| reg = inl(PCI_MODE1_DATA_REG); |
| #endif |
| if (reg != 0xFFFFFFFF) |
| return 1; |
| else |
| return 0; |
| } |
| |
| static int |
| checkSlotCfg2(CARD32 bus, int dev) |
| { |
| CARD32 val; |
| |
| outb(PCI_MODE2_ENABLE_REG, 0xF1); |
| outb(PCI_MODE2_FORWARD_REG, bus); |
| val = inl(dev << 8); |
| outb(PCI_MODE2_FORWARD_REG, 0x00); |
| outb(PCI_MODE2_ENABLE_REG, 0x00); |
| if (val == 0xFFFFFFFF) |
| return 0; |
| if (val == 0xF0F0F0F0) |
| return 0; |
| return 1; |
| } |
| |
| static void |
| readConfigSpaceCfg2(CARD32 bus, int dev, CARD32 *reg) |
| { |
| int i; |
| |
| outb(PCI_MODE2_ENABLE_REG, 0xF1); |
| outb(PCI_MODE2_FORWARD_REG, bus); |
| for (i = 0; i<64;i+=4) { |
| reg[i] = inl((dev << 8) + i); |
| #ifdef V86BIOS_DEBUG |
| P_printf("0x%lx\n",reg[i]); |
| #endif |
| } |
| outb(PCI_MODE2_ENABLE_REG, 0x00); |
| } |
| |
| static CARD8 |
| interpretConfigSpace(CARD32 *reg, int busidx, CARD8 dev, CARD8 func) |
| { |
| CARD32 config_cmd; |
| CARD16 vendor, device; |
| CARD8 baseclass, subclass; |
| CARD8 primary, secondary; |
| CARD8 header, interface; |
| int i; |
| |
| config_cmd = PCI_EN | busidx<<16 | |
| (dev<<11) | (func<<8); |
| |
| for (i = 0x10; i < 0x28; i+=4) { |
| if (IS_MEM32(reg[i])) |
| if ((reg[i] & 0xFFFFFFF0) < pciMinMemReg) |
| pciMinMemReg = (reg[i] & 0xFFFFFFF0); |
| #ifdef __alpha__ |
| if (IS_MEM64(reg[i])) { |
| unsigned long addr = reg[i] | |
| (unsigned long)(reg[i+4]) << 32; |
| if ((addr & ~0xfL) < pciMinMemReg) |
| pciMinMemReg = (addr & ~0xfL); |
| i+=4; |
| } |
| #endif |
| } |
| vendor = reg[0] & 0xFFFF; |
| device = reg[0] >> 16; |
| P_printf("bus: %i card: %i func %i reg0: 0x%x ", busidx,dev,func,reg[0]); |
| baseclass = reg[8] >> 24; |
| subclass = (reg[8] >> 16) & 0xFF; |
| interface = (reg[8] >> 8) & 0xFF; |
| |
| header = (reg[0x0c] >> 16) & 0xff; |
| P_printf("bc 0x%x, sub 0x%x, if 0x%x, hdr 0x%x\n", |
| baseclass,subclass,interface,header); |
| if (BRIDGE_CLASS(baseclass)) { |
| if (BRIDGE_PCI_CLASS(subclass)) { |
| PciBusPtr pbp = malloc(sizeof(PciBusRec)); |
| P_printf("Pci-Pci Bridge found; "); |
| primary = reg[0x18] & 0xFF; |
| secondary = (reg[0x18] >> 8) & 0xFF; |
| P_printf("primary: 0x%x secondary: 0x%x\n", |
| primary,secondary); |
| pbp->bctl = reg[0x3c]; |
| pbp->primary = primary; |
| pbp->secondary = secondary; |
| pbp->Slot.l = config_cmd; |
| pbp->next = PciBuses; |
| PciBuses = pbp; |
| numbus++; |
| } else if (BRIDGE_HOST_CLASS(subclass) |
| && (hostbridges++ > 1)) { |
| numbus++; |
| } |
| } else if (VIDEO_CLASS(baseclass,subclass)) { |
| PciStructPtr pcp = malloc(sizeof(PciStructRec)); |
| P_printf("Display adapter found\n"); |
| pcp->RomBase = reg[0x30]; |
| pcp->cmd_st = reg[4]; |
| pcp->active = (reg[4] & 0x03) == 3 ? 1 : 0; |
| pcp->VendorID = vendor; |
| pcp->DeviceID = device; |
| pcp->Interface = interface; |
| pcp->BaseClass = baseclass; |
| pcp->SubClass = subclass; |
| pcp->Slot.l = config_cmd; |
| pcp->bus = busidx; |
| pcp->dev = dev; |
| pcp->func = func; |
| pcp->next = PciStruct; |
| PciStruct = pcp; |
| } |
| if ((func == 0) |
| && ((header & PCI_MULTIFUNC_DEV) == 0)) |
| func = 8; |
| else |
| func++; |
| return func; |
| } |
| |
| static CARD32 remapMEM_val; |
| static int remapMEM_num; |
| |
| static int /* map it on some other video device */ |
| remapMem(PciStructPtr pciP, int num, CARD32 size) |
| { |
| PciStructPtr pciPtr = PciStruct; |
| int i; |
| CARD32 org; |
| CARD32 val; |
| CARD32 size_n; |
| |
| org = PciRead32(num + 0x10,pciP->Slot.l); |
| |
| while (pciPtr) { |
| for (i = 0; i < 20; i=i+4) { |
| |
| val = PciRead32(i + 0x10,pciPtr->Slot.l); |
| /* don't map it on itself */ |
| if ((org & 0xfffffff0) == (val & 0xfffffff0)) |
| continue; |
| if (val && !(val & 1)) |
| PciWrite32(i + 0x10,0xffffffff,pciPtr->Slot.l); |
| else |
| continue; |
| size_n = PciRead32(i + 0x10,pciPtr->Slot.l); |
| PciWrite32(i + 0x10,val,pciPtr->Slot.l); |
| size_n = ~(CARD32)(size_n & 0xfffffff0) + 1; |
| |
| if (size_n >= size) { |
| PciWrite32(num + 0x10,val,pciP->Slot.l); |
| return 1; |
| } |
| } |
| pciPtr = pciPtr->next; |
| } |
| /* last resort: try to go below lowest PCI mem address */ |
| val = ((pciMinMemReg & ~(CARD32)(size - 1)) - size); |
| if (val > 0x7fffffff) { |
| PciWrite32(num + 0x10,val, pciP->Slot.l); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| static void |
| restoreMem(PciStructPtr pciP) |
| { |
| if (remapMEM_val == 0) return; |
| PciWrite32(remapMEM_num + 0x10,remapMEM_val,pciP->Slot.l); |
| return; |
| } |
| |
| static CARD32 |
| findBIOSMap(PciStructPtr pciP, CARD32 *biosSize) |
| { |
| PciStructPtr pciPtr = PciStruct; |
| int i; |
| CARD32 val; |
| CARD32 size; |
| |
| PciWrite32(0x30,0xffffffff,pciP->Slot.l); |
| *biosSize = PciRead32(0x30,pciP->Slot.l); |
| P_printf("bios size: 0x%x\n",*biosSize); |
| PciWrite32(0x30,pciP->RomBase,pciP->Slot.l); |
| *biosSize = ~(*biosSize & 0xFFFFFF00) + 1; |
| P_printf("bios size masked: 0x%x\n",*biosSize); |
| if (*biosSize > (1024 * 1024 * 16)) { |
| *biosSize = 1024 * 1024 * 16; |
| P_printf("fixing broken BIOS size: 0x%x\n",*biosSize); |
| } |
| while (pciPtr) { |
| if (pciPtr->bus != pciP->bus) { |
| pciPtr = pciPtr->next; |
| continue; |
| } |
| for (i = 0; i < 20; i=i+4) { |
| |
| val = PciRead32(i + 0x10,pciPtr->Slot.l); |
| if (!(val & 1)) |
| |
| PciWrite32(i + 0x10,0xffffffff,pciPtr->Slot.l); |
| else |
| continue; |
| size = PciRead32(i + 0x10,pciPtr->Slot.l); |
| PciWrite32(i + 0x10,val,pciPtr->Slot.l); |
| size = ~(CARD32)(size & 0xFFFFFFF0) + 1; |
| #ifdef V86_BIOS_DEBUG |
| P_printf("size: 0x%x\n",size); |
| #endif |
| if (size >= *biosSize) { |
| if (pciP == pciPtr) { /* if same device remap ram*/ |
| if (!(remapMem(pciP,i,size))) |
| continue; |
| remapMEM_val = val; |
| remapMEM_num = i; |
| } else { |
| remapMEM_val = 0; |
| } |
| return val & 0xFFFFFF00; |
| } |
| } |
| pciPtr = pciPtr->next; |
| } |
| remapMEM_val = 0; |
| /* very last resort */ |
| if (pciP->bus == 0 && (pciMinMemReg > *biosSize)) |
| return (pciMinMemReg - size) & ~(size - 1); |
| |
| return 0; |
| } |
| |
| int |
| cfg1out(CARD16 addr, CARD32 val) |
| { |
| if (addr == 0xCF8) { |
| PciCfg1Addr = val; |
| return 1; |
| } else if (addr == 0xCFC) { |
| writePci(PciCfg1Addr, val); |
| return 1; |
| } |
| return 0; |
| } |
| |
| int |
| cfg1in(CARD16 addr, CARD32 *val) |
| { |
| if (addr == 0xCF8) { |
| *val = PciCfg1Addr; |
| return 1; |
| } else if (addr == 0xCFC) { |
| *val = readPci(PciCfg1Addr); |
| return 1; |
| } |
| return 0; |
| } |
| |
| void |
| list_pci(void) |
| { |
| PciStructPtr pci = PciList; |
| |
| while (pci) { |
| printf("[0x%x:0x%x:0x%x] vendor: 0x%4.4x dev: 0x%4.4x class: 0x%4.4x" |
| " subclass: 0x%4.4x\n",pci->bus,pci->dev,pci->func, |
| pci->VendorID,pci->DeviceID,pci->BaseClass,pci->SubClass); |
| pci = pci->next; |
| } |
| } |
| |
| PciStructPtr |
| findPciByIDs(int bus, int dev, int func) |
| { |
| PciStructPtr pciP = PciList; |
| |
| while (pciP) { |
| if (pciP->bus == bus && pciP->dev == dev && pciP->func == func) |
| return pciP; |
| pciP = pciP->next; |
| } |
| return NULL; |
| } |