📄 pci.c
字号:
if ((buses & 0xFFFFFF) != 0) { unsigned int cmax; child->primary = buses & 0xFF; child->secondary = (buses >> 8) & 0xFF; child->subordinate = (buses >> 16) & 0xFF; child->number = child->secondary; cmax = pci_scan_bus(child); if (cmax > max) max = cmax; } else { /* * Configure the bus numbers for this bridge: */ buses &= 0xff000000; buses |= (((unsigned int)(child->primary) << 0) | ((unsigned int)(child->secondary) << 8) | ((unsigned int)(child->subordinate) << 16)); pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); /* * Now we can scan all subordinate buses: */ max = pci_scan_bus(child); /* * Set the subordinate bus number to its real * value: */ child->subordinate = max; buses = (buses & 0xff00ffff) | ((unsigned int)(child->subordinate) << 16); pcibios_write_config_dword(bus->number, devfn, PCI_PRIMARY_BUS, buses); } pcibios_write_config_word(bus->number, devfn, PCI_COMMAND, cr ); } /* * We've scanned the bus and so we know all about what's on * the other side of any bridges that may be on this bus plus * any devices. * * Return how far we've got finding sub-buses. */ return max;}#if 0voidpci_fixup(void) { struct pci_dev *p; struct pci_bus *bus; for (bus = &pci_root; bus; bus=bus->next) { for (p=bus->devices; p; p=p->sibling) { } }}static void print_pci_info(){ pci_resource *r; struct pci_bus *pb = &pci_root; printk("\n"); printk("PCI busses:\n"); for(pb= &pci_root; pb; pb=pb->children ) { printk(" number %d, primary %d, secondary %d, subordinate %d\n", pb->number, pb->primary, pb->secondary, pb->subordinate ); printk(" bridge; vendor %04x, device %04x\n", pb->self->vendor, pb->self->device ); { struct pci_dev *pd; for(pd= pb->devices; pd; pd=pd->sibling ) { printk(" vendor %04x, device %04x, irq %d\n", pd->vendor, pd->device, pd->irq ); } printk("\n"); } } printk("\n"); printk("PCI resources:\n"); for (r=pci->resources; r; r= r->next) { printk(" bus %d, vendor %04x, device %04x, base %08x, size %08x, type %d\n", r->dev->bus->number, r->dev->vendor, r->dev->device, r->base, r->size, r->type ); } printk("\n"); return;}#endifstatic struct _addr_start{ unsigned32 start_pcimem; unsigned32 start_pciio; unsigned32 start_prefetch;} astart;static pci_resource *enum_device_resources( struct pci_dev *pdev, int i ){ pci_resource *r; for(r= pci->resources; r; r= r->next ) { if( r->dev == pdev ) { if( i-- == 0 ) break; } } return r;}static void recursive_bus_reconfigure( struct pci_bus *pbus ){ struct pci_dev *pdev; struct pci_bus *childbus; int isroot = 0; if( !pbus ) { /* start with the root bus */ astart.start_pcimem = BUSREST_MEM_START; astart.start_pciio = BUSREST_IO_START; astart.start_prefetch = ((BUSREST_MEM_END >> 16) << 16); pbus = &pci_root; isroot = -1; }#define WRITE_BRIDGE_IO#define WRITE_BRIDGE_MEM#define WRITE_BRIDGE_PF#define WRITE_BRIDGE_ENABLE/*** Run thru the p2p bridges on this bus and recurse into subordinate busses*/ for( childbus= pbus->children; childbus; childbus= childbus->next ) { pdev= childbus->self; pcibios_write_config_byte(pdev->bus->number, pdev->devfn, PCI_LATENCY_TIMER, 0x80 ); pcibios_write_config_byte(pdev->bus->number, pdev->devfn, PCI_SEC_LATENCY_TIMER, 0x80 ); { struct _addr_start addrhold; unsigned8 base8, limit8; unsigned16 base16, limit16, ubase16, ulimit16; /* save the base address values */ memcpy( &addrhold, &astart, sizeof(struct _addr_start)); recursive_bus_reconfigure( childbus );#ifdef PCI_DEBUG printk("pci: configuring bus %d bridge (%04x:%04x), bus %d : (%d-%d)\n", pdev->bus->number, pdev->vendor, pdev->device, childbus->primary, childbus->secondary, childbus->subordinate );#endif /* ** use the current values & the saved ones to figure out ** the address spaces for the bridge */ if( addrhold.start_pciio == astart.start_pciio ) { base8 = limit8 = 0xff; ubase16 = ulimit16 = 0xffff; } else { base8 = (unsigned8) ((addrhold.start_pciio >> 8) & 0xf0); ubase16 = (unsigned16)(addrhold.start_pciio >> 16); limit8 = (unsigned8) ((astart.start_pciio >> 8 ) & 0xf0); ulimit16 = (unsigned16)(astart.start_pciio >> 16); astart.start_pciio += 0x1000; }#ifdef PCI_DEBUG printk("pci: io base %08x limit %08x\n", (base8<<8)+(ubase16<<16), (limit8<<8)+(ulimit16<<16));#endif#ifdef WRITE_BRIDGE_IO pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_IO_BASE_UPPER16, ubase16 ); pcibios_write_config_byte(pdev->bus->number, pdev->devfn, PCI_IO_BASE, base8 ); pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_IO_LIMIT_UPPER16, ulimit16 ); pcibios_write_config_byte(pdev->bus->number, pdev->devfn, PCI_IO_LIMIT, limit8 );#endif if( addrhold.start_pcimem == astart.start_pcimem ) { limit16 = 0; base16 = 0xffff; } else { limit16= (unsigned16)((astart.start_pcimem >> 16) & 0xfff0); base16 = (unsigned16)((addrhold.start_pcimem >> 16) & 0xfff0); astart.start_pcimem += 0x100000; }#ifdef PCI_DEBUG printk("pci: memory %04x, limit %04x\n", base16, limit16);#endif#ifdef WRITE_BRIDGE_MEM pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_MEMORY_BASE, base16 ); pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_MEMORY_LIMIT, limit16 );#endif if( astart.start_prefetch == addrhold.start_prefetch ) { limit16 = 0; base16 = 0xffff; } else { limit16= (unsigned16)((addrhold.start_prefetch >> 16) & 0xfff0); base16 = (unsigned16)((astart.start_prefetch >> 16) & 0xfff0); astart.start_prefetch -= 0x100000; }#ifdef PCI_DEBUG printk("pci: pf memory %04x, limit %04x\n", base16, limit16);#endif#ifdef WRITE_BRIDGE_PF pcibios_write_config_dword(pdev->bus->number, pdev->devfn, PCI_PREF_BASE_UPPER32, 0); pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_PREF_MEMORY_BASE, base16 ); pcibios_write_config_dword(pdev->bus->number, pdev->devfn, PCI_PREF_LIMIT_UPPER32, 0); pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_PREF_MEMORY_LIMIT, limit16 );#endif#ifdef WRITE_BRIDGE_ENABLE pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_BRIDGE_CONTROL, (unsigned16)( 0 )); pcibios_write_config_word(pdev->bus->number, pdev->devfn, PCI_COMMAND, (unsigned16)( PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER ));#endif } } if( !isroot ) {#ifdef PCI_DEBUG printk("pci: Configuring devices on bus %d\n", pbus->number);#endif /* ** Run thru this bus and set up addresses for all the non-bridge devices */ for( pdev = pbus->devices; pdev; pdev= pdev->sibling ) { if( (pdev->class >> 8) != PCI_CLASS_BRIDGE_PCI ) { pci_resource *r; int i = 0; unsigned alloc; /* enumerate all the resources defined by this device & reserve space ** for each of their defined regions. */#ifdef PCI_DEBUG printk("pci: configuring; vendor %04x, device %04x\n", pdev->vendor, pdev->device );#endif while( (r= enum_device_resources( pdev, i++ )) ) { /* ** Force all memory spaces to be non-prefetchable because ** on the pci bus, byte-wise reads against prefetchable ** memory are applied as 32 bit reads, which is a pain ** when you're trying to talk to hardware. This is a ** little sub-optimal because the algorithm doesn't sort ** the address regions to pack them in, OTOH, perhaps its ** not so bad because the inefficient packing will help ** avoid buffer overflow/underflow problems. */#if 0 if( (r->type & PCI_BASE_ADDRESS_MEM_PREFETCH) ) { /* prefetchable space */ /* shift base pointer down to an integer multiple of the size of the desired region */ astart.start_prefetch -= (alloc= ((r->size / PAGE_SIZE) + 1) * PAGE_SIZE); /* shift base pointer down to an integer multiple of the size of the desired region */ astart.start_prefetch = (astart.start_prefetch / r->size) * r->size; r->base = astart.start_prefetch;#ifdef PCI_DEBUG printk("pci: pf %08X, size %08X, alloc %08X\n", r->base, r->size, alloc );#endif }#endif if( r->type & PCI_BASE_ADDRESS_SPACE_IO ) { /* io space */ /* shift base pointer up to an integer multiple of the size of the desired region */ if( astart.start_pciio % r->size ) astart.start_pciio = (((astart.start_pciio / r->size) + 1) * r->size); r->base = astart.start_pciio; astart.start_pciio += (alloc= ((r->size / PAGE_SIZE) + 1) * PAGE_SIZE);#ifdef PCI_DEBUG printk("pci: io %08X, size %08X, alloc %08X\n", r->base, r->size, alloc );#endif } else { /* memory space */ /* shift base pointer up to an integer multiple of the size of the desired region */ if( astart.start_pcimem % r->size ) astart.start_pcimem = (((astart.start_pcimem / r->size) + 1) * r->size); r->base = astart.start_pcimem; astart.start_pcimem += (alloc= ((r->size / PAGE_SIZE) + 1) * PAGE_SIZE);#ifdef PCI_DEBUG printk("pci: mem %08X, size %08X, alloc %08X\n", r->base, r->size, alloc );#endif } } } } }}void pci_init(void) { PPC_DEVICE *hostbridge; if (pci->last_dev_p) { printk("Two or more calls to pci_init!\n"); return; } pci->last_dev_p = &(bd->pci_devices); hostbridge=residual_find_device(PROCESSORDEVICE, NULL, BridgeController, PCIBridge, -1, 0); if (hostbridge) { if (hostbridge->DeviceId.Interface==PCIBridgeIndirect) { bd->pci_functions=&indirect_functions; /* Should be extracted from residual data, * indeed MPC106 in CHRP mode is different, * but we should not use residual data in * this case anyway. */ pci->config_addr = ((volatile u_int *) (ptr_mem_map->io_base+0xcf8)); pci->config_data = ptr_mem_map->io_base+0xcfc; } else if(hostbridge->DeviceId.Interface==PCIBridgeDirect) { bd->pci_functions=&direct_functions; pci->config_data=(u_char *) 0x80800000; } else { } } else { /* Let us try by experimentation at our own risk! */ u_int id0; bd->pci_functions = &direct_functions; /* On all direct bridges I know the host bridge itself * appears as device 0 function 0. */ pcibios_read_config_dword(0, 0, PCI_VENDOR_ID, &id0); if (id0==~0U) { bd->pci_functions = &indirect_functions; pci->config_addr = ((volatile u_int *) (ptr_mem_map->io_base+0xcf8)); pci->config_data = ptr_mem_map->io_base+0xcfc; } /* Here we should check that the host bridge is actually * present, but if it not, we are in such a desperate * situation, that we probably can't even tell it. */ } /* Now build a small database of all found PCI devices */ printk("\nPCI: Probing PCI hardware\n"); pci_root.subordinate=pci_scan_bus(&pci_root); print_pci_resources("Installed PCI resources:\n"); recursive_bus_reconfigure(NULL); reconfigure_pci(); print_pci_resources("Allocated PCI resources:\n");#if 0 print_pci_info();#endif}/* eof */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -