pseries_pci.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 800 行 · 第 1/2 页
C
800 行
struct reg_property64 reg_struct; int *bus_range; char *model; enum phb_types phb_type; struct property *of_prop; model = (char *)get_property(dev, "model", NULL); if (!model) { printk(KERN_ERR "alloc_phb: phb has no model property\n"); model = "<empty>"; } /* Found a PHB, now figure out where his registers are mapped. */ ui_ptr = (unsigned int *) get_property(dev, "reg", &len); if (ui_ptr == NULL) { PPCDBG(PPCDBG_PHBINIT, "\tget reg failed.\n"); return NULL; } if (addr_size_words == 1) { reg_struct.address = ((struct reg_property32 *)ui_ptr)->address; reg_struct.size = ((struct reg_property32 *)ui_ptr)->size; } else { reg_struct = *((struct reg_property64 *)ui_ptr); } if (strstr(model, "Python")) { phb_type = phb_type_python; } else if (strstr(model, "Speedwagon")) { phb_type = phb_type_speedwagon; } else if (strstr(model, "Winnipeg")) { phb_type = phb_type_winnipeg; } else { printk(KERN_ERR "alloc_phb: unknown PHB %s\n", model); phb_type = phb_type_unknown; } phb = pci_alloc_pci_controller(phb_type); if (phb == NULL) return NULL; if (phb_type == phb_type_python) python_countermeasures(reg_struct.address); bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { kfree(phb); return NULL; } of_prop = (struct property *)alloc_bootmem(sizeof(struct property) + sizeof(phb->global_number)); if (!of_prop) { kfree(phb); return NULL; } memset(of_prop, 0, sizeof(struct property)); of_prop->name = "linux,pci-domain"; of_prop->length = sizeof(phb->global_number); of_prop->value = (unsigned char *)&of_prop[1]; memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); prom_add_property(dev, of_prop); phb->first_busno = bus_range[0]; phb->last_busno = bus_range[1]; phb->arch_data = dev; phb->ops = &rtas_pci_ops; phb->buid = get_phb_buid(dev); return phb;}unsigned long __init find_and_init_phbs(void){ struct device_node *node; struct pci_controller *phb; unsigned int root_size_cells = 0; unsigned int index; unsigned int *opprop; struct device_node *root = of_find_node_by_path("/"); if (naca->interrupt_controller == IC_OPEN_PIC) { opprop = (unsigned int *)get_property(root, "platform-open-pic", NULL); } root_size_cells = prom_n_size_cells(root); index = 0; for (node = of_get_next_child(root, NULL); node != NULL; node = of_get_next_child(root, node)) { if (node->type == NULL || strcmp(node->type, "pci") != 0) continue; phb = alloc_phb(node, root_size_cells); if (!phb) continue; pci_process_bridge_OF_ranges(phb, node, index == 0); if (naca->interrupt_controller == IC_OPEN_PIC) { int addr = root_size_cells * (index + 2) - 1; openpic_setup_ISU(index, opprop[addr]); } index++; } of_node_put(root); pci_devs_phb_init(); return 0;}void pcibios_name_device(struct pci_dev *dev){#if 0 struct device_node *dn; /* * Add IBM loc code (slot) as a prefix to the device names for service */ dn = pci_device_to_OF_node(dev); if (dn) { char *loc_code = get_property(dn, "ibm,loc-code", 0); if (loc_code) { int loc_len = strlen(loc_code); if (loc_len < sizeof(dev->dev.name)) { memmove(dev->dev.name+loc_len+1, dev->dev.name, sizeof(dev->dev.name)-loc_len-1); memcpy(dev->dev.name, loc_code, loc_len); dev->dev.name[loc_len] = ' '; dev->dev.name[sizeof(dev->dev.name)-1] = '\0'; } } }#endif} void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus){ /* Update device resources. */ struct pci_controller *hose = PCI_GET_PHB_PTR(bus); int i; for (i = 0; i < PCI_NUM_RESOURCES; i++) { if (dev->resource[i].flags & IORESOURCE_IO) { unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; unsigned long start, end, mask; start = dev->resource[i].start += offset; end = dev->resource[i].end += offset; /* Need to allow IO access to pages that are in the ISA range */ if (start < MAX_ISA_PORT) { if (end > MAX_ISA_PORT) end = MAX_ISA_PORT; start >>= PAGE_SHIFT; end >>= PAGE_SHIFT; /* get the range of pages for the map */ mask = ((1 << (end+1))-1) ^ ((1 << start)-1); io_page_mask |= mask; } } else if (dev->resource[i].flags & IORESOURCE_MEM) { dev->resource[i].start += hose->pci_mem_offset; dev->resource[i].end += hose->pci_mem_offset; } }}EXPORT_SYMBOL(pcibios_fixup_device_resources);void __devinit pcibios_fixup_bus(struct pci_bus *bus){ struct pci_controller *hose = PCI_GET_PHB_PTR(bus); struct list_head *ln; /* XXX or bus->parent? */ struct pci_dev *dev = bus->self; struct resource *res; int i; if (!dev) { /* Root bus. */ hose->bus = bus; bus->resource[0] = res = &hose->io_resource; if (!res->flags) BUG(); /* No I/O resource for this PHB? */ if (request_resource(&ioport_resource, res)) printk(KERN_ERR "Failed to request IO on " "PCI domain %d\n", pci_domain_nr(bus)); for (i = 0; i < 3; ++i) { res = &hose->mem_resources[i]; if (!res->flags && i == 0) BUG(); /* No memory resource for this PHB? */ bus->resource[i+1] = res; if (res->flags && request_resource(&iomem_resource, res)) printk(KERN_ERR "Failed to request MEM on " "PCI domain %d\n", pci_domain_nr(bus)); } } else if (pci_probe_only && (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { /* This is a subordinate bridge */ pci_read_bridge_bases(bus); pcibios_fixup_device_resources(dev, bus); } /* XXX Need to check why Alpha doesnt do this - Anton */ if (!pci_probe_only) return; for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) { struct pci_dev *dev = pci_dev_b(ln); if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) pcibios_fixup_device_resources(dev, bus); }}EXPORT_SYMBOL(pcibios_fixup_bus);static void check_s7a(void){ struct device_node *root; char *model; root = of_find_node_by_path("/"); if (root) { model = get_property(root, "model", NULL); if (model && !strcmp(model, "IBM,7013-S7A")) s7a_workaround = 1; of_node_put(root); }}static int get_bus_io_range(struct pci_bus *bus, unsigned long *start_phys, unsigned long *start_virt, unsigned long *size){ struct pci_controller *hose = PCI_GET_PHB_PTR(bus); struct pci_bus_region region; struct resource *res; if (bus->self) { res = bus->resource[0]; pcibios_resource_to_bus(bus->self, ®ion, res); *start_phys = hose->io_base_phys + region.start; *start_virt = (unsigned long) hose->io_base_virt + region.start; if (region.end > region.start) *size = region.end - region.start + 1; else { printk("%s(): unexpected region 0x%lx->0x%lx\n", __FUNCTION__, region.start, region.end); return 1; } } else { /* Root Bus */ res = &hose->io_resource; *start_phys = hose->io_base_phys; *start_virt = (unsigned long) hose->io_base_virt; if (res->end > res->start) *size = res->end - res->start + 1; else { printk("%s(): unexpected region 0x%lx->0x%lx\n", __FUNCTION__, res->start, res->end); return 1; } } return 0;}int unmap_bus_range(struct pci_bus *bus){ unsigned long start_phys; unsigned long start_virt; unsigned long size; if (!bus) { printk(KERN_ERR "%s() expected bus\n", __FUNCTION__); return 1; } if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) return 1; if (iounmap_explicit((void *) start_virt, size)) return 1; return 0;}EXPORT_SYMBOL(unmap_bus_range);int remap_bus_range(struct pci_bus *bus){ unsigned long start_phys; unsigned long start_virt; unsigned long size; if (!bus) { printk(KERN_ERR "%s() expected bus\n", __FUNCTION__); return 1; } if (get_bus_io_range(bus, &start_phys, &start_virt, &size)) return 1; if (__ioremap_explicit(start_phys, start_virt, size, _PAGE_NO_CACHE)) return 1; return 0;}EXPORT_SYMBOL(remap_bus_range);static void phbs_fixup_io(void){ struct pci_controller *hose; for (hose=hose_head;hose;hose=hose->next) remap_bus_range(hose->bus);}extern void chrp_request_regions(void);void __init pSeries_final_fixup(void){ struct pci_dev *dev = NULL; check_s7a(); while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) pci_read_irq_line(dev); phbs_fixup_io(); chrp_request_regions(); pci_fix_bus_sysdata(); if (!ppc64_iommu_off) iommu_setup_pSeries();}/*********************************************************************** * pci_find_hose_for_OF_device * * This function finds the PHB that matching device_node in the * OpenFirmware by scanning all the pci_controllers. * ***********************************************************************/struct pci_controller*pci_find_hose_for_OF_device(struct device_node *node){ 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;}/* * ppc64 can have multifunction devices that do not respond to function 0. * In this case we must scan all functions. */intpcibios_scan_all_fns(struct pci_bus *bus, int devfn){ struct device_node *busdn, *dn; if (bus->self) busdn = pci_device_to_OF_node(bus->self); else busdn = bus->sysdata; /* must be a phb */ /* * Check to see if there is any of the 8 functions are in the * device tree. If they are then we need to scan all the * functions of this slot. */ for (dn = busdn->child; dn; dn = dn->sibling) if ((dn->devfn >> 3) == (devfn >> 3)) return 1; return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?