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

📄 pcibr_error.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 5 页
字号:
    /* We read the INT_STATUS register as a 64bit picreg_t for PIC and a     * 32bit bridgereg_t for BRIDGE, but always process the result as a     * 64bit value so the code can be "common" for both PIC and BRIDGE...     */    if (IS_PIC_SOFT(pcibr_soft)) {        int_status_64 = (bridge->p_int_status_64 & ~BRIDGE_ISR_INT_MSK);        int_status = (uint64_t)int_status_64;        number_bits = PCIBR_ISR_MAX_ERRS_PIC;    } else {        int_status_32 = (bridge->b_int_status & ~BRIDGE_ISR_INT_MSK);        int_status = ((uint64_t)int_status_32) & 0xffffffff;        number_bits = PCIBR_ISR_MAX_ERRS_BRIDGE;    }    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_INTR_ERROR, pcibr_soft->bs_conn,		"pcibr_error_intr_handler: int_status=0x%x\n", int_status));    /* int_status is which bits we have to clear;     * err_status is the bits we haven't handled yet.     */    err_status = int_status & ~BRIDGE_ISR_MULTI_ERR;    if (!(int_status & ~BRIDGE_ISR_INT_MSK)) {	/*	 * No error bit set!!.	 */	return;    }    /*     * If we have a PCIBUS_PIOERR, hand it to the logger.     */    if (int_status & BRIDGE_ISR_PCIBUS_PIOERR) {	pcibr_pioerr_check(pcibr_soft);    }#ifdef BRIDGE_B_DATACORR_WAR    if ((pcibr_soft->bs_rev_num == BRIDGE_PART_REV_B) &&	(err_status & BRIDGE_IMR_LLP_REC_CBERR)) {	if (bridge_rev_b_data_check_disable)	    printk(KERN_WARNING "\n%s%s: %s%s\n", rev_b_datacorr_warning,		    pcibr_soft->bs_name, rev_b_datacorr_mesg,		    rev_b_datacorr_warning);	else {	    ql_bridge_rev_b_war(pcibr_soft->bs_vhdl);	    PRINT_PANIC( "\n%s%s: %s%s\n", rev_b_datacorr_warning,		    pcibr_soft->bs_name, rev_b_datacorr_mesg,		    rev_b_datacorr_warning);	}	err_status &= ~BRIDGE_IMR_LLP_REC_CBERR;    }#endif				/* BRIDGE_B_DATACORR_WAR */    if (err_status) {	struct bs_errintr_stat_s *bs_estat = pcibr_soft->bs_errintr_stat;	for (i = PCIBR_ISR_ERR_START; i < number_bits; i++, bs_estat++) {	    if (err_status & (1ull << i)) {		uint32_t              errrate = 0;		uint32_t              errcount = 0;		uint32_t              errinterval = 0, current_tick = 0;		int                     llp_tx_retry_errors = 0;		int                     is_llp_tx_retry_intr = 0;		bs_estat->bs_errcount_total++;		current_tick = jiffies;		errinterval = (current_tick - bs_estat->bs_lasterr_timestamp);		errcount = (bs_estat->bs_errcount_total -			    bs_estat->bs_lasterr_snapshot);		/* LLP interrrupt errors are only valid on BUS0 of the PIC */		if (pcibr_soft->bs_busnum == 0)		    is_llp_tx_retry_intr = (BRIDGE_ISR_LLP_TX_RETRY==(1ull << i));		/* Check for the divide by zero condition while		 * calculating the error rates.		 */		if (errinterval) {		    errrate = errcount / errinterval;		    /* If able to calculate error rate		     * on a LLP transmitter retry interrupt, check		     * if the error rate is nonzero and we have seen		     * a certain minimum number of errors.		     *		     * NOTE : errcount is being compared to		     * PCIBR_ERRTIME_THRESHOLD to make sure that we are not		     * seeing cases like x error interrupts per y ticks for		     * very low x ,y (x > y ) which could result in a		     * rate > 100/tick.		     */		    if (is_llp_tx_retry_intr &&			errrate &&			(errcount >= PCIBR_ERRTIME_THRESHOLD)) {			llp_tx_retry_errors = 1;		    }		} else {		    errrate = 0;		    /* Since we are not able to calculate the		     * error rate check if we exceeded a certain		     * minimum number of errors for LLP transmitter		     * retries. Note that this can only happen		     * within the first tick after the last snapshot.		     */		    if (is_llp_tx_retry_intr &&			(errcount >= PCIBR_ERRINTR_DISABLE_LEVEL)) {			llp_tx_retry_errors = 1;		    }		}		/*		 * If a non-zero error rate (which is equivalent to		 * to 100 errors/tick at least) for the LLP transmitter		 * retry interrupt was seen, check if we should print		 * a warning message.		 */		if (llp_tx_retry_errors) {		    static uint32_t       last_printed_rate;		    if (errrate > last_printed_rate) {			last_printed_rate = errrate;			/* Print the warning only if the error rate			 * for the transmitter retry interrupt			 * exceeded the previously printed rate.			 */			printk(KERN_WARNING				"%s: %s, Excessive error interrupts : %d/tick\n",				pcibr_soft->bs_name,				pcibr_isr_errs[i],				errrate);		    }		    /*		     * Update snapshot, and time		     */		    bs_estat->bs_lasterr_timestamp = current_tick;		    bs_estat->bs_lasterr_snapshot =			bs_estat->bs_errcount_total;		}		/*		 * If the error rate is high enough, print the error rate.		 */		if (errinterval > PCIBR_ERRTIME_THRESHOLD) {		    if (errrate > PCIBR_ERRRATE_THRESHOLD) {			printk(KERN_NOTICE "%s: %s, Error rate %d/tick",				pcibr_soft->bs_name,				pcibr_isr_errs[i],				errrate);			/*			 * Update snapshot, and time			 */			bs_estat->bs_lasterr_timestamp = current_tick;			bs_estat->bs_lasterr_snapshot =			    bs_estat->bs_errcount_total;		    }		}		/* PIC BRINGUP WAR (PV# 856155):		 * Dont disable PCI_X_ARB_ERR interrupts, we need the		 * interrupt inorder to clear the DEV_BROKE bits in		 * b_arb register to re-enable the device.		 */		if (IS_PIC_SOFT(pcibr_soft) &&				!(err_status & PIC_ISR_PCIX_ARB_ERR) &&				PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) {		if (bs_estat->bs_errcount_total > PCIBR_ERRINTR_DISABLE_LEVEL) {		    /*		     * We have seen a fairly large number of errors of		     * this type. Let's disable the interrupt. But flash		     * a message about the interrupt being disabled.		     */		    printk(KERN_NOTICE			    "%s Disabling error interrupt type %s. Error count %d",			    pcibr_soft->bs_name,			    pcibr_isr_errs[i],			    bs_estat->bs_errcount_total);		    disable_errintr_mask |= (1ull << i);		}		} /* PIC: WAR for PV 856155 end-of-if */	    }	}    }    if (disable_errintr_mask) {	unsigned s;	/*	 * Disable some high frequency errors as they	 * could eat up too much cpu time.	 */	s = pcibr_lock(pcibr_soft);	if (IS_PIC_SOFT(pcibr_soft)) {	    bridge->p_int_enable_64 &= (picreg_t)(~disable_errintr_mask);	} else {	    bridge->b_int_enable &= (bridgereg_t)(~disable_errintr_mask);	}	pcibr_unlock(pcibr_soft, s);    }    /*     * If we leave the PROM cacheable, T5 might     * try to do a cache line sized writeback to it,     * which will cause a BRIDGE_ISR_INVLD_ADDR.     */    if ((err_status & BRIDGE_ISR_INVLD_ADDR) &&	(0x00000000 == bridge->b_wid_err_upper) &&	(0x00C00000 == (0xFFC00000 & bridge->b_wid_err_lower)) &&	(0x00402000 == (0x00F07F00 & bridge->b_wid_err_cmdword))) {	err_status &= ~BRIDGE_ISR_INVLD_ADDR;    }#if defined (PCIBR_LLP_CONTROL_WAR)    /*     * The bridge bug, where the llp_config or control registers     * need to be read back after being written, affects an MP     * system since there could be small windows between writing     * the register and reading it back on one cpu while another     * cpu is fielding an interrupt. If we run into this scenario,     * workaround the problem by ignoring the error. (bug 454474)     * pcibr_llp_control_war_cnt keeps an approximate number of     * times we saw this problem on a system.     */    if ((err_status & BRIDGE_ISR_INVLD_ADDR) &&	((((uint64_t) bridge->b_wid_err_upper << 32) | (bridge->b_wid_err_lower))	 == (BRIDGE_INT_RST_STAT & 0xff0))) {#if 0	if (kdebug)	    printk(KERN_NOTICE "%s bridge: ignoring llp/control address interrupt",		    pcibr_soft->bs_name);#endif	pcibr_llp_control_war_cnt++;	err_status &= ~BRIDGE_ISR_INVLD_ADDR;    }#endif				/* PCIBR_LLP_CONTROL_WAR */#ifdef EHE_ENABLE    /* Check if this is the RESP_XTALK_ERROR interrupt.      * This can happen due to a failed DMA READ operation.     */    if (err_status & BRIDGE_ISR_RESP_XTLK_ERR) {	/* Phase 1 : Look at the error state in the bridge and further	 * down in the device layers.	 */	(void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_LOOKUP);	IOERROR_SETVALUE(&ioe, widgetnum, pcibr_soft->bs_xid);	(void)pcibr_error_handler((error_handler_arg_t)pcibr_soft,				  error_code,				  mode,				  &ioe);	/* Phase 2 : Perform the action agreed upon in phase 1.	 */	(void)error_state_set(pcibr_soft->bs_conn, ERROR_STATE_ACTION);	rv = pcibr_error_handler((error_handler_arg_t)pcibr_soft,				 error_code,				 mode,				 &ioe);    }    if (rv != IOERROR_HANDLED) {#endif /* EHE_ENABLE */    bridge_errors_to_dump |= BRIDGE_ISR_PCIBUS_PIOERR;    /* Dump/Log Bridge error interrupt info */    if (err_status & bridge_errors_to_dump) {	printk("BRIDGE ERR_STATUS 0x%lx\n", err_status);	pcibr_error_dump(pcibr_soft);    }    /* PIC BRINGUP WAR (PV# 867308):     * Make BRIDGE_ISR_LLP_REC_SNERR & BRIDGE_ISR_LLP_REC_CBERR fatal errors     * so we know we've hit the problem defined in PV 867308 that we believe     * has only been seen in simulation     */    if (IS_PIC_SOFT(pcibr_soft) && PCIBR_WAR_ENABLED(PV867308, pcibr_soft) &&        (err_status & (BRIDGE_ISR_LLP_REC_SNERR | BRIDGE_ISR_LLP_REC_CBERR))) {        printk("BRIDGE ERR_STATUS 0x%x\n", err_status);        pcibr_error_dump(pcibr_soft);#ifdef LATER        machine_error_dump("");#endif        PRINT_PANIC("PCI Bridge Error interrupt killed the system");    }    if (err_status & BRIDGE_ISR_ERROR_FATAL) {#ifdef LATER	machine_error_dump("");#endif	PRINT_PANIC("PCI Bridge Error interrupt killed the system");	    /*NOTREACHED */    }#ifdef EHE_ENABLE    }#endif    /*     * We can't return without re-enabling the interrupt, since     * it would cause problems for devices like IOC3 (Lost     * interrupts ?.). So, just cleanup the interrupt, and     * use saved values later..     *      * PIC doesn't require groups of interrupts to be cleared...     */    if (IS_PIC_SOFT(pcibr_soft)) {	bridge->p_int_rst_stat_64 = (picreg_t)(int_status | BRIDGE_IRR_MULTI_CLR);    } else {	bridge->b_int_rst_stat = (bridgereg_t)pcibr_errintr_group(int_status);    }    /* PIC BRINGUP WAR (PV# 856155):     * On a PCI_X_ARB_ERR error interrupt clear the DEV_BROKE bits from     * the b_arb register to re-enable the device.     */    if (IS_PIC_SOFT(pcibr_soft) &&		(err_status & PIC_ISR_PCIX_ARB_ERR) &&		PCIBR_WAR_ENABLED(PV856155, pcibr_soft)) {	bridge->b_arb |= (0xf << 20);    }    /* Zero out bserr_intstat field */    pcibr_soft->bs_errinfo.bserr_intstat = 0;}/* * pcibr_addr_toslot *      Given the 'pciaddr' find out which slot this address is *      allocated to, and return the slot number. *      While we have the info handy, construct the *      function number, space code and offset as well. * * NOTE: if this routine is called, we don't know whether * the address is in CFG, MEM, or I/O space. We have to guess. * This will be the case on PIO stores, where the only way * we have of getting the address is to check the Bridge, which * stores the PCI address but not the space and not the xtalk * address (from which we could get it). */intpcibr_addr_toslot(pcibr_soft_t pcibr_soft,		  iopaddr_t pciaddr,		  pciio_space_t *spacep,		  iopaddr_t *offsetp,		  pciio_function_t *funcp){    int                     s, f = 0, w;    iopaddr_t               base;    size_t                  size;    pciio_piospace_t        piosp;    /*     * Check if the address is in config space     */    if ((pciaddr >= BRIDGE_CONFIG_BASE) && (pciaddr < BRIDGE_CONFIG_END)) {	if (pciaddr >= BRIDGE_CONFIG1_BASE)	    pciaddr -= BRIDGE_CONFIG1_BASE;	else	    pciaddr -= BRIDGE_CONFIG_BASE;	s = pciaddr / BRIDGE_CONFIG_SLOT_SIZE;	pciaddr %= BRIDGE_CONFIG_SLOT_SIZE;	if (funcp) {	    f = pciaddr / 0x100;	    pciaddr %= 0x100;	}	if (spacep)	    *spacep = PCIIO_SPACE_CFG;	if (offsetp)	    *offsetp = pciaddr;	if (funcp)	    *funcp = f;	return s;    }    for (s = pcibr_soft->bs_min_slot; s < PCIBR_NUM_SLOTS(pcibr_soft); ++s) {	int                     nf = pcibr_soft->bs_slot[s].bss_ninfo;	pcibr_info_h            pcibr_infoh = pcibr_soft->bs_slot[s].bss_infos;	for (f = 0; f < nf; f++) {	    pcibr_info_t            pcibr_info = pcibr_infoh[f];	    if (!pcibr_info)		continue;	    for (w = 0; w < 6; w++) {		if (pcibr_info->f_window[w].w_space == PCIIO_SPACE_NONE) {		    continue;		}		base = pcibr_info->f_window[w].w_base;		size = pcibr_info->f_window[w].w_size;		if ((pciaddr >= base) && (pciaddr < (base + size))) {		    if (spacep)			*spacep = PCIIO_SPACE_WIN(w);		    if (offsetp)			*offsetp = pciaddr - base;		    if (funcp)			*funcp = f;		    return s;		}			/* endif match */	    }				/* next window */	}				/* next func */    }					/* next slot */

⌨️ 快捷键说明

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