📄 pci_schizo.c
字号:
pci_setup_busmastering(pbm, pbm->pci_bus);}static void __init schizo_scan_bus(struct pci_controller_info *p){ pbm_bridge_reconfigure(p); pbm_config_busmastering(&p->pbm_B); p->pbm_B.is_66mhz_capable = 0; pbm_config_busmastering(&p->pbm_A); p->pbm_A.is_66mhz_capable = 1; pbm_scan_bus(p, &p->pbm_B); pbm_scan_bus(p, &p->pbm_A); /* After the PCI bus scan is complete, we can register * the error interrupt handlers. */ schizo_register_error_handlers(p);}static void __init schizo_base_address_update(struct pci_dev *pdev, int resource){ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; struct resource *res, *root; 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) root = &pbm->io_space; else { root = &pbm->mem_space; 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 - root->start)) & ~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 schizo_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root){ res->start += root->start; res->end += root->start;}/* Interrogate Safari match/mask registers to figure out where * PCI MEM, I/O, and Config space are for this PCI bus module. */#define SCHIZO_PCI_A_MEM_MATCH 0x00040UL#define SCHIZO_PCI_A_MEM_MASK 0x00048UL#define SCHIZO_PCI_A_IO_MATCH 0x00050UL#define SCHIZO_PCI_A_IO_MASK 0x00058UL#define SCHIZO_PCI_B_MEM_MATCH 0x00060UL#define SCHIZO_PCI_B_MEM_MASK 0x00068UL#define SCHIZO_PCI_B_IO_MATCH 0x00070UL#define SCHIZO_PCI_B_IO_MASK 0x00078UL/* VAL must be non-zero. */static unsigned long strip_to_lowest_bit_set(unsigned long val){ unsigned long tmp; tmp = 1UL; while (!(tmp & val)) tmp <<= 1UL; return tmp;}static void schizo_determine_mem_io_space(struct pci_pbm_info *pbm, int is_pbm_a, unsigned long reg_base){ u64 mem_match, mem_mask; u64 io_match; u64 long a, b; if (is_pbm_a) { mem_match = reg_base + SCHIZO_PCI_A_MEM_MATCH; io_match = reg_base + SCHIZO_PCI_A_IO_MATCH; } else { mem_match = reg_base + SCHIZO_PCI_B_MEM_MATCH; io_match = reg_base + SCHIZO_PCI_B_IO_MATCH; } mem_mask = mem_match + 0x8UL; a = schizo_read(mem_match) & ~0x8000000000000000UL; b = strip_to_lowest_bit_set(schizo_read(mem_mask)); /* It should be 2GB in size. */ pbm->mem_space.start = a; pbm->mem_space.end = a + (b - 1UL); pbm->mem_space.flags = IORESOURCE_MEM; /* This 32MB area is divided into two pieces. The first * 16MB is Config space, the next 16MB is I/O space. */ a = schizo_read(io_match) & ~0x8000000000000000UL; pbm->config_space = a; printk("SCHIZO PBM%c: Local PCI config space at %016lx\n", (is_pbm_a ? 'A' : 'B'), pbm->config_space); a += (16UL * 1024UL * 1024UL); pbm->io_space.start = a; pbm->io_space.end = a + ((16UL * 1024UL * 1024UL) - 1UL); pbm->io_space.flags = IORESOURCE_IO;}static void __init pbm_register_toplevel_resources(struct pci_controller_info *p, struct pci_pbm_info *pbm){ char *name = pbm->name; sprintf(name, "SCHIZO%d PBM%c", p->index, (pbm == &p->pbm_A ? 'A' : 'B')); pbm->io_space.name = pbm->mem_space.name = 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_A (SCHIZO_PBM_A_REGS_OFF + 0x02800UL)#define SCHIZO_STRBUF_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02808UL)#define SCHIZO_STRBUF_FSYNC_A (SCHIZO_PBM_A_REGS_OFF + 0x02810UL)#define SCHIZO_STRBUF_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x02818UL)#define SCHIZO_STRBUF_CTXMATCH_A (SCHIZO_PBM_A_REGS_OFF + 0x10000UL)#define SCHIZO_STRBUF_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x02800UL)#define SCHIZO_STRBUF_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02808UL)#define SCHIZO_STRBUF_FSYNC_B (SCHIZO_PBM_B_REGS_OFF + 0x02810UL)#define SCHIZO_STRBUF_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x02818UL)#define SCHIZO_STRBUF_CTXMATCH_B (SCHIZO_PBM_B_REGS_OFF + 0x10000UL)static void schizo_pbm_strbuf_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a){ unsigned long base = p->controller_regs; u64 control; /* SCHIZO has context flushing. */ if (is_pbm_a) { pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_A; pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_A; pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_A; pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_A; pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_A; } else { pbm->stc.strbuf_control = base + SCHIZO_STRBUF_CONTROL_B; pbm->stc.strbuf_pflush = base + SCHIZO_STRBUF_FLUSH_B; pbm->stc.strbuf_fsync = base + SCHIZO_STRBUF_FSYNC_B; pbm->stc.strbuf_ctxflush = base + SCHIZO_STRBUF_CTXFLUSH_B; pbm->stc.strbuf_ctxmatch_base = base + SCHIZO_STRBUF_CTXMATCH_B; } 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_A (SCHIZO_PBM_A_REGS_OFF + 0x00200UL)#define SCHIZO_IOMMU_TSBBASE_A (SCHIZO_PBM_A_REGS_OFF + 0x00208UL)#define SCHIZO_IOMMU_FLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00210UL)#define SCHIZO_IOMMU_CTXFLUSH_A (SCHIZO_PBM_A_REGS_OFF + 0x00218UL)#define SCHIZO_IOMMU_TAG_A (SCHIZO_PBM_A_REGS_OFF + 0x0a580UL)#define SCHIZO_IOMMU_DATA_A (SCHIZO_PBM_A_REGS_OFF + 0x0a600UL)#define SCHIZO_IOMMU_CONTROL_B (SCHIZO_PBM_B_REGS_OFF + 0x00200UL)#define SCHIZO_IOMMU_TSBBASE_B (SCHIZO_PBM_B_REGS_OFF + 0x00208UL)#define SCHIZO_IOMMU_FLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00210UL)#define SCHIZO_IOMMU_CTXFLUSH_B (SCHIZO_PBM_B_REGS_OFF + 0x00218UL)#define SCHIZO_IOMMU_TAG_B (SCHIZO_PBM_B_REGS_OFF + 0x0a580UL)#define SCHIZO_IOMMU_DATA_B (SCHIZO_PBM_B_REGS_OFF + 0x0a600UL)static void schizo_pbm_iommu_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, int is_pbm_a){ struct pci_iommu *iommu = pbm->iommu; unsigned long tsbbase, i, tagbase, database; u64 control; /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); iommu->iommu_cur_ctx = 0; /* Register addresses, SCHIZO has iommu ctx flushing. */ if (is_pbm_a) { iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_A; iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_A; iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_A; iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_A; } else { iommu->iommu_control = p->controller_regs + SCHIZO_IOMMU_CONTROL_B; iommu->iommu_tsbbase = p->controller_regs + SCHIZO_IOMMU_TSBBASE_B; iommu->iommu_flush = p->controller_regs + SCHIZO_IOMMU_FLUSH_B; iommu->iommu_ctxflush = p->controller_regs + SCHIZO_IOMMU_CTXFLUSH_B; } /* We use the main control/status register of SCHIZO as the write * completion register. */ iommu->write_complete_reg = p->controller_regs + 0x10000UL; /* * Invalidate TLB Entries. */ control = schizo_read(iommu->iommu_control); control |= SCHIZO_IOMMU_CTRL_DENAB; schizo_write(iommu->iommu_control, control); if (is_pbm_a) tagbase = SCHIZO_IOMMU_TAG_A, database = SCHIZO_IOMMU_DATA_A; else tagbase = SCHIZO_IOMMU_TAG_B, database = SCHIZO_IOMMU_DATA_B; for(i = 0; i < 16; i++) { schizo_write(p->controller_regs + tagbase + (i * 8UL), 0); schizo_write(p->controller_regs + database + (i * 8UL), 0); } /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ /* 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. */ tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE)); if (!tsbbase) { prom_printf("SCHIZO_IOMMU: Error, gfp(tsb) failed.\n"); prom_halt(); } iommu->page_table = (iopte_t *)tsbbase; iommu->page_table_sz_bits = 17; iommu->page_table_map_base = 0xc0000000; iommu->dma_addr_mask = 0xffffffff; memset((char *)tsbbase, 0, IO_TSB_SIZE); /* 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); control |= (SCHIZO_IOMMU_TSBSZ_128K | SCHIZO_IOMMU_CTRL_ENAB); schizo_write(iommu->iommu_control, control);}static void schizo_pbm_init(struct pci_controller_info *p, int prom_node, int is_pbm_a){ unsigned int busrange[2]; struct pci_pbm_info *pbm; int err; if (is_pbm_a) pbm = &p->pbm_A; else pbm = &p->pbm_B; schizo_determine_mem_io_space(pbm, is_pbm_a, p->controller_regs); pbm_register_toplevel_resources(p, pbm); pbm->parent = p; pbm->prom_node = prom_node; pbm->pci_first_slot = 1; prom_getstring(prom_node, "name", pbm->prom_name, sizeof(pbm->prom_name)); err = prom_getproperty(prom_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(prom_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(prom_node, "interrupt-map-mask", (char *)&pbm->pbm_intmask, sizeof(pbm->pbm_intmask)); if (err == -1) { prom_printf("SCHIZO-PBM: Fatal error, no " "interrupt-map-mask.\n"); prom_halt(); } } else { pbm->num_pbm_intmap = 0; memset(&pbm->pbm_intmask, 0, sizeof(pbm->pbm_intmask)); } err = prom_getproperty(prom_node, "bus-range", (char *)&busrange[0], sizeof(busrange)); if (err == 0 || err == -1) { prom_printf("SCHIZO-PBM: Fatal error, no bus-range.\n"); prom_halt(); } pbm->pci_first_busno = busrange[0]; pbm->pci_last_busno = busrange[1]; schizo_pbm_iommu_init(p, pbm, is_pbm_a); schizo_pbm_strbuf_init(p, pbm, is_pbm_a);}static void schizo_controller_hwinit(struct pci_controller_info *p){ unsigned long pbm_a_base, pbm_b_base; u64 tmp; pbm_a_base = p->controller_regs + SCHIZO_PBM_A_REGS_OFF; pbm_b_base = p->controller_regs + SCHIZO_PBM_B_REGS_OFF; /* Set IRQ retry to infinity. */ schizo_write(pbm_a_base + 0x1a00UL, 0xff); schizo_write(pbm_b_base + 0x1a00UL, 0xff); /* Enable arbiter for all PCI slots. */ tmp = schizo_read(pbm_a_base + 0x2000UL); tmp |= 0x3fUL; schizo_write(pbm_a_base + 0x2000UL, tmp); tmp = schizo_read(pbm_b_base + 0x2000UL); tmp |= 0x3fUL; schizo_write(pbm_b_base + 0x2000UL, tmp);}void __init schizo_init(int node, char *model_name){ struct linux_prom64_registers pr_regs[3]; struct pci_controller_info *p; struct pci_iommu *iommu; unsigned long flags; u32 portid; int is_pbm_a, err; portid = prom_getintdefault(node, "portid", 0xff); spin_lock_irqsave(&pci_controller_lock, flags); for(p = pci_controller_root; p; p = p->next) { if (p->portid == portid) { spin_unlock_irqrestore(&pci_controller_lock, flags); is_pbm_a = (p->pbm_A.prom_node == 0); schizo_pbm_init(p, node, is_pbm_a); return; } } spin_unlock_irqrestore(&pci_controller_lock, flags); p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) { prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_halt(); } memset(p, 0, sizeof(*p)); iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) { prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_halt(); } memset(iommu, 0, sizeof(*iommu)); p->pbm_A.iommu = iommu; iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); if (!iommu) { prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_halt(); } memset(iommu, 0, sizeof(*iommu)); p->pbm_B.iommu = iommu; 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 = portid; p->index = pci_num_controllers++; p->pbms_same_domain = 0; p->scan_bus = schizo_scan_bus; p->irq_build = schizo_irq_build; p->base_address_update = schizo_base_address_update; p->resource_adjust = schizo_resource_adjust; p->pci_ops = &schizo_ops; /* Three OBP regs: * 1) PBM controller regs * 2) Schizo front-end controller regs (same for both PBMs) * 3) PBM PCI config space */ err = prom_getproperty(node, "reg", (char *)&pr_regs[0], sizeof(pr_regs)); if (err == 0 || err == -1) { prom_printf("SCHIZO: Fatal error, no reg property.\n"); prom_halt(); } p->controller_regs = pr_regs[1].phys_addr - 0x10000UL; printk("PCI: Found SCHIZO, control regs at %016lx\n", p->controller_regs); /* Like PSYCHO we have a 2GB aligned area for memory space. */ pci_memspace_mask = 0x7fffffffUL; /* Init core controller. */ schizo_controller_hwinit(p); is_pbm_a = ((pr_regs[0].phys_addr & 0x00700000) == 0x00600000); schizo_pbm_init(p, node, is_pbm_a);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -