📄 ml_iograph.c
字号:
/* $Id$ * * 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-2003 Silicon Graphics, Inc. All rights reserved. */#include <linux/types.h>#include <linux/slab.h>#include <linux/ctype.h>#include <asm/sn/sgi.h>#include <asm/sn/sn_sal.h>#include <asm/sn/io.h>#include <asm/sn/sn_cpuid.h>#include <asm/sn/iograph.h>#include <asm/sn/invent.h>#include <asm/sn/hcl.h>#include <asm/sn/hcl_util.h>#include <asm/sn/labelcl.h>#include <asm/sn/xtalk/xbow.h>#include <asm/sn/pci/bridge.h>#include <asm/sn/klconfig.h>#include <asm/sn/sn_private.h>#include <asm/sn/pci/pcibr.h>#include <asm/sn/xtalk/xtalk.h>#include <asm/sn/xtalk/xswitch.h>#include <asm/sn/xtalk/xwidget.h>#include <asm/sn/xtalk/xtalk_private.h>#include <asm/sn/xtalk/xtalkaddrs.h>/* #define IOGRAPH_DEBUG */#ifdef IOGRAPH_DEBUG#define DBG(x...) printk(x)#else#define DBG(x...)#endif /* IOGRAPH_DEBUG *//* #define PROBE_TEST *//* At most 2 hubs can be connected to an xswitch */#define NUM_XSWITCH_VOLUNTEER 2/* * Track which hubs have volunteered to manage devices hanging off of * a Crosstalk Switch (e.g. xbow). This structure is allocated, * initialized, and hung off the xswitch vertex early on when the * xswitch vertex is created. */typedef struct xswitch_vol_s { struct semaphore xswitch_volunteer_mutex; int xswitch_volunteer_count; vertex_hdl_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];} *xswitch_vol_t;voidxswitch_vertex_init(vertex_hdl_t xswitch){ xswitch_vol_t xvolinfo; int rc; xvolinfo = snia_kmem_zalloc(sizeof(struct xswitch_vol_s)); init_MUTEX(&xvolinfo->xswitch_volunteer_mutex); rc = hwgraph_info_add_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t)xvolinfo); ASSERT(rc == GRAPH_SUCCESS); rc = rc;}/* * When assignment of hubs to widgets is complete, we no longer need the * xswitch volunteer structure hanging around. Destroy it. */static voidxswitch_volunteer_delete(vertex_hdl_t xswitch){ xswitch_vol_t xvolinfo; int rc; extern void snia_kmem_free(void *ptr, size_t size); rc = hwgraph_info_remove_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); snia_kmem_free(xvolinfo, sizeof(struct xswitch_vol_s));}/* * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. *//* ARGSUSED */static voidvolunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master){ xswitch_vol_t xvolinfo = NULL; vertex_hdl_t hubv; hubinfo_t hubinfo; (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { if (!is_headless_node_vertex(master)) printk(KERN_WARNING "volunteer for widgets: vertex 0x%p has no info label", (void *)xswitch); return; } down(&xvolinfo->xswitch_volunteer_mutex); ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; xvolinfo->xswitch_volunteer_count++; /* * if dual ported, make the lowest widgetid always be * xswitch_volunteer[0]. */ if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) { hubv = xvolinfo->xswitch_volunteer[0]; hubinfo_get(hubv, &hubinfo); if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) { xvolinfo->xswitch_volunteer[0] = xvolinfo->xswitch_volunteer[1]; xvolinfo->xswitch_volunteer[1] = hubv; } } up(&xvolinfo->xswitch_volunteer_mutex);}extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);/* * Assign all the xwidgets hanging off the specified xswitch to the * Crosstalk masters that have volunteered for xswitch duty. *//* ARGSUSED */static voidassign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv){ xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; xwidgetnum_t widgetnum; int num_volunteer; nasid_t nasid; hubinfo_t hubinfo; extern int iobrick_type_get_nasid(nasid_t); hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; xswitch_info = xswitch_info_get(xswitch); ASSERT(xswitch_info != NULL); (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { if (!is_headless_node_vertex(hubv)) printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%p has " " no info label", (void *)xswitch); return; } num_volunteer = xvolinfo->xswitch_volunteer_count; ASSERT(num_volunteer > 0); /* Assign master hub for xswitch itself. */ if (HUB_WIDGET_ID_MIN > 0) { hubv = xvolinfo->xswitch_volunteer[0]; xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); } /* * TBD: Use administrative information to alter assignment of * widgets to hubs. */ for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { int i; /* * Ignore disabled/empty ports. */ if (!xbow_port_io_enabled(nasid, widgetnum)) continue; /* * If this is the master IO board, assign it to the same * hub that owned it in the prom. */ if (is_master_baseio_nasid_widget(nasid, widgetnum)) { extern nasid_t snia_get_master_baseio_nasid(void); for (i=0; i<num_volunteer; i++) { hubv = xvolinfo->xswitch_volunteer[i]; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; if (nasid == snia_get_master_baseio_nasid()) goto do_assignment; } panic("Nasid == %d, console nasid == %d", nasid, snia_get_master_baseio_nasid()); } /* * Assuming that we're dual-hosted and that PCI cards * are naturally placed left-to-right, alternate PCI * buses across both Cbricks. For Pbricks, and Ibricks, * io_brick_map_widget() returns the PCI bus number * associated with the given brick type and widget number. * For Xbricks, it returns the XIO slot number. */ i = 0; if (num_volunteer > 1) { int bt; bt = iobrick_type_get_nasid(nasid); if (bt >= 0) { i = io_brick_map_widget(bt, widgetnum) & 1; } } hubv = xvolinfo->xswitch_volunteer[i];do_assignment: /* * At this point, we want to make hubv the master of widgetnum. */ xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); } xswitch_volunteer_delete(xswitch);}/* * Let boot processor know that we're done initializing our node's IO * and then exit. *//* ARGSUSED */static voidio_init_done(cnodeid_t cnodeid,cpuid_t c){ /* Let boot processor know that we're done. */}/* * Probe to see if this hub's xtalk link is active. If so, * return the Crosstalk Identification of the widget that we talk to. * This is called before any of the Crosstalk infrastructure for * this hub is set up. It's usually called on the node that we're * probing, but not always. * * TBD: Prom code should actually do this work, and pass through * hwid for our use. */static voidearly_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid){ hubreg_t llp_csr_reg; nasid_t nasid; hubinfo_t hubinfo; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); /* * If link is up, read the widget's part number. * A direct connect widget must respond to widgetnum=0. */ if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { /* TBD: Put hub into "indirect" mode */ /* * We're able to read from a widget because our hub's * WIDGET_ID was set up earlier. */ widgetreg_t widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); /* TBD: link reset */ } else { hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; }}/* Add inventory information to the widget vertex * Right now (module,slot,revision) is being * added as inventory information. */static voidxwidget_inventory_add(vertex_hdl_t widgetv, lboard_t *board, struct xwidget_hwid_s hwid){ if (!board) return; /* Donot add inventory information for the baseio * on a speedo with an xbox. It has already been * taken care of in SN00_vmc. * Speedo with xbox's baseio comes in at slot io1 (widget 9) */ device_inventory_add(widgetv,INV_IOBD,board->brd_type, geo_module(board->brd_geoid), SLOTNUM_GETSLOT(board->brd_slot), hwid.rev_num);}/* * io_xswitch_widget_init * */voidio_xswitch_widget_init(vertex_hdl_t xswitchv, vertex_hdl_t hubv, xwidgetnum_t widgetnum){ xswitch_info_t xswitch_info; xwidgetnum_t hub_widgetid; vertex_hdl_t widgetv; cnodeid_t cnode; widgetreg_t widget_id; nasid_t nasid, peer_nasid; struct xwidget_hwid_s hwid; hubinfo_t hubinfo; /*REFERENCED*/ int rc; char pathname[128]; lboard_t *board = NULL; char buffer[16]; char bt; moduleid_t io_module; slotid_t get_widget_slotnum(int xbow, int widget); DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); /* * Verify that xswitchv is indeed an attached xswitch. */ xswitch_info = xswitch_info_get(xswitchv); ASSERT(xswitch_info != NULL); hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; cnode = NASID_TO_COMPACT_NODEID(nasid); hub_widgetid = hubinfo->h_widgetid;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -