2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
6 * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
9 #include <linux/ctype.h>
10 #include <asm/sn/sgi.h>
11 #include <asm/sn/sn_sal.h>
12 #include <asm/sn/iograph.h>
13 #include <asm/sn/hcl.h>
14 #include <asm/sn/hcl_util.h>
15 #include <asm/sn/sn_private.h>
16 #include <asm/sn/pci/pcibr_private.h>
17 #include <asm/sn/xtalk/xtalkaddrs.h>
18 #include <asm/sn/ksys/l1.h>
20 /* #define IOGRAPH_DEBUG */
22 #define DBG(x...) printk(x)
25 #endif /* IOGRAPH_DEBUG */
27 /* At most 2 hubs can be connected to an xswitch */
28 #define NUM_XSWITCH_VOLUNTEER 2
31 * Track which hubs have volunteered to manage devices hanging off of
32 * a Crosstalk Switch (e.g. xbow). This structure is allocated,
33 * initialized, and hung off the xswitch vertex early on when the
34 * xswitch vertex is created.
36 typedef struct xswitch_vol_s {
37 struct semaphore xswitch_volunteer_mutex;
38 int xswitch_volunteer_count;
39 vertex_hdl_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
43 xswitch_vertex_init(vertex_hdl_t xswitch)
45 xswitch_vol_t xvolinfo;
48 xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
50 printk(KERN_WARNING "xswitch_vertex_init(): Unable to "
54 memset(xvolinfo, 0, sizeof(struct xswitch_vol_s));
55 init_MUTEX(&xvolinfo->xswitch_volunteer_mutex);
56 rc = hwgraph_info_add_LBL(xswitch, INFO_LBL_XSWITCH_VOL,
57 (arbitrary_info_t)xvolinfo);
58 ASSERT(rc == GRAPH_SUCCESS); rc = rc;
63 * When assignment of hubs to widgets is complete, we no longer need the
64 * xswitch volunteer structure hanging around. Destroy it.
67 xswitch_volunteer_delete(vertex_hdl_t xswitch)
69 xswitch_vol_t xvolinfo;
72 rc = hwgraph_info_remove_LBL(xswitch,
74 (arbitrary_info_t *)&xvolinfo);
79 * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
83 volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master)
85 xswitch_vol_t xvolinfo = NULL;
89 (void)hwgraph_info_get_LBL(xswitch,
91 (arbitrary_info_t *)&xvolinfo);
92 if (xvolinfo == NULL) {
93 if (!is_headless_node_vertex(master)) {
94 char name[MAXDEVNAME];
96 "volunteer for widgets: vertex %s has no info label",
97 vertex_to_name(xswitch, name, MAXDEVNAME));
102 down(&xvolinfo->xswitch_volunteer_mutex);
103 ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
104 xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
105 xvolinfo->xswitch_volunteer_count++;
108 * if dual ported, make the lowest widgetid always be
109 * xswitch_volunteer[0].
111 if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) {
112 hubv = xvolinfo->xswitch_volunteer[0];
113 hubinfo_get(hubv, &hubinfo);
114 if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) {
115 xvolinfo->xswitch_volunteer[0] =
116 xvolinfo->xswitch_volunteer[1];
117 xvolinfo->xswitch_volunteer[1] = hubv;
120 up(&xvolinfo->xswitch_volunteer_mutex);
123 extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
126 * Assign all the xwidgets hanging off the specified xswitch to the
127 * Crosstalk masters that have volunteered for xswitch duty.
131 assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv)
133 xswitch_info_t xswitch_info;
134 xswitch_vol_t xvolinfo = NULL;
135 xwidgetnum_t widgetnum;
139 extern int iobrick_type_get_nasid(nasid_t);
142 hubinfo_get(hubv, &hubinfo);
143 nasid = hubinfo->h_nasid;
145 xswitch_info = xswitch_info_get(xswitch);
146 ASSERT(xswitch_info != NULL);
148 (void)hwgraph_info_get_LBL(xswitch,
149 INFO_LBL_XSWITCH_VOL,
150 (arbitrary_info_t *)&xvolinfo);
151 if (xvolinfo == NULL) {
152 if (!is_headless_node_vertex(hubv)) {
153 char name[MAXDEVNAME];
155 "assign_widgets_to_volunteers:vertex %s has "
157 vertex_to_name(xswitch, name, MAXDEVNAME));
162 num_volunteer = xvolinfo->xswitch_volunteer_count;
163 ASSERT(num_volunteer > 0);
165 /* Assign master hub for xswitch itself. */
166 if (HUB_WIDGET_ID_MIN > 0) {
167 hubv = xvolinfo->xswitch_volunteer[0];
168 xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
172 * TBD: Use administrative information to alter assignment of
175 for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
178 if (!xbow_port_io_enabled(nasid, widgetnum))
182 * If this is the master IO board, assign it to the same
183 * hub that owned it in the prom.
185 if (is_master_baseio_nasid_widget(nasid, widgetnum)) {
186 extern nasid_t snia_get_master_baseio_nasid(void);
187 for (i=0; i<num_volunteer; i++) {
188 hubv = xvolinfo->xswitch_volunteer[i];
189 hubinfo_get(hubv, &hubinfo);
190 nasid = hubinfo->h_nasid;
191 if (nasid == snia_get_master_baseio_nasid())
194 printk("Nasid == %d, console nasid == %d",
195 nasid, snia_get_master_baseio_nasid());
200 * Assuming that we're dual-hosted and that PCI cards
201 * are naturally placed left-to-right, alternate PCI
202 * buses across both Cbricks. For Pbricks, and Ibricks,
203 * io_brick_map_widget() returns the PCI bus number
204 * associated with the given brick type and widget number.
205 * For Xbricks, it returns the XIO slot number.
209 if (num_volunteer > 1) {
212 bt = iobrick_type_get_nasid(nasid);
214 i = io_brick_map_widget(bt, widgetnum) & 1;
218 hubv = xvolinfo->xswitch_volunteer[i];
222 * At this point, we want to make hubv the master of widgetnum.
224 xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
227 xswitch_volunteer_delete(xswitch);
231 * Probe to see if this hub's xtalk link is active. If so,
232 * return the Crosstalk Identification of the widget that we talk to.
233 * This is called before any of the Crosstalk infrastructure for
234 * this hub is set up. It's usually called on the node that we're
235 * probing, but not always.
237 * TBD: Prom code should actually do this work, and pass through
241 early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid)
245 hubreg_t llp_csr_reg;
246 widgetreg_t widget_id;
249 hwid->part_num = XWIDGET_PART_NUM_NONE;
250 hwid->rev_num = XWIDGET_REV_NUM_NONE;
251 hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
253 hubinfo_get(hubv, &hubinfo);
254 nasid = hubinfo->h_nasid;
256 llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
257 if (!(llp_csr_reg & IIO_LLP_CSR_IS_UP))
260 /* Read the Cross-Talk Widget Id on the other end */
261 result = snia_badaddr_val((volatile void *)
262 (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID),
263 4, (void *) &widget_id);
265 if (result == 0) { /* Found something connected */
266 hwid->part_num = XWIDGET_PART_NUM(widget_id);
267 hwid->rev_num = XWIDGET_REV_NUM(widget_id);
268 hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
270 /* TBD: link reset */
273 hwid->part_num = XWIDGET_PART_NUM_NONE;
274 hwid->rev_num = XWIDGET_REV_NUM_NONE;
275 hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
280 * io_xswitch_widget_init
285 io_xswitch_widget_init(vertex_hdl_t xswitchv,
287 xwidgetnum_t widgetnum)
289 xswitch_info_t xswitch_info;
290 xwidgetnum_t hub_widgetid;
291 vertex_hdl_t widgetv;
293 widgetreg_t widget_id;
294 nasid_t nasid, peer_nasid;
295 struct xwidget_hwid_s hwid;
300 lboard_t *board = NULL;
303 moduleid_t io_module;
304 slotid_t get_widget_slotnum(int xbow, int widget);
306 DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
309 * Verify that xswitchv is indeed an attached xswitch.
311 xswitch_info = xswitch_info_get(xswitchv);
312 ASSERT(xswitch_info != NULL);
314 hubinfo_get(hubv, &hubinfo);
315 nasid = hubinfo->h_nasid;
316 cnode = nasid_to_cnodeid(nasid);
317 hub_widgetid = hubinfo->h_widgetid;
320 * Check that the widget is an io widget and is enabled
321 * on this nasid or the `peer' nasid. The peer nasid
322 * is the other hub/bedrock connected to the xbow.
324 peer_nasid = NODEPDA(cnode)->xbow_peer;
325 if (peer_nasid == INVALID_NASID)
326 /* If I don't have a peer, use myself. */
328 if (!xbow_port_io_enabled(nasid, widgetnum) &&
329 !xbow_port_io_enabled(peer_nasid, widgetnum)) {
333 if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
339 * If the current hub is not supposed to be the master
340 * for this widgetnum, then skip this widget.
342 if (xswitch_info_master_assignment_get(xswitch_info,
343 widgetnum) != hubv) {
347 board = find_lboard_class_nasid( (lboard_t *)KL_CONFIG_INFO(nasid),
348 nasid, KLCLASS_IOBRICK);
349 if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) {
350 board = find_lboard_class_nasid(
351 (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer),
352 NODEPDA(cnode)->xbow_peer, KLCLASS_IOBRICK);
356 DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
358 DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
363 /* Copy over the nodes' geoid info */
367 brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
368 if ( brd != (lboard_t *)0 ) {
369 board->brd_geoid = brd->brd_geoid;
374 * Make sure we really want to say xbrick, pbrick,
375 * etc. rather than XIO, graphics, etc.
378 memset(buffer, 0, 16);
379 format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
381 sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d",
383 geo_slab(board->brd_geoid),
384 (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK :
385 (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK :
386 (board->brd_type == KLTYPE_CGBRICK) ? EDGE_LBL_CGBRICK :
387 (board->brd_type == KLTYPE_OPUSBRICK) ? EDGE_LBL_OPUSBRICK : "?brick",
388 EDGE_LBL_XTALK, widgetnum);
390 DBG("io_xswitch_widget_init: path= %s\n", pathname);
391 rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
393 ASSERT(rc == GRAPH_SUCCESS);
395 /* This is needed to let the user programs to map the
396 * module,slot numbers to the corresponding widget numbers
399 device_master_set(hwgraph_connectpt_get(widgetv), hubv);
400 sprintf(name, "%d", widgetnum);
401 DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
402 rc = hwgraph_edge_add(xswitchv, widgetv, name);
405 * crosstalk switch code tracks which
406 * widget is attached to each link.
408 xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
411 * Peek at the widget to get its crosstalk part and
412 * mfgr numbers, then present it to the generic xtalk
413 * bus provider to have its driver attach routine
416 widget_id = XWIDGET_ID_READ(nasid, widgetnum);
417 hwid.part_num = XWIDGET_PART_NUM(widget_id);
418 hwid.rev_num = XWIDGET_REV_NUM(widget_id);
419 hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
421 (void)xwidget_register(&hwid, widgetv, widgetnum,
424 io_module = iomoduleid_get(nasid);
425 if (io_module >= 0) {
427 vertex_hdl_t to, from;
429 extern char *iobrick_L1bricktype_to_name(int type);
432 memset(buffer, 0, 16);
433 format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
435 if ( isupper(MODULE_GET_BTCHAR(io_module)) ) {
436 bt = tolower(MODULE_GET_BTCHAR(io_module));
439 bt = MODULE_GET_BTCHAR(io_module);
442 brick_name = iobrick_L1bricktype_to_name(bt);
444 /* Add a helper vertex so xbow monitoring
445 * can identify the brick type. It's simply
446 * an edge from the widget 0 vertex to the
450 sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/"
452 EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/"
454 buffer, geo_slab(board->brd_geoid));
455 from = hwgraph_path_to_vertex(pathname);
457 sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/"
460 buffer, geo_slab(board->brd_geoid), brick_name);
462 to = hwgraph_path_to_vertex(pathname);
464 rc = hwgraph_edge_add(from, to,
465 EDGE_LBL_INTERCONNECT);
466 if (rc != -EEXIST && rc != GRAPH_SUCCESS) {
467 printk("%s: Unable to establish link"
468 " for xbmon.", pathname);
477 io_init_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnode)
479 xwidgetnum_t widgetnum;
481 DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
483 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
485 io_xswitch_widget_init(xswitchv,
486 cnodeid_to_vertex(cnode),
492 * Initialize all I/O on the specified node.
495 io_init_node(cnodeid_t cnodeid)
498 vertex_hdl_t hubv, switchv, widgetv;
499 struct xwidget_hwid_s hwid;
503 struct semaphore *peer_sema = 0;
504 uint32_t widget_partnum;
506 npdap = NODEPDA(cnodeid);
509 * Get the "top" vertex for this node's hardware
510 * graph; it will carry the per-hub hub-specific
511 * data, and act as the crosstalk provider master.
512 * It's canonical path is probably something of the
513 * form /hw/module/%M/slot/%d/node
515 hubv = cnodeid_to_vertex(cnodeid);
516 DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
518 ASSERT(hubv != GRAPH_VERTEX_NONE);
521 * If nothing connected to this hub's xtalk port, we're done.
523 early_probe_for_widget(hubv, &hwid);
524 if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
525 DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
531 * attach our hub_provider information to hubv,
532 * so we can use it as a crosstalk provider "master"
535 xtalk_provider_register(hubv, &hub_provider);
536 xtalk_provider_startup(hubv);
539 * Create a vertex to represent the crosstalk bus
540 * attached to this hub, and a vertex to be used
541 * as the connect point for whatever is out there
542 * on the other side of our crosstalk connection.
544 * Crosstalk Switch drivers "climb up" from their
545 * connection point to try and take over the switch
548 * Of course, the edges and verticies may already
549 * exist, in which case our net effect is just to
550 * associate the "xtalk_" driver with the connection
551 * point for the device.
554 (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
556 DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
558 ASSERT(switchv != GRAPH_VERTEX_NONE);
560 (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
562 DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
565 * We need to find the widget id and update the basew_id field
566 * accordingly. In particular, SN00 has direct connected bridge,
567 * and hence widget id is Not 0.
569 widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE
570 (cnodeid_to_nasid(cnodeid), 0) +
571 WIDGET_ID))) & WIDGET_PART_NUM)
572 >> WIDGET_PART_NUM_SHFT;
574 if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
575 (widget_partnum == XXBOW_WIDGET_PART_NUM) ||
576 (widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
578 * Xbow control register does not have the widget ID field.
579 * So, hard code the widget ID to be zero.
581 DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
587 bridge = (void *)NODE_SWIN_BASE(cnodeid_to_nasid(cnodeid), 0);
588 npdap->basew_id = pcireg_bridge_control_get(bridge) & WIDGET_WIDGET_ID;
590 printk(" ****io_init_node: Unknown Widget Part Number 0x%x Widget ID 0x%x attached to Hubv 0x%p ****\n", widget_partnum, npdap->basew_id, (void *)hubv);
595 sprintf(widname, "%x", npdap->basew_id);
596 (void)hwgraph_path_add(switchv, widname, &widgetv);
597 DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
598 ASSERT(widgetv != GRAPH_VERTEX_NONE);
601 nodepda->basew_xc = widgetv;
603 is_xswitch = xwidget_hwid_is_xswitch(&hwid);
606 * Try to become the master of the widget. If this is an xswitch
607 * with multiple hubs connected, only one will succeed. Mastership
608 * of an xswitch is used only when touching registers on that xswitch.
609 * The slave xwidgets connected to the xswitch can be owned by various
612 if (device_master_set(widgetv, hubv) == 0) {
614 /* Only one hub (thread) per Crosstalk device or switch makes
619 * Initialize whatever xwidget is hanging off our hub.
620 * Whatever it is, it's accessible through widgetnum 0.
622 hubinfo_get(hubv, &hubinfo);
624 (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid);
627 * Special handling for Crosstalk Switches (e.g. xbow).
628 * We need to do things in roughly the following order:
629 * 1) Initialize xswitch hardware (done above)
630 * 2) Determine which hubs are available to be widget masters
631 * 3) Discover which links are active from the xswitch
632 * 4) Assign xwidgets hanging off the xswitch to hubs
633 * 5) Initialize all xwidgets on the xswitch
636 volunteer_for_widgets(switchv, hubv);
638 /* If there's someone else on this crossbow, recognize him */
639 if (npdap->xbow_peer != INVALID_NASID) {
640 nodepda_t *peer_npdap = NODEPDA(nasid_to_cnodeid(npdap->xbow_peer));
641 peer_sema = &peer_npdap->xbow_sema;
642 volunteer_for_widgets(switchv, peer_npdap->node_vertex);
645 assign_widgets_to_volunteers(switchv, hubv);
647 /* Signal that we're done */
654 /* Wait 'til master is done assigning widgets. */
655 down(&npdap->xbow_sema);
658 /* Now both nodes can safely inititialize widgets */
659 io_init_xswitch_widgets(switchv, cnodeid);
661 DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
664 #include <asm/sn/ioerror_handling.h>
667 * Initialize all I/O devices. Starting closest to nodes, probe and
668 * initialize outward.
671 init_all_devices(void)
673 cnodeid_t cnodeid, active;
676 for (cnodeid = 0; cnodeid < numionodes; cnodeid++) {
677 DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
678 io_init_node(cnodeid);
680 DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
683 for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
685 * Update information generated by IO init.
687 update_node_information(cnodeid);
692 struct io_brick_map_s io_brick_tab[] = {
694 /* PXbrick widget number to PCI bus number map */
695 { MODULE_PXBRICK, /* PXbrick type */
696 /* PCI Bus # Widget # */
697 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
700 0, 0, /* 0xa - 0xb */
708 /* OPUSbrick widget number to PCI bus number map */
709 { MODULE_OPUSBRICK, /* OPUSbrick type */
710 /* PCI Bus # Widget # */
711 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
714 0, 0, /* 0xa - 0xb */
722 /* IXbrick widget number to PCI bus number map */
723 { MODULE_IXBRICK, /* IXbrick type */
724 /* PCI Bus # Widget # */
725 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
728 0, 0, /* 0xa - 0xb */
736 /* CG brick widget number to PCI bus number map */
737 { MODULE_CGBRICK, /* CG brick */
738 /* PCI Bus # Widget # */
739 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
742 0, 1, /* 0xa - 0xb */
752 * Use the brick's type to map a widget number to a meaningful int
755 io_brick_map_widget(int brick_type, int widget_num)
759 /* Calculate number of bricks in table */
760 num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
762 /* Look for brick prefix in table */
763 for (i = 0; i < num_bricks; i++) {
764 if (brick_type == io_brick_tab[i].ibm_type)
765 return io_brick_tab[i].ibm_map_wid[widget_num];