📄 pci_sabre.c
字号:
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(); } iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = dvma_offset; 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; iommu->page_table_sz_bits = 16; break; case 128: control |= SABRE_IOMMU_TSBSZ_128K; 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. */ iommu->lowest_consistent_map = 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS); for (i = 0; i < PBM_NCLUSTERS; i++) { iommu->alloc_info[i].flush = 0; 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(); } /* Register legacy regions if this PBM covers that area. */ if (pbm->io_space.start == ibase && pbm->mem_space.start == mbase) pci_register_legacy_regions(&pbm->io_space, &pbm->mem_space);}static void __init sabre_pbm_init(struct pci_controller_info *p, int sabre_node, u32 dma_begin){ struct pci_pbm_info *pbm; char namebuf[128]; u32 busrange[2]; int node, simbas_found; simbas_found = 0; node = prom_getchild(sabre_node); while ((node = prom_searchsiblings(node, "pci")) != 0) { 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(); } simbas_found++; if (busrange[0] == 1) pbm = &p->pbm_B; else pbm = &p->pbm_A; pbm->parent = p; pbm->prom_node = node; pbm->pci_first_slot = 1; 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; } if (simbas_found == 0) { int err; /* No APBs underneath, probably this is a hummingbird * system. */ pbm = &p->pbm_A; pbm->parent = p; pbm->prom_node = sabre_node; pbm->pci_first_busno = p->pci_first_busno; pbm->pci_last_busno = p->pci_last_busno; for (err = pbm->pci_first_busno; err <= pbm->pci_last_busno; err++) pci_bus2pbm[err] = pbm; prom_getstring(sabre_node, "name", pbm->prom_name, sizeof(pbm->prom_name)); err = prom_getproperty(sabre_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(sabre_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(sabre_node, "interrupt-map-mask", (char *)&pbm->pbm_intmask, sizeof(pbm->pbm_intmask)); if (err == -1) { prom_printf("Hummingbird: Fatal error, no interrupt-map-mask.\n"); prom_halt(); } } else { pbm->num_pbm_intmap = 0; memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } sprintf(pbm->name, "SABRE%d PBM%c", p->index, (pbm == &p->pbm_A ? 'A' : 'B')); pbm->io_space.name = pbm->mem_space.name = pbm->name; /* Hack up top-level resources. */ pbm->io_space.start = p->controller_regs + SABRE_IOSPACE; pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL; pbm->io_space.flags = IORESOURCE_IO; pbm->mem_space.start = p->controller_regs + SABRE_MEMSPACE; pbm->mem_space.end = pbm->mem_space.start + (unsigned long)dma_begin - 1UL; pbm->mem_space.flags = IORESOURCE_MEM; if (request_resource(&ioport_resource, &pbm->io_space) < 0) { prom_printf("Cannot register Hummingbird's IO space.\n"); prom_halt(); } if (request_resource(&iomem_resource, &pbm->mem_space) < 0) { prom_printf("Cannot register Hummingbird's MEM space.\n"); prom_halt(); } pci_register_legacy_regions(&pbm->io_space, &pbm->mem_space); }}void __init sabre_init(int pnode, char *model_name){ struct linux_prom64_registers pr_regs[2]; struct pci_controller_info *p; struct pci_iommu *iommu; unsigned long flags; int tsbsize, err; u32 busrange[2]; u32 vdma[2]; u32 upa_portid, dma_mask; int bus; hummingbird_p = 0; if (!strcmp(model_name, "pci108e,a001")) hummingbird_p = 1; else if (!strcmp(model_name, "SUNW,sabre")) { char compat[64]; if (prom_getproperty(pnode, "compatible", compat, sizeof(compat)) > 0 && !strcmp(compat, "pci108e,a001")) { hummingbird_p = 1; } else { int cpu_node = linux_cpus[0].prom_node; /* Of course, Sun has to encode things a thousand * different ways, inconsistently. */ if (prom_getproperty(cpu_node, "name", compat, sizeof(compat)) > 0 && !strcmp(compat, "SUNW,UltraSPARC-IIe")) hummingbird_p = 1; } } p = kmalloc(sizeof(*p), GFP_ATOMIC); if (!p) { prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); prom_halt(); } memset(p, 0, sizeof(*p)); iommu = kmalloc(sizeof(*iommu), GFP_ATOMIC); if (!iommu) { prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); prom_halt(); } memset(iommu, 0, sizeof(*iommu)); p->pbm_A.iommu = p->pbm_B.iommu = iommu; upa_portid = prom_getintdefault(pnode, "upa-portid", 0xff); 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->pbms_same_domain = 1; 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->pbm_A.config_space = p->pbm_B.config_space = (p->controller_regs + SABRE_CONFIGSPACE); printk("SABRE: Shared PCI config space at %016lx\n", p->pbm_A.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, vdma[0]);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -