📄 pmac_pci.c
字号:
if (k2_skiplist[i] && k2_skiplist[i]->bus == bus && k2_skiplist[i]->devfn == devfn) return PCIBIOS_SUCCESSFUL; addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); if (!addr) return PCIBIOS_DEVICE_NOT_FOUND; /* * Note: the caller has already checked that offset is * suitably aligned and that len is 1, 2 or 4. */ switch (len) { case 1: out_8((u8 *)addr, val); (void) in_8((u8 *)addr); break; case 2: out_le16((u16 *)addr, val); (void) in_le16((u16 *)addr); break; default: out_le32((u32 *)addr, val); (void) in_le32((u32 *)addr); break; } return PCIBIOS_SUCCESSFUL;}static struct pci_ops u3_ht_pci_ops ={ u3_ht_read_config, u3_ht_write_config};#endif /* CONFIG_POWER4 *//* * For a bandit bridge, turn on cache coherency if necessary. * N.B. we could clean this up using the hose ops directly. */static void __initinit_bandit(struct pci_controller *bp){ unsigned int vendev, magic; int rev; /* read the word at offset 0 in config space for device 11 */ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_VENDOR_ID); udelay(2); vendev = in_le32((volatile unsigned int *)bp->cfg_data); if (vendev == (PCI_DEVICE_ID_APPLE_BANDIT << 16) + PCI_VENDOR_ID_APPLE) { /* read the revision id */ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + PCI_REVISION_ID); udelay(2); rev = in_8(bp->cfg_data); if (rev != BANDIT_REVID) printk(KERN_WARNING "Unknown revision %d for bandit\n", rev); } else if (vendev != (BANDIT_DEVID_2 << 16) + PCI_VENDOR_ID_APPLE) { printk(KERN_WARNING "bandit isn't? (%x)\n", vendev); return; } /* read the word at offset 0x50 */ out_le32(bp->cfg_addr, (1UL << BANDIT_DEVNUM) + BANDIT_MAGIC); udelay(2); magic = in_le32((volatile unsigned int *)bp->cfg_data); if ((magic & BANDIT_COHERENT) != 0) return; magic |= BANDIT_COHERENT; udelay(2); out_le32((volatile unsigned int *)bp->cfg_data, magic); printk(KERN_INFO "Cache coherency enabled for bandit/PSX\n");}/* * Tweak the PCI-PCI bridge chip on the blue & white G3s. */static void __initinit_p2pbridge(void){ struct device_node *p2pbridge; struct pci_controller* hose; u8 bus, devfn; u16 val; /* XXX it would be better here to identify the specific PCI-PCI bridge chip we have. */ if ((p2pbridge = find_devices("pci-bridge")) == 0 || p2pbridge->parent == NULL || strcmp(p2pbridge->parent->name, "pci") != 0) return; if (pci_device_from_OF_node(p2pbridge, &bus, &devfn) < 0) { DBG("Can't find PCI infos for PCI<->PCI bridge\n"); return; } /* Warning: At this point, we have not yet renumbered all busses. * So we must use OF walking to find out hose */ hose = pci_find_hose_for_OF_device(p2pbridge); if (!hose) { DBG("Can't find hose for PCI<->PCI bridge\n"); return; } if (early_read_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, &val) < 0) { printk(KERN_ERR "init_p2pbridge: couldn't read bridge control\n"); return; } val &= ~PCI_BRIDGE_CTL_MASTER_ABORT; early_write_config_word(hose, bus, devfn, PCI_BRIDGE_CONTROL, val);}/* * Some Apple desktop machines have a NEC PD720100A USB2 controller * on the motherboard. Open Firmware, on these, will disable the * EHCI part of it so it behaves like a pair of OHCI's. This fixup * code re-enables it ;) */static void __initfixup_nec_usb2(void){ struct device_node *nec; for (nec = NULL; (nec = of_find_node_by_name(nec, "usb")) != NULL;) { struct pci_controller *hose; u32 data, *prop; u8 bus, devfn; prop = (u32 *)get_property(nec, "vendor-id", NULL); if (prop == NULL) continue; if (0x1033 != *prop) continue; prop = (u32 *)get_property(nec, "device-id", NULL); if (prop == NULL) continue; if (0x0035 != *prop) continue; prop = (u32 *)get_property(nec, "reg", NULL); if (prop == NULL) continue; devfn = (prop[0] >> 8) & 0xff; bus = (prop[0] >> 16) & 0xff; if (PCI_FUNC(devfn) != 0) continue; hose = pci_find_hose_for_OF_device(nec); if (!hose) continue; early_read_config_dword(hose, bus, devfn, 0xe4, &data); if (data & 1UL) { printk("Found NEC PD720100A USB2 chip with disabled EHCI, fixing up...\n"); data &= ~1UL; early_write_config_dword(hose, bus, devfn, 0xe4, data); early_write_config_byte(hose, bus, devfn | 2, PCI_INTERRUPT_LINE, nec->intrs[0].line); } }}void __initpmac_find_bridges(void){ struct device_node *np, *root; struct device_node *ht = NULL; 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, "bandit") == 0 || strcmp(np->name, "chaos") == 0 || 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); /* Probe HT last as it relies on the agp resources to be already * setup */ if (ht && add_bridge(ht) != 0) of_node_put(ht); init_p2pbridge(); fixup_nec_usb2();#ifdef CONFIG_POWER4 /* There is something wrong with DMA on U3/HT. I haven't figured out * the details yet, but if I set the cache line size to 128 bytes like * it should, I'm getting memory corruption caused by devices like * sungem (even without the MWI bit set, but maybe sungem doesn't * care). Right now, it appears that setting up a 64 bytes line size * works properly, 64 bytes beeing the max transfer size of HT, I * suppose this is related the way HT/PCI are hooked together. I still * need to dive into more specs though to be really sure of what's * going on. --BenH. * * Ok, apparently, it's just that HT can't do more than 64 bytes * transactions. MWI seem to be meaningless there as well, it may * be worth nop'ing out pci_set_mwi too though I haven't done that * yet. * * Note that it's a bit different for whatever is in the AGP slot. * For now, I don't care, but this can become a real issue, we * should probably hook pci_set_mwi anyway to make sure it sets * the real cache line size in there. */ if (machine_is_compatible("MacRISC4")) pci_cache_line_size = 16; /* 64 bytes */ pmac_check_ht_link();#endif /* CONFIG_POWER4 */}#define GRACKLE_CFA(b, d, o) (0x80 | ((b) << 8) | ((d) << 16) \ | (((o) & ~3) << 24))#define GRACKLE_PICR1_STG 0x00000040#define GRACKLE_PICR1_LOOPSNOOP 0x00000010/* N.B. this is called before bridges is initialized, so we can't use grackle_pcibios_{read,write}_config_dword. */static inline void grackle_set_stg(struct pci_controller* bp, int enable){ unsigned int val; out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); val = in_le32((volatile unsigned int *)bp->cfg_data); val = enable? (val | GRACKLE_PICR1_STG) : (val & ~GRACKLE_PICR1_STG); out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); out_le32((volatile unsigned int *)bp->cfg_data, val); (void)in_le32((volatile unsigned int *)bp->cfg_data);}static inline void grackle_set_loop_snoop(struct pci_controller *bp, int enable){ unsigned int val; out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); val = in_le32((volatile unsigned int *)bp->cfg_data); val = enable? (val | GRACKLE_PICR1_LOOPSNOOP) : (val & ~GRACKLE_PICR1_LOOPSNOOP); out_be32(bp->cfg_addr, GRACKLE_CFA(0, 0, 0xa8)); out_le32((volatile unsigned int *)bp->cfg_data, val); (void)in_le32((volatile unsigned int *)bp->cfg_data);}static int __initsetup_uninorth(struct pci_controller* hose, struct reg_property* addr){ pci_assign_all_busses = 1; has_uninorth = 1; hose->ops = ¯isc_pci_ops; hose->cfg_addr = ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = ioremap(addr->address + 0xc00000, 0x1000); /* We "know" that the bridge at f2000000 has the PCI slots. */ return addr->address == 0xf2000000;}static void __initsetup_bandit(struct pci_controller* hose, struct reg_property* addr){ hose->ops = ¯isc_pci_ops; hose->cfg_addr = (volatile unsigned int *) ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000); init_bandit(hose);}static void __initsetup_chaos(struct pci_controller* hose, struct reg_property* addr){ /* assume a `chaos' bridge */ hose->ops = &chaos_pci_ops; hose->cfg_addr = (volatile unsigned int *) ioremap(addr->address + 0x800000, 0x1000); hose->cfg_data = (volatile unsigned char *) ioremap(addr->address + 0xc00000, 0x1000);}#ifdef CONFIG_POWER4static void __initsetup_u3_agp(struct pci_controller* hose, struct reg_property* addr){ /* On G5, we move AGP up to high bus number so we don't need * to reassign bus numbers for HT. If we ever have P2P bridges * on AGP, we'll have to move pci_assign_all_busses to the * pci_controller structure so we enable it for AGP and not for * HT childs. * 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->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 __initsetup_u3_ht(struct pci_controller* hose, struct reg_property *addr){ 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 its configuration register (if any). */ hose->io_base_phys = 0xf4000000 + 0x00400000; hose->io_base_virt = ioremap(hose->io_base_phys, 0x00400000); isa_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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -