📄 pci_schizo.c
字号:
/* Use ranges property to determine where PCI MEM, I/O, and Config * space are for this PCI bus module. */static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm){ int i, saw_cfg, saw_mem, saw_io; saw_cfg = saw_mem = saw_io = 0; for (i = 0; i < pbm->num_pbm_ranges; i++) { struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; unsigned long a; int type; type = (pr->child_phys_hi >> 24) & 0x3; a = (((unsigned long)pr->parent_phys_hi << 32UL) | ((unsigned long)pr->parent_phys_lo << 0UL)); switch (type) { case 0: /* PCI config space, 16MB */ pbm->config_space = a; saw_cfg = 1; break; case 1: /* 16-bit IO space, 16MB */ pbm->io_space.start = a; pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); pbm->io_space.flags = IORESOURCE_IO; saw_io = 1; break; case 2: /* 32-bit MEM space, 2GB */ pbm->mem_space.start = a; pbm->mem_space.end = a + (0x80000000UL - 1UL); pbm->mem_space.flags = IORESOURCE_MEM; saw_mem = 1; break; default: break; }; } if (!saw_cfg || !saw_io || !saw_mem) { prom_printf("%s: Fatal error, missing %s PBM range.\n", pbm->name, ((!saw_cfg ? "CFG" : (!saw_io ? "IO" : "MEM")))); prom_halt(); } printk("%s: PCI CFG[%lx] IO[%lx] MEM[%lx]\n", pbm->name, pbm->config_space, pbm->io_space.start, pbm->mem_space.start);}static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, struct pci_pbm_info *pbm){ pbm->io_space.name = pbm->mem_space.name = pbm->name; request_resource(&ioport_resource, &pbm->io_space); request_resource(&iomem_resource, &pbm->mem_space); pci_register_legacy_regions(&pbm->io_space, &pbm->mem_space);}#define SCHIZO_STRBUF_CONTROL (0x02800UL)#define SCHIZO_STRBUF_FLUSH (0x02808UL)#define SCHIZO_STRBUF_FSYNC (0x02810UL)#define SCHIZO_STRBUF_CTXFLUSH (0x02818UL)#define SCHIZO_STRBUF_CTXMATCH (0x10000UL)static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm){ unsigned long base = pbm->pbm_regs; u64 control; if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { /* TOMATILLO lacks streaming cache. */ return; } /* SCHIZO has context flushing. */ pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL; pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH; pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC; pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH; pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH; pbm->stc.strbuf_flushflag = (volatile unsigned long *) ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + 63UL) & ~63UL); pbm->stc.strbuf_flushflag_pa = (unsigned long) __pa(pbm->stc.strbuf_flushflag); /* Turn off LRU locking and diag mode, enable the * streaming buffer and leave the rerun-disable * setting however OBP set it. */ control = schizo_read(pbm->stc.strbuf_control); control &= ~(SCHIZO_STRBUF_CTRL_LPTR | SCHIZO_STRBUF_CTRL_LENAB | SCHIZO_STRBUF_CTRL_DENAB); control |= SCHIZO_STRBUF_CTRL_ENAB; schizo_write(pbm->stc.strbuf_control, control); pbm->stc.strbuf_enabled = 1;}#define SCHIZO_IOMMU_CONTROL (0x00200UL)#define SCHIZO_IOMMU_TSBBASE (0x00208UL)#define SCHIZO_IOMMU_FLUSH (0x00210UL)#define SCHIZO_IOMMU_CTXFLUSH (0x00218UL)static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm){ struct pci_iommu *iommu = pbm->iommu; unsigned long tsbbase, i, tagbase, database, order; u32 vdma[2], dma_mask; u64 control; int err, tsbsize; err = prom_getproperty(pbm->prom_node, "virtual-dma", (char *)&vdma[0], sizeof(vdma)); if (err == 0 || err == -1) { /* No property, use default values. */ vdma[0] = 0xc0000000; vdma[1] = 0x40000000; } 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("SCHIZO: strange virtual-dma size.\n"); prom_halt(); }; /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); iommu->iommu_cur_ctx = 0; /* Register addresses, SCHIZO has iommu ctx flushing. */ iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE; iommu->iommu_flush = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH; iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH; /* We use the main control/status register of SCHIZO as the write * completion register. */ iommu->write_complete_reg = pbm->controller_regs + 0x10000UL; /* * Invalidate TLB Entries. */ control = schizo_read(iommu->iommu_control); control |= SCHIZO_IOMMU_CTRL_DENAB; schizo_write(iommu->iommu_control, control); tagbase = SCHIZO_IOMMU_TAG, database = SCHIZO_IOMMU_DATA; for(i = 0; i < 16; i++) { schizo_write(pbm->pbm_regs + tagbase + (i * 8UL), 0); schizo_write(pbm->pbm_regs + database + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); if (!iommu->dummy_page) { prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); prom_halt(); } memset((void *)iommu->dummy_page, 0, PAGE_SIZE); iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); /* Using assumed page size 8K with 128K entries we need 1MB iommu page * table (128K ioptes * 8 bytes per iopte). This is * page order 7 on UltraSparc. */ order = get_order(tsbsize * 8 * 1024); tsbbase = __get_free_pages(GFP_KERNEL, order); if (!tsbbase) { prom_printf("%s: Error, gfp(tsb) failed.\n", pbm->name); prom_halt(); } iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_map_base = vdma[0]; iommu->dma_addr_mask = dma_mask; pci_iommu_table_init(iommu, PAGE_SIZE << order); switch (tsbsize) { case 64: iommu->page_table_sz_bits = 16; break; case 128: iommu->page_table_sz_bits = 17; break; default: prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); prom_halt(); break; }; /* 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; } schizo_write(iommu->iommu_tsbbase, __pa(tsbbase)); control = schizo_read(iommu->iommu_control); control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ); switch (tsbsize) { case 64: control |= SCHIZO_IOMMU_TSBSZ_64K; break; case 128: control |= SCHIZO_IOMMU_TSBSZ_128K; break; }; control |= SCHIZO_IOMMU_CTRL_ENAB; schizo_write(iommu->iommu_control, control);}#define SCHIZO_PCI_IRQ_RETRY (0x1a00UL)#define SCHIZO_IRQ_RETRY_INF 0xffUL#define SCHIZO_PCI_DIAG (0x2020UL)#define SCHIZO_PCIDIAG_D_BADECC (1UL << 10UL) /* Disable BAD ECC errors (Schizo) */#define SCHIZO_PCIDIAG_D_BYPASS (1UL << 9UL) /* Disable MMU bypass mode (Schizo/Tomatillo) */#define SCHIZO_PCIDIAG_D_TTO (1UL << 8UL) /* Disable TTO errors (Schizo/Tomatillo) */#define SCHIZO_PCIDIAG_D_RTRYARB (1UL << 7UL) /* Disable retry arbitration (Schizo) */#define SCHIZO_PCIDIAG_D_RETRY (1UL << 6UL) /* Disable retry limit (Schizo/Tomatillo) */#define SCHIZO_PCIDIAG_D_INTSYNC (1UL << 5UL) /* Disable interrupt/DMA synch (Schizo/Tomatillo) */#define SCHIZO_PCIDIAG_I_DMA_PARITY (1UL << 3UL) /* Invert DMA parity (Schizo/Tomatillo) */#define SCHIZO_PCIDIAG_I_PIOD_PARITY (1UL << 2UL) /* Invert PIO data parity (Schizo/Tomatillo) */#define SCHIZO_PCIDIAG_I_PIOA_PARITY (1UL << 1UL) /* Invert PIO address parity (Schizo/Tomatillo) */#define TOMATILLO_PCI_IOC_CSR (0x2248UL)#define TOMATILLO_IOC_PART_WPENAB 0x0000000000080000UL#define TOMATILLO_IOC_RDMULT_PENAB 0x0000000000040000UL#define TOMATILLO_IOC_RDONE_PENAB 0x0000000000020000UL#define TOMATILLO_IOC_RDLINE_PENAB 0x0000000000010000UL#define TOMATILLO_IOC_RDMULT_PLEN 0x000000000000c000UL#define TOMATILLO_IOC_RDMULT_PLEN_SHIFT 14UL#define TOMATILLO_IOC_RDONE_PLEN 0x0000000000003000UL#define TOMATILLO_IOC_RDONE_PLEN_SHIFT 12UL#define TOMATILLO_IOC_RDLINE_PLEN 0x0000000000000c00UL#define TOMATILLO_IOC_RDLINE_PLEN_SHIFT 10UL#define TOMATILLO_IOC_PREF_OFF 0x00000000000003f8UL#define TOMATILLO_IOC_PREF_OFF_SHIFT 3UL#define TOMATILLO_IOC_RDMULT_CPENAB 0x0000000000000004UL#define TOMATILLO_IOC_RDONE_CPENAB 0x0000000000000002UL#define TOMATILLO_IOC_RDLINE_CPENAB 0x0000000000000001UL#define TOMATILLO_PCI_IOC_TDIAG (0x2250UL)#define TOMATILLO_PCI_IOC_DDIAG (0x2290UL)static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm){ u64 tmp; /* Set IRQ retry to infinity. */ schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, SCHIZO_IRQ_RETRY_INF); /* Enable arbiter for all PCI slots. Also, disable PCI interval * timer so that DTO (Discard TimeOuts) are not reported because * some Schizo revisions report them erroneously. */ tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL); if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS && pbm->chip_version == 0x5 && pbm->chip_revision == 0x1) tmp |= 0x0f; else tmp |= 0xff; tmp &= ~SCHIZO_PCICTRL_PTO; if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO && pbm->chip_version == 0x2) tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT; else tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT; if (!prom_getbool(pbm->prom_node, "no-bus-parking")) tmp |= SCHIZO_PCICTRL_PARK; if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) tmp |= SCHIZO_PCICTRL_MRM_PREF; schizo_write(pbm->pbm_regs + SCHIZO_PCI_CTRL, tmp); tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_DIAG); tmp &= ~(SCHIZO_PCIDIAG_D_RTRYARB | SCHIZO_PCIDIAG_D_RETRY | SCHIZO_PCIDIAG_D_INTSYNC); schizo_write(pbm->pbm_regs + SCHIZO_PCI_DIAG, tmp); if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) { /* Clear prefetch lengths to workaround a bug in * Jalapeno... */ tmp = (TOMATILLO_IOC_PART_WPENAB | (1 << TOMATILLO_IOC_PREF_OFF_SHIFT) | TOMATILLO_IOC_RDMULT_CPENAB | TOMATILLO_IOC_RDONE_CPENAB | TOMATILLO_IOC_RDLINE_CPENAB); schizo_write(pbm->pbm_regs + TOMATILLO_PCI_IOC_CSR, tmp); }}static void __init schizo_pbm_init(struct pci_controller_info *p, int prom_node, u32 portid, int chip_type){ struct linux_prom64_registers pr_regs[4]; unsigned int busrange[2]; struct pci_pbm_info *pbm; const char *chipset_name; u32 ino_bitmap[2]; int is_pbm_a; int err; switch (chip_type) { case PBM_CHIP_TYPE_TOMATILLO: chipset_name = "TOMATILLO"; break; case PBM_CHIP_TYPE_SCHIZO_PLUS: chipset_name = "SCHIZO+"; break; case PBM_CHIP_TYPE_SCHIZO: default: chipset_name = "SCHIZO"; break; }; /* For SCHIZO, three OBP regs: * 1) PBM controller regs * 2) Schizo front-end controller regs (same for both PBMs) * 3) PBM PCI config space * * For TOMATILLO, four OBP regs: * 1) PBM controller regs * 2) Tomatillo front-end controller regs * 3) PBM PCI config space * 4) Ichip regs */ err = prom_getproperty(prom_node, "reg", (char *)&pr_regs[0], sizeof(pr_regs)); if (err == 0 || err == -1) { prom_printf("%s: Fatal error, no reg property.\n", chipset_name); prom_halt(); } is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000); if (is_pbm_a) pbm = &p->pbm_A; else pbm = &p->pbm_B; pbm->portid = portid; pbm->parent = p; pbm->prom_node = prom_node; pbm->pci_first_slot = 1; pbm->chip_type = chip_type; pbm->chip_version = prom_getintdefault(prom_node, "version#", 0); pbm->chip_revision =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -