📄 shubio.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 + -