pci_schizo.c

来自「linux 内核源代码」· C语言 代码 · 共 1,492 行 · 第 1/4 页

C
1,492
字号
/* pci_schizo.c: SCHIZO/TOMATILLO specific PCI controller support. * * Copyright (C) 2001, 2002, 2003, 2007 David S. Miller (davem@davemloft.net) */#include <linux/kernel.h>#include <linux/types.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <asm/iommu.h>#include <asm/irq.h>#include <asm/upa.h>#include <asm/pstate.h>#include <asm/prom.h>#include <asm/of_device.h>#include <asm/oplib.h>#include "pci_impl.h"#include "iommu_common.h"/* All SCHIZO registers are 64-bits.  The following accessor * routines are how they are accessed.  The REG parameter * is a physical address. */#define schizo_read(__reg) \({	u64 __ret; \	__asm__ __volatile__("ldxa [%1] %2, %0" \			     : "=r" (__ret) \			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \			     : "memory"); \	__ret; \})#define schizo_write(__reg, __val) \	__asm__ __volatile__("stxa %0, [%1] %2" \			     : /* no outputs */ \			     : "r" (__val), "r" (__reg), \			       "i" (ASI_PHYS_BYPASS_EC_E) \			     : "memory")/* This is a convention that at least Excalibur and Merlin * follow.  I suppose the SCHIZO used in Starcat and friends * will do similar. * * The only way I could see this changing is if the newlink * block requires more space in Schizo's address space than * they predicted, thus requiring an address space reorg when * the newer Schizo is taped out. *//* Streaming buffer control register. */#define SCHIZO_STRBUF_CTRL_LPTR    0x00000000000000f0UL /* LRU Lock Pointer */#define SCHIZO_STRBUF_CTRL_LENAB   0x0000000000000008UL /* LRU Lock Enable */#define SCHIZO_STRBUF_CTRL_RRDIS   0x0000000000000004UL /* Rerun Disable */#define SCHIZO_STRBUF_CTRL_DENAB   0x0000000000000002UL /* Diagnostic Mode Enable */#define SCHIZO_STRBUF_CTRL_ENAB    0x0000000000000001UL /* Streaming Buffer Enable *//* IOMMU control register. */#define SCHIZO_IOMMU_CTRL_RESV     0xfffffffff9000000UL /* Reserved                      */#define SCHIZO_IOMMU_CTRL_XLTESTAT 0x0000000006000000UL /* Translation Error Status      */#define SCHIZO_IOMMU_CTRL_XLTEERR  0x0000000001000000UL /* Translation Error encountered */#define SCHIZO_IOMMU_CTRL_LCKEN    0x0000000000800000UL /* Enable translation locking    */#define SCHIZO_IOMMU_CTRL_LCKPTR   0x0000000000780000UL /* Translation lock pointer      */#define SCHIZO_IOMMU_CTRL_TSBSZ    0x0000000000070000UL /* TSB Size                      */#define SCHIZO_IOMMU_TSBSZ_1K      0x0000000000000000UL /* TSB Table 1024 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_2K      0x0000000000010000UL /* TSB Table 2048 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_4K      0x0000000000020000UL /* TSB Table 4096 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_8K      0x0000000000030000UL /* TSB Table 8192 8-byte entries */#define SCHIZO_IOMMU_TSBSZ_16K     0x0000000000040000UL /* TSB Table 16k 8-byte entries  */#define SCHIZO_IOMMU_TSBSZ_32K     0x0000000000050000UL /* TSB Table 32k 8-byte entries  */#define SCHIZO_IOMMU_TSBSZ_64K     0x0000000000060000UL /* TSB Table 64k 8-byte entries  */#define SCHIZO_IOMMU_TSBSZ_128K    0x0000000000070000UL /* TSB Table 128k 8-byte entries */#define SCHIZO_IOMMU_CTRL_RESV2    0x000000000000fff8UL /* Reserved                      */#define SCHIZO_IOMMU_CTRL_TBWSZ    0x0000000000000004UL /* Assumed page size, 0=8k 1=64k */#define SCHIZO_IOMMU_CTRL_DENAB    0x0000000000000002UL /* Diagnostic mode enable        */#define SCHIZO_IOMMU_CTRL_ENAB     0x0000000000000001UL /* IOMMU Enable                  *//* Schizo config space address format is nearly identical to * that of PSYCHO: * *  32             24 23 16 15    11 10       8 7   2  1 0 * --------------------------------------------------------- * |0 0 0 0 0 0 0 0 0| bus | device | function | reg | 0 0 | * --------------------------------------------------------- */#define SCHIZO_CONFIG_BASE(PBM)	((PBM)->config_space)#define SCHIZO_CONFIG_ENCODE(BUS, DEVFN, REG)	\	(((unsigned long)(BUS)   << 16) |	\	 ((unsigned long)(DEVFN) << 8)  |	\	 ((unsigned long)(REG)))static void *schizo_pci_config_mkaddr(struct pci_pbm_info *pbm,				      unsigned char bus,				      unsigned int devfn,				      int where){	if (!pbm)		return NULL;	bus -= pbm->pci_first_busno;	return (void *)		(SCHIZO_CONFIG_BASE(pbm) |		 SCHIZO_CONFIG_ENCODE(bus, devfn, where));}/* 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 */#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 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 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 */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?