📄 pci_32.c
字号:
/* Initialize bridges with base/limit values we have collected */static void __initdo_update_p2p_io_resource(struct pci_bus *bus, int enable_vga){ struct pci_dev *bridge = bus->self; struct pci_controller* hose = (struct pci_controller *)bridge->sysdata; u32 l; u16 w; struct resource res; if (bus->resource[0] == NULL) return; res = *(bus->resource[0]); DBG("Remapping Bus %d, bridge: %s\n", bus->number, pci_name(bridge)); res.start -= ((unsigned long) hose->io_base_virt - isa_io_base); res.end -= ((unsigned long) hose->io_base_virt - isa_io_base); DBG(" IO window: %016llx-%016llx\n", res.start, res.end); /* Set up the top and bottom of the PCI I/O segment for this bus. */ pci_read_config_dword(bridge, PCI_IO_BASE, &l); l &= 0xffff000f; l |= (res.start >> 8) & 0x00f0; l |= res.end & 0xf000; pci_write_config_dword(bridge, PCI_IO_BASE, l); if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { l = (res.start >> 16) | (res.end & 0xffff0000); pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l); } pci_read_config_word(bridge, PCI_COMMAND, &w); w |= PCI_COMMAND_IO; pci_write_config_word(bridge, PCI_COMMAND, w);#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */ if (enable_vga) { pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w); w |= PCI_BRIDGE_CTL_VGA; pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w); }#endif}/* This function is pretty basic and actually quite broken for the * general case, it's enough for us right now though. It's supposed * to tell us if we need to open an IO range at all or not and what * size. */static int __initcheck_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga){ struct pci_dev *dev; int i; int rc = 0;#define push_end(res, mask) do { \ BUG_ON((mask+1) & mask); \ res->end = (res->end + mask) | mask; \} while (0) list_for_each_entry(dev, &bus->devices, bus_list) { u16 class = dev->class >> 8; if (class == PCI_CLASS_DISPLAY_VGA || class == PCI_CLASS_NOT_DEFINED_VGA) *found_vga = 1; if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate) rc |= check_for_io_childs(dev->subordinate, res, found_vga); if (class == PCI_CLASS_BRIDGE_CARDBUS) push_end(res, 0xfff); for (i=0; i<PCI_NUM_RESOURCES; i++) { struct resource *r; unsigned long r_size; if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI && i >= PCI_BRIDGE_RESOURCES) continue; r = &dev->resource[i]; r_size = r->end - r->start; if (r_size < 0xfff) r_size = 0xfff; if (r->flags & IORESOURCE_IO && (r_size) != 0) { rc = 1; push_end(res, r_size); } } } return rc;}/* Here we scan all P2P bridges of a given level that have a closed * IO window. Note that the test for the presence of a VGA card should * be improved to take into account already configured P2P bridges, * currently, we don't see them and might end up configuring 2 bridges * with VGA pass through enabled */static void __initdo_fixup_p2p_level(struct pci_bus *bus){ struct pci_bus *b; int i, parent_io; int has_vga = 0; for (parent_io=0; parent_io<4; parent_io++) if (bus->resource[parent_io] && bus->resource[parent_io]->flags & IORESOURCE_IO) break; if (parent_io >= 4) return; list_for_each_entry(b, &bus->children, node) { struct pci_dev *d = b->self; struct pci_controller* hose = (struct pci_controller *)d->sysdata; struct resource *res = b->resource[0]; struct resource tmp_res; unsigned long max; int found_vga = 0; memset(&tmp_res, 0, sizeof(tmp_res)); tmp_res.start = bus->resource[parent_io]->start; /* We don't let low addresses go through that closed P2P bridge, well, * that may not be necessary but I feel safer that way */ if (tmp_res.start == 0) tmp_res.start = 0x1000; if (!list_empty(&b->devices) && res && res->flags == 0 && res != bus->resource[parent_io] && (d->class >> 8) == PCI_CLASS_BRIDGE_PCI && check_for_io_childs(b, &tmp_res, &found_vga)) { u8 io_base_lo; printk(KERN_INFO "Fixing up IO bus %s\n", b->name); if (found_vga) { if (has_vga) { printk(KERN_WARNING "Skipping VGA, already active" " on bus segment\n"); found_vga = 0; } else has_vga = 1; } pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo); if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffffffff; else max = ((unsigned long) hose->io_base_virt - isa_io_base) + 0xffff; *res = tmp_res; res->flags = IORESOURCE_IO; res->name = b->name; /* Find a resource in the parent where we can allocate */ for (i = 0 ; i < 4; i++) { struct resource *r = bus->resource[i]; if (!r) continue; if ((r->flags & IORESOURCE_IO) == 0) continue; DBG("Trying to allocate from %016llx, size %016llx from parent" " res %d: %016llx -> %016llx\n", res->start, res->end, i, r->start, r->end); if (allocate_resource(r, res, res->end + 1, res->start, max, res->end + 1, NULL, NULL) < 0) { DBG("Failed !\n"); continue; } do_update_p2p_io_resource(b, found_vga); break; } } do_fixup_p2p_level(b); }}static voidpcibios_fixup_p2p_bridges(void){ struct pci_bus *b; list_for_each_entry(b, &pci_root_buses, node) do_fixup_p2p_level(b);}#endif /* CONFIG_PPC_PMAC */static int __initpcibios_init(void){ struct pci_controller *hose, *tmp; struct pci_bus *bus; int next_busno = 0; printk(KERN_INFO "PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { if (pci_assign_all_buses) hose->first_busno = next_busno; hose->last_busno = 0xff; bus = pci_scan_bus_parented(hose->parent, hose->first_busno, hose->ops, hose); if (bus) pci_bus_add_devices(bus); hose->last_busno = bus->subordinate; if (pci_assign_all_buses || next_busno <= hose->last_busno) next_busno = hose->last_busno + pcibios_assign_bus_offset; } pci_bus_count = next_busno; /* OpenFirmware based machines need a map of OF bus * numbers vs. kernel bus numbers since we may have to * remap them. */ if (pci_assign_all_buses && have_of) pcibios_make_OF_bus_map(); /* Call machine dependent fixup */ if (ppc_md.pcibios_fixup) ppc_md.pcibios_fixup(); /* Allocate and assign resources */ pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1);#ifdef CONFIG_PPC_PMAC pcibios_fixup_p2p_bridges();#endif /* CONFIG_PPC_PMAC */ pcibios_assign_resources(); /* Call machine dependent post-init code */ if (ppc_md.pcibios_after_init) ppc_md.pcibios_after_init(); return 0;}subsys_initcall(pcibios_init);void pcibios_fixup_bus(struct pci_bus *bus){ struct pci_controller *hose = (struct pci_controller *) bus->sysdata; unsigned long io_offset; struct resource *res; struct pci_dev *dev; int i; io_offset = (unsigned long)hose->io_base_virt - isa_io_base; if (bus->parent == NULL) { /* This is a host bridge - fill in its resources */ hose->bus = bus; bus->resource[0] = res = &hose->io_resource; if (!res->flags) { if (io_offset) printk(KERN_ERR "I/O resource not set for host" " bridge %d\n", hose->global_number); res->start = 0; res->end = IO_SPACE_LIMIT; res->flags = IORESOURCE_IO; } res->start += io_offset; res->end += io_offset; for (i = 0; i < 3; ++i) { res = &hose->mem_resources[i]; if (!res->flags) { if (i > 0) continue; printk(KERN_ERR "Memory resource not set for " "host bridge %d\n", hose->global_number); res->start = hose->pci_mem_offset; res->end = ~0U; res->flags = IORESOURCE_MEM; } bus->resource[i+1] = res; } } else { /* This is a subordinate bridge */ pci_read_bridge_bases(bus); for (i = 0; i < 4; ++i) { if ((res = bus->resource[i]) == NULL) continue; if (!res->flags || bus->self->transparent) continue; if (io_offset && (res->flags & IORESOURCE_IO)) { res->start += io_offset; res->end += io_offset; } else if (hose->pci_mem_offset && (res->flags & IORESOURCE_MEM)) { res->start += hose->pci_mem_offset; res->end += hose->pci_mem_offset; } } } /* Platform specific bus fixups */ if (ppc_md.pcibios_fixup_bus) ppc_md.pcibios_fixup_bus(bus); /* Read default IRQs and fixup if necessary */ list_for_each_entry(dev, &bus->devices, bus_list) { pci_read_irq_line(dev); if (ppc_md.pci_irq_fixup) ppc_md.pci_irq_fixup(dev); }}/* the next one is stolen from the alpha port... */void __initpcibios_update_irq(struct pci_dev *dev, int irq){ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq); /* XXX FIXME - update OF device tree node interrupt property */}int pcibios_enable_device(struct pci_dev *dev, int mask){ u16 cmd, old_cmd; int idx; struct resource *r; if (ppc_md.pcibios_enable_device_hook) if (ppc_md.pcibios_enable_device_hook(dev, 0)) return -EINVAL; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for (idx=0; idx<6; idx++) { r = &dev->resource[idx]; if (r->flags & IORESOURCE_UNSET) { printk(KERN_ERR "PCI: Device %s not available because of resource collisions\n", pci_name(dev)); return -EINVAL; } if (r->flags & IORESOURCE_IO) cmd |= PCI_COMMAND_IO; if (r->flags & IORESOURCE_MEM) cmd |= PCI_COMMAND_MEMORY; } if (cmd != old_cmd) { printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd); } return 0;}static struct pci_controller*pci_bus_to_hose(int bus){ struct pci_controller *hose, *tmp; list_for_each_entry_safe(hose, tmp, &hose_list, list_node) if (bus >= hose->first_busno && bus <= hose->last_busno) return hose; return NULL;}/* Provide information on locations of various I/O regions in physical * memory. Do this on a per-card basis so that we choose the right * root bridge. * Note that the returned IO or memory base is a physical address */long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn){ struct pci_controller* hose; long result = -EOPNOTSUPP; /* Argh ! Please forgive me for that hack, but that's the * simplest way to get existing XFree to not lockup on some * G5 machines... So when something asks for bus 0 io base * (bus 0 is HT root), we return the AGP one instead. */#ifdef CONFIG_PPC_PMAC if (machine_is(powermac) && machine_is_compatible("MacRISC4")) if (bus == 0) bus = 0xf0;#endif /* CONFIG_PPC_PMAC */ hose = pci_bus_to_hose(bus); if (!hose) return -ENODEV; switch (which) { case IOBASE_BRIDGE_NUMBER: return (long)hose->first_busno; case IOBASE_MEMORY: return (long)hose->pci_mem_offset; case IOBASE_IO: return (long)hose->io_base_phys; case IOBASE_ISA_IO: return (long)isa_io_base; case IOBASE_ISA_MEM: return (long)isa_mem_base; } return result;}unsigned long pci_address_to_pio(phys_addr_t address){ struct pci_controller *hose, *tmp; list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { unsigned int size = hose->io_resource.end - hose->io_resource.start + 1; if (address >= hose->io_base_phys && address < (hose->io_base_phys + size)) { unsigned long base = (unsigned long)hose->io_base_virt - _IO_BASE; return base + (address - hose->io_base_phys); } } return (unsigned int)-1;}EXPORT_SYMBOL(pci_address_to_pio);/* * Null PCI config access functions, for the case when we can't * find a hose. */#define NULL_PCI_OP(rw, size, type) \static int \null_##rw##_config_##size(struct pci_dev *dev, int offset, type val) \{ \ return PCIBIOS_DEVICE_NOT_FOUND; \}static intnull_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val){ return PCIBIOS_DEVICE_NOT_FOUND;}static intnull_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val){ return PCIBIOS_DEVICE_NOT_FOUND;}static struct pci_ops null_pci_ops ={ .read = null_read_config, .write = null_write_config,};/* * These functions are used early on before PCI scanning is done * and all of the pci_dev and pci_bus structures have been created. */static struct pci_bus *fake_pci_bus(struct pci_controller *hose, int busnr){ static struct pci_bus bus; if (hose == 0) { hose = pci_bus_to_hose(busnr); if (hose == 0) printk(KERN_ERR "Can't find hose for PCI bus %d!\n", busnr); } bus.number = busnr; bus.sysdata = hose; bus.ops = hose? hose->ops: &null_pci_ops; return &bus;}#define EARLY_PCI_OP(rw, size, type) \int early_##rw##_config_##size(struct pci_controller *hose, int bus, \ int devfn, int offset, type value) \{ \ return pci_bus_##rw##_config_##size(fake_pci_bus(hose, bus), \ devfn, offset, value); \}EARLY_PCI_OP(read, byte, u8 *)EARLY_PCI_OP(read, word, u16 *)EARLY_PCI_OP(read, dword, u32 *)EARLY_PCI_OP(write, byte, u8)EARLY_PCI_OP(write, word, u16)EARLY_PCI_OP(write, dword, u32)extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);int early_find_capability(struct pci_controller *hose, int bus, int devfn, int cap){ return pci_bus_find_capability(fake_pci_bus(hose, bus), devfn, cap);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -