📄 pci.c
字号:
struct pci_dev *dev = bus->self; struct pci_controller *hose = dev->sysdata; if (!hose) { printk("update_bridge_base: no hose?\n"); return; } pci_read_config_word(dev, PCI_COMMAND, &cmd); pci_write_config_word(dev, PCI_COMMAND, cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)); if (res->flags & IORESOURCE_IO) { off = (unsigned long) hose->io_base_virt - isa_io_base; start = res->start - off; end = res->end - off; io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK; io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK; if (end > 0xffff) { pci_write_config_word(dev, PCI_IO_BASE_UPPER16, start >> 16); pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, end >> 16); io_base_lo |= PCI_IO_RANGE_TYPE_32; } else io_base_lo |= PCI_IO_RANGE_TYPE_16; pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo); pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo); } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) == IORESOURCE_MEM) { off = hose->pci_mem_offset; mem_base = ((res->start - off) >> 16) & PCI_MEMORY_RANGE_MASK; mem_limit = ((res->end - off) >> 16) & PCI_MEMORY_RANGE_MASK; pci_write_config_word(dev, PCI_MEMORY_BASE, mem_base); pci_write_config_word(dev, PCI_MEMORY_LIMIT, mem_limit); } else if ((res->flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH)) == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) { off = hose->pci_mem_offset; mem_base = ((res->start - off) >> 16) & PCI_PREF_RANGE_MASK; mem_limit = ((res->end - off) >> 16) & PCI_PREF_RANGE_MASK; pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, mem_base); pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, mem_limit); } else { DBG(KERN_ERR "PCI: ugh, bridge %s res %d has flags=%lx\n", pci_name(dev), i, res->flags); } pci_write_config_word(dev, PCI_COMMAND, cmd);}static inline void alloc_resource(struct pci_dev *dev, int idx){ struct resource *pr, *r = &dev->resource[idx]; DBG("PCI:%s: Resource %d: %08lx-%08lx (f=%lx)\n", pci_name(dev), idx, r->start, r->end, r->flags); pr = pci_find_parent_resource(dev, r); if (!pr || request_resource(pr, r) < 0) { printk(KERN_ERR "PCI: Cannot allocate resource region %d" " of device %s\n", idx, pci_name(dev)); if (pr) DBG("PCI: parent is %p: %08lx-%08lx (f=%lx)\n", pr, pr->start, pr->end, pr->flags); /* We'll assign a new address later */ r->flags |= IORESOURCE_UNSET; r->end -= r->start; r->start = 0; }}static void __initpcibios_allocate_resources(int pass){ struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; if (r->parent) /* Already allocated */ continue; if (!r->flags || (r->flags & IORESOURCE_UNSET)) continue; /* Not assigned at all */ if (r->flags & IORESOURCE_IO) disabled = !(command & PCI_COMMAND_IO); else disabled = !(command & PCI_COMMAND_MEMORY); if (pass == disabled) alloc_resource(dev, idx); } if (pass) continue; r = &dev->resource[PCI_ROM_RESOURCE]; if (r->flags & PCI_ROM_ADDRESS_ENABLE) { /* Turn the ROM off, leave the resource region, but keep it unregistered. */ u32 reg; DBG("PCI: Switching off ROM of %s\n", pci_name(dev)); r->flags &= ~PCI_ROM_ADDRESS_ENABLE; pci_read_config_dword(dev, dev->rom_base_reg, ®); pci_write_config_dword(dev, dev->rom_base_reg, reg & ~PCI_ROM_ADDRESS_ENABLE); } }}static void __initpcibios_assign_resources(void){ struct pci_dev *dev = NULL; int idx; struct resource *r; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ if (!class || class == PCI_CLASS_BRIDGE_HOST) continue; for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; /* * We shall assign a new address to this resource, * either because the BIOS (sic) forgot to do so * 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 void __openfirmwaremake_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); }} void __openfirmwarepcibios_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* __openfirmwarescan_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* __openfirmwarescan_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. */#ifdef CONFIG_PPC_PMAC /* The G5 need a special case here. Basically, we don't remap all * busses on it so we don't create the pci-OF-map. However, we do * remap the AGP bus and so have to deal with it. A future better * fix has to be done by making the remapping per-host and always * filling the pci_to_OF map. --BenH */ if (_machine == _MACH_Pmac && busnr >= 0xf0) busnr -= 0xf0; else#endif 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);}struct device_node*pci_device_to_OF_node(struct pci_dev *dev){ return pci_busdev_to_OF_node(dev->bus, dev->devfn);}/* 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_busses 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 int __openfirmwarefind_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; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_to_OF_bus_map[dev->bus->number] != *bus) continue; if (dev->devfn != *devfn) continue; *bus = dev->bus->number; return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -