static void psycho_controller_hwinit(struct pci_pbm_info *pbm) { u64 tmp; upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY); /* Enable arbiter for all PCI slots. */ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL); tmp |= PSYCHO_PCICTRL_AEN; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL); tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL); tmp |= PSYCHO_PCICTRL_AEN; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL); /* Disable DMA write / PIO read synchronization on * both PCI bus segments. * [ U2P Erratum 1243770, STP2223BGA data sheet ] */ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG); tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG); }
static irqreturn_t psycho_ce_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; unsigned long afsr_reg = pbm->controller_regs + PSYCHO_CE_AFSR; unsigned long afar_reg = pbm->controller_regs + PSYCHO_CE_AFAR; unsigned long afsr, afar, error_bits; int reported; afar = upa_readq(afar_reg); afsr = upa_readq(afsr_reg); 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; upa_writeq(error_bits, afsr_reg); printk("%s: Correctable Error, primary error type[%s]\n", pbm->name, (((error_bits & PSYCHO_CEAFSR_PPIO) ? "PIO" : ((error_bits & PSYCHO_CEAFSR_PDRD) ? "DMA Read" : ((error_bits & PSYCHO_CEAFSR_PDWR) ? "DMA Write" : "???"))))); printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] " "UPA_MID[%02lx] was_block(%d)\n", pbm->name, (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("%s: CE AFAR [%016lx]\n", pbm->name, afar); printk("%s: CE Secondary errors [", pbm->name); 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; }
static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction) { unsigned long n; int limit; n = npages; while (n--) upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush); /* If the device could not have possibly put dirty data into * the streaming cache, no flush-flag synchronization needs * to be performed. */ if (direction == SBUS_DMA_TODEVICE) return; *(strbuf->strbuf_flushflag) = 0UL; /* Whoopee cushion! */ upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync); upa_readq(iommu->write_complete_reg); limit = 100000; while (*(strbuf->strbuf_flushflag) == 0UL) { limit--; if (!limit) break; udelay(1); rmb(); } if (!limit) printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout " "vaddr[%08x] npages[%ld]\n", base, npages); }
static void psycho_register_error_handlers(struct pci_pbm_info *pbm) { struct platform_device *op = of_find_device_by_node(pbm->op->dev.of_node); unsigned long base = pbm->controller_regs; u64 tmp; int err; if (!op) return; if (op->archdata.num_irqs < 6) return; err = request_irq(op->archdata.irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO_UE", pbm); err = request_irq(op->archdata.irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO_CE", pbm); err = request_irq(op->archdata.irqs[0], psycho_pcierr_intr, IRQF_SHARED, "PSYCHO_PCIERR", pbm); if (err) printk(KERN_WARNING "%s: Could not register PCIERR, " "err=%d\n", pbm->name, err); upa_writeq((PSYCHO_ECCCTRL_EE | PSYCHO_ECCCTRL_UE | PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL); tmp = upa_readq(base + PSYCHO_PCIA_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); upa_writeq(tmp, base + PSYCHO_PCIA_CTRL); tmp = upa_readq(base + PSYCHO_PCIB_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); upa_writeq(tmp, base + PSYCHO_PCIB_CTRL); }
static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, int is_pbm_a) { unsigned long base = pbm->controller_regs; u64 control; if (is_pbm_a) { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A; pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A; pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A; } else { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B; pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B; pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B; } /* PSYCHO's streaming buffer lacks ctx flushing. */ pbm->stc.strbuf_ctxflush = 0; pbm->stc.strbuf_ctxmatch_base = 0; pbm->stc.strbuf_flushflag = (volatile unsigned long *) ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + 63UL) & ~63UL); pbm->stc.strbuf_flushflag_pa = (unsigned long) __pa(pbm->stc.strbuf_flushflag); /* Enable the streaming buffer. We have to be careful * just in case OBP left it with LRU locking enabled. * * It is possible to control if PBM will be rerun on * line misses. Currently I just retain whatever setting * OBP left us with. All checks so far show it having * a value of zero. */ #undef PSYCHO_STRBUF_RERUN_ENABLE #undef PSYCHO_STRBUF_RERUN_DISABLE control = upa_readq(pbm->stc.strbuf_control); control |= PSYCHO_STRBUF_CTRL_ENAB; control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR); #ifdef PSYCHO_STRBUF_RERUN_ENABLE control &= ~(PSYCHO_STRBUF_CTRL_RRDIS); #else #ifdef PSYCHO_STRBUF_RERUN_DISABLE control |= PSYCHO_STRBUF_CTRL_RRDIS; #endif #endif upa_writeq(control, pbm->stc.strbuf_control); pbm->stc.strbuf_enabled = 1; }
static void psycho_controller_hwinit(struct pci_pbm_info *pbm) { u64 tmp; upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY); /* Enable arbiter for all PCI slots. */ tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL); tmp |= PSYCHO_PCICTRL_AEN; upa_wri
static void __iommu_flushall(struct sbus_iommu *iommu) { unsigned long tag = iommu->iommu_regs + IOMMU_TAGDIAG; int entry; for (entry = 0; entry < 16; entry++) { upa_writeq(0, tag); tag += 8UL; } upa_readq(iommu->sbus_control_reg); }
static void __iommu_flushall(struct iommu *iommu) { unsigned long tag; int entry; tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL); for (entry = 0; entry < 16; entry++) { upa_writeq(0, tag); tag += 8UL; } upa_readq(iommu->write_complete_reg); }
static void psycho_controller_hwinit(struct pci_pbm_info *pbm) { u64 tmp; upa_writeq(5, pbm->controller_regs + PSYCHO_IRQ_RETRY); tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_CTRL); tmp |= PSYCHO_PCICTRL_AEN; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_CTRL); tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_CTRL); tmp |= PSYCHO_PCICTRL_AEN; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_CTRL); tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIA_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIA_DIAG); tmp = upa_readq(pbm->controller_regs + PSYCHO_PCIB_DIAG); tmp |= PSYCHO_PCIDIAG_DDWSYNC; upa_writeq(tmp, pbm->controller_regs + PSYCHO_PCIB_DIAG); }
static void psycho_pbm_strbuf_init(struct pci_pbm_info *pbm, int is_pbm_a) { unsigned long base = pbm->controller_regs; u64 control; if (is_pbm_a) { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_A; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_A; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_A; pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_A; pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_A; pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_A; } else { pbm->stc.strbuf_control = base + PSYCHO_STRBUF_CONTROL_B; pbm->stc.strbuf_pflush = base + PSYCHO_STRBUF_FLUSH_B; pbm->stc.strbuf_fsync = base + PSYCHO_STRBUF_FSYNC_B; pbm->stc.strbuf_err_stat = base + PSYCHO_STC_ERR_B; pbm->stc.strbuf_tag_diag = base + PSYCHO_STC_TAG_B; pbm->stc.strbuf_line_diag= base + PSYCHO_STC_LINE_B; } pbm->stc.strbuf_ctxflush = 0; pbm->stc.strbuf_ctxmatch_base = 0; pbm->stc.strbuf_flushflag = (volatile unsigned long *) ((((unsigned long)&pbm->stc.__flushflag_buf[0]) + 63UL) & ~63UL); pbm->stc.strbuf_flushflag_pa = (unsigned long) __pa(pbm->stc.strbuf_flushflag); #undef PSYCHO_STRBUF_RERUN_ENABLE #undef PSYCHO_STRBUF_RERUN_DISABLE control = upa_readq(pbm->stc.strbuf_control); control |= PSYCHO_STRBUF_CTRL_ENAB; control &= ~(PSYCHO_STRBUF_CTRL_LENAB | PSYCHO_STRBUF_CTRL_LPTR); #ifdef PSYCHO_STRBUF_RERUN_ENABLE control &= ~(PSYCHO_STRBUF_CTRL_RRDIS); #else #ifdef PSYCHO_STRBUF_RERUN_DISABLE control |= PSYCHO_STRBUF_CTRL_RRDIS; #endif #endif upa_writeq(control, pbm->stc.strbuf_control); pbm->stc.strbuf_enabled = 1; }
/* 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 */ static void psycho_register_error_handlers(struct pci_pbm_info *pbm) { struct platform_device *op = of_find_device_by_node(pbm->op->dev.of_node); unsigned long base = pbm->controller_regs; u64 tmp; int err; if (!op) return; /* Psycho interrupt property order is: * 0: PCIERR INO for this PBM * 1: UE ERR * 2: CE ERR * 3: POWER FAIL * 4: SPARE HARDWARE * 5: POWER MANAGEMENT */ if (op->archdata.num_irqs < 6) return; /* We really mean to ignore the return result here. Two * PCI controller share the same interrupt numbers and * drive the same front-end hardware. */ err = request_irq(op->archdata.irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO_UE", pbm); err = request_irq(op->archdata.irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO_CE", pbm); /* This one, however, ought not to fail. We can just warn * about it since the system can still operate properly even * if this fails. */ err = request_irq(op->archdata.irqs[0], psycho_pcierr_intr, IRQF_SHARED, "PSYCHO_PCIERR", pbm); if (err) printk(KERN_WARNING "%s: Could not register PCIERR, " "err=%d\n", pbm->name, err); /* Enable UE and CE interrupts for controller. */ upa_writeq((PSYCHO_ECCCTRL_EE | PSYCHO_ECCCTRL_UE | PSYCHO_ECCCTRL_CE), base + PSYCHO_ECC_CTRL); /* Enable PCI Error interrupts and clear error * bits for each PBM. */ tmp = upa_readq(base + PSYCHO_PCIA_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); upa_writeq(tmp, base + PSYCHO_PCIA_CTRL); tmp = upa_readq(base + PSYCHO_PCIB_CTRL); tmp |= (PSYCHO_PCICTRL_SERR | PSYCHO_PCICTRL_SBH_ERR | PSYCHO_PCICTRL_EEN); tmp &= ~(PSYCHO_PCICTRL_SBH_INT); upa_writeq(tmp, base + PSYCHO_PCIB_CTRL); }
static irqreturn_t psycho_ue_intr(int irq, void *dev_id) { struct pci_pbm_info *pbm = dev_id; unsigned long afsr_reg = pbm->controller_regs + PSYCHO_UE_AFSR; unsigned long afar_reg = pbm->controller_regs + PSYCHO_UE_AFAR; unsigned long afsr, afar, error_bits; int reported; /* Latch uncorrectable error status. */ afar = upa_readq(afar_reg); afsr = upa_readq(afsr_reg); /* Clear the primary/secondary error status bits. */ error_bits = afsr & (PSYCHO_UEAFSR_PPIO | PSYCHO_UEAFSR_PDRD | PSYCHO_UEAFSR_PDWR | PSYCHO_UEAFSR_SPIO | PSYCHO_UEAFSR_SDRD | PSYCHO_UEAFSR_SDWR); if (!error_bits) return IRQ_NONE; upa_writeq(error_bits, afsr_reg); /* Log the error. */ printk("%s: Uncorrectable Error, primary error type[%s]\n", pbm->name, (((error_bits & PSYCHO_UEAFSR_PPIO) ? "PIO" : ((error_bits & PSYCHO_UEAFSR_PDRD) ? "DMA Read" : ((error_bits & PSYCHO_UEAFSR_PDWR) ? "DMA Write" : "???"))))); printk("%s: bytemask[%04lx] dword_offset[%lx] UPA_MID[%02lx] was_block(%d)\n", pbm->name, (afsr & PSYCHO_UEAFSR_BMSK) >> 32UL, (afsr & PSYCHO_UEAFSR_DOFF) >> 29UL, (afsr & PSYCHO_UEAFSR_MID) >> 24UL, ((afsr & PSYCHO_UEAFSR_BLK) ? 1 : 0)); printk("%s: UE AFAR [%016lx]\n", pbm->name, afar); printk("%s: UE Secondary errors [", pbm->name); reported = 0; if (afsr & PSYCHO_UEAFSR_SPIO) { reported++; printk("(PIO)"); } if (afsr & PSYCHO_UEAFSR_SDRD) { reported++; printk("(DMA Read)"); } if (afsr & PSYCHO_UEAFSR_SDWR) { reported++; printk("(DMA Write)"); } if (!reported) printk("(none)"); printk("]\n"); /* Interrogate both IOMMUs for error status. */ psycho_check_iommu_error(pbm, afsr, afar, UE_ERR); if (pbm->sibling) psycho_check_iommu_error(pbm->sibling, afsr, afar, UE_ERR); return IRQ_HANDLED; }