📄 pci_schizo.c
字号:
prom_printf("%s: Cannot register CE interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | SCHIZO_PCIERR_A_INO)); if (request_irq(irq, schizo_pcierr_intr, SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); irq = schizo_irq_build(pbm, NULL, ((pbm->portid << 6) | SCHIZO_PCIERR_B_INO)); if (request_irq(irq, schizo_pcierr_intr, SA_SHIRQ, "TOMATILLO PCIERR", pbm) < 0) { prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); if (request_irq(irq, schizo_safarierr_intr, SA_SHIRQ, "TOMATILLO SERR", p) < 0) { prom_printf("%s: Cannot register SafariERR interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, (SCHIZO_ECCCTRL_EE | SCHIZO_ECCCTRL_UE | SCHIZO_ECCCTRL_CE)); schizo_write(p->pbm_B.controller_regs + SCHIZO_ECC_CTRL, (SCHIZO_ECCCTRL_EE | SCHIZO_ECCCTRL_UE | SCHIZO_ECCCTRL_CE)); /* Enable PCI Error interrupts and clear error * bits. */ err_mask = (SCHIZO_PCICTRL_BUS_UNUS | SCHIZO_PCICTRL_TTO_ERR | SCHIZO_PCICTRL_RTRY_ERR | SCHIZO_PCICTRL_SERR | SCHIZO_PCICTRL_EEN); err_no_mask = SCHIZO_PCICTRL_DTO_ERR; tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL); tmp |= err_mask; tmp &= ~err_no_mask; schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp); tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL); tmp |= err_mask; tmp &= ~err_no_mask; schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp); err_mask = (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | SCHIZO_PCIAFSR_STTO); schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, err_mask); schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, err_mask); err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SNOOP_GR | BUS_ERROR_SNOOP_PCI | BUS_ERROR_SNOOP_RD | BUS_ERROR_SNOOP_RDS | BUS_ERROR_SNOOP_RDSA | BUS_ERROR_SNOOP_OWN | BUS_ERROR_SNOOP_RDO | BUS_ERROR_WDATA_PERR | BUS_ERROR_CTRL_PERR | BUS_ERROR_SNOOP_ERR | BUS_ERROR_JBUS_ILL_B | BUS_ERROR_JBUS_ILL_C | BUS_ERROR_RD_PERR | BUS_ERROR_APERR | BUS_ERROR_UNMAP | BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT); schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL, (SCHIZO_SAFERRCTRL_EN | err_mask)); schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_ERRCTRL, (SCHIZO_SAFERRCTRL_EN | err_mask)); schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL, (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP))); schizo_write(p->pbm_B.controller_regs + SCHIZO_SAFARI_IRQCTRL, (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));}static void schizo_register_error_handlers(struct pci_controller_info *p){ struct pci_pbm_info *pbm; unsigned int irq; struct ino_bucket *bucket; u64 tmp, err_mask, err_no_mask; /* Build IRQs and register handlers. */ pbm = pbm_for_ino(p, SCHIZO_UE_INO); irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_UE_INO); if (request_irq(irq, schizo_ue_intr, SA_SHIRQ, "SCHIZO UE", p) < 0) { prom_printf("%s: Cannot register UE interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_UE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_CE_INO); irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_CE_INO); if (request_irq(irq, schizo_ce_intr, SA_SHIRQ, "SCHIZO CE", p) < 0) { prom_printf("%s: Cannot register CE interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_CE_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_A_INO); irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_A_INO); if (request_irq(irq, schizo_pcierr_intr, SA_SHIRQ, "SCHIZO PCIERR", pbm) < 0) { prom_printf("%s: Cannot register PBM A PciERR interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_A_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_PCIERR_B_INO); irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_PCIERR_B_INO); if (request_irq(irq, schizo_pcierr_intr, SA_SHIRQ, "SCHIZO PCIERR", &p->pbm_B) < 0) { prom_printf("%s: Cannot register PBM B PciERR interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_PCIERR_B_INO) + 4)); pbm = pbm_for_ino(p, SCHIZO_SERR_INO); irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | SCHIZO_SERR_INO); if (request_irq(irq, schizo_safarierr_intr, SA_SHIRQ, "SCHIZO SERR", p) < 0) { prom_printf("%s: Cannot register SafariERR interrupt.\n", pbm->name); prom_halt(); } bucket = __bucket(irq); tmp = upa_readl(bucket->imap); upa_writel(tmp, (pbm->pbm_regs + schizo_imap_offset(SCHIZO_SERR_INO) + 4)); /* Enable UE and CE interrupts for controller. */ schizo_write(p->pbm_A.controller_regs + SCHIZO_ECC_CTRL, (SCHIZO_ECCCTRL_EE | SCHIZO_ECCCTRL_UE | SCHIZO_ECCCTRL_CE)); err_mask = (SCHIZO_PCICTRL_BUS_UNUS | SCHIZO_PCICTRL_ESLCK | SCHIZO_PCICTRL_TTO_ERR | SCHIZO_PCICTRL_RTRY_ERR | SCHIZO_PCICTRL_SBH_ERR | SCHIZO_PCICTRL_SERR | SCHIZO_PCICTRL_EEN); err_no_mask = (SCHIZO_PCICTRL_DTO_ERR | SCHIZO_PCICTRL_SBH_INT); /* Enable PCI Error interrupts and clear error * bits for each PBM. */ tmp = schizo_read(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL); tmp |= err_mask; tmp &= ~err_no_mask; schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_CTRL, tmp); schizo_write(p->pbm_A.pbm_regs + SCHIZO_PCI_AFSR, (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); tmp = schizo_read(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL); tmp |= err_mask; tmp &= ~err_no_mask; schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_CTRL, tmp); schizo_write(p->pbm_B.pbm_regs + SCHIZO_PCI_AFSR, (SCHIZO_PCIAFSR_PMA | SCHIZO_PCIAFSR_PTA | SCHIZO_PCIAFSR_PRTRY | SCHIZO_PCIAFSR_PPERR | SCHIZO_PCIAFSR_PTTO | SCHIZO_PCIAFSR_PUNUS | SCHIZO_PCIAFSR_SMA | SCHIZO_PCIAFSR_STA | SCHIZO_PCIAFSR_SRTRY | SCHIZO_PCIAFSR_SPERR | SCHIZO_PCIAFSR_STTO | SCHIZO_PCIAFSR_SUNUS)); /* Make all Safari error conditions fatal except unmapped * errors which we make generate interrupts. */ err_mask = (BUS_ERROR_BADCMD | BUS_ERROR_SSMDIS | BUS_ERROR_BADMA | BUS_ERROR_BADMB | BUS_ERROR_BADMC | BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB | BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB | BUS_ERROR_CIQTO | BUS_ERROR_LPQTO | BUS_ERROR_SFPQTO | BUS_ERROR_UFPQTO | BUS_ERROR_APERR | BUS_ERROR_BUSERR | BUS_ERROR_TIMEOUT | BUS_ERROR_ILL);#if 1 /* XXX Something wrong with some Excalibur systems * XXX Sun is shipping. The behavior on a 2-cpu * XXX machine is that both CPU1 parity error bits * XXX are set and are immediately set again when * XXX their error status bits are cleared. Just * XXX ignore them for now. -DaveM */ err_mask &= ~(BUS_ERROR_CPU1PS | BUS_ERROR_CPU1PB | BUS_ERROR_CPU0PS | BUS_ERROR_CPU0PB);#endif schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_ERRCTRL, (SCHIZO_SAFERRCTRL_EN | err_mask)); schizo_write(p->pbm_A.controller_regs + SCHIZO_SAFARI_IRQCTRL, (SCHIZO_SAFIRQCTRL_EN | (BUS_ERROR_UNMAP)));}static void pbm_config_busmastering(struct pci_pbm_info *pbm){ u8 *addr; /* Set cache-line size to 64 bytes, this is actually * a nop but I do it for completeness. */ addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, 0, PCI_CACHE_LINE_SIZE); pci_config_write8(addr, 64 / sizeof(u32)); /* Set PBM latency timer to 64 PCI clocks. */ addr = schizo_pci_config_mkaddr(pbm, pbm->pci_first_busno, 0, PCI_LATENCY_TIMER); pci_config_write8(addr, 64);}static void pbm_scan_bus(struct pci_controller_info *p, struct pci_pbm_info *pbm){ struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) { prom_printf("%s: Critical allocation failure.\n", pbm->name); prom_halt(); } /* All we care about is the PBM. */ memset(cookie, 0, sizeof(*cookie)); cookie->pbm = pbm; pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); pci_fixup_host_bridge_self(pbm->pci_bus); pbm->pci_bus->self->sysdata = cookie; pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbm->pci_bus); pci_assign_unassigned(pbm, pbm->pci_bus); pci_fixup_irq(pbm, pbm->pci_bus); pci_determine_66mhz_disposition(pbm, pbm->pci_bus); pci_setup_busmastering(pbm, pbm->pci_bus);}static void __schizo_scan_bus(struct pci_controller_info *p, int chip_type){ if (!p->pbm_B.prom_node || !p->pbm_A.prom_node) { printk("PCI: Only one PCI bus module of controller found.\n"); printk("PCI: Ignoring entire controller.\n"); return; } pbm_config_busmastering(&p->pbm_B); p->pbm_B.is_66mhz_capable = prom_getbool(p->pbm_B.prom_node, "66mhz-capable"); pbm_config_busmastering(&p->pbm_A); p->pbm_A.is_66mhz_capable = prom_getbool(p->pbm_A.prom_node, "66mhz-capable"); 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. */ if (chip_type == PBM_CHIP_TYPE_TOMATILLO) tomatillo_register_error_handlers(p); else schizo_register_error_handlers(p);}static void schizo_scan_bus(struct pci_controller_info *p){ __schizo_scan_bus(p, PBM_CHIP_TYPE_SCHIZO);}static void tomatillo_scan_bus(struct pci_controller_info *p){ __schizo_scan_bus(p, PBM_CHIP_TYPE_TOMATILLO);}static void 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]; 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 |= IORESOURCE_ROM_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 schizo_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root){ res->start += root->start; res->end += root->start;}/* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -