3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
10 #include <linux/types.h>
11 #include <linux/config.h>
12 #include <linux/slab.h>
13 #include <linux/ctype.h>
14 #include <asm/sn/sgi.h>
15 #include <asm/sn/sn_sal.h>
16 #include <asm/sn/io.h>
17 #include <asm/sn/sn_cpuid.h>
18 #include <asm/sn/iograph.h>
19 #include <asm/sn/invent.h>
20 #include <asm/sn/hcl.h>
21 #include <asm/sn/hcl_util.h>
22 #include <asm/sn/labelcl.h>
23 #include <asm/sn/xtalk/xbow.h>
24 #include <asm/sn/pci/bridge.h>
25 #include <asm/sn/klconfig.h>
26 #include <asm/sn/eeprom.h>
27 #include <asm/sn/sn_private.h>
28 #include <asm/sn/pci/pcibr.h>
29 #include <asm/sn/xtalk/xtalk.h>
30 #include <asm/sn/xtalk/xswitch.h>
31 #include <asm/sn/xtalk/xwidget.h>
32 #include <asm/sn/xtalk/xtalk_private.h>
33 #include <asm/sn/xtalk/xtalkaddrs.h>
35 /* #define IOGRAPH_DEBUG */
37 #define DBG(x...) printk(x)
40 #endif /* IOGRAPH_DEBUG */
42 /* #define PROBE_TEST */
44 /* At most 2 hubs can be connected to an xswitch */
45 #define NUM_XSWITCH_VOLUNTEER 2
48 * Track which hubs have volunteered to manage devices hanging off of
49 * a Crosstalk Switch (e.g. xbow). This structure is allocated,
50 * initialized, and hung off the xswitch vertex early on when the
51 * xswitch vertex is created.
53 typedef struct xswitch_vol_s {
54 mutex_t xswitch_volunteer_mutex;
55 int xswitch_volunteer_count;
56 devfs_handle_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
60 xswitch_vertex_init(devfs_handle_t xswitch)
62 xswitch_vol_t xvolinfo;
65 xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
66 mutex_init(&xvolinfo->xswitch_volunteer_mutex);
67 xvolinfo->xswitch_volunteer_count = 0;
68 rc = hwgraph_info_add_LBL(xswitch,
70 (arbitrary_info_t)xvolinfo);
71 ASSERT(rc == GRAPH_SUCCESS); rc = rc;
76 * When assignment of hubs to widgets is complete, we no longer need the
77 * xswitch volunteer structure hanging around. Destroy it.
80 xswitch_volunteer_delete(devfs_handle_t xswitch)
82 xswitch_vol_t xvolinfo;
85 rc = hwgraph_info_remove_LBL(xswitch,
87 (arbitrary_info_t *)&xvolinfo);
89 ASSERT(rc == GRAPH_SUCCESS); rc = rc;
95 * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
99 volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master)
101 xswitch_vol_t xvolinfo = NULL;
103 (void)hwgraph_info_get_LBL(xswitch,
104 INFO_LBL_XSWITCH_VOL,
105 (arbitrary_info_t *)&xvolinfo);
106 if (xvolinfo == NULL) {
108 if (!is_headless_node_vertex(master)) {
109 #if defined(SUPPORT_PRINTING_V_FORMAT)
110 printk(KERN_WARNING "volunteer for widgets: vertex %v has no info label",
113 printk(KERN_WARNING "volunteer for widgets: vertex 0x%x has no info label",
121 mutex_lock(&xvolinfo->xswitch_volunteer_mutex);
122 ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
123 xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
124 xvolinfo->xswitch_volunteer_count++;
125 mutex_unlock(&xvolinfo->xswitch_volunteer_mutex);
128 extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
131 * Assign all the xwidgets hanging off the specified xswitch to the
132 * Crosstalk masters that have volunteered for xswitch duty.
136 assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv)
138 int curr_volunteer, num_volunteer;
139 xwidgetnum_t widgetnum;
140 xswitch_info_t xswitch_info;
141 xswitch_vol_t xvolinfo = NULL;
145 hubinfo_get(hubv, &hubinfo);
146 nasid = hubinfo->h_nasid;
148 xswitch_info = xswitch_info_get(xswitch);
149 ASSERT(xswitch_info != NULL);
151 (void)hwgraph_info_get_LBL(xswitch,
152 INFO_LBL_XSWITCH_VOL,
153 (arbitrary_info_t *)&xvolinfo);
154 if (xvolinfo == NULL) {
156 if (!is_headless_node_vertex(hubv)) {
157 #if defined(SUPPORT_PRINTING_V_FORMAT)
158 printk(KERN_WARNING "assign_widgets_to_volunteers:vertex %v has "
162 printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%x has "
171 num_volunteer = xvolinfo->xswitch_volunteer_count;
172 ASSERT(num_volunteer > 0);
175 /* Assign master hub for xswitch itself. */
176 if (HUB_WIDGET_ID_MIN > 0) {
177 hubv = xvolinfo->xswitch_volunteer[0];
178 xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
182 * TBD: Use administrative information to alter assignment of
185 for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
188 * Ignore disabled/empty ports.
190 if (!xbow_port_io_enabled(nasid, widgetnum))
194 * If this is the master IO board, assign it to the same
195 * hub that owned it in the prom.
197 if (is_master_nasid_widget(nasid, widgetnum)) {
200 for (i=0; i<num_volunteer; i++) {
201 hubv = xvolinfo->xswitch_volunteer[i];
202 hubinfo_get(hubv, &hubinfo);
203 nasid = hubinfo->h_nasid;
204 if (nasid == get_console_nasid())
208 PRINT_PANIC("Nasid == %d, console nasid == %d",
209 nasid, get_console_nasid());
215 * Do a round-robin assignment among the volunteer nodes.
217 hubv = xvolinfo->xswitch_volunteer[curr_volunteer];
218 curr_volunteer = (curr_volunteer + 1) % num_volunteer;
223 * At this point, we want to make hubv the master of widgetnum.
225 xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
228 xswitch_volunteer_delete(xswitch);
232 * Early iograph initialization. Called by master CPU in mlreset().
233 * Useful for including iograph.o in kernel.o.
236 iograph_early_init(void)
239 * Need new way to get this information ..
246 * Init. the board-to-hwgraph link early, so FRU analyzer
247 * doesn't trip on leftover values if we panic early on.
249 for(cnode = 0; cnode < numnodes; cnode++) {
250 nasid = COMPACT_TO_NASID_NODEID(cnode);
251 board = (lboard_t *)KL_CONFIG_INFO(nasid);
252 DBG("iograph_early_init: Found board 0x%p\n", board);
254 /* Check out all the board info stored on a node */
256 board->brd_graph_link = GRAPH_VERTEX_NONE;
257 board = KLCF_NEXT(board);
258 DBG("iograph_early_init: Found board 0x%p\n", board);
267 #ifdef LINUX_KERNEL_THREADS
268 static struct semaphore io_init_sema;
272 * Let boot processor know that we're done initializing our node's IO
277 io_init_done(cnodeid_t cnodeid,cpu_cookie_t c)
279 /* Let boot processor know that we're done. */
280 #ifdef LINUX_KERNEL_THREADS
284 /* This is for the setnoderun done when the io_init thread
293 * Probe to see if this hub's xtalk link is active. If so,
294 * return the Crosstalk Identification of the widget that we talk to.
295 * This is called before any of the Crosstalk infrastructure for
296 * this hub is set up. It's usually called on the node that we're
297 * probing, but not always.
299 * TBD: Prom code should actually do this work, and pass through
303 early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid)
305 hubreg_t llp_csr_reg;
309 hubinfo_get(hubv, &hubinfo);
310 nasid = hubinfo->h_nasid;
312 llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
314 * If link is up, read the widget's part number.
315 * A direct connect widget must respond to widgetnum=0.
317 if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
318 /* TBD: Put hub into "indirect" mode */
320 * We're able to read from a widget because our hub's
321 * WIDGET_ID was set up earlier.
323 widgetreg_t widget_id = *(volatile widgetreg_t *)
324 (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
326 DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
327 (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
329 hwid->part_num = XWIDGET_PART_NUM(widget_id);
330 hwid->rev_num = XWIDGET_REV_NUM(widget_id);
331 hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
333 /* TBD: link reset */
336 hwid->part_num = XWIDGET_PART_NUM_NONE;
337 hwid->rev_num = XWIDGET_REV_NUM_NONE;
338 hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
343 /* Add inventory information to the widget vertex
344 * Right now (module,slot,revision) is being
345 * added as inventory information.
348 xwidget_inventory_add(devfs_handle_t widgetv,
350 struct xwidget_hwid_s hwid)
354 /* Donot add inventory information for the baseio
355 * on a speedo with an xbox. It has already been
356 * taken care of in SN00_vmc.
357 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
359 device_inventory_add(widgetv,INV_IOBD,board->brd_type,
361 SLOTNUM_GETSLOT(board->brd_slot),
366 * io_xswitch_widget_init
370 /* defined in include/linux/ctype.h */
371 /* #define toupper(c) (islower(c) ? (c) - 'a' + 'A' : (c)) */
374 io_xswitch_widget_init(devfs_handle_t xswitchv,
376 xwidgetnum_t widgetnum,
379 xswitch_info_t xswitch_info;
380 xwidgetnum_t hub_widgetid;
381 devfs_handle_t widgetv;
383 widgetreg_t widget_id;
384 nasid_t nasid, peer_nasid;
385 struct xwidget_hwid_s hwid;
389 char slotname[SLOTNUM_MAXLENGTH];
394 lboard_t *board = NULL;
396 slotid_t get_widget_slotnum(int xbow, int widget);
398 DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
400 * Verify that xswitchv is indeed an attached xswitch.
402 xswitch_info = xswitch_info_get(xswitchv);
403 ASSERT(xswitch_info != NULL);
405 hubinfo_get(hubv, &hubinfo);
406 nasid = hubinfo->h_nasid;
407 cnode = NASID_TO_COMPACT_NODEID(nasid);
408 hub_widgetid = hubinfo->h_widgetid;
411 /* Who's the other guy on out crossbow (if anyone) */
412 peer_nasid = NODEPDA(cnode)->xbow_peer;
413 if (peer_nasid == INVALID_NASID)
414 /* If I don't have a peer, use myself. */
418 /* Check my xbow structure and my peer's */
419 if (!xbow_port_io_enabled(nasid, widgetnum) &&
420 !xbow_port_io_enabled(peer_nasid, widgetnum)) {
424 if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
427 * If the current hub is not supposed to be the master
428 * for this widgetnum, then skip this widget.
430 if (xswitch_info_master_assignment_get(xswitch_info,
431 widgetnum) != hubv) {
435 module = NODEPDA(cnode)->module_id;
436 #ifdef XBRIDGE_REGS_SIM
437 /* hardwire for now...could do this with something like:
438 * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl);
439 * xbow_t xbow = soft->base;
440 * xbowreg_t xwidget_id = xbow->xb_wid_id;
441 * but I don't feel like figuring out vhdl right now..
442 * and I know for a fact the answer is 0x2d000049
444 DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
445 DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049));
446 if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) {
448 if (nasid_has_xbridge(nasid)) {
449 #endif /* XBRIDGE_REGS_SIM */
450 board = find_lboard_module_class(
451 (lboard_t *)KL_CONFIG_INFO(nasid),
455 DBG("io_xswitch_widget_init: Board 0x%p\n", board);
461 DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
463 DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
470 * Make sure we really want to say xbrick, pbrick,
471 * etc. rather than XIO, graphics, etc.
474 #ifdef SUPPORT_PRINTING_M_FORMAT
475 sprintf(pathname, EDGE_LBL_MODULE "/%M/"
477 NODEPDA(cnode)->module_id,
480 memset(buffer, 0, 16);
481 format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
482 sprintf(pathname, EDGE_LBL_MODULE "/%s/"
487 (board->brd_type == KLTYPE_IBRICK) ? 'I' :
488 (board->brd_type == KLTYPE_PBRICK) ? 'P' :
489 (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?',
490 EDGE_LBL_XTALK, widgetnum);
493 DBG("io_xswitch_widget_init: path= %s\n", pathname);
494 rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
496 ASSERT(rc == GRAPH_SUCCESS);
498 /* This is needed to let the user programs to map the
499 * module,slot numbers to the corresponding widget numbers
502 rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
504 /* If we are looking at the global master io6
505 * then add information about the version of
506 * the io6prom as a part of "detailed inventory"
509 if (is_master_baseio(nasid,
510 NODEPDA(cnode)->module_id,
511 get_widget_slotnum(0,widgetnum))) {
512 extern void klhwg_baseio_inventory_add(devfs_handle_t,
514 module = NODEPDA(cnode)->module_id;
516 #ifdef XBRIDGE_REGS_SIM
517 DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n");
518 if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) {
520 if (nasid_has_xbridge(nasid)) {
521 #endif /* XBRIDGE_REGS_SIM */
522 board = find_lboard_module(
523 (lboard_t *)KL_CONFIG_INFO(nasid),
526 * Change iobrick to correct i/o brick
528 #ifdef SUPPORT_PRINTING_M_FORMAT
529 sprintf(pathname, EDGE_LBL_MODULE "/%M/"
531 sprintf(pathname, EDGE_LBL_MODULE "/%x/"
534 NODEPDA(cnode)->module_id,
535 EDGE_LBL_XTALK, widgetnum);
537 slot = get_widget_slotnum(0, widgetnum);
538 board = get_board_name(nasid, module, slot,
541 * Create the vertex for the widget,
543 * widgetnum as the name of the primary edge.
545 #ifdef SUPPORT_PRINTING_M_FORMAT
546 sprintf(pathname, EDGE_LBL_MODULE "/%M/"
547 EDGE_LBL_SLOT "/%s/%s",
548 NODEPDA(cnode)->module_id,
551 memset(buffer, 0, 16);
552 format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF);
553 sprintf(pathname, EDGE_LBL_MODULE "/%s/"
554 EDGE_LBL_SLOT "/%s/%s",
560 rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
561 DBG("io_xswitch_widget_init: (2) path= %s\n", pathname);
563 * This is a weird ass code needed for error injection
566 rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv);
568 klhwg_baseio_inventory_add(widgetv,cnode);
570 sprintf(name, "%d", widgetnum);
571 DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
572 rc = hwgraph_edge_add(xswitchv, widgetv, name);
575 * crosstalk switch code tracks which
576 * widget is attached to each link.
578 xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
581 * Peek at the widget to get its crosstalk part and
582 * mfgr numbers, then present it to the generic xtalk
583 * bus provider to have its driver attach routine
586 #ifdef XBRIDGE_REGS_SIM
587 widget_id = 0x2d000049;
588 DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n");
590 widget_id = XWIDGET_ID_READ(nasid, widgetnum);
591 #endif /* XBRIDGE_REGS_SIM */
592 hwid.part_num = XWIDGET_PART_NUM(widget_id);
593 hwid.rev_num = XWIDGET_REV_NUM(widget_id);
594 hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
595 /* Store some inventory information about
596 * the xwidget in the hardware graph.
598 xwidget_inventory_add(widgetv,board,hwid);
600 (void)xwidget_register(&hwid, widgetv, widgetnum,
605 bte_bpush_war(cnode, (void *)board);
613 io_init_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnode)
615 xwidgetnum_t widgetnum;
618 aa = async_attach_new();
620 DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
622 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
624 io_xswitch_widget_init(xswitchv,
625 cnodeid_to_vertex(cnode),
629 * Wait for parallel attach threads, if any, to complete.
631 async_attach_waitall(aa);
632 async_attach_free(aa);
636 * For each PCI bridge connected to the xswitch, add a link from the
637 * board's klconfig info to the bridge's hwgraph vertex. This lets
638 * the FRU analyzer find the bridge without traversing the hardware
639 * graph and risking hangs.
642 io_link_xswitch_widgets(devfs_handle_t xswitchv, cnodeid_t cnodeid)
644 xwidgetnum_t widgetnum;
647 nasid_t nasid, peer_nasid;
652 /* And its connected hub's nasids */
653 nasid = COMPACT_TO_NASID_NODEID(cnodeid);
654 peer_nasid = NODEPDA(cnodeid)->xbow_peer;
657 * Look for paths matching "<widgetnum>/pci" under xswitchv.
658 * For every widget, init. its lboard's hwgraph link. If the
659 * board has a PCI bridge, point the link to it.
661 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
663 sprintf(pathname, "%d", widgetnum);
664 if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
668 board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
669 NODEPDA(cnodeid)->module_id);
670 if (board == NULL && peer_nasid != INVALID_NASID) {
672 * Try to find the board on our peer
674 board = find_lboard_module(
675 (lboard_t *)KL_CONFIG_INFO(peer_nasid),
676 NODEPDA(cnodeid)->module_id);
679 #if defined(SUPPORT_PRINTING_V_FORMAT)
680 printk(KERN_WARNING "Could not find PROM info for vertex %v, "
681 "FRU analyzer may fail",
684 printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, "
685 "FRU analyzer may fail",
691 sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum);
692 if (hwgraph_traverse(xswitchv, pathname, &vhdl) ==
694 board->brd_graph_link = vhdl;
696 board->brd_graph_link = GRAPH_VERTEX_NONE;
701 * Initialize all I/O on the specified node.
704 io_init_node(cnodeid_t cnodeid)
707 devfs_handle_t hubv, switchv, widgetv;
708 struct xwidget_hwid_s hwid;
712 struct semaphore *peer_sema = 0;
713 uint32_t widget_partnum;
714 nodepda_router_info_t *npda_rip;
716 extern int hubdev_docallouts(devfs_handle_t);
719 /* Try to execute on the node that we're initializing. */
720 c = setnoderun(cnodeid);
722 npdap = NODEPDA(cnodeid);
725 * Get the "top" vertex for this node's hardware
726 * graph; it will carry the per-hub hub-specific
727 * data, and act as the crosstalk provider master.
728 * It's canonical path is probably something of the
729 * form /hw/module/%M/slot/%d/node
731 hubv = cnodeid_to_vertex(cnodeid);
732 DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
734 ASSERT(hubv != GRAPH_VERTEX_NONE);
736 hubdev_docallouts(hubv);
739 * Set up the dependent routers if we have any.
741 npda_rip = npdap->npda_rip_first;
744 /* If the router info has not been initialized
745 * then we need to do the router initialization
747 if (!npda_rip->router_infop) {
748 router_init(cnodeid,0,npda_rip);
750 npda_rip = npda_rip->router_next;
754 * Read mfg info on this hub
757 printk("io_init_node: FIXME need to implement HUB_VERTEX_MFG_INFO\n");
758 HUB_VERTEX_MFG_INFO(hubv);
762 * If nothing connected to this hub's xtalk port, we're done.
764 early_probe_for_widget(hubv, &hwid);
765 if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
767 if ((cnodeid == 1) || (cnodeid == 2)) {
770 for (index = 0; index < 600; index++)
771 DBG("Interfering with device probing!!!\n");
774 /* io_init_done takes cpu cookie as 2nd argument
775 * to do a restorenoderun for the setnoderun done
776 * at the start of this thread
779 DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
785 * attach our hub_provider information to hubv,
786 * so we can use it as a crosstalk provider "master"
789 xtalk_provider_register(hubv, &hub_provider);
790 xtalk_provider_startup(hubv);
793 * Create a vertex to represent the crosstalk bus
794 * attached to this hub, and a vertex to be used
795 * as the connect point for whatever is out there
796 * on the other side of our crosstalk connection.
798 * Crosstalk Switch drivers "climb up" from their
799 * connection point to try and take over the switch
802 * Of course, the edges and verticies may already
803 * exist, in which case our net effect is just to
804 * associate the "xtalk_" driver with the connection
805 * point for the device.
808 (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
810 DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
812 ASSERT(switchv != GRAPH_VERTEX_NONE);
814 (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
816 DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
819 * We need to find the widget id and update the basew_id field
820 * accordingly. In particular, SN00 has direct connected bridge,
821 * and hence widget id is Not 0.
824 widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
826 if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
827 widget_partnum == XBRIDGE_WIDGET_PART_NUM){
828 npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
830 DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
832 } else if (widget_partnum == XBOW_WIDGET_PART_NUM ||
833 widget_partnum == XXBOW_WIDGET_PART_NUM) {
835 * Xbow control register does not have the widget ID field.
836 * So, hard code the widget ID to be zero.
838 DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
841 } else if (widget_partnum == XG_WIDGET_PART_NUM) {
843 * OK, WTF do we do here if we have an XG direct connected to a HUB/Bedrock???
844 * So, hard code the widget ID to be zero?
847 npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
849 npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
851 panic(" ****io_init_node: Unknown Widget Part Number 0x%x Widgt ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv);
857 sprintf(widname, "%x", npdap->basew_id);
858 (void)hwgraph_path_add(switchv, widname, &widgetv);
859 DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
860 ASSERT(widgetv != GRAPH_VERTEX_NONE);
863 nodepda->basew_xc = widgetv;
865 is_xswitch = xwidget_hwid_is_xswitch(&hwid);
868 * Try to become the master of the widget. If this is an xswitch
869 * with multiple hubs connected, only one will succeed. Mastership
870 * of an xswitch is used only when touching registers on that xswitch.
871 * The slave xwidgets connected to the xswitch can be owned by various
874 if (device_master_set(widgetv, hubv) == 0) {
876 /* Only one hub (thread) per Crosstalk device or switch makes
881 * Initialize whatever xwidget is hanging off our hub.
882 * Whatever it is, it's accessible through widgetnum 0.
884 hubinfo_get(hubv, &hubinfo);
886 (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid, NULL);
889 /* io_init_done takes cpu cookie as 2nd argument
890 * to do a restorenoderun for the setnoderun done
891 * at the start of this thread
893 io_init_done(cnodeid,c);
898 * Special handling for Crosstalk Switches (e.g. xbow).
899 * We need to do things in roughly the following order:
900 * 1) Initialize xswitch hardware (done above)
901 * 2) Determine which hubs are available to be widget masters
902 * 3) Discover which links are active from the xswitch
903 * 4) Assign xwidgets hanging off the xswitch to hubs
904 * 5) Initialize all xwidgets on the xswitch
907 volunteer_for_widgets(switchv, hubv);
909 /* If there's someone else on this crossbow, recognize him */
910 if (npdap->xbow_peer != INVALID_NASID) {
911 nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
912 peer_sema = &peer_npdap->xbow_sema;
913 volunteer_for_widgets(switchv, peer_npdap->node_vertex);
916 assign_widgets_to_volunteers(switchv, hubv);
918 /* Signal that we're done */
920 mutex_unlock(peer_sema);
925 /* Wait 'til master is done assigning widgets. */
926 mutex_lock(&npdap->xbow_sema);
930 if ((cnodeid == 1) || (cnodeid == 2)) {
933 for (index = 0; index < 500; index++)
934 DBG("Interfering with device probing!!!\n");
937 /* Now both nodes can safely inititialize widgets */
938 io_init_xswitch_widgets(switchv, cnodeid);
939 io_link_xswitch_widgets(switchv, cnodeid);
941 /* io_init_done takes cpu cookie as 2nd argument
942 * to do a restorenoderun for the setnoderun done
943 * at the start of this thread
945 io_init_done(cnodeid,c);
947 DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
951 #define IOINIT_STKSZ (16 * 1024)
953 #define __DEVSTR1 "/../.master/"
954 #define __DEVSTR2 "/target/"
955 #define __DEVSTR3 "/lun/0/disk/partition/"
956 #define __DEVSTR4 "/../ef"
958 #if defined(CONFIG_IA64_SGI_SN1)
960 * Currently, we need to allow for 5 IBrick slots with 1 FC each
961 * plus an internal 1394.
963 * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
965 #define NUM_BASE_IO_SCSI_CTLR 6
967 #define NUM_BASE_IO_SCSI_CTLR 6
970 * This tells ioconfig where it can start numbering scsi controllers.
971 * Below this base number, platform-specific handles the numbering.
972 * XXX Irix legacy..controller numbering should be part of devfsd's job
974 int num_base_io_scsi_ctlr = 2; /* used by syssgi */
975 devfs_handle_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
976 static devfs_handle_t baseio_enet_vhdl,baseio_console_vhdl;
979 * Put the logical controller number information in the
980 * scsi controller vertices for each scsi controller that
981 * is in a "fixed position".
984 scsi_ctlr_nums_add(devfs_handle_t pci_vhdl)
989 num_base_io_scsi_ctlr = NUM_BASE_IO_SCSI_CTLR;
991 /* Initialize base_io_scsi_ctlr_vhdl array */
992 for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++)
993 base_io_scsi_ctlr_vhdl[i] = GRAPH_VERTEX_NONE;
997 * May want to consider changing the SN0 code, above, to work more like
998 * the way this works.
1000 devfs_handle_t base_ibrick_xbridge_vhdl;
1001 devfs_handle_t base_ibrick_xtalk_widget_vhdl;
1002 devfs_handle_t scsi_ctlr_vhdl;
1007 * This is a table of "well-known" SCSI controllers and their well-known
1008 * controller numbers. The names in the table start from the base IBrick's
1009 * Xbridge vertex, so the first component is the xtalk widget number.
1012 char *base_ibrick_scsi_path;
1013 int controller_number;
1014 } hardwired_scsi_controllers[] = {
1015 {"15/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 0},
1016 {"15/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 1},
1017 {"15/" EDGE_LBL_PCI "/3/" EDGE_LBL_SCSI_CTLR "/0", 2},
1018 {"14/" EDGE_LBL_PCI "/1/" EDGE_LBL_SCSI_CTLR "/0", 3},
1019 {"14/" EDGE_LBL_PCI "/2/" EDGE_LBL_SCSI_CTLR "/0", 4},
1020 {"15/" EDGE_LBL_PCI "/6/ohci/0/" EDGE_LBL_SCSI_CTLR "/0", 5},
1021 {NULL, -1} /* must be last */
1024 base_ibrick_xtalk_widget_vhdl = hwgraph_connectpt_get(pci_vhdl);
1025 ASSERT_ALWAYS(base_ibrick_xtalk_widget_vhdl != GRAPH_VERTEX_NONE);
1027 base_ibrick_xbridge_vhdl = hwgraph_connectpt_get(base_ibrick_xtalk_widget_vhdl);
1028 ASSERT_ALWAYS(base_ibrick_xbridge_vhdl != GRAPH_VERTEX_NONE);
1029 hwgraph_vertex_unref(base_ibrick_xtalk_widget_vhdl);
1032 * Iterate through the list of well-known SCSI controllers.
1033 * For each controller found, set it's controller number according
1036 for (i=0; hardwired_scsi_controllers[i].base_ibrick_scsi_path != NULL; i++) {
1037 rv = hwgraph_path_lookup(base_ibrick_xbridge_vhdl,
1038 hardwired_scsi_controllers[i].base_ibrick_scsi_path, &scsi_ctlr_vhdl, NULL);
1040 if (rv != GRAPH_SUCCESS) /* No SCSI at this path */
1043 ASSERT(hardwired_scsi_controllers[i].controller_number < NUM_BASE_IO_SCSI_CTLR);
1044 base_io_scsi_ctlr_vhdl[hardwired_scsi_controllers[i].controller_number] = scsi_ctlr_vhdl;
1045 device_controller_num_set(scsi_ctlr_vhdl, hardwired_scsi_controllers[i].controller_number);
1046 hwgraph_vertex_unref(scsi_ctlr_vhdl); /* (even though we're actually keeping a reference) */
1049 hwgraph_vertex_unref(base_ibrick_xbridge_vhdl);
1054 #include <asm/sn/ioerror_handling.h>
1055 devfs_handle_t sys_critical_graph_root = GRAPH_VERTEX_NONE;
1057 /* Define the system critical vertices and connect them through
1058 * a canonical parent-child relationships for easy traversal
1059 * during io error handling.
1062 sys_critical_graph_init(void)
1064 devfs_handle_t bridge_vhdl,master_node_vhdl;
1065 devfs_handle_t xbow_vhdl = GRAPH_VERTEX_NONE;
1066 extern devfs_handle_t hwgraph_root;
1067 devfs_handle_t pci_slot_conn;
1069 devfs_handle_t baseio_console_conn;
1071 DBG("sys_critical_graph_init: FIXME.\n");
1072 baseio_console_conn = hwgraph_connectpt_get(baseio_console_vhdl);
1074 if (baseio_console_conn == NULL) {
1078 /* Get the vertex handle for the baseio bridge */
1079 bridge_vhdl = device_master_get(baseio_console_conn);
1081 /* Get the master node of the baseio card */
1082 master_node_vhdl = cnodeid_to_vertex(
1083 master_node_get(baseio_console_vhdl));
1085 /* Add the "root->node" part of the system critical graph */
1087 sys_critical_graph_vertex_add(hwgraph_root,master_node_vhdl);
1089 /* Check if we have a crossbow */
1090 if (hwgraph_traverse(master_node_vhdl,
1092 &xbow_vhdl) == GRAPH_SUCCESS) {
1093 /* We have a crossbow.Add "node->xbow" part of the system
1096 sys_critical_graph_vertex_add(master_node_vhdl,xbow_vhdl);
1098 /* Add "xbow->baseio bridge" of the system critical graph */
1099 sys_critical_graph_vertex_add(xbow_vhdl,bridge_vhdl);
1101 hwgraph_vertex_unref(xbow_vhdl);
1103 /* We donot have a crossbow. Add "node->baseio_bridge"
1104 * part of the system critical graph.
1106 sys_critical_graph_vertex_add(master_node_vhdl,bridge_vhdl);
1108 /* Add all the populated PCI slot vertices to the system critical
1109 * graph with the bridge vertex as the parent.
1111 for (slot = 0 ; slot < 8; slot++) {
1114 sprintf(slot_edge,"%d",slot);
1115 if (hwgraph_traverse(bridge_vhdl,slot_edge, &pci_slot_conn)
1118 sys_critical_graph_vertex_add(bridge_vhdl,pci_slot_conn);
1119 hwgraph_vertex_unref(pci_slot_conn);
1122 hwgraph_vertex_unref(bridge_vhdl);
1124 /* Add the "ioc3 pci connection point -> console ioc3" part
1125 * of the system critical graph
1128 if (hwgraph_traverse(baseio_console_vhdl,"..",&pci_slot_conn) ==
1130 sys_critical_graph_vertex_add(pci_slot_conn,
1131 baseio_console_vhdl);
1132 hwgraph_vertex_unref(pci_slot_conn);
1135 /* Add the "ethernet pci connection point -> base ethernet" part of
1136 * the system critical graph
1138 if (hwgraph_traverse(baseio_enet_vhdl,"..",&pci_slot_conn) ==
1140 sys_critical_graph_vertex_add(pci_slot_conn,
1142 hwgraph_vertex_unref(pci_slot_conn);
1145 /* Add the "scsi controller pci connection point -> base scsi
1146 * controller" part of the system critical graph
1148 if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[0],
1149 "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
1150 sys_critical_graph_vertex_add(pci_slot_conn,
1151 base_io_scsi_ctlr_vhdl[0]);
1152 hwgraph_vertex_unref(pci_slot_conn);
1154 if (hwgraph_traverse(base_io_scsi_ctlr_vhdl[1],
1155 "../..",&pci_slot_conn) == GRAPH_SUCCESS) {
1156 sys_critical_graph_vertex_add(pci_slot_conn,
1157 base_io_scsi_ctlr_vhdl[1]);
1158 hwgraph_vertex_unref(pci_slot_conn);
1160 hwgraph_vertex_unref(baseio_console_conn);
1165 baseio_ctlr_num_set(void)
1167 char name[MAXDEVNAME];
1168 devfs_handle_t console_vhdl, pci_vhdl, enet_vhdl;
1169 devfs_handle_t ioc3_console_vhdl_get(void);
1172 DBG("baseio_ctlr_num_set; FIXME\n");
1173 console_vhdl = ioc3_console_vhdl_get();
1174 if (console_vhdl == GRAPH_VERTEX_NONE)
1176 /* Useful for setting up the system critical graph */
1177 baseio_console_vhdl = console_vhdl;
1179 vertex_to_name(console_vhdl,name,MAXDEVNAME);
1181 strcat(name,__DEVSTR1);
1182 pci_vhdl = hwgraph_path_to_vertex(name);
1183 scsi_ctlr_nums_add(pci_vhdl);
1184 /* Unref the pci_vhdl due to the reference by hwgraph_path_to_vertex
1186 hwgraph_vertex_unref(pci_vhdl);
1188 vertex_to_name(console_vhdl, name, MAXDEVNAME);
1189 strcat(name, __DEVSTR4);
1190 enet_vhdl = hwgraph_path_to_vertex(name);
1192 /* Useful for setting up the system critical graph */
1193 baseio_enet_vhdl = enet_vhdl;
1195 device_controller_num_set(enet_vhdl, 0);
1196 /* Unref the enet_vhdl due to the reference by hwgraph_path_to_vertex
1198 hwgraph_vertex_unref(enet_vhdl);
1203 sn00_rrb_alloc(devfs_handle_t vhdl, int *vendor_list)
1209 ** sn00 population: errb orrb
1212 ** 2- ioc3 ethernet 2+?
1213 ** 3- ioc3 secondary 1
1220 /* The following code implements this heuristic for getting
1221 * maximum usage out of the rrbs
1224 * 8 bit ql1 needs 1+1
1225 * ql0 or ql5,6,7 wants 1+2
1226 * ethernet wants 2 or more
1228 * rules for even rrbs:
1229 * if nothing in slot 6
1230 * 4 rrbs to 0 and 2 (0xc8889999)
1232 * 3 2 3 to slots 0 2 6 (0xc8899bbb)
1234 * rules for odd rrbs
1235 * if nothing in slot 5 or 7 (0xc8889999)
1237 * else if 1 thing in 5 or 7 (0xc8899aaa) or (0xc8899bbb)
1238 * 3 2 3 to slots 1 3 5|7
1240 * 2 1 3 2 to slots 1 3 5 7 (note: if there's a ql card in 7 this
1241 * (0xc89aaabb) may short what it wants therefore the
1242 * rule should be to plug pci slots in order)
1246 if (vendor_list[6] != PCIIO_VENDOR_ID_NONE) {
1247 /* something in slot 6 */
1248 rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 3,1, 2,0, 0,0, 3,0);
1251 rtn_val = pcibr_alloc_all_rrbs(vhdl, 0, 4,1, 4,0, 0,0, 0,0);
1254 printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
1256 if ((vendor_list[5] != PCIIO_VENDOR_ID_NONE) &&
1257 (vendor_list[7] != PCIIO_VENDOR_ID_NONE)) {
1258 /* soemthing in slot 5 and 7 */
1259 rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 2,1, 1,0, 3,0, 2,0);
1261 else if (vendor_list[5] != PCIIO_VENDOR_ID_NONE) {
1262 /* soemthing in slot 5 but not 7 */
1263 rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 3,0, 0,0);
1265 else if (vendor_list[7] != PCIIO_VENDOR_ID_NONE) {
1266 /* soemthing in slot 7 but not 5 */
1267 rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 3,1, 2,0, 0,0, 3,0);
1270 /* nothing in slot 5 or 7 */
1271 rtn_val = pcibr_alloc_all_rrbs(vhdl, 1, 4,1, 4,0, 0,0, 0,0);
1274 printk(KERN_WARNING "sn00_rrb_alloc: pcibr_alloc_all_rrbs failed");
1279 * Initialize all I/O devices. Starting closest to nodes, probe and
1280 * initialize outward.
1283 init_all_devices(void)
1285 /* Governor on init threads..bump up when safe
1286 * (beware many devfs races)
1289 int io_init_node_threads = 2;
1291 cnodeid_t cnodeid, active;
1293 #ifdef LINUX_KERNEL_THREADS
1294 sema_init(&io_init_sema, 0);
1298 for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
1299 #ifdef LINUX_KERNEL_THREADS
1300 char thread_name[16];
1301 extern int io_init_pri;
1304 * Spawn a service thread for each node to initialize all
1305 * I/O on that node. Each thread attempts to bind itself
1306 * to the node whose I/O it's initializing.
1308 sprintf(thread_name, "IO_init[%d]", cnodeid);
1310 (void)sthread_create(thread_name, 0, IOINIT_STKSZ, 0,
1311 io_init_pri, KT_PS, (st_func_t *)io_init_node,
1312 (void *)(long)cnodeid, 0, 0, 0);
1314 DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
1315 io_init_node(cnodeid);
1317 DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
1319 #endif /* LINUX_KERNEL_THREADS */
1321 #ifdef LINUX_KERNEL_THREADS
1322 /* Limit how many nodes go at once, to not overload hwgraph */
1323 /* TBD: Should timeout */
1324 DBG("started thread for cnode %d\n", cnodeid);
1326 if (io_init_node_threads &&
1327 active >= io_init_node_threads) {
1328 down(&io_init_sema);
1331 #endif /* LINUX_KERNEL_THREADS */
1334 #ifdef LINUX_KERNEL_THREADS
1335 /* Wait until all IO_init threads are done */
1337 while (active > 0) {
1339 DBG("waiting, %d still active\n", active);
1341 down(&io_init_sema);
1345 #endif /* LINUX_KERNEL_THREADS */
1347 for (cnodeid = 0; cnodeid < numnodes; cnodeid++)
1349 * Update information generated by IO init.
1351 update_node_information(cnodeid);
1353 baseio_ctlr_num_set();
1354 /* Setup the system critical graph (which is a subgraph of the
1355 * main hwgraph). This information is useful during io error
1358 sys_critical_graph_init();
1366 #define toint(x) ((int)(x) - (int)('0'))
1369 devnamefromarcs(char *devnm)
1372 char tmpnm[MAXDEVNAME];
1375 val = strncmp(devnm, "dks", 3);
1379 if (!isdigit(*tmp1))
1383 while (isdigit(*tmp1)) {
1384 val = 10*val+toint(*tmp1);
1393 if ((val < 0) || (val >= NUM_BASE_IO_SCSI_CTLR)) {
1395 int viable_found = 0;
1397 DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
1398 DBG("prom \"root\" variables of the form dksXdXsX.\n");
1399 DBG("To use another disk you must use the full hardware graph path\n\n");
1400 DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
1401 for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
1402 if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
1410 DBG("none found!\n");
1418 panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
1422 ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
1423 vertex_to_name(base_io_scsi_ctlr_vhdl[val],
1426 tmp2 = tmpnm + strlen(tmpnm);
1427 strcpy(tmp2, __DEVSTR2);
1428 tmp2 += strlen(__DEVSTR2);
1429 while (*tmp1 != 's') {
1430 if((*tmp2++ = *tmp1++) == '\0')
1434 strcpy(tmp2, __DEVSTR3);
1435 tmp2 += strlen(__DEVSTR3);
1436 while ( (*tmp2++ = *tmp1++) )
1440 strcpy(tmp2, EDGE_LBL_BLOCK);
1441 strcpy(devnm,tmpnm);
1445 struct io_brick_map_s io_brick_tab[] = {
1447 /* Ibrick widget number to PCI bus number map */
1449 'I', /* Ibrick type */
1450 /* PCI Bus # Widget # */
1451 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1454 0, 0, /* 0xa - 0xb */
1462 /* Pbrick widget number to PCI bus number map */
1464 'P', /* Pbrick type */
1465 /* PCI Bus # Widget # */
1466 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1469 0, 0, /* 0xa - 0xb */
1477 /* Xbrick widget to XIO slot map */
1479 'X', /* Xbrick type */
1480 /* XIO Slot # Widget # */
1481 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1484 0, 0, /* 0xa - 0xb */
1494 * Use the brick's type to map a widget number to a meaningful int
1497 io_brick_map_widget(char brick_type, int widget_num)
1501 /* Calculate number of bricks in table */
1502 num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
1504 /* Look for brick prefix in table */
1505 for (i = 0; i < num_bricks; i++) {
1506 if (brick_type == io_brick_tab[i].ibm_type)
1507 return(io_brick_tab[i].ibm_map_wid[widget_num]);
1515 * Use the device's vertex to map the device's widget to a meaningful int
1518 io_path_map_widget(devfs_handle_t vertex)
1520 char hw_path_name[MAXDEVNAME];
1521 char *wp, *bp, *sp = NULL;
1524 int hwgraph_vertex_name_get(devfs_handle_t vhdl, char *buf, uint buflen);
1527 /* Get the full path name of the vertex */
1528 if (GRAPH_SUCCESS != hwgraph_vertex_name_get(vertex, hw_path_name,
1532 /* Find the widget number in the path name */
1533 wp = strstr(hw_path_name, "/"EDGE_LBL_XTALK"/");
1536 widget_num = atoi(wp+7);
1537 if (widget_num < XBOW_PORT_8 || widget_num > XBOW_PORT_F)
1540 /* Find "brick" in the path name */
1541 bp = strstr(hw_path_name, "brick");
1545 /* Find preceding slash */
1547 while (sp > hw_path_name) {
1553 /* Invalid if no preceding slash */
1557 /* Bump slash pointer to "brick" prefix */
1560 * Verify "brick" prefix length; valid exaples:
1561 * 'I' from "/Ibrick"
1562 * 'P' from "/Pbrick"
1563 * 'X' from "/Xbrick"
1568 return (io_brick_map_widget(*sp, widget_num));