⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci_sabre.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
		pci_config_write16((u16 *) addr, value);		break;	case 4:		if (where & 0x03) {			printk("pci_write_config_dword: misaligned reg [%x]\n",			       where);			return PCIBIOS_SUCCESSFUL;		}		pci_config_write32(addr, value);		break;	}	return PCIBIOS_SUCCESSFUL;}static int sabre_write_pci_cfg(struct pci_bus *bus, unsigned int devfn,			       int where, int size, u32 value){	if (bus->number)		return __sabre_write_pci_cfg(bus, devfn, where, size, value);	if (sabre_out_of_range(devfn))		return PCIBIOS_SUCCESSFUL;	switch (size) {	case 1:		if (where < 8) {			u32 tmp32;			u16 tmp16;			__sabre_read_pci_cfg(bus, devfn, where & ~1, 2, &tmp32);			tmp16 = (u16) tmp32;			if (where & 1) {				value &= 0x00ff;				value |= tmp16 << 8;			} else {				value &= 0xff00;				value |= tmp16;			}			tmp32 = (u32) tmp16;			return __sabre_write_pci_cfg(bus, devfn, where & ~1, 2, tmp32);		} else			return __sabre_write_pci_cfg(bus, devfn, where, 1, value);		break;	case 2:		if (where < 8)			return __sabre_write_pci_cfg(bus, devfn, where, 2, value);		else {			__sabre_write_pci_cfg(bus, devfn, where, 1, value & 0xff);			__sabre_write_pci_cfg(bus, devfn, where + 1, 1, value >> 8);		}		break;	case 4:		sabre_write_pci_cfg(bus, devfn, where, 2, value & 0xffff);		sabre_write_pci_cfg(bus, devfn, where + 2, 2, value >> 16);		break;	}	return PCIBIOS_SUCCESSFUL;}static struct pci_ops sabre_ops = {	.read =		sabre_read_pci_cfg,	.write =	sabre_write_pci_cfg,};static unsigned long sabre_pcislot_imap_offset(unsigned long ino){	unsigned int bus =  (ino & 0x10) >> 4;	unsigned int slot = (ino & 0x0c) >> 2;	if (bus == 0)		return SABRE_IMAP_A_SLOT0 + (slot * 8);	else		return SABRE_IMAP_B_SLOT0 + (slot * 8);}static unsigned long __onboard_imap_off[] = {/*0x20*/	SABRE_IMAP_SCSI,/*0x21*/	SABRE_IMAP_ETH,/*0x22*/	SABRE_IMAP_BPP,/*0x23*/	SABRE_IMAP_AU_REC,/*0x24*/	SABRE_IMAP_AU_PLAY,/*0x25*/	SABRE_IMAP_PFAIL,/*0x26*/	SABRE_IMAP_KMS,/*0x27*/	SABRE_IMAP_FLPY,/*0x28*/	SABRE_IMAP_SHW,/*0x29*/	SABRE_IMAP_KBD,/*0x2a*/	SABRE_IMAP_MS,/*0x2b*/	SABRE_IMAP_SER,/*0x2c*/	0 /* reserved */,/*0x2d*/	0 /* reserved */,/*0x2e*/	SABRE_IMAP_UE,/*0x2f*/	SABRE_IMAP_CE,/*0x30*/	SABRE_IMAP_PCIERR,};#define SABRE_ONBOARD_IRQ_BASE		0x20#define SABRE_ONBOARD_IRQ_LAST		0x30#define sabre_onboard_imap_offset(__ino) \	__onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE]#define sabre_iclr_offset(ino)					      \	((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) :  \			(SABRE_ICLR_A_SLOT0 + (((ino) & 0x1f)<<3)))/* PCI SABRE INO number to Sparc PIL level. */static unsigned char sabre_pil_table[] = {/*0x00*/0, 0, 0, 0,	/* PCI A slot 0  Int A, B, C, D *//*0x04*/0, 0, 0, 0,	/* PCI A slot 1  Int A, B, C, D *//*0x08*/0, 0, 0, 0,	/* PCI A slot 2  Int A, B, C, D *//*0x0c*/0, 0, 0, 0,	/* PCI A slot 3  Int A, B, C, D *//*0x10*/0, 0, 0, 0,	/* PCI B slot 0  Int A, B, C, D *//*0x14*/0, 0, 0, 0,	/* PCI B slot 1  Int A, B, C, D *//*0x18*/0, 0, 0, 0,	/* PCI B slot 2  Int A, B, C, D *//*0x1c*/0, 0, 0, 0,	/* PCI B slot 3  Int A, B, C, D *//*0x20*/4,		/* SCSI				*//*0x21*/5,		/* Ethernet			*//*0x22*/8,		/* Parallel Port		*//*0x23*/13,		/* Audio Record			*//*0x24*/14,		/* Audio Playback		*//*0x25*/15,		/* PowerFail			*//*0x26*/4,		/* second SCSI			*//*0x27*/11,		/* Floppy			*//*0x28*/4,		/* Spare Hardware		*//*0x29*/9,		/* Keyboard			*//*0x2a*/4,		/* Mouse			*//*0x2b*/12,		/* Serial			*//*0x2c*/10,		/* Timer 0			*//*0x2d*/11,		/* Timer 1			*//*0x2e*/15,		/* Uncorrectable ECC		*//*0x2f*/15,		/* Correctable ECC		*//*0x30*/15,		/* PCI Bus A Error		*//*0x31*/15,		/* PCI Bus B Error		*//*0x32*/15,		/* Power Management		*/};static int sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino){	int ret;	if (pdev &&	    pdev->vendor == PCI_VENDOR_ID_SUN &&	    pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)		return 9;	ret = sabre_pil_table[ino];	if (ret == 0 && pdev == NULL) {		ret = 4;	} else if (ret == 0) {		switch ((pdev->class >> 16) & 0xff) {		case PCI_BASE_CLASS_STORAGE:			ret = 4;			break;		case PCI_BASE_CLASS_NETWORK:			ret = 6;			break;		case PCI_BASE_CLASS_DISPLAY:			ret = 9;			break;		case PCI_BASE_CLASS_MULTIMEDIA:		case PCI_BASE_CLASS_MEMORY:		case PCI_BASE_CLASS_BRIDGE:		case PCI_BASE_CLASS_SERIAL:			ret = 10;			break;		default:			ret = 4;			break;		};	}	return ret;}/* When a device lives behind a bridge deeper in the PCI bus topology * than APB, a special sequence must run to make sure all pending DMA * transfers at the time of IRQ delivery are visible in the coherency * domain by the cpu.  This sequence is to perform a read on the far * side of the non-APB bridge, then perform a read of Sabre's DMA * write-sync register. */static void sabre_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2){	struct pci_dev *pdev = _arg1;	unsigned long sync_reg = (unsigned long) _arg2;	u16 _unused;	pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused);	sabre_read(sync_reg);}static unsigned int sabre_irq_build(struct pci_pbm_info *pbm,				    struct pci_dev *pdev,				    unsigned int ino){	struct ino_bucket *bucket;	unsigned long imap, iclr;	unsigned long imap_off, iclr_off;	int pil, inofixup = 0;	ino &= PCI_IRQ_INO;	if (ino < SABRE_ONBOARD_IRQ_BASE) {		/* PCI slot */		imap_off = sabre_pcislot_imap_offset(ino);	} else {		/* onboard device */		if (ino > SABRE_ONBOARD_IRQ_LAST) {			prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino);			prom_halt();		}		imap_off = sabre_onboard_imap_offset(ino);	}	/* Now build the IRQ bucket. */	pil = sabre_ino_to_pil(pdev, ino);	if (PIL_RESERVED(pil))		BUG();	imap = pbm->controller_regs + imap_off;	imap += 4;	iclr_off = sabre_iclr_offset(ino);	iclr = pbm->controller_regs + iclr_off;	iclr += 4;	if ((ino & 0x20) == 0)		inofixup = ino & 0x03;	bucket = __bucket(build_irq(pil, inofixup, iclr, imap));	bucket->flags |= IBF_PCI;	if (pdev) {		struct pcidev_cookie *pcp = pdev->sysdata;		if (pdev->bus->number != pcp->pbm->pci_first_busno) {			struct pci_controller_info *p = pcp->pbm->parent;			struct irq_desc *d = bucket->irq_info;			d->pre_handler = sabre_wsync_handler;			d->pre_handler_arg1 = pdev;			d->pre_handler_arg2 = (void *)				p->pbm_A.controller_regs + SABRE_WRSYNC;		}	}	return __irq(bucket);}/* SABRE error handling support. */static void sabre_check_iommu_error(struct pci_controller_info *p,				    unsigned long afsr,				    unsigned long afar){	struct pci_iommu *iommu = p->pbm_A.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("SABRE%d: IOMMU Error, type[%s]\n",		       p->index, 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 = p->pbm_A.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("SABRE%d: IOMMU TAG(%d)[RAW(%016lx)error(%s)wr(%d)sz(%dK)vpg(%08lx)]\n",			       p->index, i, tag, type_string,			       ((tag & SABRE_IOMMUTAG_WRITE) ? 1 : 0),			       ((tag & SABRE_IOMMUTAG_SIZE) ? 64 : 8),			       ((tag & SABRE_IOMMUTAG_VPN) << IOMMU_PAGE_SHIFT));			printk("SABRE%d: IOMMU DATA(%d)[RAW(%016lx)valid(%d)used(%d)cache(%d)ppg(%016lx)\n",			       p->index, 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 pt_regs *regs){	struct pci_controller_info *p = dev_id;	unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_UE_AFSR;	unsigned long afar_reg = p->pbm_A.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("SABRE%d: Uncorrectable Error, primary error type[%s%s]\n",	       p->index,	       ((error_bits & SABRE_UEAFSR_PDRD) ?		"DMA Read" :		((error_bits & SABRE_UEAFSR_PDWR) ?		 "DMA Write" : "???")),	       ((error_bits & SABRE_UEAFSR_PDTE) ?		":Translation Error" : ""));	printk("SABRE%d: bytemask[%04lx] dword_offset[%lx] was_block(%d)\n",	       p->index,	       (afsr & SABRE_UEAFSR_BMSK) >> 32UL,	       (afsr & SABRE_UEAFSR_OFF) >> 29UL,	       ((afsr & SABRE_UEAFSR_BLK) ? 1 : 0));	printk("SABRE%d: UE AFAR [%016lx]\n", p->index, afar);	printk("SABRE%d: UE Secondary errors [", p->index);	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(p, afsr, afar);	return IRQ_HANDLED;}static irqreturn_t sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs){	struct pci_controller_info *p = dev_id;	unsigned long afsr_reg = p->pbm_A.controller_regs + SABRE_CE_AFSR;	unsigned long afar_reg = p->pbm_A.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);

⌨️ 快捷键说明

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