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

📄 pci_sabre.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (where & 0x01) {		printk("pcibios_write_config_word: misaligned reg [%x]\n",		       where);		return PCIBIOS_SUCCESSFUL;	}	pci_config_write16(addr, value);	return PCIBIOS_SUCCESSFUL;}static int __sabre_write_dword(struct pci_dev *dev, int where, u32 value){	struct pci_pbm_info *pbm = pci_bus2pbm[dev->bus->number];	unsigned char bus = dev->bus->number;	unsigned int devfn = dev->devfn;	u32 *addr;	addr = sabre_pci_config_mkaddr(pbm, bus, devfn, where);	if (!addr)		return PCIBIOS_SUCCESSFUL;	if (__sabre_out_of_range(pbm, bus, devfn))		return PCIBIOS_SUCCESSFUL;	if (where & 0x03) {		printk("pcibios_write_config_dword: misaligned reg [%x]\n",		       where);		return PCIBIOS_SUCCESSFUL;	}	pci_config_write32(addr, value);	return PCIBIOS_SUCCESSFUL;}static int sabre_write_byte(struct pci_dev *dev, int where, u8 value){	if (dev->bus->number)		return __sabre_write_byte(dev, where, value);	if (sabre_out_of_range(dev->devfn))		return PCIBIOS_SUCCESSFUL;	if (where < 8) {		u16 tmp;		__sabre_read_word(dev, where & ~1, &tmp);		if (where & 1) {			value &= 0x00ff;			value |= tmp << 8;		} else {			value &= 0xff00;			value |= tmp;		}		return __sabre_write_word(dev, where & ~1, tmp);	} else		return __sabre_write_byte(dev, where, value);}static int sabre_write_word(struct pci_dev *dev, int where, u16 value){	if (dev->bus->number)		return __sabre_write_word(dev, where, value);	if (sabre_out_of_range(dev->devfn))		return PCIBIOS_SUCCESSFUL;	if (where < 8)		return __sabre_write_word(dev, where, value);	else {		__sabre_write_byte(dev, where, value & 0xff);		__sabre_write_byte(dev, where + 1, value >> 8);		return PCIBIOS_SUCCESSFUL;	}}static int sabre_write_dword(struct pci_dev *dev, int where, u32 value){	if (dev->bus->number)		return __sabre_write_dword(dev, where, value);	if (sabre_out_of_range(dev->devfn))		return PCIBIOS_SUCCESSFUL;	sabre_write_word(dev, where, value & 0xffff);	sabre_write_word(dev, where + 2, value >> 16);	return PCIBIOS_SUCCESSFUL;}static struct pci_ops sabre_ops = {	sabre_read_byte,	sabre_read_word,	sabre_read_dword,	sabre_write_byte,	sabre_write_word,	sabre_write_dword};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 __init 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;}static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,					   struct pci_dev *pdev,					   unsigned int ino){	struct pci_controller_info *p = pbm->parent;	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 = p->controller_regs + imap_off;	imap += 4;	iclr_off = sabre_iclr_offset(ino);	iclr = p->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;		/* 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.		 *		 * Currently, the PCI_CONFIG register for the device		 * is used for this read from the far side of the bridge.		 */		if (pdev->bus->number != pcp->pbm->pci_first_busno) {			bucket->flags |= IBF_DMA_SYNC;			bucket->synctab_ent = dma_sync_reg_table_entry++;			dma_sync_reg_table[bucket->synctab_ent] =				(unsigned long) sabre_pci_config_mkaddr(					pcp->pbm,					pdev->bus->number, pdev->devfn, PCI_COMMAND);		}	}	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->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 void sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs){	struct pci_controller_info *p = dev_id;	unsigned long afsr_reg = p->controller_regs + SABRE_UE_AFSR;	unsigned long afar_reg = p->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;	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);}static void sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs)

⌨️ 快捷键说明

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