📄 pci_schizo.c
字号:
int where, size, is_64bit; res = &pdev->resource[resource]; if (resource < 6) { where = PCI_BASE_ADDRESS_0 + (resource * 4); } else if (resource == PCI_ROM_RESOURCE) { where = pdev->rom_base_reg; } else { /* Somebody might have asked allocation of a non-standard resource */ return; } 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)); if (resource == PCI_ROM_RESOURCE) { reg |= PCI_ROM_ADDRESS_ENABLE; res->flags |= PCI_ROM_ADDRESS_ENABLE; } 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 0x00078ULstatic 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 a; 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; /* It should be 2GB in size but the decode is set for the full * 4GB so we have to add the 2G by hand. */ pbm->mem_space.start = a; pbm->mem_space.end = a + 0x80000000; 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);}#define SCHIZO_PCIA_IRQ_RETRY (SCHIZO_PBM_A_REGS_OFF + 0x1a00UL)#define SCHIZO_PCIB_IRQ_RETRY (SCHIZO_PBM_B_REGS_OFF + 0x1a00UL)#define SCHIZO_IRQ_RETRY_INF 0xffUL#define SCHIZO_PCIA_DIAG (SCHIZO_PBM_A_REGS_OFF + 0x2020UL)#define SCHIZO_PCIB_DIAG (SCHIZO_PBM_B_REGS_OFF + 0x2020UL)#define SCHIZO_PCIDIAG_D_BADECC (1UL << 10UL) /* Disable BAD ECC errors */#define SCHIZO_PCIDIAG_D_BYPASS (1UL << 9UL) /* Disable MMU bypass mode */#define SCHIZO_PCIDIAG_D_TTO (1UL << 8UL) /* Disable TTO errors */#define SCHIZO_PCIDIAG_D_RTRYARB (1UL << 7UL) /* Disable retry arbitration */#define SCHIZO_PCIDIAG_D_RETRY (1UL << 6UL) /* Disable retry limit */#define SCHIZO_PCIDIAG_D_INTSYNC (1UL << 5UL) /* Disable interrupt/DMA synch */#define SCHIZO_PCIDIAG_I_DMA_PARITY (1UL << 3UL) /* Invert DMA parity */#define SCHIZO_PCIDIAG_I_PIOD_PARITY (1UL << 2UL) /* Invert PIO data parity */#define SCHIZO_PCIDIAG_I_PIOA_PARITY (1UL << 1U)L /* Invert PIO address parity */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(p->controller_regs + SCHIZO_PCIA_IRQ_RETRY, SCHIZO_IRQ_RETRY_INF); schizo_write(p->controller_regs + SCHIZO_PCIB_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(p->controller_regs + SCHIZO_PCIA_CTRL); tmp |= SCHIZO_PCICTRL_ARB; tmp &= ~SCHIZO_PCICTRL_PTO; schizo_write(p->controller_regs + SCHIZO_PCIA_CTRL, tmp); tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_CTRL); tmp |= SCHIZO_PCICTRL_ARB; tmp &= ~SCHIZO_PCICTRL_PTO; schizo_write(p->controller_regs + SCHIZO_PCIB_CTRL, tmp); /* Disable TTO error reporting (won't happen anyway since we * disabled the PCI interval timer above) and retry arbitration * (can cause hangs in some Schizo revisions). */ tmp = schizo_read(p->controller_regs + SCHIZO_PCIA_DIAG); tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB); schizo_write(p->controller_regs + SCHIZO_PCIA_DIAG, tmp); tmp = schizo_read(p->controller_regs + SCHIZO_PCIB_DIAG); tmp |= (SCHIZO_PCIDIAG_D_TTO | SCHIZO_PCIDIAG_D_RTRYARB); schizo_write(p->controller_regs + SCHIZO_PCIB_DIAG, 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 + -