📄 pci_sabre.c
字号:
prom_halt(); } irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_PCIERR_INO); if (request_irq(irq, sabre_pcierr_intr, SA_SHIRQ, "SABRE PCIERR", p) < 0) { prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", p->index); prom_halt(); } tmp = sabre_read(base + SABRE_PCICTRL); tmp |= SABRE_PCICTRL_ERREN; sabre_write(base + SABRE_PCICTRL, tmp);}static void __init sabre_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root){ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_controller_info *p = pcp->pbm->parent; unsigned long base; if (res->flags & IORESOURCE_IO) base = p->controller_regs + SABRE_IOSPACE; else base = p->controller_regs + SABRE_MEMSPACE; res->start += base; res->end += base;}static void __init sabre_base_address_update(struct pci_dev *pdev, int resource){ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; struct pci_controller_info *p = pbm->parent; struct resource *res; unsigned long base; u32 reg; int where, size, is_64bit; res = &pdev->resource[resource]; where = PCI_BASE_ADDRESS_0 + (resource * 4); is_64bit = 0; if (res->flags & IORESOURCE_IO) base = p->controller_regs + SABRE_IOSPACE; else { base = p->controller_regs + SABRE_MEMSPACE; if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) is_64bit = 1; } size = res->end - res->start; pci_read_config_dword(pdev, where, ®); reg = ((reg & size) | (((u32)(res->start - base)) & ~size)); pci_write_config_dword(pdev, where, reg); /* This knows that the upper 32-bits of the address * must be zero. Our PCI common layer enforces this. */ if (is_64bit) pci_write_config_dword(pdev, where + 4, 0);}static void __init apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus){ struct list_head *walk = &sabre_bus->devices; for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { struct pci_dev *pdev = pci_dev_b(walk); if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { u16 word; sabre_read_word(pdev, PCI_COMMAND, &word); word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; sabre_write_word(pdev, PCI_COMMAND, word); /* Status register bits are "write 1 to clear". */ sabre_write_word(pdev, PCI_STATUS, 0xffff); sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); /* Use a primary/seconday latency timer value * of 64. */ sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); /* Enable reporting/forwarding of master aborts, * parity, and SERR. */ sabre_write_byte(pdev, PCI_BRIDGE_CONTROL, (PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_MASTER_ABORT)); } }}static void __init sabre_scan_bus(struct pci_controller_info *p){ static int once = 0; struct pci_bus *sabre_bus; struct list_head *walk; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. */ p->pbm_A.is_66mhz_capable = 0; p->pbm_B.is_66mhz_capable = 0; /* Unlike for PSYCHO, we can only have one SABRE * in a system. Having multiple SABREs is thus * and error, and as a consequence we do not need * to do any bus renumbering but we do have to have * the pci_bus2pbm array setup properly. * * Also note that the SABRE host bridge is hardwired * to live at bus 0. */ if (once != 0) { prom_printf("SABRE: Multiple controllers unsupported.\n"); prom_halt(); } once++; /* The pci_bus2pbm table has already been setup in sabre_init. */ sabre_bus = pci_scan_bus(p->pci_first_busno, p->pci_ops, &p->pbm_A); apb_init(p, sabre_bus); walk = &sabre_bus->children; for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) { struct pci_bus *pbus = pci_bus_b(walk); struct pci_pbm_info *pbm; if (pbus->number == p->pbm_A.pci_first_busno) { pbm = &p->pbm_A; } else if (pbus->number == p->pbm_B.pci_first_busno) { pbm = &p->pbm_B; } else continue; pbus->sysdata = pbm; pbm->pci_bus = pbus; pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbus); pci_assign_unassigned(pbm, pbus); pci_fixup_irq(pbm, pbus); pci_determine_66mhz_disposition(pbm, pbus); pci_setup_busmastering(pbm, pbus); } sabre_register_error_handlers(p);}static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset, u32 dma_mask){ unsigned long tsbbase, i, order; u64 control; /* Setup initial software IOMMU state. */ spin_lock_init(&p->iommu.lock); p->iommu.iommu_cur_ctx = 0; /* Register addresses. */ p->iommu.iommu_control = p->controller_regs + SABRE_IOMMU_CONTROL; p->iommu.iommu_tsbbase = p->controller_regs + SABRE_IOMMU_TSBBASE; p->iommu.iommu_flush = p->controller_regs + SABRE_IOMMU_FLUSH; p->iommu.write_complete_reg = p->controller_regs + SABRE_WRSYNC; /* Sabre's IOMMU lacks ctx flushing. */ p->iommu.iommu_ctxflush = 0; /* Invalidate TLB Entries. */ control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); control |= SABRE_IOMMUCTRL_DENAB; sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); for(i = 0; i < 16; i++) { sabre_write(p->controller_regs + SABRE_IOMMU_TAG + (i * 8UL), 0); sabre_write(p->controller_regs + SABRE_IOMMU_DATA + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); if (!tsbbase) { prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); } p->iommu.page_table = (iopte_t *)tsbbase; p->iommu.page_table_map_base = dvma_offset; p->iommu.dma_addr_mask = dma_mask; memset((char *)tsbbase, 0, PAGE_SIZE << order); sabre_write(p->controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); control = sabre_read(p->controller_regs + SABRE_IOMMU_CONTROL); control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); control |= SABRE_IOMMUCTRL_ENAB; switch(tsbsize) { case 64: control |= SABRE_IOMMU_TSBSZ_64K; p->iommu.page_table_sz_bits = 16; break; case 128: control |= SABRE_IOMMU_TSBSZ_128K; p->iommu.page_table_sz_bits = 17; break; default: prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); prom_halt(); break; } sabre_write(p->controller_regs + SABRE_IOMMU_CONTROL, control); /* We start with no consistent mappings. */ p->iommu.lowest_consistent_map = 1 << (p->iommu.page_table_sz_bits - PBM_LOGCLUSTERS); for (i = 0; i < PBM_NCLUSTERS; i++) { p->iommu.alloc_info[i].flush = 0; p->iommu.alloc_info[i].next = 0; }}static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, struct pci_pbm_info *pbm){ char *name = pbm->name; unsigned long ibase = p->controller_regs + SABRE_IOSPACE; unsigned long mbase = p->controller_regs + SABRE_MEMSPACE; unsigned int devfn; unsigned long first, last, i; u8 *addr, map; sprintf(name, "SABRE%d PBM%c", p->index, (pbm == &p->pbm_A ? 'A' : 'B')); pbm->io_space.name = pbm->mem_space.name = name; devfn = PCI_DEVFN(1, (pbm == &p->pbm_A) ? 0 : 1); addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_IO_ADDRESS_MAP); map = 0; pci_config_read8(addr, &map); first = 8; last = 0; for (i = 0; i < 8; i++) { if ((map & (1 << i)) != 0) { if (first > i) first = i; if (last < i) last = i; } } pbm->io_space.start = ibase + (first << 21UL); pbm->io_space.end = ibase + (last << 21UL) + ((1 << 21UL) - 1); pbm->io_space.flags = IORESOURCE_IO; addr = sabre_pci_config_mkaddr(pbm, 0, devfn, APB_MEM_ADDRESS_MAP); map = 0; pci_config_read8(addr, &map); first = 8; last = 0; for (i = 0; i < 8; i++) { if ((map & (1 << i)) != 0) { if (first > i) first = i; if (last < i) last = i; } } pbm->mem_space.start = mbase + (first << 29UL); pbm->mem_space.end = mbase + (last << 29UL) + ((1 << 29UL) - 1); pbm->mem_space.flags = IORESOURCE_MEM; if (request_resource(&ioport_resource, &pbm->io_space) < 0) { prom_printf("Cannot register PBM-%c's IO space.\n", (pbm == &p->pbm_A ? 'A' : 'B')); prom_halt(); } if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { prom_printf("Cannot register PBM-%c's MEM space.\n", (pbm == &p->pbm_A ? 'A' : 'B')); prom_halt(); }}static void __init sabre_pbm_init(struct pci_controller_info *p, int sabre_node){ char namebuf[128]; u32 busrange[2]; int node; node = prom_getchild(sabre_node); while ((node = prom_searchsiblings(node, "pci")) != 0) { struct pci_pbm_info *pbm; int err; err = prom_getproperty(node, "model", namebuf, sizeof(namebuf)); if ((err <= 0) || strncmp(namebuf, "SUNW,simba", err)) goto next_pci; err = prom_getproperty(node, "bus-range", (char *)&busrange[0], sizeof(busrange)); if (err == 0 || err == -1) { prom_printf("APB: Error, cannot get PCI bus-range.\n"); prom_halt(); } if (busrange[0] == 1) pbm = &p->pbm_B; else pbm = &p->pbm_A; pbm->parent = p; pbm->prom_node = node; pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; for (err = pbm->pci_first_busno; err <= pbm->pci_last_busno; err++) pci_bus2pbm[err] = pbm; prom_getstring(node, "name", pbm->prom_name, sizeof(pbm->prom_name)); err = prom_getproperty(node, "ranges", (char *)pbm->pbm_ranges, sizeof(pbm->pbm_ranges)); if (err != -1) pbm->num_pbm_ranges = (err / sizeof(struct linux_prom_pci_ranges)); else pbm->num_pbm_ranges = 0; err = prom_getproperty(node, "interrupt-map", (char *)pbm->pbm_intmap, sizeof(pbm->pbm_intmap)); if (err != -1) { pbm->num_pbm_intmap = (err / sizeof(struct linux_prom_pci_intmap)); err = prom_getproperty(node, "interrupt-map-mask", (char *)&pbm->pbm_intmask, sizeof(pbm->pbm_intmask)); if (err == -1) { prom_printf("APB: Fatal error, no interrupt-map-mask.\n"); prom_halt(); } } else { pbm->num_pbm_intmap = 0; memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } pbm_register_toplevel_resources(p, pbm); next_pci: node = prom_getsibling(node); if (!node) break; }}void __init sabre_init(int pnode){ struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; unsigned long flags; int tsbsize, err; u32 busrange[2]; u32 vdma[2]; u32 upa_portid, dma_mask; int bus; p = kmalloc(sizeof(*p), GFP_ATOMIC); if (!p) { prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); prom_halt(); } upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); memset(p, 0, sizeof(*p)); spin_lock_irqsave(&pci_controller_lock, flags); p->next = pci_controller_root; pci_controller_root = p; spin_unlock_irqrestore(&pci_controller_lock, flags); p->portid = upa_portid; p->index = pci_num_controllers++; p->scan_bus = sabre_scan_bus; p->irq_build = sabre_irq_build; p->base_address_update = sabre_base_address_update; p->resource_adjust = sabre_resource_adjust; p->pci_ops = &sabre_ops; /* * Map in SABRE register set and report the presence of this SABRE. */ err = prom_getproperty(pnode, "reg", (char *)&pr_regs[0], sizeof(pr_regs)); if(err == 0 || err == -1) { prom_printf("SABRE: Error, cannot get U2P registers " "from PROM.\n"); prom_halt(); } /* * First REG in property is base of entire SABRE register space. */ p->controller_regs = pr_regs[0].phys_addr; pci_dma_wsync = p->controller_regs + SABRE_WRSYNC; printk("PCI: Found SABRE, main regs at %016lx, wsync at %016lx\n", p->controller_regs, pci_dma_wsync); /* Error interrupts are enabled later after the bus scan. */ sabre_write(p->controller_regs + SABRE_PCICTRL, (SABRE_PCICTRL_MRLEN | SABRE_PCICTRL_SERR | SABRE_PCICTRL_ARBPARK | SABRE_PCICTRL_AEN)); /* Now map in PCI config space for entire SABRE. */ p->config_space = p->controller_regs + SABRE_CONFIGSPACE; printk("SABRE: PCI config space at %016lx\n", p->config_space); err = prom_getproperty(pnode, "virtual-dma", (char *)&vdma[0], sizeof(vdma)); if(err == 0 || err == -1) { prom_printf("SABRE: Error, cannot get virtual-dma property " "from PROM.\n"); prom_halt(); } dma_mask = vdma[0]; switch(vdma[1]) { case 0x20000000: dma_mask |= 0x1fffffff; tsbsize = 64; break; case 0x40000000: dma_mask |= 0x3fffffff; tsbsize = 128; break; case 0x80000000: dma_mask |= 0x7fffffff; tsbsize = 128; break; default: prom_printf("SABRE: strange virtual-dma size.\n"); prom_halt(); } sabre_iommu_init(p, tsbsize, vdma[0], dma_mask); printk("SABRE: DVMA at %08x [%08x]\n", vdma[0], vdma[1]); err = prom_getproperty(pnode, "bus-range", (char *)&busrange[0], sizeof(busrange)); if(err == 0 || err == -1) { prom_printf("SABRE: Error, cannot get PCI bus-range " " from PROM.\n"); prom_halt(); } p->pci_first_busno = busrange[0]; p->pci_last_busno = busrange[1]; /* * Handle config space reads through any Simba on APB. */ for (bus = p->pci_first_busno; bus <= p->pci_last_busno; bus++) pci_bus2pbm[bus] = &p->pbm_A; /* * Look for APB underneath. */ sabre_pbm_init(p, pnode);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -