📄 pci_sabre.c
字号:
{ struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->controller_regs + SABRE_CE_AFSR; unsigned long afar_reg = p->controller_regs + SABRE_UECE_AFAR; unsigned long afsr, afar, error_bits; int reported; /* Latch error status. */ afar = sabre_read(afar_reg); afsr = sabre_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR); if (!error_bits) return; sabre_write(afsr_reg, error_bits); /* Log the error. */ printk("SABRE%d: Correctable Error, primary error type[%s]\n", p->index, ((error_bits & SABRE_CEAFSR_PDRD) ? "DMA Read" : ((error_bits & SABRE_CEAFSR_PDWR) ? "DMA Write" : "???"))); /* XXX Use syndrome and afar to print out module string just like * XXX UDB CE trap handler does... -DaveM */ printk("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " "was_block(%d)\n", p->index, (afsr & SABRE_CEAFSR_ESYND) >> 48UL, (afsr & SABRE_CEAFSR_BMSK) >> 32UL, (afsr & SABRE_CEAFSR_OFF) >> 29UL, ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0)); printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar); printk("SABRE%d: CE Secondary errors [", p->index); reported = 0; if (afsr & SABRE_CEAFSR_SDRD) { reported++; printk("(DMA Read)"); } if (afsr & SABRE_CEAFSR_SDWR) { reported++; printk("(DMA Write)"); } if (!reported) printk("(none)"); printk("]\n");}static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs){ struct pci_controller_info *p = dev_id; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; int reported; afsr_reg = p->controller_regs + SABRE_PIOAFSR; afar_reg = p->controller_regs + SABRE_PIOAFAR; /* Latch error status. */ afar = sabre_read(afar_reg); afsr = sabre_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA | SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR); if (!error_bits) return; sabre_write(afsr_reg, error_bits); /* Log the error. */ printk("SABRE%d: PCI Error, primary error type[%s]\n", p->index, (((error_bits & SABRE_PIOAFSR_PMA) ? "Master Abort" : ((error_bits & SABRE_PIOAFSR_PTA) ? "Target Abort" : ((error_bits & SABRE_PIOAFSR_PRTRY) ? "Excessive Retries" : ((error_bits & SABRE_PIOAFSR_PPERR) ? "Parity Error" : "???")))))); printk("SABRE%d: bytemask[%04lx] was_block(%d)\n", p->index, (afsr & SABRE_PIOAFSR_BMSK) >> 32UL, (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0); printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar); printk("SABRE%d: PCI Secondary errors [", p->index); reported = 0; if (afsr & SABRE_PIOAFSR_SMA) { reported++; printk("(Master Abort)"); } if (afsr & SABRE_PIOAFSR_STA) { reported++; printk("(Target Abort)"); } if (afsr & SABRE_PIOAFSR_SRTRY) { reported++; printk("(Excessive Retries)"); } if (afsr & SABRE_PIOAFSR_SPERR) { reported++; printk("(Parity Error)"); } if (!reported) printk("(none)"); printk("]\n"); /* For the error types shown, scan both PCI buses for devices * which have logged that error type. */ /* If we see a Target Abort, this could be the result of an * IOMMU translation error of some sort. It is extremely * useful to log this information as usually it indicates * a bug in the IOMMU support code or a PCI device driver. */ if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) { sabre_check_iommu_error(p, afsr, afar); pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus); pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus); } if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) { pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus); pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus); } /* For excessive retries, SABRE/PBM will abort the device * and there is no way to specifically check for excessive * retries in the config space status registers. So what * we hope is that we'll catch it via the master/target * abort events. */ if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) { pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus); pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus); }}/* XXX What about PowerFail/PowerManagement??? -DaveM */#define SABRE_UE_INO 0x2e#define SABRE_CE_INO 0x2f#define SABRE_PCIERR_INO 0x30static void __init sabre_register_error_handlers(struct pci_controller_info *p){ struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ unsigned long base = p->controller_regs; unsigned long irq, portid = p->portid; u64 tmp; /* We clear the error bits in the appropriate AFSR before * registering the handler so that we don't get spurious * interrupts. */ sabre_write(base + SABRE_UE_AFSR, (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR | SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR | SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE)); irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_UE_INO); if (request_irq(irq, sabre_ue_intr, SA_SHIRQ, "SABRE UE", p) < 0) { prom_printf("SABRE%d: Cannot register UE interrupt.\n", p->index); prom_halt(); } sabre_write(base + SABRE_CE_AFSR, (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR | SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR)); irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_CE_INO); if (request_irq(irq, sabre_ce_intr, SA_SHIRQ, "SABRE CE", p) < 0) { prom_printf("SABRE%d: Cannot register CE interrupt.\n", p->index); prom_halt(); } irq = sabre_irq_build(pbm, NULL, (portid << 6) | SABRE_PCIERR_INO); if (request_irq(irq, sabre_pcierr_intr, SA_SHIRQ, "SABRE PCIERR", p) < 0) { prom_printf("SABRE%d: Cannot register PciERR interrupt.\n", p->index); prom_halt(); } tmp = sabre_read(base + SABRE_PCICTRL); tmp |= SABRE_PCICTRL_ERREN; sabre_write(base + SABRE_PCICTRL, tmp);}static void __init sabre_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root){ struct pci_pbm_info *pbm = pci_bus2pbm[pdev->bus->number]; struct pci_controller_info *p = pbm->parent; unsigned long base; if (res->flags & IORESOURCE_IO) base = p->controller_regs + SABRE_IOSPACE; else base = p->controller_regs + SABRE_MEMSPACE; res->start += base; res->end += base;}static void __init sabre_base_address_update(struct pci_dev *pdev, int resource){ struct pcidev_cookie *pcp = pdev->sysdata; struct pci_pbm_info *pbm = pcp->pbm; struct pci_controller_info *p = pbm->parent; struct resource *res; unsigned long base; 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) base = p->controller_regs + SABRE_IOSPACE; else { base = p->controller_regs + SABRE_MEMSPACE; 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 - base)) & ~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 apb_init(struct pci_controller_info *p, struct pci_bus *sabre_bus){ struct list_head *walk = &sabre_bus->devices; for (walk = walk->next; walk != &sabre_bus->devices; walk = walk->next) { struct pci_dev *pdev = pci_dev_b(walk); if (pdev->vendor == PCI_VENDOR_ID_SUN && pdev->device == PCI_DEVICE_ID_SUN_SIMBA) { u16 word; sabre_read_word(pdev, PCI_COMMAND, &word); word |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; sabre_write_word(pdev, PCI_COMMAND, word); /* Status register bits are "write 1 to clear". */ sabre_write_word(pdev, PCI_STATUS, 0xffff); sabre_write_word(pdev, PCI_SEC_STATUS, 0xffff); /* Use a primary/seconday latency timer value * of 64. */ sabre_write_byte(pdev, PCI_LATENCY_TIMER, 64); sabre_write_byte(pdev, PCI_SEC_LATENCY_TIMER, 64); /* Enable reporting/forwarding of master aborts, * parity, and SERR. */ sabre_write_byte(pdev, PCI_BRIDGE_CONTROL, (PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_MASTER_ABORT)); } }}static struct pcidev_cookie *alloc_bridge_cookie(struct pci_pbm_info *pbm){ struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); if (!cookie) { prom_printf("SABRE: Critical allocation failure.\n"); prom_halt(); } /* All we care about is the PBM. */ memset(cookie, 0, sizeof(*cookie)); cookie->pbm = pbm; return cookie;}static void __init sabre_scan_bus(struct pci_controller_info *p){ static int once; struct pci_bus *sabre_bus; struct pci_pbm_info *pbm; struct pcidev_cookie *cookie; struct list_head *walk; int sabres_scanned; /* The APB bridge speaks to the Sabre host PCI bridge * at 66Mhz, but the front side of APB runs at 33Mhz * for both segments. */ p->pbm_A.is_66mhz_capable = 0; p->pbm_B.is_66mhz_capable = 0; /* Unlike for PSYCHO, we can only have one SABRE * in a system. Having multiple SABREs is thus * and error, and as a consequence we do not need * to do any bus renumbering but we do have to have * the pci_bus2pbm array setup properly. * * Also note that the SABRE host bridge is hardwired * to live at bus 0. */ if (once != 0) { prom_printf("SABRE: Multiple controllers unsupported.\n"); prom_halt(); } once++; cookie = alloc_bridge_cookie(&p->pbm_A); /* The pci_bus2pbm table has already been setup in sabre_init. */ sabre_bus = pci_scan_bus(p->pci_first_busno, p->pci_ops, &p->pbm_A); pci_fixup_host_bridge_self(sabre_bus); sabre_bus->self->sysdata = cookie; apb_init(p, sabre_bus); sabres_scanned = 0; walk = &sabre_bus->children; for (walk = walk->next; walk != &sabre_bus->children; walk = walk->next) { struct pci_bus *pbus = pci_bus_b(walk); if (pbus->number == p->pbm_A.pci_first_busno) { pbm = &p->pbm_A; } else if (pbus->number == p->pbm_B.pci_first_busno) { pbm = &p->pbm_B; } else continue; cookie = alloc_bridge_cookie(pbm); pbus->self->sysdata = cookie; sabres_scanned++; pbus->sysdata = pbm; pbm->pci_bus = pbus; pci_fill_in_pbm_cookies(pbus, pbm, pbm->prom_node); pci_record_assignments(pbm, pbus); pci_assign_unassigned(pbm, pbus); pci_fixup_irq(pbm, pbus); pci_determine_66mhz_disposition(pbm, pbus); pci_setup_busmastering(pbm, pbus); } if (!sabres_scanned) { /* Hummingbird, no APBs. */ pbm = &p->pbm_A; sabre_bus->sysdata = pbm; pbm->pci_bus = sabre_bus; pci_fill_in_pbm_cookies(sabre_bus, pbm, pbm->prom_node); pci_record_assignments(pbm, sabre_bus); pci_assign_unassigned(pbm, sabre_bus); pci_fixup_irq(pbm, sabre_bus); pci_determine_66mhz_disposition(pbm, sabre_bus); pci_setup_busmastering(pbm, sabre_bus); } sabre_register_error_handlers(p);}static void __init sabre_iommu_init(struct pci_controller_info *p, int tsbsize, unsigned long dvma_offset, u32 dma_mask){ struct pci_iommu *iommu = p->pbm_A.iommu; unsigned long tsbbase, i, order; u64 control; /* Setup initial software IOMMU state. */ spin_lock_init(&iommu->lock); iommu->iommu_cur_ctx = 0; /* Register addresses. */ iommu->iommu_control = p->controller_regs + SABRE_IOMMU_CONTROL; iommu->iommu_tsbbase = p->controller_regs + SABRE_IOMMU_TSBBASE; iommu->iommu_flush = p->controller_regs + SABRE_IOMMU_FLUSH; iommu->write_complete_reg = p->controller_regs + SABRE_WRSYNC; /* Sabre's IOMMU lacks ctx flushing. */ iommu->iommu_ctxflush = 0; /* Invalidate TLB Entries. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -