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

📄 pci_psycho.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
	/* Interrogate IOMMU for error status. */	psycho_check_iommu_error(p, afsr, afar, UE_ERR);}/* Correctable Errors. */#define PSYCHO_CE_AFSR	0x0040UL#define  PSYCHO_CEAFSR_PPIO	0x8000000000000000 /* Primary PIO is cause         */#define  PSYCHO_CEAFSR_PDRD	0x4000000000000000 /* Primary DVMA read is cause   */#define  PSYCHO_CEAFSR_PDWR	0x2000000000000000 /* Primary DVMA write is cause  */#define  PSYCHO_CEAFSR_SPIO	0x1000000000000000 /* Secondary PIO is cause       */#define  PSYCHO_CEAFSR_SDRD	0x0800000000000000 /* Secondary DVMA read is cause */#define  PSYCHO_CEAFSR_SDWR	0x0400000000000000 /* Secondary DVMA write is cause*/#define  PSYCHO_CEAFSR_RESV1	0x0300000000000000 /* Reserved                     */#define  PSYCHO_CEAFSR_ESYND	0x00ff000000000000 /* Syndrome Bits                */#define  PSYCHO_CEAFSR_BMSK	0x0000ffff00000000 /* Bytemask of failed transfer  */#define  PSYCHO_CEAFSR_DOFF	0x00000000e0000000 /* Double Offset                */#define  PSYCHO_CEAFSR_MID	0x000000001f000000 /* UPA MID causing the fault    */#define  PSYCHO_CEAFSR_BLK	0x0000000000800000 /* Trans was block operation    */#define  PSYCHO_CEAFSR_RESV2	0x00000000007fffff /* Reserved                     */#define PSYCHO_CE_AFAR	0x0040ULstatic void psycho_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 + PSYCHO_CE_AFSR;	unsigned long afar_reg = p->controller_regs + PSYCHO_CE_AFAR;	unsigned long afsr, afar, error_bits;	int reported;	/* Latch error status. */	afar = psycho_read(afar_reg);	afsr = psycho_read(afsr_reg);	/* Clear primary/secondary error status bits. */	error_bits = afsr &		(PSYCHO_CEAFSR_PPIO | PSYCHO_CEAFSR_PDRD | PSYCHO_CEAFSR_PDWR |		 PSYCHO_CEAFSR_SPIO | PSYCHO_CEAFSR_SDRD | PSYCHO_CEAFSR_SDWR);	psycho_write(afsr_reg, error_bits);	/* Log the error. */	printk("PSYCHO%d: Correctable Error, primary error type[%s]\n",	       p->index,	       (((error_bits & PSYCHO_CEAFSR_PPIO) ?		 "PIO" :		 ((error_bits & PSYCHO_CEAFSR_PDRD) ?		  "DMA Read" :		  ((error_bits & PSYCHO_CEAFSR_PDWR) ?		   "DMA Write" : "???")))));	/* XXX Use syndrome and afar to print out module string just like	 * XXX UDB CE trap handler does... -DaveM	 */	printk("PSYCHO%d: syndrome[%02lx] bytemask[%04lx] dword_offset[%lx] "	       "UPA_MID[%02lx] was_block(%d)\n",	       p->index,	       (afsr & PSYCHO_CEAFSR_ESYND) >> 48UL,	       (afsr & PSYCHO_CEAFSR_BMSK) >> 32UL,	       (afsr & PSYCHO_CEAFSR_DOFF) >> 29UL,	       (afsr & PSYCHO_CEAFSR_MID) >> 24UL,	       ((afsr & PSYCHO_CEAFSR_BLK) ? 1 : 0));	printk("PSYCHO%d: CE AFAR [%016lx]\n", p->index, afar);	printk("PSYCHO%d: CE Secondary errors [", p->index);	reported = 0;	if (afsr & PSYCHO_CEAFSR_SPIO) {		reported++;		printk("(PIO)");	}	if (afsr & PSYCHO_CEAFSR_SDRD) {		reported++;		printk("(DMA Read)");	}	if (afsr & PSYCHO_CEAFSR_SDWR) {		reported++;		printk("(DMA Write)");	}	if (!reported)		printk("(none)");	printk("]\n");}/* PCI Errors.  They are signalled by the PCI bus module since they * are assosciated with a specific bus segment. */#define PSYCHO_PCI_AFSR_A	0x2010UL#define PSYCHO_PCI_AFSR_B	0x4010UL#define  PSYCHO_PCIAFSR_PMA	0x8000000000000000 /* Primary Master Abort Error   */#define  PSYCHO_PCIAFSR_PTA	0x4000000000000000 /* Primary Target Abort Error   */#define  PSYCHO_PCIAFSR_PRTRY	0x2000000000000000 /* Primary Excessive Retries    */#define  PSYCHO_PCIAFSR_PPERR	0x1000000000000000 /* Primary Parity Error         */#define  PSYCHO_PCIAFSR_SMA	0x0800000000000000 /* Secondary Master Abort Error */#define  PSYCHO_PCIAFSR_STA	0x0400000000000000 /* Secondary Target Abort Error */#define  PSYCHO_PCIAFSR_SRTRY	0x0200000000000000 /* Secondary Excessive Retries  */#define  PSYCHO_PCIAFSR_SPERR	0x0100000000000000 /* Secondary Parity Error       */#define  PSYCHO_PCIAFSR_RESV1	0x00ff000000000000 /* Reserved                     */#define  PSYCHO_PCIAFSR_BMSK	0x0000ffff00000000 /* Bytemask of failed transfer  */#define  PSYCHO_PCIAFSR_BLK	0x0000000080000000 /* Trans was block operation    */#define  PSYCHO_PCIAFSR_RESV2	0x0000000040000000 /* Reserved                     */#define  PSYCHO_PCIAFSR_MID	0x000000003e000000 /* MID causing the error        */#define  PSYCHO_PCIAFSR_RESV3	0x0000000001ffffff /* Reserved                     */#define PSYCHO_PCI_AFAR_A	0x2018UL#define PSYCHO_PCI_AFAR_B	0x4018ULstatic void psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs){	struct pci_pbm_info *pbm = dev_id;	struct pci_controller_info *p = pbm->parent;	unsigned long afsr_reg, afar_reg;	unsigned long afsr, afar, error_bits;	int is_pbm_a, reported;	is_pbm_a = (pbm == &pbm->parent->pbm_A);	if (is_pbm_a) {		afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_A;		afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_A;	} else {		afsr_reg = p->controller_regs + PSYCHO_PCI_AFSR_B;		afar_reg = p->controller_regs + PSYCHO_PCI_AFAR_B;	}	/* Latch error status. */	afar = psycho_read(afar_reg);	afsr = psycho_read(afsr_reg);	/* Clear primary/secondary error status bits. */	error_bits = afsr &		(PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_PTA |		 PSYCHO_PCIAFSR_PRTRY | PSYCHO_PCIAFSR_PPERR |		 PSYCHO_PCIAFSR_SMA | PSYCHO_PCIAFSR_STA |		 PSYCHO_PCIAFSR_SRTRY | PSYCHO_PCIAFSR_SPERR);	psycho_write(afsr_reg, error_bits);	/* Log the error. */	printk("PSYCHO%d(PBM%c): PCI Error, primary error type[%s]\n",	       p->index, (is_pbm_a ? 'A' : 'B'),	       (((error_bits & PSYCHO_PCIAFSR_PMA) ?		 "Master Abort" :		 ((error_bits & PSYCHO_PCIAFSR_PTA) ?		  "Target Abort" :		  ((error_bits & PSYCHO_PCIAFSR_PRTRY) ?		   "Excessive Retries" :		   ((error_bits & PSYCHO_PCIAFSR_PPERR) ?		    "Parity Error" : "???"))))));	printk("PSYCHO%d(PBM%c): bytemask[%04lx] UPA_MID[%02lx] was_block(%d)\n",	       p->index, (is_pbm_a ? 'A' : 'B'),	       (afsr & PSYCHO_PCIAFSR_BMSK) >> 32UL,	       (afsr & PSYCHO_PCIAFSR_MID) >> 25UL,	       (afsr & PSYCHO_PCIAFSR_BLK) ? 1 : 0);	printk("PSYCHO%d(PBM%c): PCI AFAR [%016lx]\n",	       p->index, (is_pbm_a ? 'A' : 'B'), afar);	printk("PSYCHO%d(PBM%c): PCI Secondary errors [",	       p->index, (is_pbm_a ? 'A' : 'B'));	reported = 0;	if (afsr & PSYCHO_PCIAFSR_SMA) {		reported++;		printk("(Master Abort)");	}	if (afsr & PSYCHO_PCIAFSR_STA) {		reported++;		printk("(Target Abort)");	}	if (afsr & PSYCHO_PCIAFSR_SRTRY) {		reported++;		printk("(Excessive Retries)");	}	if (afsr & PSYCHO_PCIAFSR_SPERR) {		reported++;		printk("(Parity Error)");	}	if (!reported)		printk("(none)");	printk("]\n");	/* For the error types shown, scan PBM's PCI bus 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 & (PSYCHO_PCIAFSR_PTA | PSYCHO_PCIAFSR_STA)) {		psycho_check_iommu_error(p, afsr, afar, PCI_ERR);		pci_scan_for_target_abort(p, pbm, pbm->pci_bus);	}	if (error_bits & (PSYCHO_PCIAFSR_PMA | PSYCHO_PCIAFSR_SMA))		pci_scan_for_master_abort(p, pbm, pbm->pci_bus);	/* For excessive retries, PSYCHO/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 & (PSYCHO_PCIAFSR_PPERR | PSYCHO_PCIAFSR_SPERR))		pci_scan_for_parity_error(p, pbm, pbm->pci_bus);}/* XXX What about PowerFail/PowerManagement??? -DaveM */#define PSYCHO_ECC_CTRL		0x0020#define  PSYCHO_ECCCTRL_EE	 0x8000000000000000 /* Enable ECC Checking */#define  PSYCHO_ECCCTRL_UE	 0x4000000000000000 /* Enable UE Interrupts */#define  PSYCHO_ECCCTRL_CE	 0x2000000000000000 /* Enable CE INterrupts */#define PSYCHO_UE_INO		0x2e#define PSYCHO_CE_INO		0x2f#define PSYCHO_PCIERR_A_INO	0x30#define PSYCHO_PCIERR_B_INO	0x31static void __init psycho_register_error_handlers(struct pci_controller_info *p){	unsigned long base = p->controller_regs;	unsigned int irq, portid = p->portid;	u64 tmp;	/* Build IRQs and register handlers. */	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_UE_INO);	if (request_irq(irq, psycho_ue_intr,			SA_SHIRQ, "PSYCHO UE", p) < 0) {		prom_printf("PSYCHO%d: Cannot register UE interrupt.\n",			    p->index);		prom_halt();	}	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_CE_INO);	if (request_irq(irq, psycho_ce_intr,			SA_SHIRQ, "PSYCHO CE", p) < 0) {		prom_printf("PSYCHO%d: Cannot register CE interrupt.\n",			    p->index);		prom_halt();	}	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_A_INO);	if (request_irq(irq, psycho_pcierr_intr,			SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_A) < 0) {		prom_printf("PSYCHO%d(PBMA): Cannot register PciERR interrupt.\n",			    p->index);		prom_halt();	}	irq = psycho_irq_build(p, NULL, (portid << 6) | PSYCHO_PCIERR_B_INO);	if (request_irq(irq, psycho_pcierr_intr,			SA_SHIRQ, "PSYCHO PCIERR", &p->pbm_B) < 0) {		prom_printf("PSYCHO%d(PBMB): Cannot register PciERR interrupt.\n",			    p->index);		prom_halt();	}	/* Enable UE and CE interrupts for controller. */	psycho_write(base + PSYCHO_ECC_CTRL,		     (PSYCHO_ECCCTRL_EE |		      PSYCHO_ECCCTRL_UE |		      PSYCHO_ECCCTRL_CE));	/* Enable PCI Error interrupts and clear error	 * bits for each PBM.	 */	tmp = psycho_read(base + PSYCHO_PCIA_CTRL);	tmp |= (PSYCHO_PCICTRL_SBH_ERR |		PSYCHO_PCICTRL_SERR |		PSYCHO_PCICTRL_SBH_INT |		PSYCHO_PCICTRL_EEN);	psycho_write(base + PSYCHO_PCIA_CTRL, tmp);		     	tmp = psycho_read(base + PSYCHO_PCIB_CTRL);	tmp |= (PSYCHO_PCICTRL_SBH_ERR |		PSYCHO_PCICTRL_SERR |		PSYCHO_PCICTRL_SBH_INT |		PSYCHO_PCICTRL_EEN);	psycho_write(base + PSYCHO_PCIB_CTRL, tmp);}/* PSYCHO boot time probing and initialization. */static void __init psycho_resource_adjust(struct pci_dev *pdev,					  struct resource *res,					  struct resource *root){	res->start += root->start;	res->end += root->start;}static void __init psycho_base_address_update(struct pci_dev *pdev, int resource){	struct pcidev_cookie *pcp = pdev->sysdata;	struct pci_pbm_info *pbm = pcp->pbm;	struct resource *res, *root;	u32 reg;	int where, size, is_64bit;	res = &pdev->resource[resource];	where = PCI_BASE_ADDRESS_0 + (resource * 4);	is_64bit = 0;	if (res->flags & IORESOURCE_IO)		root = &pbm->io_space;	else {		root = &pbm->mem_space;		if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK)		    == PCI_BASE_ADDRESS_MEM_TYPE_64)			is_64bit = 1;	}	size = res->end - res->start;	pci_read_config_dword(pdev, where, &reg);	reg = ((reg & size) |	       (((u32)(res->start - root->start)) & ~size));	pci_write_config_dword(pdev, where, reg);	/* This knows that the upper 32-bits of the address	 * must be zero.  Our PCI common layer enforces this.	 */	if (is_64bit)		pci_write_config_dword(pdev, where + 4, 0);}/* We have to do the config space accesses by hand, thus... */#define PBM_BRIDGE_BUS		0x40#define PBM_BRIDGE_SUBORDINATE	0x41static void __init pbm_renumber(struct pci_pbm_info *pbm, u8 orig_busno){	u8 *addr, busno;	int nbus;	busno = pci_highest_busnum;	nbus = pbm->pci_last_busno - pbm->pci_first_busno;	addr = psycho_pci_config_mkaddr(pbm, orig_busno,					0, PBM_BRIDGE_BUS);	pci_config_write8(addr, busno);	addr = psycho_pci_config_mkaddr(pbm, busno,					0, PBM_BRIDGE_SUBORDINATE);	pci_config_write8(addr, busno + nbus);	pbm->pci_first_busno = busno;	pbm->pci_last_busno = busno + nbus;	pci_highest_busnum = busno + nbus + 1;	do {		pci_bus2pbm[busno++] = pbm;	} while (nbus--);}/* We have to do the config space accesses by hand here since * the pci_bus2pbm array is not ready yet. */static void __init pbm_pci_bridge_renumber(struct pci_pbm_info *pbm,					   u8 busno){	u32 devfn, l, class;	u8 hdr_type;	int is_multi = 0;	for(devfn = 0; devfn < 0xff; ++devfn) {		u32 *dwaddr;		u8 *baddr;		if (PCI_FUNC(devfn) != 0 && is_multi == 0)			continue;		/* Anything there? */		dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_VENDOR_ID);		l = 0xffffffff;		pci_config_read32(dwaddr, &l);		if (l == 0xffffffff || l == 0x00000000 ||		    l == 0x0000ffff || l == 0xffff0000) {			is_multi = 0;			continue;		}		baddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_HEADER_TYPE);		pci_config_read8(baddr, &hdr_type);		if (PCI_FUNC(devfn) == 0)			is_multi = hdr_type & 0x80;		dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn, PCI_CLASS_REVISION);		class = 0xffffffff;		pci_config_read32(dwaddr, &class);		if ((class >> 16) == PCI_CLASS_BRIDGE_PCI) {			u32 buses = 0xffffffff;			dwaddr = psycho_pci_config_mkaddr(pbm, busno, devfn,							  PCI_PRIMARY_BUS);			pci_config_read32(dwaddr, &buses);			pbm_pci_bridge_renumber(pbm, (buses >> 8) & 0xff);			buses &= 0xff000000;			pci_config_write32(dwaddr, buses);		}	}}static void __init pbm_bridge_reconfigure(struct pci_controller_info *p){	struct pci_pbm_info *pbm;	u8 *addr;	/* Clear out primary/secondary/subordinate bus numbers on

⌨️ 快捷键说明

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