📄 pci_psycho.c
字号:
if (!reported) printk("(none)"); printk("]\n"); /* Interrogate IOMMU for error status. */ psycho_check_iommu_error(p, afsr, afar, UE_ERR); return IRQ_HANDLED;}/* Correctable Errors. */#define PSYCHO_CE_AFSR 0x0040UL#define PSYCHO_CEAFSR_PPIO 0x8000000000000000UL /* Primary PIO is cause */#define PSYCHO_CEAFSR_PDRD 0x4000000000000000UL /* Primary DVMA read is cause */#define PSYCHO_CEAFSR_PDWR 0x2000000000000000UL /* Primary DVMA write is cause */#define PSYCHO_CEAFSR_SPIO 0x1000000000000000UL /* Secondary PIO is cause */#define PSYCHO_CEAFSR_SDRD 0x0800000000000000UL /* Secondary DVMA read is cause */#define PSYCHO_CEAFSR_SDWR 0x0400000000000000UL /* Secondary DVMA write is cause*/#define PSYCHO_CEAFSR_RESV1 0x0300000000000000UL /* Reserved */#define PSYCHO_CEAFSR_ESYND 0x00ff000000000000UL /* Syndrome Bits */#define PSYCHO_CEAFSR_BMSK 0x0000ffff00000000UL /* Bytemask of failed transfer */#define PSYCHO_CEAFSR_DOFF 0x00000000e0000000UL /* Double Offset */#define PSYCHO_CEAFSR_MID 0x000000001f000000UL /* UPA MID causing the fault */#define PSYCHO_CEAFSR_BLK 0x0000000000800000UL /* Trans was block operation */#define PSYCHO_CEAFSR_RESV2 0x00000000007fffffUL /* Reserved */#define PSYCHO_CE_AFAR 0x0040ULstatic irqreturn_t psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs){ struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_A.controller_regs + PSYCHO_CE_AFSR; unsigned long afar_reg = p->pbm_A.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); if (!error_bits) return IRQ_NONE; 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"); return IRQ_HANDLED;}/* PCI Errors. They are signalled by the PCI bus module since they * are associated with a specific bus segment. */#define PSYCHO_PCI_AFSR_A 0x2010UL#define PSYCHO_PCI_AFSR_B 0x4010UL#define PSYCHO_PCIAFSR_PMA 0x8000000000000000UL /* Primary Master Abort Error */#define PSYCHO_PCIAFSR_PTA 0x4000000000000000UL /* Primary Target Abort Error */#define PSYCHO_PCIAFSR_PRTRY 0x2000000000000000UL /* Primary Excessive Retries */#define PSYCHO_PCIAFSR_PPERR 0x1000000000000000UL /* Primary Parity Error */#define PSYCHO_PCIAFSR_SMA 0x0800000000000000UL /* Secondary Master Abort Error */#define PSYCHO_PCIAFSR_STA 0x0400000000000000UL /* Secondary Target Abort Error */#define PSYCHO_PCIAFSR_SRTRY 0x0200000000000000UL /* Secondary Excessive Retries */#define PSYCHO_PCIAFSR_SPERR 0x0100000000000000UL /* Secondary Parity Error */#define PSYCHO_PCIAFSR_RESV1 0x00ff000000000000UL /* Reserved */#define PSYCHO_PCIAFSR_BMSK 0x0000ffff00000000UL /* Bytemask of failed transfer */#define PSYCHO_PCIAFSR_BLK 0x0000000080000000UL /* Trans was block operation */#define PSYCHO_PCIAFSR_RESV2 0x0000000040000000UL /* Reserved */#define PSYCHO_PCIAFSR_MID 0x000000003e000000UL /* MID causing the error */#define PSYCHO_PCIAFSR_RESV3 0x0000000001ffffffUL /* Reserved */#define PSYCHO_PCI_AFAR_A 0x2018UL#define PSYCHO_PCI_AFAR_B 0x4018ULstatic irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm_a){ unsigned long csr_reg, csr, csr_error_bits; irqreturn_t ret = IRQ_NONE; u16 stat; if (is_pbm_a) { csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL; } else { csr_reg = pbm->controller_regs + PSYCHO_PCIB_CTRL; } csr = psycho_read(csr_reg); csr_error_bits = csr & (PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_SERR); if (csr_error_bits) { /* Clear the errors. */ psycho_write(csr_reg, csr); /* Log 'em. */ if (csr_error_bits & PSYCHO_PCICTRL_SBH_ERR) printk("%s: PCI streaming byte hole error asserted.\n", pbm->name); if (csr_error_bits & PSYCHO_PCICTRL_SERR) printk("%s: PCI SERR signal asserted.\n", pbm->name); ret = IRQ_HANDLED; } pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat); if (stat & (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT | PCI_STATUS_SIG_SYSTEM_ERROR)) { printk("%s: PCI bus error, PCI_STATUS[%04x]\n", pbm->name, stat); pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff); ret = IRQ_HANDLED; } return ret;}static irqreturn_t 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->pbm_A.controller_regs + PSYCHO_PCI_AFSR_A; afar_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFAR_A; } else { afsr_reg = p->pbm_A.controller_regs + PSYCHO_PCI_AFSR_B; afar_reg = p->pbm_A.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); if (!error_bits) return psycho_pcierr_intr_other(pbm, is_pbm_a); 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); return IRQ_HANDLED;}/* XXX What about PowerFail/PowerManagement??? -DaveM */#define PSYCHO_ECC_CTRL 0x0020#define PSYCHO_ECCCTRL_EE 0x8000000000000000UL /* Enable ECC Checking */#define PSYCHO_ECCCTRL_UE 0x4000000000000000UL /* Enable UE Interrupts */#define PSYCHO_ECCCTRL_CE 0x2000000000000000UL /* 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 psycho_register_error_handlers(struct pci_controller_info *p){ struct pci_pbm_info *pbm = &p->pbm_A; /* arbitrary */ unsigned long base = p->pbm_A.controller_regs; unsigned int irq, portid = pbm->portid; u64 tmp; /* Build IRQs and register handlers. */ irq = psycho_irq_build(pbm, 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(pbm, 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(); } pbm = &p->pbm_A; irq = psycho_irq_build(pbm, 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(); } pbm = &p->pbm_B; irq = psycho_irq_build(pbm, 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_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIA_CTRL, tmp); tmp = psycho_read(base + PSYCHO_PCIB_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); psycho_write(base + PSYCHO_PCIB_CTRL, tmp);}/* PSYCHO boot time probing and initialization. */static void psycho_resource_adjust(struct pci_dev *pdev, struct resource *res, struct resource *root){ res->start += root->start; res->end += root->start;}static void 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]; 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -