📄 pci.c
字号:
} return -ENODEV;}void __initpci_process_bridge_OF_ranges(struct pci_controller *hose, struct device_node *dev, int primary){ static unsigned int static_lc_ranges[256] __initdata; unsigned int *dt_ranges, *lc_ranges, *ranges, *prev; unsigned int size; int rlen = 0, orig_rlen; int memno = 0; struct resource *res; int np, na = prom_n_addr_cells(dev); np = na + 5; /* First we try to merge ranges to fix a problem with some pmacs * that can have more than 3 ranges, fortunately using contiguous * addresses -- BenH */ dt_ranges = (unsigned int *) get_property(dev, "ranges", &rlen); if (!dt_ranges) return; /* Sanity check, though hopefully that never happens */ if (rlen > sizeof(static_lc_ranges)) { printk(KERN_WARNING "OF ranges property too large !\n"); rlen = sizeof(static_lc_ranges); } lc_ranges = static_lc_ranges; memcpy(lc_ranges, dt_ranges, rlen); orig_rlen = rlen; /* Let's work on a copy of the "ranges" property instead of damaging * the device-tree image in memory */ ranges = lc_ranges; prev = NULL; while ((rlen -= np * sizeof(unsigned int)) >= 0) { if (prev) { if (prev[0] == ranges[0] && prev[1] == ranges[1] && (prev[2] + prev[na+4]) == ranges[2] && (prev[na+2] + prev[na+4]) == ranges[na+2]) { prev[na+4] += ranges[na+4]; ranges[0] = 0; ranges += np; continue; } } prev = ranges; ranges += np; } /* * The ranges property is laid out as an array of elements, * each of which comprises: * cells 0 - 2: a PCI address * cells 3 or 3+4: a CPU physical address * (size depending on dev->n_addr_cells) * cells 4+5 or 5+6: the size of the range */ ranges = lc_ranges; rlen = orig_rlen; while (ranges && (rlen -= np * sizeof(unsigned int)) >= 0) { res = NULL; size = ranges[na+4]; switch (ranges[0] >> 24) { case 1: /* I/O space */ if (ranges[2] != 0) break; hose->io_base_phys = ranges[na+2]; /* limit I/O space to 16MB */ if (size > 0x01000000) size = 0x01000000; hose->io_base_virt = ioremap(ranges[na+2], size); if (primary) isa_io_base = (unsigned long) hose->io_base_virt; res = &hose->io_resource; res->flags = IORESOURCE_IO; res->start = ranges[2]; break; case 2: /* memory space */ memno = 0; if (ranges[1] == 0 && ranges[2] == 0 && ranges[na+4] <= (16 << 20)) { /* 1st 16MB, i.e. ISA memory area */ if (primary) isa_mem_base = ranges[na+2]; memno = 1; } while (memno < 3 && hose->mem_resources[memno].flags) ++memno; if (memno == 0) hose->pci_mem_offset = ranges[na+2] - ranges[2]; if (memno < 3) { res = &hose->mem_resources[memno]; res->flags = IORESOURCE_MEM; res->start = ranges[na+2]; } break; } if (res != NULL) { res->name = dev->full_name; res->end = res->start + size - 1; res->parent = NULL; res->sibling = NULL; res->child = NULL; } ranges += np; }}/* We create the "pci-OF-bus-map" property now so it appears in the * /proc device tree */void __initpci_create_OF_bus_map(void){ struct property* of_prop; of_prop = (struct property*) alloc_bootmem(sizeof(struct property) + 256); if (of_prop && find_path_device("/")) { memset(of_prop, -1, sizeof(struct property) + 256); of_prop->name = "pci-OF-bus-map"; of_prop->length = 256; of_prop->value = (unsigned char *)&of_prop[1]; prom_add_property(find_path_device("/"), of_prop); }}static ssize_t pci_show_devspec(struct device *dev, char *buf){ struct pci_dev *pdev; struct device_node *np; pdev = to_pci_dev (dev); np = pci_device_to_OF_node(pdev); if (np == NULL || np->full_name == NULL) return 0; return sprintf(buf, "%s", np->full_name);}static DEVICE_ATTR(devspec, S_IRUGO, pci_show_devspec, NULL);#endif /* CONFIG_PPC_OF *//* Add sysfs properties */void pcibios_add_platform_entries(struct pci_dev *pdev){#ifdef CONFIG_PPC_OF device_create_file(&pdev->dev, &dev_attr_devspec);#endif /* CONFIG_PPC_OF */}#ifdef CONFIG_PPC_PMAC/* * This set of routines checks for PCI<->PCI bridges that have closed * IO resources and have child devices. It tries to re-open an IO * window on them. * * This is a _temporary_ fix to workaround a problem with Apple's OF * closing IO windows on P2P bridges when the OF drivers of cards * below this bridge don't claim any IO range (typically ATI or * Adaptec). * * A more complete fix would be to use drivers/pci/setup-bus.c, which * involves a working pcibios_fixup_pbus_ranges(), some more care about * ordering when creating the host bus resources, and maybe a few more * minor tweaks *//* 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, bridge->slot_name); 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: %08lx-%08lx\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 list_head *ln; int i; int rc = 0;#define push_end(res, size) do { unsigned long __sz = (size) ; \ res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \ } while (0) for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { struct pci_dev *dev = pci_dev_b(ln); 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 list_head *ln; 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; for (ln=bus->children.next; ln != &bus->children; ln=ln->next) { struct pci_bus *b = pci_bus_b(ln); 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 %08lx, size %08lx from parent" " res %d: %08lx -> %08lx\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 list_head *ln; for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) { struct pci_bus *b = pci_bus_b(ln); do_fixup_p2p_level(b); }}#endif /* CONFIG_PPC_PMAC */static int __initpcibios_init(void){ struct pci_controller *hose; struct pci_bus *bus; int next_busno; printk(KERN_INFO "PCI: Probing PCI hardware\n"); /* Scan all of the recorded PCI controllers. */ for (next_busno = 0, hose = hose_head; hose; hose = hose->next) { if (pci_assign_all_busses) hose->first_busno = next_busno; hose->last_busno = 0xff; bus = pci_scan_bus(hose->first_busno, hose->ops, hose); hose->last_busno = bus->subordinate; if (pci_assign_all_busses || next_busno <= hose->last_busno) next_busno = hose->last_busno+1; } 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_busses && have_of) pcibios_make_OF_bus_map(); /* Do machine dependent PCI interrupt routing */ if (ppc_md.pci_swizzle && ppc_md.pci_map_irq) pci_fixup_irqs(ppc_md.pci_swizzle, ppc_md.pci_map_irq); /* 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);unsigned char __initcommon_swizzle(struct pci_dev *dev, unsigned char *pinp){ struct pci_controller *hose = dev->sysdata; if (dev->bus->number != hose->first_busno) { u8 pin = *pinp; do { pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn)); /* Move up the chain of bridges. */ dev = dev->bus->self; } while (dev->bus->self); *pinp = pin; /* The slot is the idsel of the last bridge. */ } return PCI_SLOT(dev->devfn);}unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, unsigned long start, unsigned long size){ return start;}void __init pcibios_fixup_bus(struct pci_bus *bus)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -