pci_sabre.c

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

C
867
字号
/* pci_sabre.c: Sabre specific PCI controller support. * * Copyright (C) 1997, 1998, 1999, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1998, 1999 Eddie C. Dost   (ecd@skynet.be) * Copyright (C) 1999 Jakub Jelinek   (jakub@redhat.com) */#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/apb.h>#include <asm/iommu.h>#include <asm/irq.h>#include <asm/smp.h>#include <asm/oplib.h>#include <asm/prom.h>#include <asm/of_device.h>#include "pci_impl.h"#include "iommu_common.h"/* All SABRE registers are 64-bits.  The following accessor * routines are how they are accessed.  The REG parameter * is a physical address. */#define sabre_read(__reg) \({	u64 __ret; \	__asm__ __volatile__("ldxa [%1] %2, %0" \			     : "=r" (__ret) \			     : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \			     : "memory"); \	__ret; \})#define sabre_write(__reg, __val) \	__asm__ __volatile__("stxa %0, [%1] %2" \			     : /* no outputs */ \			     : "r" (__val), "r" (__reg), \			       "i" (ASI_PHYS_BYPASS_EC_E) \			     : "memory")/* SABRE PCI controller register offsets and definitions. */#define SABRE_UE_AFSR		0x0030UL#define  SABRE_UEAFSR_PDRD	 0x4000000000000000UL	/* Primary PCI DMA Read */#define  SABRE_UEAFSR_PDWR	 0x2000000000000000UL	/* Primary PCI DMA Write */#define  SABRE_UEAFSR_SDRD	 0x0800000000000000UL	/* Secondary PCI DMA Read */#define  SABRE_UEAFSR_SDWR	 0x0400000000000000UL	/* Secondary PCI DMA Write */#define  SABRE_UEAFSR_SDTE	 0x0200000000000000UL	/* Secondary DMA Translation Error */#define  SABRE_UEAFSR_PDTE	 0x0100000000000000UL	/* Primary DMA Translation Error */#define  SABRE_UEAFSR_BMSK	 0x0000ffff00000000UL	/* Bytemask */#define  SABRE_UEAFSR_OFF	 0x00000000e0000000UL	/* Offset (AFAR bits [5:3] */#define  SABRE_UEAFSR_BLK	 0x0000000000800000UL	/* Was block operation */#define SABRE_UECE_AFAR		0x0038UL#define SABRE_CE_AFSR		0x0040UL#define  SABRE_CEAFSR_PDRD	 0x4000000000000000UL	/* Primary PCI DMA Read */#define  SABRE_CEAFSR_PDWR	 0x2000000000000000UL	/* Primary PCI DMA Write */#define  SABRE_CEAFSR_SDRD	 0x0800000000000000UL	/* Secondary PCI DMA Read */#define  SABRE_CEAFSR_SDWR	 0x0400000000000000UL	/* Secondary PCI DMA Write */#define  SABRE_CEAFSR_ESYND	 0x00ff000000000000UL	/* ECC Syndrome */#define  SABRE_CEAFSR_BMSK	 0x0000ffff00000000UL	/* Bytemask */#define  SABRE_CEAFSR_OFF	 0x00000000e0000000UL	/* Offset */#define  SABRE_CEAFSR_BLK	 0x0000000000800000UL	/* Was block operation */#define SABRE_UECE_AFAR_ALIAS	0x0048UL	/* Aliases to 0x0038 */#define SABRE_IOMMU_CONTROL	0x0200UL#define  SABRE_IOMMUCTRL_ERRSTS	 0x0000000006000000UL	/* Error status bits */#define  SABRE_IOMMUCTRL_ERR	 0x0000000001000000UL	/* Error present in IOTLB */#define  SABRE_IOMMUCTRL_LCKEN	 0x0000000000800000UL	/* IOTLB lock enable */#define  SABRE_IOMMUCTRL_LCKPTR	 0x0000000000780000UL	/* IOTLB lock pointer */#define  SABRE_IOMMUCTRL_TSBSZ	 0x0000000000070000UL	/* TSB Size */#define  SABRE_IOMMU_TSBSZ_1K   0x0000000000000000#define  SABRE_IOMMU_TSBSZ_2K   0x0000000000010000#define  SABRE_IOMMU_TSBSZ_4K   0x0000000000020000#define  SABRE_IOMMU_TSBSZ_8K   0x0000000000030000#define  SABRE_IOMMU_TSBSZ_16K  0x0000000000040000#define  SABRE_IOMMU_TSBSZ_32K  0x0000000000050000#define  SABRE_IOMMU_TSBSZ_64K  0x0000000000060000#define  SABRE_IOMMU_TSBSZ_128K 0x0000000000070000#define  SABRE_IOMMUCTRL_TBWSZ	 0x0000000000000004UL	/* TSB assumed page size */#define  SABRE_IOMMUCTRL_DENAB	 0x0000000000000002UL	/* Diagnostic Mode Enable */#define  SABRE_IOMMUCTRL_ENAB	 0x0000000000000001UL	/* IOMMU Enable */#define SABRE_IOMMU_TSBBASE	0x0208UL#define SABRE_IOMMU_FLUSH	0x0210UL#define SABRE_IMAP_A_SLOT0	0x0c00UL#define SABRE_IMAP_B_SLOT0	0x0c20UL#define SABRE_IMAP_SCSI		0x1000UL#define SABRE_IMAP_ETH		0x1008UL#define SABRE_IMAP_BPP		0x1010UL#define SABRE_IMAP_AU_REC	0x1018UL#define SABRE_IMAP_AU_PLAY	0x1020UL#define SABRE_IMAP_PFAIL	0x1028UL#define SABRE_IMAP_KMS		0x1030UL#define SABRE_IMAP_FLPY		0x1038UL#define SABRE_IMAP_SHW		0x1040UL#define SABRE_IMAP_KBD		0x1048UL#define SABRE_IMAP_MS		0x1050UL#define SABRE_IMAP_SER		0x1058UL#define SABRE_IMAP_UE		0x1070UL#define SABRE_IMAP_CE		0x1078UL#define SABRE_IMAP_PCIERR	0x1080UL#define SABRE_IMAP_GFX		0x1098UL#define SABRE_IMAP_EUPA		0x10a0UL#define SABRE_ICLR_A_SLOT0	0x1400UL#define SABRE_ICLR_B_SLOT0	0x1480UL#define SABRE_ICLR_SCSI		0x1800UL#define SABRE_ICLR_ETH		0x1808UL#define SABRE_ICLR_BPP		0x1810UL#define SABRE_ICLR_AU_REC	0x1818UL#define SABRE_ICLR_AU_PLAY	0x1820UL#define SABRE_ICLR_PFAIL	0x1828UL#define SABRE_ICLR_KMS		0x1830UL#define SABRE_ICLR_FLPY		0x1838UL#define SABRE_ICLR_SHW		0x1840UL#define SABRE_ICLR_KBD		0x1848UL#define SABRE_ICLR_MS		0x1850UL#define SABRE_ICLR_SER		0x1858UL#define SABRE_ICLR_UE		0x1870UL#define SABRE_ICLR_CE		0x1878UL#define SABRE_ICLR_PCIERR	0x1880UL#define SABRE_WRSYNC		0x1c20UL#define SABRE_PCICTRL		0x2000UL#define  SABRE_PCICTRL_MRLEN	 0x0000001000000000UL	/* Use MemoryReadLine for block loads/stores */#define  SABRE_PCICTRL_SERR	 0x0000000400000000UL	/* Set when SERR asserted on PCI bus */#define  SABRE_PCICTRL_ARBPARK	 0x0000000000200000UL	/* Bus Parking 0=Ultra-IIi 1=prev-bus-owner */#define  SABRE_PCICTRL_CPUPRIO	 0x0000000000100000UL	/* Ultra-IIi granted every other bus cycle */#define  SABRE_PCICTRL_ARBPRIO	 0x00000000000f0000UL	/* Slot which is granted every other bus cycle */#define  SABRE_PCICTRL_ERREN	 0x0000000000000100UL	/* PCI Error Interrupt Enable */#define  SABRE_PCICTRL_RTRYWE	 0x0000000000000080UL	/* DMA Flow Control 0=wait-if-possible 1=retry */#define  SABRE_PCICTRL_AEN	 0x000000000000000fUL	/* Slot PCI arbitration enables */#define SABRE_PIOAFSR		0x2010UL#define  SABRE_PIOAFSR_PMA	 0x8000000000000000UL	/* Primary Master Abort */#define  SABRE_PIOAFSR_PTA	 0x4000000000000000UL	/* Primary Target Abort */#define  SABRE_PIOAFSR_PRTRY	 0x2000000000000000UL	/* Primary Excessive Retries */#define  SABRE_PIOAFSR_PPERR	 0x1000000000000000UL	/* Primary Parity Error */#define  SABRE_PIOAFSR_SMA	 0x0800000000000000UL	/* Secondary Master Abort */#define  SABRE_PIOAFSR_STA	 0x0400000000000000UL	/* Secondary Target Abort */#define  SABRE_PIOAFSR_SRTRY	 0x0200000000000000UL	/* Secondary Excessive Retries */#define  SABRE_PIOAFSR_SPERR	 0x0100000000000000UL	/* Secondary Parity Error */#define  SABRE_PIOAFSR_BMSK	 0x0000ffff00000000UL	/* Byte Mask */#define  SABRE_PIOAFSR_BLK	 0x0000000080000000UL	/* Was Block Operation */#define SABRE_PIOAFAR		0x2018UL#define SABRE_PCIDIAG		0x2020UL#define  SABRE_PCIDIAG_DRTRY	 0x0000000000000040UL	/* Disable PIO Retry Limit */#define  SABRE_PCIDIAG_IPAPAR	 0x0000000000000008UL	/* Invert PIO Address Parity */#define  SABRE_PCIDIAG_IPDPAR	 0x0000000000000004UL	/* Invert PIO Data Parity */#define  SABRE_PCIDIAG_IDDPAR	 0x0000000000000002UL	/* Invert DMA Data Parity */#define  SABRE_PCIDIAG_ELPBK	 0x0000000000000001UL	/* Loopback Enable - not supported */#define SABRE_PCITASR		0x2028UL#define  SABRE_PCITASR_EF	 0x0000000000000080UL	/* Respond to 0xe0000000-0xffffffff */#define  SABRE_PCITASR_CD	 0x0000000000000040UL	/* Respond to 0xc0000000-0xdfffffff */#define  SABRE_PCITASR_AB	 0x0000000000000020UL	/* Respond to 0xa0000000-0xbfffffff */#define  SABRE_PCITASR_89	 0x0000000000000010UL	/* Respond to 0x80000000-0x9fffffff */#define  SABRE_PCITASR_67	 0x0000000000000008UL	/* Respond to 0x60000000-0x7fffffff */#define  SABRE_PCITASR_45	 0x0000000000000004UL	/* Respond to 0x40000000-0x5fffffff */#define  SABRE_PCITASR_23	 0x0000000000000002UL	/* Respond to 0x20000000-0x3fffffff */#define  SABRE_PCITASR_01	 0x0000000000000001UL	/* Respond to 0x00000000-0x1fffffff */#define SABRE_PIOBUF_DIAG	0x5000UL#define SABRE_DMABUF_DIAGLO	0x5100UL#define SABRE_DMABUF_DIAGHI	0x51c0UL#define SABRE_IMAP_GFX_ALIAS	0x6000UL	/* Aliases to 0x1098 */#define SABRE_IMAP_EUPA_ALIAS	0x8000UL	/* Aliases to 0x10a0 */#define SABRE_IOMMU_VADIAG	0xa400UL#define SABRE_IOMMU_TCDIAG	0xa408UL#define SABRE_IOMMU_TAG		0xa580UL#define  SABRE_IOMMUTAG_ERRSTS	 0x0000000001800000UL	/* Error status bits */#define  SABRE_IOMMUTAG_ERR	 0x0000000000400000UL	/* Error present */#define  SABRE_IOMMUTAG_WRITE	 0x0000000000200000UL	/* Page is writable */#define  SABRE_IOMMUTAG_STREAM	 0x0000000000100000UL	/* Streamable bit - unused */#define  SABRE_IOMMUTAG_SIZE	 0x0000000000080000UL	/* 0=8k 1=16k */#define  SABRE_IOMMUTAG_VPN	 0x000000000007ffffUL	/* Virtual Page Number [31:13] */#define SABRE_IOMMU_DATA	0xa600UL#define SABRE_IOMMUDATA_VALID	 0x0000000040000000UL	/* Valid */#define SABRE_IOMMUDATA_USED	 0x0000000020000000UL	/* Used (for LRU algorithm) */#define SABRE_IOMMUDATA_CACHE	 0x0000000010000000UL	/* Cacheable */#define SABRE_IOMMUDATA_PPN	 0x00000000001fffffUL	/* Physical Page Number [33:13] */#define SABRE_PCI_IRQSTATE	0xa800UL#define SABRE_OBIO_IRQSTATE	0xa808UL#define SABRE_FFBCFG		0xf000UL#define  SABRE_FFBCFG_SPRQS	 0x000000000f000000	/* Slave P_RQST queue size */#define  SABRE_FFBCFG_ONEREAD	 0x0000000000004000	/* Slave supports one outstanding read */#define SABRE_MCCTRL0		0xf010UL#define  SABRE_MCCTRL0_RENAB	 0x0000000080000000	/* Refresh Enable */#define  SABRE_MCCTRL0_EENAB	 0x0000000010000000	/* Enable all ECC functions */#define  SABRE_MCCTRL0_11BIT	 0x0000000000001000	/* Enable 11-bit column addressing */#define  SABRE_MCCTRL0_DPP	 0x0000000000000f00	/* DIMM Pair Present Bits */#define  SABRE_MCCTRL0_RINTVL	 0x00000000000000ff	/* Refresh Interval */#define SABRE_MCCTRL1		0xf018UL#define  SABRE_MCCTRL1_AMDC	 0x0000000038000000	/* Advance Memdata Clock */#define  SABRE_MCCTRL1_ARDC	 0x0000000007000000	/* Advance DRAM Read Data Clock */#define  SABRE_MCCTRL1_CSR	 0x0000000000e00000	/* CAS to RAS delay for CBR refresh */#define  SABRE_MCCTRL1_CASRW	 0x00000000001c0000	/* CAS length for read/write */#define  SABRE_MCCTRL1_RCD	 0x0000000000038000	/* RAS to CAS delay */#define  SABRE_MCCTRL1_CP	 0x0000000000007000	/* CAS Precharge */#define  SABRE_MCCTRL1_RP	 0x0000000000000e00	/* RAS Precharge */#define  SABRE_MCCTRL1_RAS	 0x00000000000001c0	/* Length of RAS for refresh */#define  SABRE_MCCTRL1_CASRW2	 0x0000000000000038	/* Must be same as CASRW */#define  SABRE_MCCTRL1_RSC	 0x0000000000000007	/* RAS after CAS hold time */#define SABRE_RESETCTRL		0xf020UL#define SABRE_CONFIGSPACE	0x001000000UL#define SABRE_IOSPACE		0x002000000UL#define SABRE_IOSPACE_SIZE	0x000ffffffUL#define SABRE_MEMSPACE		0x100000000UL#define SABRE_MEMSPACE_SIZE	0x07fffffffULstatic int hummingbird_p;static struct pci_bus *sabre_root_bus;/* SABRE error handling support. */static void sabre_check_iommu_error(struct pci_pbm_info *pbm,				    unsigned long afsr,				    unsigned long afar){	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 = sabre_read(iommu->iommu_control);	if (control & SABRE_IOMMUCTRL_ERR) {		char *type_string;		/* Clear the error encountered bit.		 * NOTE: On Sabre this is write 1 to clear,		 *       which is different from Psycho.		 */		sabre_write(iommu->iommu_control, control);		switch((control & SABRE_IOMMUCTRL_ERRSTS) >> 25UL) {		case 1:			type_string = "Invalid Error";			break;		case 3:			type_string = "ECC Error";			break;		default:			type_string = "Unknown";			break;		};		printk("%s: IOMMU Error, type[%s]\n",		       pbm->name, type_string);		/* Enter diagnostic mode and probe for error'd		 * entries in the IOTLB.		 */		control &= ~(SABRE_IOMMUCTRL_ERRSTS | SABRE_IOMMUCTRL_ERR);		sabre_write(iommu->iommu_control,			    (control | SABRE_IOMMUCTRL_DENAB));		for (i = 0; i < 16; i++) {			unsigned long base = pbm->controller_regs;			iommu_tag[i] =				sabre_read(base + SABRE_IOMMU_TAG + (i * 8UL));			iommu_data[i] =				sabre_read(base + SABRE_IOMMU_DATA + (i * 8UL));			sabre_write(base + SABRE_IOMMU_TAG + (i * 8UL), 0);			sabre_write(base + SABRE_IOMMU_DATA + (i * 8UL), 0);		}		sabre_write(iommu->iommu_control, control);		for (i = 0; i < 16; i++) {			unsigned long tag, data;			tag = iommu_tag[i];			if (!(tag & SABRE_IOMMUTAG_ERR))				continue;			data = iommu_data[i];			switch((tag & SABRE_IOMMUTAG_ERRSTS) >> 23UL) {			case 1:				type_string = "Invalid Error";				break;			case 3:				type_string = "ECC Error";				break;			default:				type_string = "Unknown";				break;			};			printk("%s: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",			       pbm->name, i, tag, type_string,			       ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),			       ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),			       ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));			printk("%s: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",			       pbm->name, i, data,			       ((data & SABRE_IOMMUDATA_VALID) ? 1 : 0),			       ((data & SABRE_IOMMUDATA_USED) ? 1 : 0),			       ((data & SABRE_IOMMUDATA_CACHE) ? 1 : 0),			       ((data & SABRE_IOMMUDATA_PPN) << IOMMU_PAGE_SHIFT));		}	}	spin_unlock_irqrestore(&iommu->lock, flags);}static irqreturn_t sabre_ue_intr(int irq, void *dev_id){	struct pci_pbm_info *pbm = dev_id;	unsigned long afsr_reg = pbm->controller_regs + SABRE_UE_AFSR;	unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;	unsigned long afsr, afar, error_bits;	int reported;	/* Latch uncorrectable error status. */	afar = sabre_read(afar_reg);	afsr = sabre_read(afsr_reg);	/* Clear the primary/secondary error status bits. */	error_bits = afsr &		(SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |		 SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |		 SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE);	if (!error_bits)		return IRQ_NONE;	sabre_write(afsr_reg, error_bits);	/* Log the error. */	printk("%s: Uncorrectable Error, primary error type[%s%s]\n",	       pbm->name,	       ((error_bits & SABRE_UEAFSR_PDRD) ?		"DMA Read" :		((error_bits & SABRE_UEAFSR_PDWR) ?		 "DMA Write" : "???")),	       ((error_bits & SABRE_UEAFSR_PDTE) ?		":Translation Error" : ""));	printk("%s: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",	       pbm->name,	       (afsr & SABRE_UEAFSR_BMSK) >> 32UL,	       (afsr & SABRE_UEAFSR_OFF) >> 29UL,	       ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));	printk("%s: UE AFAR [%016lx]\n", pbm->name, afar);	printk("%s: UE Secondary errors [", pbm->name);	reported = 0;	if (afsr & SABRE_UEAFSR_SDRD) {		reported++;		printk("(DMA Read)");	}	if (afsr & SABRE_UEAFSR_SDWR) {		reported++;		printk("(DMA Write)");	}	if (afsr & SABRE_UEAFSR_SDTE) {		reported++;		printk("(Translation Error)");	}	if (!reported)		printk("(none)");	printk("]\n");	/* Interrogate IOMMU for error status. */	sabre_check_iommu_error(pbm, afsr, afar);	return IRQ_HANDLED;}static irqreturn_t sabre_ce_intr(int irq, void *dev_id){	struct pci_pbm_info *pbm = dev_id;	unsigned long afsr_reg = pbm->controller_regs + SABRE_CE_AFSR;	unsigned long afar_reg = pbm->controller_regs + SABRE_UECE_AFAR;	unsigned long afsr, afar, error_bits;	int reported;	/* Latch error status. */	afar = sabre_read(afar_reg);	afsr = sabre_read(afsr_reg);	/* Clear primary/secondary error status bits. */	error_bits = afsr &		(SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |		 SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR);	if (!error_bits)		return IRQ_NONE;	sabre_write(afsr_reg, error_bits);	/* Log the error. */	printk("%s: Correctable Error, primary error type[%s]\n",	       pbm->name,	       ((error_bits & SABRE_CEAFSR_PDRD) ?		"DMA Read" :		((error_bits & SABRE_CEAFSR_PDWR) ?		 "DMA Write" : "???")));	/* XXX Use syndrome and afar to print out module string just like	 * XXX UDB CE trap handler does... -DaveM	 */	printk("%s: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "	       "was_block(%d)\n",	       pbm->name,	       (afsr & SABRE_CEAFSR_ESYND) >> 48UL,	       (afsr & SABRE_CEAFSR_BMSK) >> 32UL,	       (afsr & SABRE_CEAFSR_OFF) >> 29UL,	       ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));	printk("%s: CE AFAR [%016lx]\n", pbm->name, afar);	printk("%s: CE Secondary errors [", pbm->name);	reported = 0;	if (afsr & SABRE_CEAFSR_SDRD) {		reported++;		printk("(DMA Read)");	}	if (afsr & SABRE_CEAFSR_SDWR) {		reported++;		printk("(DMA Write)");	}	if (!reported)		printk("(none)");	printk("]\n");	return IRQ_HANDLED;}static irqreturn_t sabre_pcierr_intr_other(struct pci_pbm_info *pbm){	unsigned long csr_reg, csr, csr_error_bits;	irqreturn_t ret = IRQ_NONE;	u16 stat;	csr_reg = pbm->controller_regs + SABRE_PCICTRL;	csr = sabre_read(csr_reg);	csr_error_bits =		csr & SABRE_PCICTRL_SERR;	if (csr_error_bits) {		/* Clear the errors.  */		sabre_write(csr_reg, csr);		/* Log 'em.  */		if (csr_error_bits & SABRE_PCICTRL_SERR)			printk("%s: PCI SERR signal asserted.\n",			       pbm->name);		ret = IRQ_HANDLED;

⌨️ 快捷键说明

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