📄 pci_schizo.c
字号:
p->pre_handler_arg2 = (void *) pbm->sync_reg; } return __irq(bucket);}/* SCHIZO error handling support. */enum schizo_error_type { UE_ERR, CE_ERR, PCI_ERR, SAFARI_ERR};static DEFINE_SPINLOCK(stc_buf_lock);static unsigned long stc_error_buf[128];static unsigned long stc_tag_buf[16];static unsigned long stc_line_buf[16];#define SCHIZO_UE_INO 0x30 /* Uncorrectable ECC error */#define SCHIZO_CE_INO 0x31 /* Correctable ECC error */#define SCHIZO_PCIERR_A_INO 0x32 /* PBM A PCI bus error */#define SCHIZO_PCIERR_B_INO 0x33 /* PBM B PCI bus error */#define SCHIZO_SERR_INO 0x34 /* Safari interface error */struct pci_pbm_info *pbm_for_ino(struct pci_controller_info *p, u32 ino){ ino &= IMAP_INO; if (p->pbm_A.ino_bitmap & (1UL << ino)) return &p->pbm_A; if (p->pbm_B.ino_bitmap & (1UL << ino)) return &p->pbm_B; printk("PCI%d: No ino_bitmap entry for ino[%x], bitmaps " "PBM_A[%016lx] PBM_B[%016lx]", p->index, ino, p->pbm_A.ino_bitmap, p->pbm_B.ino_bitmap); printk("PCI%d: Using PBM_A, report this problem immediately.\n", p->index); return &p->pbm_A;}static void schizo_clear_other_err_intr(struct pci_controller_info *p, int irq){ struct pci_pbm_info *pbm; struct ino_bucket *bucket; unsigned long iclr; /* Do not clear the interrupt for the other PCI bus. * * This "ACK both PBM IRQs" only needs to be performed * for chip-wide error interrupts. */ if ((irq & IMAP_INO) == SCHIZO_PCIERR_A_INO || (irq & IMAP_INO) == SCHIZO_PCIERR_B_INO) return; pbm = pbm_for_ino(p, irq); if (pbm == &p->pbm_A) pbm = &p->pbm_B; else pbm = &p->pbm_A; irq = schizo_irq_build(pbm, NULL, (pbm->portid << 6) | (irq & IMAP_INO)); bucket = __bucket(irq); iclr = bucket->iclr; upa_writel(ICLR_IDLE, iclr);}#define SCHIZO_STC_ERR 0xb800UL /* --> 0xba00 */#define SCHIZO_STC_TAG 0xba00UL /* --> 0xba80 */#define SCHIZO_STC_LINE 0xbb00UL /* --> 0xbb80 */#define SCHIZO_STCERR_WRITE 0x2UL#define SCHIZO_STCERR_READ 0x1UL#define SCHIZO_STCTAG_PPN 0x3fffffff00000000UL#define SCHIZO_STCTAG_VPN 0x00000000ffffe000UL#define SCHIZO_STCTAG_VALID 0x8000000000000000UL#define SCHIZO_STCTAG_READ 0x4000000000000000UL#define SCHIZO_STCLINE_LINDX 0x0000000007800000UL#define SCHIZO_STCLINE_SPTR 0x000000000007e000UL#define SCHIZO_STCLINE_LADDR 0x0000000000001fc0UL#define SCHIZO_STCLINE_EPTR 0x000000000000003fUL#define SCHIZO_STCLINE_VALID 0x0000000000600000UL#define SCHIZO_STCLINE_FOFN 0x0000000000180000ULstatic void __schizo_check_stc_error_pbm(struct pci_pbm_info *pbm, enum schizo_error_type type){ struct pci_strbuf *strbuf = &pbm->stc; unsigned long regbase = pbm->pbm_regs; unsigned long err_base, tag_base, line_base; u64 control; int i; 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("%s: STC_ERR(%d)[wr(%d)rd(%d)]\n", 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("%s: STC_TAG(%d)[PA(%016lx)VA(%08lx)V(%d)R(%d)]\n", 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("%s: STC_LINE(%d)[LIDX(%lx)SP(%lx)LADDR(%lx)EP(%lx)" "V(%d)FOFN(%d)]\n", 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_iommu *iommu = pbm->iommu; unsigned long iommu_tag[16]; unsigned long iommu_data[16]; unsigned long flags; u64 control; 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("%s: IOMMU Error, type[%s]\n", 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 = pbm->pbm_regs; 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("%s: IOMMU TAG(%d)[error(%s) ctx(%x) wr(%d) str(%d) " "sz(%dK) vpg(%08lx)]\n", 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("%s: IOMMU DATA(%d)[valid(%d) cache(%d) ppg(%016lx)]\n", 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); } } if (pbm->stc.strbuf_enabled) __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 /* Safari */#define SCHIZO_UEAFSR_PDRD 0x4000000000000000UL /* Safari/Tomatillo */#define SCHIZO_UEAFSR_PDWR 0x2000000000000000UL /* Safari */#define SCHIZO_UEAFSR_SPIO 0x1000000000000000UL /* Safari */#define SCHIZO_UEAFSR_SDMA 0x0800000000000000UL /* Safari/Tomatillo */#define SCHIZO_UEAFSR_ERRPNDG 0x0300000000000000UL /* Safari */#define SCHIZO_UEAFSR_BMSK 0x000003ff00000000UL /* Safari */#define SCHIZO_UEAFSR_QOFF 0x00000000c0000000UL /* Safari/Tomatillo */#define SCHIZO_UEAFSR_AID 0x000000001f000000UL /* Safari/Tomatillo */#define SCHIZO_UEAFSR_PARTIAL 0x0000000000800000UL /* Safari */#define SCHIZO_UEAFSR_OWNEDIN 0x0000000000400000UL /* Safari */#define SCHIZO_UEAFSR_MTAGSYND 0x00000000000f0000UL /* Safari */#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL /* Safari */#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL /* Safari */static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs){ struct pci_controller_info *p = dev_id; unsigned long afsr_reg = p->pbm_B.controller_regs + SCHIZO_UE_AFSR; unsigned long afar_reg = p->pbm_B.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 IRQ_NONE; schizo_write(afsr_reg, error_bits); /* Log the error. */ printk("PCI%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("PCI%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("PCI%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("PCI%d: UE AFAR [%016lx]\n", p->index, afar); printk("PCI%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(p, irq); return IRQ_HANDLED;}#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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -