📄 pseries_pci.c
字号:
res->end = range.parent_addr + range.size - 1;#endif res->parent = NULL; res->sibling = NULL; res->child = NULL; } break; } } PPCDBG(PPCDBG_PHBINIT, "\tphb->io_base_phys = 0x%lx\n", phb->io_base_phys); PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%lx\n", phb->pci_mem_offset); if (naca->interrupt_controller == IC_OPEN_PIC) { int addr = root_addr_size_words * (index + 2) - 1; openpic_setup_ISU(index, opprop[addr]); } index++; } pci_devs_phb_init(); return 0; /*Success */}/****************************************************************** * * Allocate and partially initialize a structure to represent a PHB. * ******************************************************************/struct pci_controller *alloc_phb(struct device_node *dev, char *model, unsigned int addr_size_words){ struct pci_controller *phb; unsigned int *ui_ptr = NULL, len; struct reg_property64 reg_struct; int *bus_range; int *buid_vals; PPCDBG(PPCDBG_PHBINIT, "alloc_phb: %s\n", dev->full_name); PPCDBG(PPCDBG_PHBINIT, "\tdev = 0x%lx\n", dev); PPCDBG(PPCDBG_PHBINIT, "\tmodel = 0x%lx\n", model); PPCDBG(PPCDBG_PHBINIT, "\taddr_size_words = 0x%lx\n", addr_size_words); /* 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); } PPCDBG(PPCDBG_PHBINIT, "\treg_struct.address = 0x%lx\n", reg_struct.address); PPCDBG(PPCDBG_PHBINIT, "\treg_struct.size = 0x%lx\n", reg_struct.size); /*************************************************************** * Set chip specific data in the phb, including types & * register pointers. ***************************************************************/ /**************************************************************** * Python ***************************************************************/ if (strstr(model, "Python")) { PPCDBG(PPCDBG_PHBINIT, "\tCreate python\n"); phb = pci_alloc_pci_controller("PHB PY",phb_type_python); if (phb == NULL) return NULL; phb->cfg_addr = (volatile unsigned long *) ioremap(reg_struct.address + 0xf8000, PAGE_SIZE); PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_r = 0x%lx\n", reg_struct.address + 0xf8000); PPCDBG(PPCDBG_PHBINIT, "\tcfg_addr_v = 0x%lx\n", phb->cfg_addr); phb->cfg_data = (char*)(phb->cfg_addr + 0x02); phb->phb_regs = (volatile unsigned long *) ioremap(reg_struct.address + 0xf7000, PAGE_SIZE); /* Python's register file is 1 MB in size. */ phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); /* * Firmware doesnt always clear this bit which is critical * for good performance - Anton */ { volatile u32 *tmp, i;#define PRG_CL_RESET_VALID 0x00010000 tmp = (u32 *)((unsigned long)phb->chip_regs + 0xf6030); if (*tmp & PRG_CL_RESET_VALID) { printk("Python workaround: "); *tmp &= ~PRG_CL_RESET_VALID; /* * We must read it back for changes to * take effect */ i = *tmp; printk("reg0: %x\n", i); } } /*************************************************************** * Speedwagon ***************************************************************/ } else if (strstr(model, "Speedwagon")) { PPCDBG(PPCDBG_PHBINIT, "\tCreate speedwagon\n"); phb = pci_alloc_pci_controller("PHB SW",phb_type_speedwagon); if (phb == NULL) return NULL; if (_machine == _MACH_pSeries) { phb->cfg_addr = (volatile unsigned long *) ioremap(reg_struct.address + 0x140, PAGE_SIZE); phb->cfg_data = (char*)(phb->cfg_addr - 0x02); /* minus is correct */ phb->phb_regs = (volatile unsigned long *) ioremap(reg_struct.address, PAGE_SIZE); /* Speedwagon's register file is 1 MB in size. */ phb->chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); PPCDBG(PPCDBG_PHBINIT, "\tmapping chip_regs from 0x%lx -> 0x%lx\n", reg_struct.address & 0xfffff, phb->chip_regs); } else { phb->cfg_addr = NULL; phb->cfg_data = NULL; phb->phb_regs = NULL; phb->chip_regs = NULL; } phb->local_number = ((reg_struct.address >> 12) & 0xf) - 0x8; /*************************************************************** * Trying to build a known just gets the code in trouble. ***************************************************************/ } else { PPCDBG(PPCDBG_PHBINIT, "\tUnknown PHB Type!\n"); printk("PCI: Unknown Phb Type!\n"); return NULL; } bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { PPCDBG(PPCDBG_PHBINIT, "Can't get bus-range for %s\n", dev->full_name); kfree(phb); return(NULL); } /*************************************************************** * Finished with the initialization ***************************************************************/ phb->first_busno = bus_range[0]; phb->last_busno = bus_range[1]; phb->arch_data = dev; phb->ops = &rtas_pci_ops; buid_vals = (int *) get_property(dev, "ibm,fw-phb-id", &len); if (buid_vals == NULL || len < 2 * sizeof(int)) { phb->buid = 0; } else { /* Big bus system. These systems start new bus numbers under * each phb. Until pci domains are standard, we depend on a * patch which makes bus numbers ints and we shift the phb * number into the upper bits. */ struct pci_bus check; if (sizeof(check.number) == 1 || sizeof(check.primary) == 1 || sizeof(check.secondary) == 1 || sizeof(check.subordinate) == 1) { udbg_printf("pSeries_pci: this system has large bus numbers and the kernel was not\n" "built with the patch that fixes include/linux/pci.h struct pci_bus so\n" "number, primary, secondary and subordinate are ints.\n"); panic("pSeries_pci: this system has large bus numbers and the kernel was not\n" "built with the patch that fixes include/linux/pci.h struct pci_bus so\n" "number, primary, secondary and subordinate are ints.\n"); } phb->buid = (((unsigned long)buid_vals[0]) << 32UL) | (((unsigned long)buid_vals[1]) & 0xffffffff); phb->first_busno += (phb->global_number << 8); phb->last_busno += (phb->global_number << 8); } /* Dump PHB information for Debug */ PPCDBGCALL(PPCDBG_PHBINIT,dumpPci_Controller(phb) ); return phb;}void fixup_resources(struct pci_dev *dev){ int i; struct pci_controller *phb = PCI_GET_PHB_PTR(dev);#ifdef CONFIG_PPC_EEH struct device_node *dn; unsigned long eeh_disable_bit; /* 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->name)) { memmove(dev->name+loc_len+1, dev->name, sizeof(dev->name)-loc_len-1); memcpy(dev->name, loc_code, loc_len); dev->name[loc_len] = ' '; dev->name[sizeof(dev->name)-1] = '\0'; } } } if (is_eeh_configured(dev)) { eeh_disable_bit = 0; printk("PCI: eeh configured for %s %s\n", dev->slot_name, dev->name); if (eeh_set_option(dev, EEH_ENABLE) != 0) { printk("PCI: failed to enable eeh for %s %s\n", dev->slot_name, dev->name); eeh_disable_bit = EEH_TOKEN_DISABLED; } } else { /* Assume device is by default EEH_DISABLE'd */ printk("PCI: eeh NOT configured for %s %s\n", dev->slot_name, dev->name); eeh_disable_bit = EEH_TOKEN_DISABLED; }#endif PPCDBG(PPCDBG_PHBINIT, "fixup_resources:\n"); PPCDBG(PPCDBG_PHBINIT, "\tphb = 0x%016LX\n", phb); PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_io_offset = 0x%016LX\n", phb->pci_io_offset); PPCDBG(PPCDBG_PHBINIT, "\tphb->pci_mem_offset = 0x%016LX\n", phb->pci_mem_offset); PPCDBG(PPCDBG_PHBINIT, "\tdev->name = %s\n", dev->name); PPCDBG(PPCDBG_PHBINIT, "\tdev->vendor:device = 0x%04X : 0x%04X\n", dev->vendor, dev->device); if (phb == NULL) return; for (i = 0; i < DEVICE_COUNT_RESOURCE; ++i) { PPCDBG(PPCDBG_PHBINIT, "\tdevice %x.%x[%d] (flags %x) [%lx..%lx]\n", dev->bus->number, dev->devfn, i, dev->resource[i].flags, dev->resource[i].start, dev->resource[i].end); if ((dev->resource[i].start == 0) && (dev->resource[i].end == 0)) { continue; } if (dev->resource[i].flags & IORESOURCE_IO) {#ifdef CONFIG_PPC_EEH unsigned int busno = dev->bus ? dev->bus->number : 0; unsigned long size = dev->resource[i].end - dev->resource[i].start; unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->io_base_phys, size, _PAGE_NO_CACHE); if (!addr) panic("fixup_resources: ioremap failed!\n"); dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit; dev->resource[i].end = dev->resource[i].start + size;#else unsigned long offset = (unsigned long)phb->io_base_virt; dev->resource[i].start += offset; dev->resource[i].end += offset;#endif PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx .. %lx]\n", dev->resource[i].start, dev->resource[i].end); } else if (dev->resource[i].flags & IORESOURCE_MEM) { if (dev->resource[i].start == 0) { /* Bogus. Probably an unused bridge. */ dev->resource[i].end = 0; } else {#ifdef CONFIG_PPC_EEH unsigned int busno = dev->bus ? dev->bus->number : 0; unsigned long size = dev->resource[i].end - dev->resource[i].start; unsigned long addr = (unsigned long)__ioremap(dev->resource[i].start + phb->pci_mem_offset, size, _PAGE_NO_CACHE); if (!addr) panic("fixup_resources: ioremap failed!\n"); dev->resource[i].start = eeh_token(phb->global_number, busno, dev->devfn, addr) | eeh_disable_bit; dev->resource[i].end = dev->resource[i].start + size;#else dev->resource[i].start += phb->pci_mem_offset; dev->resource[i].end += phb->pci_mem_offset;#endif } PPCDBG(PPCDBG_PHBINIT, "\t\t-> now [%lx..%lx]\n", dev->resource[i].start, dev->resource[i].end); } else { continue; } /* zap the 2nd function of the winbond chip */ if (dev->resource[i].flags & IORESOURCE_IO && dev->bus->number == 0 && dev->devfn == 0x81) dev->resource[i].flags &= ~IORESOURCE_IO; }} static void check_s7a(void){ struct device_node *root; char *model; root = find_path_device("/"); if (root) { model = get_property(root, "model", NULL); if (model && !strcmp(model, "IBM,7013-S7A")) s7a_workaround = 1; }}void __initpSeries_pcibios_fixup(void){ struct pci_dev *dev; PPCDBG(PPCDBG_PHBINIT, "pSeries_pcibios_fixup: start\n"); pci_assign_all_busses = 0; check_s7a(); pci_for_each_dev(dev) { pci_read_irq_line(dev); PPCDBGCALL(PPCDBG_PHBINIT, dumpPci_Dev(dev) ); } if (naca->interrupt_controller == IC_PPC_XIC) { xics_isa_init(); }}/*********************************************************************** * 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_pcibios_init * * Chance to initialize and structures or variable before PCI Bus walk. * ***********************************************************************/void pSeries_pcibios_init(void){ PPCDBG(PPCDBG_PHBINIT, "\tppc64_pcibios_init Entry.\n"); if (get_property(find_path_device("/rtas"),"ibm,fw-phb-id",NULL) != NULL) { PPCDBG(PPCDBG_PHBINIT, "\tFound: ibm,fw-phb-id\n"); Pci_Large_Bus_System = 1; }}/* * This is called very early before the page table is setup. */void pSeries_pcibios_init_early(void){ ppc_md.pcibios_read_config_byte = rtas_read_config_byte; ppc_md.pcibios_read_config_word = rtas_read_config_word; ppc_md.pcibios_read_config_dword = rtas_read_config_dword; ppc_md.pcibios_write_config_byte = rtas_write_config_byte; ppc_md.pcibios_write_config_word = rtas_write_config_word; ppc_md.pcibios_write_config_dword = rtas_write_config_dword;}/************************************************************************//* Get a char* of the device physical location(U0.3-P1-I8) *//* See the Product Topology in the RS/6000 Architecture. *//************************************************************************/int device_Location(struct pci_dev *PciDev, char *BufPtr){ struct device_node *DevNode = (struct device_node *)PciDev->sysdata; return sprintf(BufPtr,"PCI: Bus%3d, Device%3d, Vendor %04X, Location %-12s", PciDev->bus->number, PCI_SLOT(PciDev->devfn), PciDev->vendor, (char*)get_property(DevNode,"ibm,loc-code",0));}/************************************************************************//* Set the slot reset line to the state passed in. *//* This is the platform specific for code for the pci_reset_device *//* function. *//************************************************************************/int pci_set_reset(struct pci_dev *PciDev, int state){ return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -