📄 pci_schizo.c
字号:
if (pbm == &p->pbm_A) regbase += SCHIZO_PBM_A_REGS_OFF; else regbase += SCHIZO_PBM_B_REGS_OFF; err_base = regbase + SCHIZO_STC_ERR; tag_base = regbase + SCHIZO_STC_TAG; line_base = regbase + SCHIZO_STC_LINE; spin_lock(&stc_buf_lock); /* This is __REALLY__ dangerous. When we put the * streaming buffer into diagnostic mode to probe * it's tags and error status, we _must_ clear all * of the line tag valid bits before re-enabling * the streaming buffer. If any dirty data lives * in the STC when we do this, we will end up * invalidating it before it has a chance to reach * main memory. */ control = schizo_read(strbuf->strbuf_control); schizo_write(strbuf->strbuf_control, (control | SCHIZO_STRBUF_CTRL_DENAB)); for (i = 0; i < 128; i++) { unsigned long val; val = schizo_read(err_base + (i * 8UL)); schizo_write(err_base + (i * 8UL), 0UL); stc_error_buf[i] = val; } for (i = 0; i < 16; i++) { stc_tag_buf[i] = schizo_read(tag_base + (i * 8UL)); stc_line_buf[i] = schizo_read(line_base + (i * 8UL)); schizo_write(tag_base + (i * 8UL), 0UL); schizo_write(line_base + (i * 8UL), 0UL); } /* OK, state is logged, exit diagnostic mode. */ schizo_write(strbuf->strbuf_control, control); for (i = 0; i < 16; i++) { int j, saw_error, first, last; saw_error = 0; first = i * 8; last = first + 8; for (j = first; j < last; j++) { unsigned long errval = stc_error_buf[j]; if (errval != 0) { saw_error++; printk("SCHIZO%d: PBM-%c STC_ERR(%d)[wr(%d)rd(%d)]\n", p->index, pbm_name, j, (errval & SCHIZO_STCERR_WRITE) ? 1 : 0, (errval & SCHIZO_STCERR_READ) ? 1 : 0); } } if (saw_error != 0) { unsigned long tagval = stc_tag_buf[i]; unsigned long lineval = stc_line_buf[i]; printk("SCHIZO%d: PBM-%c STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n", p->index, pbm_name, i, ((tagval & SCHIZO_STCTAG_PPN) >> 19UL), (tagval & SCHIZO_STCTAG_VPN), ((tagval & SCHIZO_STCTAG_VALID) ? 1 : 0), ((tagval & SCHIZO_STCTAG_READ) ? 1 : 0)); /* XXX Should spit out per-bank error information... -DaveM */ printk("SCHIZO%d: PBM-%c STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" "V(%d)FOFN(%d)]\n", p->index, pbm_name, i, ((lineval & SCHIZO_STCLINE_LINDX) >> 23UL), ((lineval & SCHIZO_STCLINE_SPTR) >> 13UL), ((lineval & SCHIZO_STCLINE_LADDR) >> 6UL), ((lineval & SCHIZO_STCLINE_EPTR) >> 0UL), ((lineval & SCHIZO_STCLINE_VALID) ? 1 : 0), ((lineval & SCHIZO_STCLINE_FOFN) ? 1 : 0)); } } spin_unlock(&stc_buf_lock);}/* IOMMU is per-PBM in Schizo, so interrogate both for anonymous * controller level errors. */#define SCHIZO_IOMMU_TAG 0xa580UL#define SCHIZO_IOMMU_DATA 0xa600UL#define SCHIZO_IOMMU_TAG_CTXT 0x0000001ffe000000UL#define SCHIZO_IOMMU_TAG_ERRSTS 0x0000000001800000UL#define SCHIZO_IOMMU_TAG_ERR 0x0000000000400000UL#define SCHIZO_IOMMU_TAG_WRITE 0x0000000000200000UL#define SCHIZO_IOMMU_TAG_STREAM 0x0000000000100000UL#define SCHIZO_IOMMU_TAG_SIZE 0x0000000000080000UL#define SCHIZO_IOMMU_TAG_VPAGE 0x000000000007ffffUL#define SCHIZO_IOMMU_DATA_VALID 0x0000000100000000UL#define SCHIZO_IOMMU_DATA_CACHE 0x0000000040000000UL#define SCHIZO_IOMMU_DATA_PPAGE 0x000000003fffffffULstatic void schizo_check_iommu_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type){ struct pci_controller_info *p = pbm->parent; struct pci_iommu *iommu = pbm->iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; u64 control; char pbm_name = (pbm == &p->pbm_A ? 'A' : 'B'); int i; spin_lock_irqsave(&iommu->lock, flags); control = schizo_read(iommu->iommu_control); if (control & SCHIZO_IOMMU_CTRL_XLTEERR) { unsigned long base; char *type_string; /* Clear the error encountered bit. */ control &= ~SCHIZO_IOMMU_CTRL_XLTEERR; schizo_write(iommu->iommu_control, control); switch((control & SCHIZO_IOMMU_CTRL_XLTESTAT) >> 25UL) { case 0: type_string = "Protection Error"; break; case 1: type_string = "Invalid Error"; break; case 2: type_string = "TimeOut Error"; break; case 3: default: type_string = "ECC Error"; break; }; printk("SCHIZO%d: PBM-%c IOMMU Error, type[%s]\n", p->index, pbm_name, type_string); /* Put the IOMMU into diagnostic mode and probe * it's TLB for entries with error status. * * It is very possible for another DVMA to occur * while we do this probe, and corrupt the system * further. But we are so screwed at this point * that we are likely to crash hard anyways, so * get as much diagnostic information to the * console as we can. */ schizo_write(iommu->iommu_control, control | SCHIZO_IOMMU_CTRL_DENAB); base = p->controller_regs; if (pbm == &p->pbm_A) base += SCHIZO_PBM_A_REGS_OFF; else base += SCHIZO_PBM_B_REGS_OFF; for (i = 0; i < 16; i++) { iommu_tag[i] = schizo_read(base + SCHIZO_IOMMU_TAG + (i * 8UL)); iommu_data[i] = schizo_read(base + SCHIZO_IOMMU_DATA + (i * 8UL)); /* Now clear out the entry. */ schizo_write(base + SCHIZO_IOMMU_TAG + (i * 8UL), 0); schizo_write(base + SCHIZO_IOMMU_DATA + (i * 8UL), 0); } /* Leave diagnostic mode. */ schizo_write(iommu->iommu_control, control); for (i = 0; i < 16; i++) { unsigned long tag, data; tag = iommu_tag[i]; if (!(tag & SCHIZO_IOMMU_TAG_ERR)) continue; data = iommu_data[i]; switch((tag & SCHIZO_IOMMU_TAG_ERRSTS) >> 23UL) { case 0: type_string = "Protection Error"; break; case 1: type_string = "Invalid Error"; break; case 2: type_string = "TimeOut Error"; break; case 3: default: type_string = "ECC Error"; break; }; printk("SCHIZO%d: PBM-%c IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) " "sz(%dK) vpg(%08lx)]\n", p->index, pbm_name, i, type_string, (int)((tag & SCHIZO_IOMMU_TAG_CTXT) >> 25UL), ((tag & SCHIZO_IOMMU_TAG_WRITE) ? 1 : 0), ((tag & SCHIZO_IOMMU_TAG_STREAM) ? 1 : 0), ((tag & SCHIZO_IOMMU_TAG_SIZE) ? 64 : 8), (tag & SCHIZO_IOMMU_TAG_VPAGE) << IOMMU_PAGE_SHIFT); printk("SCHIZO%d: PBM-%c IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", p->index, pbm_name, i, ((data & SCHIZO_IOMMU_DATA_VALID) ? 1 : 0), ((data & SCHIZO_IOMMU_DATA_CACHE) ? 1 : 0), (data & SCHIZO_IOMMU_DATA_PPAGE) << IOMMU_PAGE_SHIFT); } } __schizo_check_stc_error_pbm(pbm, type); spin_unlock_irqrestore(&iommu->lock, flags);}static void schizo_check_iommu_error(struct pci_controller_info *p, enum schizo_error_type type){ schizo_check_iommu_error_pbm(&p->pbm_A, type); schizo_check_iommu_error_pbm(&p->pbm_B, type);}/* Uncorrectable ECC error status gathering. */#define SCHIZO_UE_AFSR 0x10030UL#define SCHIZO_UE_AFAR 0x10038UL#define SCHIZO_UEAFSR_PPIO 0x8000000000000000UL#define SCHIZO_UEAFSR_PDRD 0x4000000000000000UL#define SCHIZO_UEAFSR_PDWR 0x2000000000000000UL#define SCHIZO_UEAFSR_SPIO 0x1000000000000000UL#define SCHIZO_UEAFSR_SDMA 0x0800000000000000UL#define SCHIZO_UEAFSR_ERRPNDG 0x0300000000000000UL#define SCHIZO_UEAFSR_BMSK 0x000003ff00000000UL#define SCHIZO_UEAFSR_QOFF 0x00000000c0000000UL#define SCHIZO_UEAFSR_AID 0x000000001f000000UL#define SCHIZO_UEAFSR_PARTIAL 0x0000000000800000UL#define SCHIZO_UEAFSR_OWNEDIN 0x0000000000400000UL#define SCHIZO_UEAFSR_MTAGSYND 0x00000000000f0000UL#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffULstatic void schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs){ struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->controller_regs + SCHIZO_UE_AFSR; unsigned long afar_reg = p->controller_regs + SCHIZO_UE_AFAR; unsigned long afsr, afar, error_bits; int reported, limit; /* Latch uncorrectable error status. */ afar = schizo_read(afar_reg); /* If either of the error pending bits are set in the * AFSR, the error status is being actively updated by * the hardware and we must re-read to get a clean value. */ limit = 1000; do { afsr = schizo_read(afsr_reg); } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); /* Clear the primary/secondary error status bits. */ error_bits = afsr & (SCHIZO_UEAFSR_PPIO | SCHIZO_UEAFSR_PDRD | SCHIZO_UEAFSR_PDWR | SCHIZO_UEAFSR_SPIO | SCHIZO_UEAFSR_SDMA); if (!error_bits) return; schizo_write(afsr_reg, error_bits); /* Log the error. */ printk("SCHIZO%d: Uncorrectable Error, primary error type[%s]\n", p->index, (((error_bits & SCHIZO_UEAFSR_PPIO) ? "PIO" : ((error_bits & SCHIZO_UEAFSR_PDRD) ? "DMA Read" : ((error_bits & SCHIZO_UEAFSR_PDWR) ? "DMA Write" : "???"))))); printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", p->index, (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, (afsr & SCHIZO_UEAFSR_AID) >> 24UL); printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", p->index, (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); printk("SCHIZO%d: UE AFAR [%016lx]\n", p->index, afar); printk("SCHIZO%d: UE Secondary errors [", p->index); reported = 0; if (afsr & SCHIZO_UEAFSR_SPIO) { reported++; printk("(PIO)"); } if (afsr & SCHIZO_UEAFSR_SDMA) { reported++; printk("(DMA)"); } if (!reported) printk("(none)"); printk("]\n"); /* Interrogate IOMMU for error status. */ schizo_check_iommu_error(p, UE_ERR); schizo_clear_other_err_intr(irq);}#define SCHIZO_CE_AFSR 0x10040UL#define SCHIZO_CE_AFAR 0x10048UL#define SCHIZO_CEAFSR_PPIO 0x8000000000000000UL#define SCHIZO_CEAFSR_PDRD 0x4000000000000000UL#define SCHIZO_CEAFSR_PDWR 0x2000000000000000UL#define SCHIZO_CEAFSR_SPIO 0x1000000000000000UL#define SCHIZO_CEAFSR_SDMA 0x0800000000000000UL#define SCHIZO_CEAFSR_ERRPNDG 0x0300000000000000UL#define SCHIZO_CEAFSR_BMSK 0x000003ff00000000UL#define SCHIZO_CEAFSR_QOFF 0x00000000c0000000UL#define SCHIZO_CEAFSR_AID 0x000000001f000000UL#define SCHIZO_CEAFSR_PARTIAL 0x0000000000800000UL#define SCHIZO_CEAFSR_OWNEDIN 0x0000000000400000UL#define SCHIZO_CEAFSR_MTAGSYND 0x00000000000f0000UL#define SCHIZO_CEAFSR_MTAG 0x000000000000e000UL#define SCHIZO_CEAFSR_ECCSYND 0x00000000000001ffULstatic void schizo_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 + SCHIZO_CE_AFSR; unsigned long afar_reg = p->controller_regs + SCHIZO_CE_AFAR; unsigned long afsr, afar, error_bits; int reported, limit; /* Latch error status. */ afar = schizo_read(afar_reg); /* If either of the error pending bits are set in the * AFSR, the error status is being actively updated by * the hardware and we must re-read to get a clean value. */ limit = 1000; do { afsr = schizo_read(afsr_reg); } while ((afsr & SCHIZO_UEAFSR_ERRPNDG) != 0 && --limit); /* Clear primary/secondary error status bits. */ error_bits = afsr & (SCHIZO_CEAFSR_PPIO | SCHIZO_CEAFSR_PDRD | SCHIZO_CEAFSR_PDWR | SCHIZO_CEAFSR_SPIO | SCHIZO_CEAFSR_SDMA); if (!error_bits) return; schizo_write(afsr_reg, error_bits); /* Log the error. */ printk("SCHIZO%d: Correctable Error, primary error type[%s]\n", p->index, (((error_bits & SCHIZO_CEAFSR_PPIO) ? "PIO" : ((error_bits & SCHIZO_CEAFSR_PDRD) ? "DMA Read" : ((error_bits & SCHIZO_CEAFSR_PDWR) ? "DMA Write" : "???"))))); /* XXX Use syndrome and afar to print out module string just like * XXX UDB CE trap handler does... -DaveM */ printk("SCHIZO%d: bytemask[%04lx] qword_offset[%lx] SAFARI_AID[%02lx]\n", p->index, (afsr & SCHIZO_UEAFSR_BMSK) >> 32UL, (afsr & SCHIZO_UEAFSR_QOFF) >> 30UL, (afsr & SCHIZO_UEAFSR_AID) >> 24UL); printk("SCHIZO%d: partial[%d] owned_in[%d] mtag[%lx] mtag_synd[%lx] ecc_sync[%lx]\n", p->index, (afsr & SCHIZO_UEAFSR_PARTIAL) ? 1 : 0, (afsr & SCHIZO_UEAFSR_OWNEDIN) ? 1 : 0, (afsr & SCHIZO_UEAFSR_MTAG) >> 13UL, (afsr & SCHIZO_UEAFSR_MTAGSYND) >> 16UL, (afsr & SCHIZO_UEAFSR_ECCSYND) >> 0UL); printk("SCHIZO%d: CE AFAR [%016lx]\n", p->index, afar); printk("SCHIZO%d: CE Secondary errors [", p->index); reported = 0; if (afsr & SCHIZO_CEAFSR_SPIO) { reported++; printk("(PIO)"); } if (afsr & SCHIZO_CEAFSR_SDMA) { reported++; printk("(DMA)"); } if (!reported) printk("(none)"); printk("]\n"); schizo_clear_other_err_intr(irq);}#define SCHIZO_PCI_AFSR 0x2010UL#define SCHIZO_PCI_AFAR 0x2018UL#define SCHIZO_PCIAFSR_PMA 0x8000000000000000UL#define SCHIZO_PCIAFSR_PTA 0x4000000000000000UL#define SCHIZO_PCIAFSR_PRTRY 0x2000000000000000UL#define SCHIZO_PCIAFSR_PPERR 0x1000000000000000UL#define SCHIZO_PCIAFSR_PTTO 0x0800000000000000UL#define SCHIZO_PCIAFSR_PUNUS 0x0400000000000000UL#define SCHIZO_PCIAFSR_SMA 0x0200000000000000UL#define SCHIZO_PCIAFSR_STA 0x0100000000000000UL#define SCHIZO_PCIAFSR_SRTRY 0x0080000000000000UL#define SCHIZO_PCIAFSR_SPERR 0x0040000000000000UL#define SCHIZO_PCIAFSR_STTO 0x0020000000000000UL#define SCHIZO_PCIAFSR_SUNUS 0x0010000000000000UL#define SCHIZO_PCIAFSR_BMSK 0x000003ff00000000UL#define SCHIZO_PCIAFSR_BLK 0x0000000080000000UL#define SCHIZO_PCIAFSR_CFG 0x0000000040000000UL#define SCHIZO_PCIAFSR_MEM 0x0000000020000000UL#define SCHIZO_PCIAFSR_IO 0x0000000010000000ULstatic void schizo_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, base; unsigned long afsr, afar, error_bits; int reported; char pbm_name; base = p->controller_regs; if (pbm == &pbm->parent->pbm_A) { base += SCHIZO_PBM_A_REGS_OFF; pbm_name = 'A'; } else { base += SCHIZO_PBM_B_REGS_OFF; pbm_name = 'B'; } afsr_reg = base + SCHIZO_PCI_AFSR; afar_reg = base + SCHIZO_PCI_AFAR; /* Latch error status. */ afar = schizo_read(afar_reg); afsr = schizo_read(afsr_reg); /* Clear primary/secondary error status bits. */ error_bits = 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); if (!error_bits) return; schizo_write(afsr_reg, error_bits);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -