📄 pmac_pci.c
字号:
hose->first_busno = 0xf0; hose->last_busno = 0xff; has_uninorth = 1; hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); u3_agp = hose;}static void __init setup_u3_ht(struct pci_controller* hose){ struct device_node *np = (struct device_node *)hose->arch_data; int i, cur; hose->ops = &u3_ht_pci_ops; /* We hard code the address because of the different size of * the reg address cell, we shall fix that by killing struct * reg_property and using some accessor functions instead */ hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000); /* * /ht node doesn't expose a "ranges" property, so we "remove" regions that * have been allocated to AGP. So far, this version of the code doesn't assign * any of the 0xfxxxxxxx "fine" memory regions to /ht. * We need to fix that sooner or later by either parsing all child "ranges" * properties or figuring out the U3 address space decoding logic and * then read it's configuration register (if any). */ hose->io_base_phys = 0xf4000000 + 0x00400000; hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); isa_io_base = pci_io_base = (unsigned long) hose->io_base_virt; hose->io_resource.name = np->full_name; hose->io_resource.start = 0; hose->io_resource.end = 0x003fffff; hose->io_resource.flags = IORESOURCE_IO; hose->pci_mem_offset = 0; hose->first_busno = 0; hose->last_busno = 0xef; hose->mem_resources[0].name = np->full_name; hose->mem_resources[0].start = 0x80000000; hose->mem_resources[0].end = 0xefffffff; hose->mem_resources[0].flags = IORESOURCE_MEM; if (u3_agp == NULL) { DBG("U3 has no AGP, using full resource range\n"); return; } /* We "remove" the AGP resources from the resources allocated to HT, that * is we create "holes". However, that code does assumptions that so far * happen to be true (cross fingers...), typically that resources in the * AGP node are properly ordered */ cur = 0; for (i=0; i<3; i++) { struct resource *res = &u3_agp->mem_resources[i]; if (res->flags != IORESOURCE_MEM) continue; /* We don't care about "fine" resources */ if (res->start >= 0xf0000000) continue; /* Check if it's just a matter of "shrinking" us in one direction */ if (hose->mem_resources[cur].start == res->start) { DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", cur, hose->mem_resources[cur].start, res->end + 1); hose->mem_resources[cur].start = res->end + 1; continue; } if (hose->mem_resources[cur].end == res->end) { DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", cur, hose->mem_resources[cur].end, res->start - 1); hose->mem_resources[cur].end = res->start - 1; continue; } /* No, it's not the case, we need a hole */ if (cur == 2) { /* not enough resources for a hole, we drop part of the range */ printk(KERN_WARNING "Running out of resources for /ht host !\n"); hose->mem_resources[cur].end = res->start - 1; continue; } cur++; DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", cur-1, res->start - 1, cur, res->end + 1); hose->mem_resources[cur].name = np->full_name; hose->mem_resources[cur].flags = IORESOURCE_MEM; hose->mem_resources[cur].start = res->end + 1; hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; hose->mem_resources[cur-1].end = res->start - 1; }}static void __init pmac_process_bridge_OF_ranges(struct pci_controller *hose, struct device_node *dev, int primary){ static unsigned int static_lc_ranges[2024]; 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; /* lc_ranges = (unsigned int *) alloc_bootmem(rlen);*/ lc_ranges = static_lc_ranges; if (!lc_ranges) return; /* what can we do here ? */ 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 0 if (primary) isa_mem_base = ranges[na+2];#endif 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 assume that if we have a G3 powermac, we have one bridge called * "pci" (a MPC106) and no bandit or chaos bridges, and contrariwise, * if we have one or more bandit or chaos bridges, we don't have a MPC106. */static int __init add_bridge(struct device_node *dev){ int len; struct pci_controller *hose; char* disp_name; int *bus_range; int primary = 1; struct property *of_prop; DBG("Adding PCI host bridge %s\n", dev->full_name); bus_range = (int *) get_property(dev, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING "Can't get bus-range for %s, assume bus 0\n", dev->full_name); } hose = pci_alloc_pci_controller(phb_type_apple); if (!hose) return -ENOMEM; hose->arch_data = dev; hose->first_busno = bus_range ? bus_range[0] : 0; hose->last_busno = bus_range ? bus_range[1] : 0xff; of_prop = (struct property *)alloc_bootmem(sizeof(struct property) + sizeof(hose->global_number)); if (of_prop) { memset(of_prop, 0, sizeof(struct property)); of_prop->name = "linux,pci-domain"; of_prop->length = sizeof(hose->global_number); of_prop->value = (unsigned char *)&of_prop[1]; memcpy(of_prop->value, &hose->global_number, sizeof(hose->global_number)); prom_add_property(dev, of_prop); } disp_name = NULL; if (device_is_compatible(dev, "u3-agp")) { setup_u3_agp(hose); disp_name = "U3-AGP"; primary = 0; } else if (device_is_compatible(dev, "u3-ht")) { setup_u3_ht(hose); disp_name = "U3-HT"; primary = 1; } printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n", disp_name, hose->first_busno, hose->last_busno); /* Interpret the "ranges" property */ /* This also maps the I/O region and sets isa_io/mem_base */ pmac_process_bridge_OF_ranges(hose, dev, primary); /* Fixup "bus-range" OF property */ fixup_bus_range(dev); return 0;}void __init pmac_pcibios_fixup(void){ struct pci_dev *dev = NULL; while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) pci_read_irq_line(dev); pci_fix_bus_sysdata();#ifdef CONFIG_PMAC_DART iommu_setup_pmac();#endif /* CONFIG_PMAC_DART */}static void __init pmac_fixup_phb_resources(void){ struct pci_controller *hose; for (hose = hose_head; hose; hose = hose->next) { unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; hose->io_resource.start += offset; hose->io_resource.end += offset; printk(KERN_INFO "PCI Host %d, io start: %lx; io end: %lx\n", hose->global_number, hose->io_resource.start, hose->io_resource.end); }}void __init pmac_pci_init(void){ struct device_node *np, *root; struct device_node *ht = NULL; /* Probe root PCI hosts, that is on U3 the AGP host and the * HyperTransport host. That one is actually "kept" around * and actually added last as it's resource management relies * on the AGP resources to have been setup first */ root = of_find_node_by_path("/"); if (root == NULL) { printk(KERN_CRIT "pmac_find_bridges: can't find root of device tree\n"); return; } for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { if (np->name == NULL) continue; if (strcmp(np->name, "pci") == 0) { if (add_bridge(np) == 0) of_node_get(np); } if (strcmp(np->name, "ht") == 0) { of_node_get(np); ht = np; } } of_node_put(root); /* Now setup the HyperTransport host if we found any */ if (ht && add_bridge(ht) != 0) of_node_put(ht); /* Fixup the IO resources on our host bridges as the common code * does it only for childs of the host bridges */ pmac_fixup_phb_resources(); /* Setup the linkage between OF nodes and PHBs */ pci_devs_phb_init(); /* Fixup the PCI<->OF mapping for U3 AGP due to bus renumbering. We * assume there is no P2P bridge on the AGP bus, which should be a * safe assumptions hopefully. */ if (u3_agp) { struct device_node *np = u3_agp->arch_data; np->busno = 0xf0; for (np = np->child; np; np = np->sibling) np->busno = 0xf0; } pmac_check_ht_link(); /* Tell pci.c to use the common resource allocation mecanism */ pci_probe_only = 0; /* HT don't do more than 64 bytes transfers. FIXME: Deal with * the exception of U3/AGP (hook into pci_set_mwi) */ pci_cache_line_size = 16; /* 64 bytes */}/* * Disable second function on K2-SATA, it's broken * and disable IO BARs on first one */void fixup_k2_sata(struct pci_dev* dev){ int i; u16 cmd; if (PCI_FUNC(dev->devfn) > 0) { pci_read_config_word(dev, PCI_COMMAND, &cmd); cmd &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY); pci_write_config_word(dev, PCI_COMMAND, cmd); for (i = 0; i < 6; i++) { dev->resource[i].start = dev->resource[i].end = 0; dev->resource[i].flags = 0; pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); } } else { pci_read_config_word(dev, PCI_COMMAND, &cmd); cmd &= ~PCI_COMMAND_IO; pci_write_config_word(dev, PCI_COMMAND, cmd); for (i = 0; i < 5; i++) { dev->resource[i].start = dev->resource[i].end = 0; dev->resource[i].flags = 0; pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, 0); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -