pci.c
来自「linux2.6.16版本」· C语言 代码 · 共 1,662 行 · 第 1/3 页
C
1,662 行
* or because we have decided the old address was * unusable for some reason. */ if ((r->flags & IORESOURCE_UNSET) && r->end && (!ppc_md.pcibios_enable_device_hook || !ppc_md.pcibios_enable_device_hook(dev, 1))) { r->flags &= ~IORESOURCE_UNSET; pci_assign_resource(dev, idx); } }#if 0 /* don't assign ROMs */ r = &dev->resource[PCI_ROM_RESOURCE]; r->end -= r->start; r->start = 0; if (r->end) pci_assign_resource(dev, PCI_ROM_RESOURCE);#endif }}intpcibios_enable_resources(struct pci_dev *dev, int mask){ u16 cmd, old_cmd; int idx; struct resource *r; pci_read_config_word(dev, PCI_COMMAND, &cmd); old_cmd = cmd; for (idx=0; idx<6; idx++) { /* Only set up the requested stuff */ if (!(mask & (1<<idx))) continue; 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 (dev->resource[PCI_ROM_RESOURCE].start) 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 int next_controller_index;struct pci_controller * __initpcibios_alloc_controller(void){ struct pci_controller *hose; hose = (struct pci_controller *)alloc_bootmem(sizeof(*hose)); memset(hose, 0, sizeof(struct pci_controller)); *hose_tail = hose; hose_tail = &hose->next; hose->index = next_controller_index++; return hose;}#ifdef CONFIG_PPC_OF/* * Functions below are used on OpenFirmware machines. */static voidmake_one_node_map(struct device_node* node, u8 pci_bus){ int *bus_range; int len; if (pci_bus >= pci_bus_count) return; bus_range = (int *) get_property(node, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, " "assuming it starts at 0\n", node->full_name); pci_to_OF_bus_map[pci_bus] = 0; } else pci_to_OF_bus_map[pci_bus] = bus_range[0]; for (node=node->child; node != 0;node = node->sibling) { struct pci_dev* dev; unsigned int *class_code, *reg; class_code = (unsigned int *) get_property(node, "class-code", NULL); if (!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) continue; reg = (unsigned int *)get_property(node, "reg", NULL); if (!reg) continue; dev = pci_find_slot(pci_bus, ((reg[0] >> 8) & 0xff)); if (!dev || !dev->subordinate) continue; make_one_node_map(node, dev->subordinate->number); }} voidpcibios_make_OF_bus_map(void){ int i; struct pci_controller* hose; u8* of_prop_map; pci_to_OF_bus_map = (u8*)kmalloc(pci_bus_count, GFP_KERNEL); if (!pci_to_OF_bus_map) { printk(KERN_ERR "Can't allocate OF bus map !\n"); return; } /* We fill the bus map with invalid values, that helps * debugging. */ for (i=0; i<pci_bus_count; i++) pci_to_OF_bus_map[i] = 0xff; /* For each hose, we begin searching bridges */ for(hose=hose_head; hose; hose=hose->next) { struct device_node* node; node = (struct device_node *)hose->arch_data; if (!node) continue; make_one_node_map(node, hose->first_busno); } of_prop_map = get_property(find_path_device("/"), "pci-OF-bus-map", NULL); if (of_prop_map) memcpy(of_prop_map, pci_to_OF_bus_map, pci_bus_count);#ifdef DEBUG printk("PCI->OF bus map:\n"); for (i=0; i<pci_bus_count; i++) { if (pci_to_OF_bus_map[i] == 0xff) continue; printk("%d -> %d\n", i, pci_to_OF_bus_map[i]); }#endif}typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);static struct device_node*scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data){ struct device_node* sub_node; for (; node != 0;node = node->sibling) { unsigned int *class_code; if (filter(node, data)) return node; /* For PCI<->PCI bridges or CardBus bridges, we go down * Note: some OFs create a parent node "multifunc-device" as * a fake root for all functions of a multi-function device, * we go down them as well. */ class_code = (unsigned int *) get_property(node, "class-code", NULL); if ((!class_code || ((*class_code >> 8) != PCI_CLASS_BRIDGE_PCI && (*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) && strcmp(node->name, "multifunc-device")) continue; sub_node = scan_OF_pci_childs(node->child, filter, data); if (sub_node) return sub_node; } return NULL;}static intscan_OF_pci_childs_iterator(struct device_node* node, void* data){ unsigned int *reg; u8* fdata = (u8*)data; reg = (unsigned int *) get_property(node, "reg", NULL); if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] && ((reg[0] >> 16) & 0xff) == fdata[0]) return 1; return 0;}static struct device_node*scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn){ u8 filter_data[2] = {bus, dev_fn}; return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);}/* * Scans the OF tree for a device node matching a PCI device */struct device_node *pci_busdev_to_OF_node(struct pci_bus *bus, int devfn){ struct pci_controller *hose; struct device_node *node; int busnr; if (!have_of) return NULL; /* Lookup the hose */ busnr = bus->number; hose = pci_bus_to_hose(busnr); if (!hose) return NULL; /* Check it has an OF node associated */ node = (struct device_node *) hose->arch_data; if (!node) return NULL; /* Fixup bus number according to what OF think it is. */ if (pci_to_OF_bus_map) busnr = pci_to_OF_bus_map[busnr]; if (busnr == 0xff) return NULL; /* Now, lookup childs of the hose */ return scan_OF_childs_for_device(node->child, busnr, devfn);}EXPORT_SYMBOL(pci_busdev_to_OF_node);struct device_node*pci_device_to_OF_node(struct pci_dev *dev){ return pci_busdev_to_OF_node(dev->bus, dev->devfn);}EXPORT_SYMBOL(pci_device_to_OF_node);/* This routine is meant to be used early during boot, when the * PCI bus numbers have not yet been assigned, and you need to * issue PCI config cycles to an OF device. * It could also be used to "fix" RTAS config cycles if you want * to set pci_assign_all_buses to 1 and still use RTAS for PCI * config cycles. */struct pci_controller* pci_find_hose_for_OF_device(struct device_node* node){ if (!have_of) return NULL; while(node) { struct pci_controller* hose; for (hose=hose_head;hose;hose=hose->next) if (hose->arch_data == node) return hose; node=node->parent; } return NULL;}static intfind_OF_pci_device_filter(struct device_node* node, void* data){ return ((void *)node == data);}/* * Returns the PCI device matching a given OF node */intpci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn){ unsigned int *reg; struct pci_controller* hose; struct pci_dev* dev = NULL; if (!have_of) return -ENODEV; /* Make sure it's really a PCI device */ hose = pci_find_hose_for_OF_device(node); if (!hose || !hose->arch_data) return -ENODEV; if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child, find_OF_pci_device_filter, (void *)node)) return -ENODEV; reg = (unsigned int *) get_property(node, "reg", NULL); if (!reg) return -ENODEV; *bus = (reg[0] >> 16) & 0xff; *devfn = ((reg[0] >> 8) & 0xff); /* Ok, here we need some tweak. If we have already renumbered * all busses, we can't rely on the OF bus number any more. * the pci_to_OF_bus_map is not enough as several PCI busses * may match the same OF bus number. */ if (!pci_to_OF_bus_map) return 0; for_each_pci_dev(dev) if (pci_to_OF_bus_map[dev->bus->number] == *bus && dev->devfn == *devfn) { *bus = dev->bus->number; pci_dev_put(dev); return 0; } return -ENODEV;}EXPORT_SYMBOL(pci_device_from_OF_node);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) & 0x3) { 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]; DBG("PCI: IO 0x%lx -> 0x%lx\n", res->start, res->start + size - 1); 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; if(ranges[0] & 0x40000000) res->flags |= IORESOURCE_PREFETCH; res->start = ranges[na+2]; DBG("PCI: MEM[%d] 0x%lx -> 0x%lx\n", memno, res->start, res->start + size - 1); } 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, struct device_attribute *attr, 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);#else /* CONFIG_PPC_OF */void pcibios_make_OF_bus_map(void){}#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 */}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_buses) 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_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(); /* 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); 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 + =
减小字号Ctrl + -
显示快捷键?