📄 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 Silicon Graphics, Inc. * Copyright (C) 2000 by Colin Ngam */#include <linux/types.h>#include <linux/config.h>#include <linux/slab.h>#include <linux/ctype.h>#include <asm/sn/sgi.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/eeprom.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>extern int maxnodes;/* #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; devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];} *xswitch_vol_t;voidxswitch_vertex_init(devfs_handle_t xswitch){ xswitch_vol_t xvolinfo; int rc; xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL); init_MUTEX(&xvolinfo->xswitch_volunteer_mutex); xvolinfo->xswitch_volunteer_count = 0; 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(devfs_handle_t xswitch){ xswitch_vol_t xvolinfo; int rc; rc = hwgraph_info_remove_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo);#ifndef CONFIG_IA64_SGI_IO ASSERT(rc == GRAPH_SUCCESS); rc = rc;#endif kfree(xvolinfo);}/* * A Crosstalk master volunteers to manage xwidgets on the specified xswitch. *//* ARGSUSED */static voidvolunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master){ xswitch_vol_t xvolinfo = NULL; (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) {#ifndef CONFIG_IA64_SGI_IO if (!is_headless_node_vertex(master)) cmn_err(CE_WARN, "volunteer for widgets: vertex %v has no info label", xswitch);#endif return; }#ifndef CONFIG_IA64_SGI_IO mutex_lock(&xvolinfo->xswitch_volunteer_mutex, PZERO);#endif ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; xvolinfo->xswitch_volunteer_count++;#ifndef CONFIG_IA64_SGI_IO mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);#endif}#ifndef BRINGUP/* * The "ideal fixed assignment" of 12 IO slots to 4 node slots. * At index N is the node slot number of the node board that should * ideally control the widget in IO slot N. Note that if there is * only one node board on a given xbow, it will control all of the * devices on that xbow regardless of these defaults. * * N1 controls IO slots IO1, IO3, IO5 (upper left) * N3 controls IO slots IO2, IO4, IO6 (upper right) * N2 controls IO slots IO7, IO9, IO11 (lower left) * N4 controls IO slots IO8, IO10, IO12 (lower right) * * This makes assignments predictable and easily controllable. * TBD: Allow administrator to override these defaults. */static slotid_t ideal_assignment[] = { -1, /* IO0 -->non-existent */ 1, /* IO1 -->N1 */ 3, /* IO2 -->N3 */ 1, /* IO3 -->N1 */ 3, /* IO4 -->N3 */ 1, /* IO5 -->N1 */ 3, /* IO6 -->N3 */ 2, /* IO7 -->N2 */ 4, /* IO8 -->N4 */ 2, /* IO9 -->N2 */ 4, /* IO10-->N4 */ 2, /* IO11-->N2 */ 4 /* IO12-->N4 */};static intis_ideal_assignment(slotid_t hubslot, slotid_t ioslot){ return(ideal_assignment[ioslot] == hubslot);}#endif /* ifndef BRINGUP */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(devfs_handle_t xswitch, devfs_handle_t hubv){ xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; xwidgetnum_t widgetnum; int curr_volunteer, num_volunteer; nasid_t nasid; hubinfo_t hubinfo;#ifndef BRINGUP int xbownum;#endif 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) {#ifndef CONFIG_IA64_SGI_IO if (!is_headless_node_vertex(hubv)) cmn_err(CE_WARN, "assign_widgets_to_volunteers:vertex %v has " " no info label", xswitch);#endif return; } num_volunteer = xvolinfo->xswitch_volunteer_count; ASSERT(num_volunteer > 0); curr_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); }#ifndef BRINGUP xbownum = get_node_crossbow(nasid);#endif /* ifndef BRINGUP */ /* * TBD: Use administrative information to alter assignment of * widgets to hubs. */ for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {#ifndef BRINGUP int i;#endif /* * 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_nasid_widget(nasid, widgetnum)) { int i; for (i=0; i<num_volunteer; i++) { hubv = xvolinfo->xswitch_volunteer[i]; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; if (nasid == get_console_nasid()) goto do_assignment; }#ifndef CONFIG_IA64_SGI_IO cmn_err(CE_PANIC, "Nasid == %d, console nasid == %d", nasid, get_console_nasid());#endif }#ifndef BRINGUP /* * Try to do the "ideal" assignment if IO slots to nodes. */ for (i=0; i<num_volunteer; i++) { hubv = xvolinfo->xswitch_volunteer[i]; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; if (is_ideal_assignment(SLOTNUM_GETSLOT(get_node_slotid(nasid)), SLOTNUM_GETSLOT(get_widget_slotnum(xbownum, widgetnum)))) { goto do_assignment; } }#endif /* ifndef BRINGUP */ /* * Do a round-robin assignment among the volunteer nodes. */ hubv = xvolinfo->xswitch_volunteer[curr_volunteer]; curr_volunteer = (curr_volunteer + 1) % num_volunteer; /* fall through */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);}/* * Early iograph initialization. Called by master CPU in mlreset(). * Useful for including iograph.o in kernel.o. */voidiograph_early_init(void){/* * Need new way to get this information .. */ cnodeid_t cnode; nasid_t nasid; lboard_t *board; /* * Init. the board-to-hwgraph link early, so FRU analyzer * doesn't trip on leftover values if we panic early on. */ for(cnode = 0; cnode < numnodes; cnode++) { nasid = COMPACT_TO_NASID_NODEID(cnode); board = (lboard_t *)KL_CONFIG_INFO(nasid); printk("iograph_early_init: Found board 0x%p\n", board); /* Check out all the board info stored on a node */ while(board) { board->brd_graph_link = GRAPH_VERTEX_NONE; board = KLCF_NEXT(board); printk("iograph_early_init: Found board 0x%p\n", board); } } hubio_init();}#ifndef CONFIG_IA64_SGI_IO/* There is an identical definition of this in os/scheduler/runq.c */#define INIT_COOKIE(cookie) cookie.must_run = 0; cookie.cpu = PDA_RUNANYWHERE/* * These functions absolutely doesn't belong here. It's here, though, * until the scheduler provides a platform-independent version * that works the way it should. The interface will definitely change, * too. Currently used only in this file and by io/cdl.c in order to * bind various I/O threads to a CPU on the proper node. */cpu_cookie_tsetnoderun(cnodeid_t cnodeid){ int i; cpuid_t cpunum; cpu_cookie_t cookie; INIT_COOKIE(cookie); if (cnodeid == CNODEID_NONE) return(cookie); /* * Do a setmustrun to one of the CPUs on the specified * node. */ if ((cpunum = CNODE_TO_CPU_BASE(cnodeid)) == CPU_NONE) { return(cookie); } cpunum += CNODE_NUM_CPUS(cnodeid) - 1; for (i = 0; i < CNODE_NUM_CPUS(cnodeid); i++, cpunum--) { if (cpu_enabled(cpunum)) { cookie = setmustrun(cpunum); break; } } return(cookie);}voidrestorenoderun(cpu_cookie_t cookie){ restoremustrun(cookie);}static sema_t io_init_sema;#endif /* !CONFIG_IA64_SGI_IO */struct semaphore io_init_sema;/* * Let boot processor know that we're done initializing our node's IO * and then exit. *//* ARGSUSED */static voidio_init_done(cnodeid_t cnodeid,cpu_cookie_t c){#ifndef CONFIG_IA64_SGI_IO /* Let boot processor know that we're done. */ up(&io_init_sema); /* This is for the setnoderun done when the io_init thread * started */ restorenoderun(c); sthread_exit();#endif}/* * 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(devfs_handle_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. */#ifdef BRINGUP widgetreg_t widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); printk("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) );#else /* !BRINGUP */ widgetreg_t widget_id = XWIDGET_ID_READ(nasid, 0);#endif /* BRINGUP */ 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 { panic("\n\n**** early_probe_for_widget: Hub Vertex 0x%p is DOWN llp_csr_reg 0x%x ****\n\n", hubv, llp_csr_reg); 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(devfs_handle_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, board->brd_module, SLOTNUM_GETSLOT(board->brd_slot), hwid.rev_num);}/* * io_xswitch_widget_init * *//* defined in include/linux/ctype.h *//* #define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) */voidio_xswitch_widget_init(devfs_handle_t xswitchv, devfs_handle_t hubv, xwidgetnum_t widgetnum, async_attach_t aa){ xswitch_info_t xswitch_info; xwidgetnum_t hub_widgetid; devfs_handle_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 slotname[SLOTNUM_MAXLENGTH]; char pathname[128]; char new_name[64]; moduleid_t module; slotid_t slot; lboard_t *board = NULL; printk("\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; /* Who's the other guy on out crossbow (if anyone) */ peer_nasid = NODEPDA(cnode)->xbow_peer; if (peer_nasid == INVALID_NASID) /* If I don't have a peer, use myself. */ peer_nasid = nasid; /* Check my xbow structure and my peer's */ if (!xbow_port_io_enabled(nasid, widgetnum) && !xbow_port_io_enabled(peer_nasid, widgetnum)) { return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -