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

📄 shubio.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
字号:
/* $Id: shubio.c,v 1.1 2002/02/28 17:31:25 marcelo Exp $ * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 1992 - 1997, 2000,2002 Silicon Graphics, Inc. All rights reserved. */#include <linux/types.h>#include <linux/slab.h>#include <asm/smp.h>#include <asm/sn/sgi.h>#include <asm/sn/io.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/labelcl.h>#include <asm/sn/sn_private.h>#include <asm/sn/klconfig.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/pci/pciio.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/xtalk/xtalk.h>#include <asm/sn/pci/pcibr_private.h>#include <asm/sn/intr.h>#include <asm/sn/ioerror_handling.h>#include <asm/sn/ioerror.h>#include <asm/sn/sn2/shubio.h>error_state_t error_state_get(devfs_handle_t v);error_return_code_t error_state_set(devfs_handle_t v,error_state_t new_state);/* * Get the xtalk provider function pointer for the * specified hub. *//*ARGSUSED*/inthub_xp_error_handler(	devfs_handle_t 	hub_v, 	nasid_t		nasid, 	int		error_code, 	ioerror_mode_t	mode, 	ioerror_t	*ioerror){	/*REFERENCED*/	hubreg_t	iio_imem;	devfs_handle_t	xswitch;	error_state_t	e_state;	cnodeid_t	cnode;	/*	 * Before walking down to the next level, check if	 * the I/O link is up. If it's been disabled by the 	 * hub ii for some reason, we can't even touch the	 * widget registers.	 */	iio_imem = REMOTE_HUB_L(nasid, IIO_IMEM);	if (!(iio_imem & (IIO_IMEM_B0ESD|IIO_IMEM_W0ESD))){		/* 		 * IIO_IMEM_B0ESD getting set, indicates II shutdown		 * on HUB0 parts.. Hopefully that's not true for 		 * Hub1 parts..		 *		 *		 * If either one of them is shut down, can't		 * go any further.		 */		return IOERROR_XTALKLEVEL;	}	/* Get the error state of the hub */	e_state = error_state_get(hub_v);	cnode = NASID_TO_COMPACT_NODEID(nasid);	xswitch = NODEPDA(cnode)->basew_xc;	/* Set the error state of the crosstalk device to that of	 * hub.	 */	if (error_state_set(xswitch , e_state) == 	    ERROR_RETURN_CODE_CANNOT_SET_STATE)		return(IOERROR_UNHANDLED);	/* Clean the error state of the hub if we are in the action handling	 * phase.	 */	if (e_state == ERROR_STATE_ACTION)		(void)error_state_set(hub_v, ERROR_STATE_NONE);	/* hand the error off to the switch or the directly	 * connected crosstalk device.	 */	return  xtalk_error_handler(xswitch,				    error_code, mode, ioerror);}/*  * Check if the widget in error has been enabled for PIO accesses */intis_widget_pio_enabled(ioerror_t *ioerror){	cnodeid_t	src_node;	nasid_t		src_nasid;	hubreg_t	ii_iowa;	xwidgetnum_t	widget;	iopaddr_t	p;	/* Get the node where the PIO error occurred */	IOERROR_GETVALUE(p,ioerror, srcnode);	src_node = p;	if (src_node == CNODEID_NONE)		return(0);	/* Get the nasid for the cnode */	src_nasid = COMPACT_TO_NASID_NODEID(src_node);	if (src_nasid == INVALID_NASID)		return(0);	/* Read the Outbound widget access register for this hub */	ii_iowa = REMOTE_HUB_L(src_nasid, IIO_IOWA);	IOERROR_GETVALUE(p,ioerror, widgetnum);	widget = p;	/* Check if the PIOs to the widget with PIO error have been	 * enabled.	 */	if (ii_iowa & IIO_IOWA_WIDGET(widget))		return(1);	return(0);}/* * Hub IO error handling. * *	Gets invoked for different types of errors found at the hub.  *	Typically this includes situations from bus error or due to  *	an error interrupt (mostly generated at the hub). */inthub_ioerror_handler(	devfs_handle_t 	hub_v, 	int		error_code,	int		mode,	struct io_error_s	*ioerror){	hubinfo_t 	hinfo; 		/* Hub info pointer */	nasid_t		nasid;	int		retval = 0;	/*REFERENCED*/	iopaddr_t 	p;	IOERROR_DUMP("hub_ioerror_handler", error_code, mode, ioerror);	hubinfo_get(hub_v, &hinfo);	if (!hinfo){		/* Print an error message and return */		goto end;	}	nasid = hinfo->h_nasid;	switch(error_code) {	case PIO_READ_ERROR:		/* 		 * Cpu got a bus error while accessing IO space.		 * hubaddr field in ioerror structure should have		 * the IO address that caused access error.		 */		/*		 * Identify if  the physical address in hub_error_data		 * corresponds to small/large window, and accordingly,		 * get the xtalk address.		 */		/*		 * Evaluate the widget number and the widget address that		 * caused the error. Use 'vaddr' if it's there.		 * This is typically true either during probing		 * or a kernel driver getting into trouble. 		 * Otherwise, use paddr to figure out widget details		 * This is typically true for user mode bus errors while		 * accessing I/O space.		 */		 IOERROR_GETVALUE(p,ioerror,vaddr);		 if (p){		    /* 		     * If neither in small window nor in large window range,		     * outright reject it.		     */		    IOERROR_GETVALUE(p,ioerror,vaddr);		    if (NODE_SWIN_ADDR(nasid, (paddr_t)p)){			iopaddr_t	hubaddr;			xwidgetnum_t	widgetnum;			iopaddr_t	xtalkaddr;			IOERROR_GETVALUE(p,ioerror,hubaddr);			hubaddr = p;			widgetnum = SWIN_WIDGETNUM(hubaddr);			xtalkaddr = SWIN_WIDGETADDR(hubaddr);			/* 			 * differentiate local register vs IO space access			 */			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);		    } else if (NODE_BWIN_ADDR(nasid, (paddr_t)p)){			/* 			 * Address corresponds to large window space. 			 * Convert it to xtalk address.			 */			int		bigwin;			hub_piomap_t    bw_piomap;			xtalk_piomap_t	xt_pmap = NULL;			iopaddr_t	hubaddr;			xwidgetnum_t	widgetnum;			iopaddr_t	xtalkaddr;			IOERROR_GETVALUE(p,ioerror,hubaddr);			hubaddr = p;			/*			 * Have to loop to find the correct xtalk_piomap 			 * because the're not allocated on a one-to-one			 * basis to the window number.			 */			for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) {				bw_piomap = hubinfo_bwin_piomap_get(hinfo,								    bigwin);				if (bw_piomap->hpio_bigwin_num ==				    (BWIN_WINDOWNUM(hubaddr) - 1)) {					xt_pmap = hub_piomap_xt_piomap(bw_piomap);					break;				}			}			ASSERT(xt_pmap);			widgetnum = xtalk_pio_target_get(xt_pmap);			xtalkaddr = xtalk_pio_xtalk_addr_get(xt_pmap) + BWIN_WIDGETADDR(hubaddr);			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);			/* 			 * Make sure that widgetnum doesnot map to hub 			 * register widget number, as we never use			 * big window to access hub registers. 			 */			ASSERT(widgetnum != HUB_REGISTER_WIDGET);		    }		} else if (IOERROR_FIELDVALID(ioerror,hubaddr)) {			iopaddr_t	hubaddr;			xwidgetnum_t	widgetnum;			iopaddr_t	xtalkaddr;			IOERROR_GETVALUE(p,ioerror,hubaddr);			hubaddr = p;			if (BWIN_WINDOWNUM(hubaddr)){				int 	window = BWIN_WINDOWNUM(hubaddr) - 1;				hubreg_t itte;				itte = (hubreg_t)HUB_L(IIO_ITTE_GET(nasid, window));				widgetnum =  (itte >> IIO_ITTE_WIDGET_SHIFT) & 						IIO_ITTE_WIDGET_MASK;				xtalkaddr = (((itte >> IIO_ITTE_OFFSET_SHIFT) &					IIO_ITTE_OFFSET_MASK) << 					     BWIN_SIZE_BITS) +					BWIN_WIDGETADDR(hubaddr);			} else {				widgetnum = SWIN_WIDGETNUM(hubaddr);				xtalkaddr = SWIN_WIDGETADDR(hubaddr);			}			IOERROR_SETVALUE(ioerror,widgetnum,widgetnum);			IOERROR_SETVALUE(ioerror,xtalkaddr,xtalkaddr);		} else {			IOERROR_DUMP("hub_ioerror_handler", error_code, 						mode, ioerror);			IOERR_PRINTF(printk(				"hub_ioerror_handler: Invalid address passed"));			return IOERROR_INVALIDADDR;		}		IOERROR_GETVALUE(p,ioerror,widgetnum);		if ((p) == HUB_REGISTER_WIDGET) {			/* 			 * Error in accessing Hub local register			 * This should happen mostly in SABLE mode..			 */			retval = 0;		} else {			/* Make sure that the outbound widget access for this			 * widget is enabled.			 */			if (!is_widget_pio_enabled(ioerror)) {				if (error_state_get(hub_v) == 				    ERROR_STATE_ACTION)					ioerror_dump("No outbound widget"						     " access - ", 						     error_code, mode, ioerror);				return(IOERROR_HANDLED);			}		  			retval = hub_xp_error_handler(				hub_v, nasid, error_code, mode, ioerror);		}		IOERR_PRINTF(printk(			"hub_ioerror_handler:PIO_READ_ERROR return: %d",				retval));		break;	case PIO_WRITE_ERROR:		/*		 * This hub received an interrupt indicating a widget 		 * attached to this hub got a timeout. 		 * widgetnum field should be filled to indicate the		 * widget that caused error.		 *		 * NOTE: This hub may have nothing to do with this error.		 * We are here since the widget attached to the xbow 		 * gets its PIOs through this hub.		 *		 * There is nothing that can be done at this level. 		 * Just invoke the xtalk error handling mechanism.		 */		IOERROR_GETVALUE(p,ioerror,widgetnum);		if ((p) == HUB_REGISTER_WIDGET) {		} else {			/* Make sure that the outbound widget access for this			 * widget is enabled.			 */			if (!is_widget_pio_enabled(ioerror)) {				if (error_state_get(hub_v) == 				    ERROR_STATE_ACTION)					ioerror_dump("No outbound widget"						     " access - ", 						     error_code, mode, ioerror);				return(IOERROR_HANDLED);			}		  			retval = hub_xp_error_handler(				hub_v, nasid, error_code, mode, ioerror);		}		break;		case DMA_READ_ERROR:		/* 		 * DMA Read error always ends up generating an interrupt		 * at the widget level, and never at the hub level. So,		 * we don't expect to come here any time		 */		ASSERT(0);		retval = IOERROR_UNHANDLED;		break;	case DMA_WRITE_ERROR:		/*		 * DMA Write error is generated when a write by an I/O 		 * device could not be completed. Problem is, device is		 * totally unaware of this problem, and would continue		 * writing to system memory. So, hub has a way to send		 * an error interrupt on the first error, and bitbucket		 * all further write transactions.		 * Coming here indicates that hub detected one such error,		 * and we need to handle it.		 *		 * Hub interrupt handler would have extracted physaddr, 		 * widgetnum, and widgetdevice from the CRB 		 *		 * There is nothing special to do here, since gathering		 * data from crb's is done elsewhere. Just pass the 		 * error to xtalk layer.		 */		retval = hub_xp_error_handler(hub_v, nasid, error_code, mode,					      ioerror);		break;		default:		ASSERT(0);		return IOERROR_BADERRORCODE;		}		/*	 * If error was not handled, we may need to take certain action	 * based on the error code.	 * For e.g. in case of PIO_READ_ERROR, we may need to release the	 * PIO Read entry table (they are sticky after errors).	 * Similarly other cases. 	 *	 * Further Action TBD 	 */end:		if (retval == IOERROR_HWGRAPH_LOOKUP) {		/*		 * If we get errors very early, we can't traverse		 * the path using hardware graph. 		 * To handle this situation, we need a functions		 * which don't depend on the hardware graph vertex to 		 * handle errors. This break the modularity of the		 * existing code. Instead we print out the reason for		 * not handling error, and return. On return, all the		 * info collected would be dumped. This should provide 		 * sufficient info to analyse the error.		 */		printk("Unable to handle IO error: hardware graph not setup\n");	}	return retval;}#define L_BITSMINOR 18#define L_MAXMAJ 0x1ff#define emajor(x) (int )(((unsigned )(x)>>L_BITSMINOR) & L_MAXMAJ)#define dev_is_vertex(dev) (emajor((dev_t)(dev)) == 0)#define INFO_LBL_ERROR_STATE    "error_state"#define v_error_state_get(v,s)                                          \(hwgraph_info_get_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t *)&s))#define v_error_state_set(v,s,replace)                                  \(replace ?                                                              \hwgraph_info_replace_LBL(v,INFO_LBL_ERROR_STATE,(arbitrary_info_t)s,0) :\hwgraph_info_add_LBL(v,INFO_LBL_ERROR_STATE, (arbitrary_info_t)s))#define v_error_state_clear(v)                                          \(hwgraph_info_remove_LBL(v,INFO_LBL_ERROR_STATE,0))/* * error_state_get *              Get the state of the vertex. *              Returns ERROR_STATE_INVALID on failure *                      current state otherwise */error_state_terror_state_get(devfs_handle_t v){        error_state_t   s;        /* Check if we have a valid hwgraph vertex */        if (!dev_is_vertex(v))                return(ERROR_STATE_NONE);        /* Get the labelled info hanging off the vertex which corresponds         * to the state.         */        if (v_error_state_get(v, s) != GRAPH_SUCCESS) {                return(ERROR_STATE_NONE);        }        return(s);}/* * error_state_set *              Set the state of the vertex *              Returns ERROR_RETURN_CODE_CANNOT_SET_STATE on failure *                      ERROR_RETURN_CODE_SUCCESS otherwise */error_return_code_terror_state_set(devfs_handle_t v,error_state_t new_state){        error_state_t   old_state;        boolean_t       replace = B_TRUE;        /* Check if we have a valid hwgraph vertex */        if (!dev_is_vertex(v))                return(ERROR_RETURN_CODE_GENERAL_FAILURE);        /* This means that the error state needs to be cleaned */        if (new_state == ERROR_STATE_NONE) {                /* Make sure that we have an error state */                if (v_error_state_get(v,old_state) == GRAPH_SUCCESS)                        v_error_state_clear(v);                return(ERROR_RETURN_CODE_SUCCESS);        }        /* Check if the state information has been set at least once         * for this vertex.         */        if (v_error_state_get(v,old_state) != GRAPH_SUCCESS)                replace = B_FALSE;        if (v_error_state_set(v,new_state,replace) != GRAPH_SUCCESS) {                return(ERROR_RETURN_CODE_CANNOT_SET_STATE);        }        return(ERROR_RETURN_CODE_SUCCESS);}

⌨️ 快捷键说明

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