📄 pci_psycho.c
字号:
/* Interrogate IOMMU for error status. */ psycho_check_iommu_error(p, afsr, afar, UE_ERR);}/* Correctable Errors. */#define PSYCHO_CE_AFSR 0x0040UL#define PSYCHO_CEAFSR_PPIO 0x8000000000000000 /* Primary PIO is cause */#define PSYCHO_CEAFSR_PDRD 0x4000000000000000 /* Primary DVMA read is cause */#define PSYCHO_CEAFSR_PDWR 0x2000000000000000 /* Primary DVMA write is cause */#define PSYCHO_CEAFSR_SPIO 0x1000000000000000 /* Secondary PIO is cause */#define PSYCHO_CEAFSR_SDRD 0x0800000000000000 /* Secondary DVMA read is cause */#define PSYCHO_CEAFSR_SDWR 0x0400000000000000 /* Secondary DVMA write is cause*/#define PSYCHO_CEAFSR_RESV1 0x0300000000000000 /* Reserved */#define PSYCHO_CEAFSR_ESYND 0x00ff000000000000 /* Syndrome Bits */#define PSYCHO_CEAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */#define PSYCHO_CEAFSR_DOFF 0x00000000e0000000 /* Double Offset */#define PSYCHO_CEAFSR_MID 0x000000001f000000 /* UPA MID causing the fault */#define PSYCHO_CEAFSR_BLK 0x0000000000800000 /* Trans was block operation */#define PSYCHO_CEAFSR_RESV2 0x00000000007fffff /* Reserved */#define PSYCHO_CE_AFAR 0x0040ULstatic void psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs){ struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->controller_regs + PSYCHO_CE_AFSR; unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR; unsigned long afsr, afar, error_bits; int reported; /* Latch error status. */ afar = psycho_read(afar_reg); afsr = psycho_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & (PSYCHO_CEAFSR_PPIO | PSYCHO_CEAFSR_PDRD | PSYCHO_CEAFSR_PDWR | PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR); psycho_write(afsr_reg, error_bits); /* Log the error. */ printk("PSYCHO%d: Correctable Error, primary error type[%s]\n", p->index, (((error_bits & PSYCHO_CEAFSR_PPIO) ? "PIO" : ((error_bits & PSYCHO_CEAFSR_PDRD) ? "DMA Read" : ((error_bits & PSYCHO_CEAFSR_PDWR) ? "DMA Write" : "???"))))); /* XXX Use syndrome and afar to print out module string just like * XXX UDB CE trap handler does... -DaveM */ printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " "UPA_MID[%02lx] was_block(%d)\n", p->index, (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL, (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL, (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL, (afsr & PSYCHO_CEAFSR_MID) >> 24UL, ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0)); printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar); printk("PSYCHO%d: CE Secondary errors [", p->index); reported = 0; if (afsr & PSYCHO_CEAFSR_SPIO) { reported++; printk("(PIO)"); } if (afsr & PSYCHO_CEAFSR_SDRD) { reported++; printk("(DMA Read)"); } if (afsr & PSYCHO_CEAFSR_SDWR) { reported++; printk("(DMA Write)"); } if (!reported) printk("(none)"); printk("]\n");}/* PCI Errors. They are signalled by the PCI bus module since they * are assosciated with a specific bus segment. */#define PSYCHO_PCI_AFSR_A 0x2010UL#define PSYCHO_PCI_AFSR_B 0x4010UL#define PSYCHO_PCIAFSR_PMA 0x8000000000000000 /* Primary Master Abort Error */#define PSYCHO_PCIAFSR_PTA 0x4000000000000000 /* Primary Target Abort Error */#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000 /* Primary Excessive Retries */#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000 /* Primary Parity Error */#define PSYCHO_PCIAFSR_SMA 0x0800000000000000 /* Secondary Master Abort Error */#define PSYCHO_PCIAFSR_STA 0x0400000000000000 /* Secondary Target Abort Error */#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000 /* Secondary Excessive Retries */#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000 /* Secondary Parity Error */#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000 /* Reserved */#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000 /* Bytemask of failed transfer */#define PSYCHO_PCIAFSR_BLK 0x0000000080000000 /* Trans was block operation */#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000 /* Reserved */#define PSYCHO_PCIAFSR_MID 0x000000003e000000 /* MID causing the error */#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffff /* Reserved */#define PSYCHO_PCI_AFAR_A 0x2018UL#define PSYCHO_PCI_AFAR_B 0x4018ULstatic void psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs){ struct pci_pbm_info *pbm = dev_id; struct pci_controller_info *p = pbm->parent; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; int is_pbm_a, reported; is_pbm_a = (pbm == &pbm->parent->pbm_A); if (is_pbm_a) { afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A; afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A; } else { afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B; afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B; } /* Latch error status. */ afar = psycho_read(afar_reg); afsr = psycho_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = afsr & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA | PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR); psycho_write(afsr_reg, error_bits); /* Log the error. */ printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n", p->index, (is_pbm_a ? 'A' : 'B'), (((error_bits & PSYCHO_PCIAFSR_PMA) ? "Master Abort" : ((error_bits & PSYCHO_PCIAFSR_PTA) ? "Target Abort" : ((error_bits & PSYCHO_PCIAFSR_PRTRY) ? "Excessive Retries" : ((error_bits & PSYCHO_PCIAFSR_PPERR) ? "Parity Error" : "???")))))); printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n", p->index, (is_pbm_a ? 'A' : 'B'), (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL, (afsr & PSYCHO_PCIAFSR_MID) >> 25UL, (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0); printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n", p->index, (is_pbm_a ? 'A' : 'B'), afar); printk("PSYCHO%d(PBM%c): PCI Secondary errors [", p->index, (is_pbm_a ? 'A' : 'B')); reported = 0; if (afsr & PSYCHO_PCIAFSR_SMA) { reported++; printk("(Master Abort)"); } if (afsr & PSYCHO_PCIAFSR_STA) { reported++; printk("(Target Abort)"); } if (afsr & PSYCHO_PCIAFSR_SRTRY) { reported++; printk("(Excessive Retries)"); } if (afsr & PSYCHO_PCIAFSR_SPERR) { reported++; printk("(Parity Error)"); } if (!reported) printk("(none)"); printk("]\n"); /* For the error types shown, scan PBM's PCI bus 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 & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) { psycho_check_iommu_error(p, afsr, afar, PCI_ERR); pci_scan_for_target_abort(p, pbm, pbm->pci_bus); } if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA)) pci_scan_for_master_abort(p, pbm, pbm->pci_bus); /* For excessive retries, PSYCHO/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 & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR)) pci_scan_for_parity_error(p, pbm, pbm->pci_bus);}/* XXX What about PowerFail/PowerManagement??? -DaveM */#define PSYCHO_ECC_CTRL 0x0020#define PSYCHO_ECCCTRL_EE 0x8000000000000000 /* Enable ECC Checking */#define PSYCHO_ECCCTRL_UE 0x4000000000000000 /* Enable UE Interrupts */#define PSYCHO_ECCCTRL_CE 0x2000000000000000 /* Enable CE INterrupts */#define PSYCHO_UE_INO 0x2e#define PSYCHO_CE_INO 0x2f#define PSYCHO_PCIERR_A_INO 0x30#define PSYCHO_PCIERR_B_INO 0x31static void __init psycho_register_error_handlers(struct pci_controller_info *p){ unsigned long base = p->controller_regs; unsigned int irq, portid = p->portid; u64 tmp; /* Build IRQs and register handlers. */ irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO); if (request_irq(irq, psycho_ue_intr, SA_SHIRQ, "PSYCHO UE", p) < 0) { prom_printf("PSYCHO%d: Cannot register UE interrupt.\n", p->index); prom_halt(); } irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO); if (request_irq(irq, psycho_ce_intr, SA_SHIRQ, "PSYCHO CE", p) < 0) { prom_printf("PSYCHO%d: Cannot register CE interrupt.\n", p->index); prom_halt(); } irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO); if (request_irq(irq, psycho_pcierr_intr, SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) { prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n", p->index); prom_halt(); } irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO); if (request_irq(irq, psycho_pcierr_intr, SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) { prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n", p->index); prom_halt(); } /* Enable UE and CE interrupts for controller. */ psycho_write(base + PSYCHO_ECC_CTRL, (PSYCHO_ECCCTRL_EE | PSYCHO_ECCCTRL_UE | PSYCHO_ECCCTRL_CE)); /* Enable PCI Error interrupts and clear error * bits for each PBM. */ tmp = psycho_read(base + PSYCHO_PCIA_CTRL); tmp |= (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_INT | PSYCHO_PCICTRL_EEN); psycho_write(base + PSYCHO_PCIA_CTRL, tmp); tmp = psycho_read(base + PSYCHO_PCIB_CTRL); tmp |= (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_INT | PSYCHO_PCICTRL_EEN); psycho_write(base + PSYCHO_PCIB_CTRL, tmp);}/* PSYCHO boot time probing and initialization. */static void __init psycho_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root){ res->start += root->start; res->end += root->start;}static void __init psycho_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);}/* We have to do the config space accesses by hand, thus... */#define PBM_BRIDGE_BUS 0x40#define PBM_BRIDGE_SUBORDINATE 0x41static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno){ u8 *addr, busno; int nbus; busno = pci_highest_busnum; nbus = pbm->pci_last_busno - pbm->pci_first_busno; addr = psycho_pci_config_mkaddr(pbm, orig_busno, 0, PBM_BRIDGE_BUS); pci_config_write8(addr, busno); addr = psycho_pci_config_mkaddr(pbm, busno, 0, PBM_BRIDGE_SUBORDINATE); pci_config_write8(addr, busno + nbus); pbm->pci_first_busno = busno; pbm->pci_last_busno = busno + nbus; pci_highest_busnum = busno + nbus + 1; do { pci_bus2pbm[busno++] = pbm; } while (nbus--);}/* We have to do the config space accesses by hand here since * the pci_bus2pbm array is not ready yet. */static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm, u8 busno){ u32 devfn, l, class; u8 hdr_type; int is_multi = 0; for(devfn = 0; devfn < 0xff; ++devfn) { u32 *dwaddr; u8 *baddr; if (PCI_FUNC(devfn) != 0 && is_multi == 0) continue; /* Anything there? */ dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID); l = 0xffffffff; pci_config_read32(dwaddr, &l); if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000) { is_multi = 0; continue; } baddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE); pci_config_read8(baddr, &hdr_type); if (PCI_FUNC(devfn) == 0) is_multi = hdr_type & 0x80; dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION); class = 0xffffffff; pci_config_read32(dwaddr, &class); if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) { u32 buses = 0xffffffff; dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_PRIMARY_BUS); pci_config_read32(dwaddr, &buses); pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff); buses &= 0xff000000; pci_config_write32(dwaddr, buses); } }}static void __init pbm_bridge_reconfigure(struct pci_controller_info *p){ struct pci_pbm_info *pbm; u8 *addr; /* Clear out primary/secondary/subordinate bus numbers on
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -