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

📄 pci_sabre.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 3 页
字号:
}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*/3,		/* SCSI				*//*0x21*/5,		/* Ethernet			*//*0x22*/8,		/* Parallel Port		*//*0x23*/13,		/* Audio Record			*//*0x24*/14,		/* Audio Playback		*//*0x25*/15,		/* PowerFail			*//*0x26*/3,		/* second SCSI			*//*0x27*/11,		/* Floppy			*//*0x28*/2,		/* 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*/1,		/* Power Management		*/};static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino){	int ret;	ret = sabre_pil_table[ino];	if (ret == 0 && pdev == NULL) {		ret = 1;	} else if (ret == 0) {		switch ((pdev->class >> 16) & 0x0f) {		case PCI_BASE_CLASS_STORAGE:			ret = 4;		case PCI_BASE_CLASS_NETWORK:			ret = 6;		case PCI_BASE_CLASS_DISPLAY:			ret = 9;		case PCI_BASE_CLASS_MULTIMEDIA:		case PCI_BASE_CLASS_MEMORY:		case PCI_BASE_CLASS_BRIDGE:			ret = 10;		default:			ret = 1;		};	}	return ret;}static unsigned int __init sabre_irq_build(struct pci_controller_info *p,					   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);	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){	unsigned long iommu_tag[16];	unsigned long iommu_data[16];	unsigned long flags;	u64 control;	int i;	spin_lock_irqsave(&p->iommu.lock, flags);	control = sabre_read(p->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(p->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(p->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(p->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) << 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) << PAGE_SHIFT));		}	}	spin_unlock_irqrestore(&p->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);	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){	struct pci_controller_info *p = dev_id;	unsigned long afsr_reg = p->controller_regs + SABRE_CE_AFSR;	unsigned long afar_reg = p->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);	sabre_write(afsr_reg, error_bits);	/* Log the error. */	printk("SABRE%d: Correctable Error, primary error type[%s]\n",	       p->index,	       ((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("SABRE%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "	       "was_block(%d)\n",	       p->index,	       (afsr & SABRE_CEAFSR_ESYND) >> 48UL,	       (afsr & SABRE_CEAFSR_BMSK) >> 32UL,	       (afsr & SABRE_CEAFSR_OFF) >> 29UL,	       ((afsr & SABRE_CEAFSR_BLK) ? 1 : 0));	printk("SABRE%d: CE AFAR [%016lx]\n", p->index, afar);	printk("SABRE%d: CE Secondary errors [", p->index);	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");}static void sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs){	struct pci_controller_info *p = dev_id;	unsigned long afsr_reg, afar_reg;	unsigned long afsr, afar, error_bits;	int reported;	afsr_reg = p->controller_regs + SABRE_PIOAFSR;	afar_reg = p->controller_regs + SABRE_PIOAFAR;	/* Latch error status. */	afar = sabre_read(afar_reg);	afsr = sabre_read(afsr_reg);	/* Clear primary/secondary error status bits. */	error_bits = afsr &		(SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_PTA |		 SABRE_PIOAFSR_PRTRY | SABRE_PIOAFSR_PPERR |		 SABRE_PIOAFSR_SMA | SABRE_PIOAFSR_STA |		 SABRE_PIOAFSR_SRTRY | SABRE_PIOAFSR_SPERR);	sabre_write(afsr_reg, error_bits);	/* Log the error. */	printk("SABRE%d: PCI Error, primary error type[%s]\n",	       p->index,	       (((error_bits & SABRE_PIOAFSR_PMA) ?		 "Master Abort" :		 ((error_bits & SABRE_PIOAFSR_PTA) ?		  "Target Abort" :		  ((error_bits & SABRE_PIOAFSR_PRTRY) ?		   "Excessive Retries" :		   ((error_bits & SABRE_PIOAFSR_PPERR) ?		    "Parity Error" : "???"))))));	printk("SABRE%d: bytemask[%04lx] was_block(%d)\n",	       p->index,	       (afsr & SABRE_PIOAFSR_BMSK) >> 32UL,	       (afsr & SABRE_PIOAFSR_BLK) ? 1 : 0);	printk("SABRE%d: PCI AFAR [%016lx]\n", p->index, afar);	printk("SABRE%d: PCI Secondary errors [", p->index);	reported = 0;	if (afsr & SABRE_PIOAFSR_SMA) {		reported++;		printk("(Master Abort)");	}	if (afsr & SABRE_PIOAFSR_STA) {		reported++;		printk("(Target Abort)");	}	if (afsr & SABRE_PIOAFSR_SRTRY) {		reported++;		printk("(Excessive Retries)");	}	if (afsr & SABRE_PIOAFSR_SPERR) {		reported++;		printk("(Parity Error)");	}	if (!reported)		printk("(none)");	printk("]\n");	/* For the error types shown, scan both PCI buses for devices	 * which have logged that error type.	 */	/* If we see a Target Abort, this could be the result of an	 * IOMMU translation error of some sort.  It is extremely	 * useful to log this information as usually it indicates	 * a bug in the IOMMU support code or a PCI device driver.	 */	if (error_bits & (SABRE_PIOAFSR_PTA | SABRE_PIOAFSR_STA)) {		sabre_check_iommu_error(p, afsr, afar);		pci_scan_for_target_abort(p, &p->pbm_A, p->pbm_A.pci_bus);		pci_scan_for_target_abort(p, &p->pbm_B, p->pbm_B.pci_bus);	}	if (error_bits & (SABRE_PIOAFSR_PMA | SABRE_PIOAFSR_SMA)) {		pci_scan_for_master_abort(p, &p->pbm_A, p->pbm_A.pci_bus);		pci_scan_for_master_abort(p, &p->pbm_B, p->pbm_B.pci_bus);	}	/* For excessive retries, SABRE/PBM will abort the device	 * and there is no way to specifically check for excessive	 * retries in the config space status registers.  So what	 * we hope is that we'll catch it via the master/target	 * abort events.	 */	if (error_bits & (SABRE_PIOAFSR_PPERR | SABRE_PIOAFSR_SPERR)) {		pci_scan_for_parity_error(p, &p->pbm_A, p->pbm_A.pci_bus);		pci_scan_for_parity_error(p, &p->pbm_B, p->pbm_B.pci_bus);	}}/* XXX What about PowerFail/PowerManagement??? -DaveM */#define SABRE_UE_INO		0x2e#define SABRE_CE_INO		0x2f#define SABRE_PCIERR_INO	0x30static void __init sabre_register_error_handlers(struct pci_controller_info *p){	unsigned long base = p->controller_regs;	unsigned long irq, portid = p->portid;	u64 tmp;	/* We clear the error bits in the appropriate AFSR before	 * registering the handler so that we don't get spurious	 * interrupts.	 */	sabre_write(base + SABRE_UE_AFSR,		    (SABRE_UEAFSR_PDRD | SABRE_UEAFSR_PDWR |		     SABRE_UEAFSR_SDRD | SABRE_UEAFSR_SDWR |		     SABRE_UEAFSR_SDTE | SABRE_UEAFSR_PDTE));	irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_UE_INO);	if (request_irq(irq, sabre_ue_intr,			SA_SHIRQ, "SABRE UE", p) < 0) {		prom_printf("SABRE%d: Cannot register UE interrupt.\n",			    p->index);		prom_halt();	}	sabre_write(base + SABRE_CE_AFSR,		    (SABRE_CEAFSR_PDRD | SABRE_CEAFSR_PDWR |		     SABRE_CEAFSR_SDRD | SABRE_CEAFSR_SDWR));	irq = sabre_irq_build(p, NULL, (portid << 6) | SABRE_CE_INO);	if (request_irq(irq, sabre_ce_intr,			SA_SHIRQ, "SABRE CE", p) < 0) {		prom_printf("SABRE%d: Cannot register CE interrupt.\n",			    p->index);

⌨️ 快捷键说明

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