patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / ia64 / sn / io / sn2 / ml_iograph.c
1 /*
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
4  * for more details.
5  *
6  * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
7  */
8
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>
19
20 /* #define IOGRAPH_DEBUG */
21 #ifdef IOGRAPH_DEBUG
22 #define DBG(x...) printk(x)
23 #else
24 #define DBG(x...)
25 #endif /* IOGRAPH_DEBUG */
26
27 /* At most 2 hubs can be connected to an xswitch */
28 #define NUM_XSWITCH_VOLUNTEER 2
29
30 /*
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.
35  */
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];
40 } *xswitch_vol_t;
41
42 void
43 xswitch_vertex_init(vertex_hdl_t xswitch)
44 {
45         xswitch_vol_t xvolinfo;
46         int rc;
47
48         xvolinfo = kmalloc(sizeof(struct xswitch_vol_s), GFP_KERNEL);
49         if (!xvolinfo) {
50                 printk(KERN_WARNING "xswitch_vertex_init(): Unable to "
51                         "allocate memory\n");
52                 return;
53         }
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;
59 }
60
61
62 /*
63  * When assignment of hubs to widgets is complete, we no longer need the
64  * xswitch volunteer structure hanging around.  Destroy it.
65  */
66 static void
67 xswitch_volunteer_delete(vertex_hdl_t xswitch)
68 {
69         xswitch_vol_t xvolinfo;
70         int rc;
71
72         rc = hwgraph_info_remove_LBL(xswitch, 
73                                 INFO_LBL_XSWITCH_VOL,
74                                 (arbitrary_info_t *)&xvolinfo);
75         if (xvolinfo > 0)
76                 kfree(xvolinfo);
77 }
78 /*
79  * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
80  */
81 /* ARGSUSED */
82 static void
83 volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master)
84 {
85         xswitch_vol_t xvolinfo = NULL;
86         vertex_hdl_t hubv;
87         hubinfo_t hubinfo;
88
89         (void)hwgraph_info_get_LBL(xswitch, 
90                                 INFO_LBL_XSWITCH_VOL, 
91                                 (arbitrary_info_t *)&xvolinfo);
92         if (xvolinfo == NULL) {
93             if (!is_headless_node_vertex(master)) {
94                     char name[MAXDEVNAME];
95                     printk(KERN_WARNING
96                         "volunteer for widgets: vertex %s has no info label",
97                         vertex_to_name(xswitch, name, MAXDEVNAME));
98             }
99             return;
100         }
101
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++;
106
107         /*
108          * if dual ported, make the lowest widgetid always be 
109          * xswitch_volunteer[0].
110          */
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;
118                 }
119         }
120         up(&xvolinfo->xswitch_volunteer_mutex);
121 }
122
123 extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
124
125 /*
126  * Assign all the xwidgets hanging off the specified xswitch to the
127  * Crosstalk masters that have volunteered for xswitch duty.
128  */
129 /* ARGSUSED */
130 static void
131 assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv)
132 {
133         xswitch_info_t xswitch_info;
134         xswitch_vol_t xvolinfo = NULL;
135         xwidgetnum_t widgetnum;
136         int num_volunteer;
137         nasid_t nasid;
138         hubinfo_t hubinfo;
139         extern int iobrick_type_get_nasid(nasid_t);
140
141
142         hubinfo_get(hubv, &hubinfo);
143         nasid = hubinfo->h_nasid;
144         
145         xswitch_info = xswitch_info_get(xswitch);
146         ASSERT(xswitch_info != NULL);
147
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];
154                     printk(KERN_WARNING
155                         "assign_widgets_to_volunteers:vertex %s has "
156                         " no info label",
157                         vertex_to_name(xswitch, name, MAXDEVNAME));
158             }
159             return;
160         }
161
162         num_volunteer = xvolinfo->xswitch_volunteer_count;
163         ASSERT(num_volunteer > 0);
164
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);
169         }
170
171         /*
172          * TBD: Use administrative information to alter assignment of
173          * widgets to hubs.
174          */
175         for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
176                 int i;
177
178                 if (!xbow_port_io_enabled(nasid, widgetnum)) 
179                     continue;
180
181                 /*
182                  * If this is the master IO board, assign it to the same 
183                  * hub that owned it in the prom.
184                  */
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())
192                                         goto do_assignment;
193                         }
194                         printk("Nasid == %d, console nasid == %d",
195                                 nasid, snia_get_master_baseio_nasid());
196                         nasid = 0;
197                 }
198
199                 /*
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.
206                  */
207
208                 i = 0;
209                 if (num_volunteer > 1) {
210                         int            bt;
211
212                         bt = iobrick_type_get_nasid(nasid);
213                         if (bt >= 0) {
214                                 i = io_brick_map_widget(bt, widgetnum) & 1;
215                         }
216                 }
217
218                 hubv = xvolinfo->xswitch_volunteer[i];
219
220 do_assignment:
221                 /*
222                  * At this point, we want to make hubv the master of widgetnum.
223                  */
224                 xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
225         }
226
227         xswitch_volunteer_delete(xswitch);
228 }
229
230 /* 
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.
236  *
237  * TBD: Prom code should actually do this work, and pass through 
238  * hwid for our use.
239  */
240 static void
241 early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid)
242 {
243         nasid_t nasid;
244         hubinfo_t hubinfo;
245         hubreg_t llp_csr_reg;
246         widgetreg_t widget_id;
247         int result = 0;
248
249         hwid->part_num = XWIDGET_PART_NUM_NONE;
250         hwid->rev_num = XWIDGET_REV_NUM_NONE;
251         hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
252
253         hubinfo_get(hubv, &hubinfo);
254         nasid = hubinfo->h_nasid;
255
256         llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
257         if (!(llp_csr_reg & IIO_LLP_CSR_IS_UP))
258                 return;
259
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);
264
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);
269
270                 /* TBD: link reset */
271         } else {
272
273                 hwid->part_num = XWIDGET_PART_NUM_NONE;
274                 hwid->rev_num = XWIDGET_REV_NUM_NONE;
275                 hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
276         }
277 }
278
279 /*
280  * io_xswitch_widget_init
281  *      
282  */
283
284 static void
285 io_xswitch_widget_init(vertex_hdl_t     xswitchv,
286                        vertex_hdl_t     hubv,
287                        xwidgetnum_t     widgetnum)
288 {
289         xswitch_info_t          xswitch_info;
290         xwidgetnum_t            hub_widgetid;
291         vertex_hdl_t            widgetv;
292         cnodeid_t               cnode;
293         widgetreg_t             widget_id;
294         nasid_t                 nasid, peer_nasid;
295         struct xwidget_hwid_s   hwid;
296         hubinfo_t               hubinfo;
297         /*REFERENCED*/
298         int                     rc;
299         char                    pathname[128];
300         lboard_t                *board = NULL;
301         char                    buffer[16];
302         char                    bt;
303         moduleid_t              io_module;
304         slotid_t get_widget_slotnum(int xbow, int widget);
305         
306         DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
307
308         /*
309          * Verify that xswitchv is indeed an attached xswitch.
310          */
311         xswitch_info = xswitch_info_get(xswitchv);
312         ASSERT(xswitch_info != NULL);
313
314         hubinfo_get(hubv, &hubinfo);
315         nasid = hubinfo->h_nasid;
316         cnode = nasid_to_cnodeid(nasid);
317         hub_widgetid = hubinfo->h_widgetid;
318
319         /*
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.
323          */
324         peer_nasid = NODEPDA(cnode)->xbow_peer;
325         if (peer_nasid == INVALID_NASID)
326                 /* If I don't have a peer, use myself. */
327                 peer_nasid = nasid;
328         if (!xbow_port_io_enabled(nasid, widgetnum) &&
329             !xbow_port_io_enabled(peer_nasid, widgetnum)) {
330                 return;
331         }
332
333         if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
334                 char                    name[4];
335                 lboard_t dummy;
336
337
338                 /*
339                  * If the current hub is not supposed to be the master 
340                  * for this widgetnum, then skip this widget.
341                  */
342                 if (xswitch_info_master_assignment_get(xswitch_info,
343                                                        widgetnum) != hubv) {
344                         return;
345                 }
346
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);
353                 }
354
355                 if (board) {
356                         DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
357                 } else {
358                         DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
359                         board = &dummy;
360                 }
361
362
363                 /* Copy over the nodes' geoid info */
364                 {
365                         lboard_t *brd;
366
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;
370                         }
371                 }
372
373                 /*
374                  * Make sure we really want to say xbrick, pbrick,
375                  * etc. rather than XIO, graphics, etc.
376                  */
377
378                 memset(buffer, 0, 16);
379                 format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
380
381                 sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d",
382                         buffer,
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);
389                 
390                 DBG("io_xswitch_widget_init: path= %s\n", pathname);
391                 rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
392                 
393                 ASSERT(rc == GRAPH_SUCCESS);
394
395                 /* This is needed to let the user programs to map the
396                  * module,slot numbers to the corresponding widget numbers
397                  * on the crossbow.
398                  */
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);
403                 
404                 /*
405                  * crosstalk switch code tracks which
406                  * widget is attached to each link.
407                  */
408                 xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
409                 
410                 /*
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
414                  * called (or not).
415                  */
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);
420
421                 (void)xwidget_register(&hwid, widgetv, widgetnum,
422                                        hubv, hub_widgetid);
423
424                 io_module = iomoduleid_get(nasid);
425                 if (io_module >= 0) {
426                         char                    buffer[16];
427                         vertex_hdl_t            to, from;
428                         char                    *brick_name;
429                         extern char *iobrick_L1bricktype_to_name(int type);
430
431
432                         memset(buffer, 0, 16);
433                         format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
434
435                         if ( isupper(MODULE_GET_BTCHAR(io_module)) ) {
436                                 bt = tolower(MODULE_GET_BTCHAR(io_module));
437                         }
438                         else {
439                                 bt = MODULE_GET_BTCHAR(io_module);
440                         }
441
442                         brick_name = iobrick_L1bricktype_to_name(bt);
443
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
447                         *  brick vertex.
448                         */
449
450                         sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/"
451                                 EDGE_LBL_SLAB "/%d/"
452                                 EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/"
453                                 "0",
454                                 buffer, geo_slab(board->brd_geoid));
455                         from = hwgraph_path_to_vertex(pathname);
456                         ASSERT_ALWAYS(from);
457                         sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/"
458                                 EDGE_LBL_SLAB "/%d/"
459                                 "%s",
460                                 buffer, geo_slab(board->brd_geoid), brick_name);
461
462                         to = hwgraph_path_to_vertex(pathname);
463                         ASSERT_ALWAYS(to);
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);
469                         }
470                 }
471
472         }
473 }
474
475
476 static void
477 io_init_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnode)
478 {
479         xwidgetnum_t            widgetnum;
480         
481         DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
482
483         for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; 
484              widgetnum++) {
485                 io_xswitch_widget_init(xswitchv,
486                                        cnodeid_to_vertex(cnode),
487                                        widgetnum);
488         }
489 }
490
491 /*
492  * Initialize all I/O on the specified node.
493  */
494 static void
495 io_init_node(cnodeid_t cnodeid)
496 {
497         /*REFERENCED*/
498         vertex_hdl_t hubv, switchv, widgetv;
499         struct xwidget_hwid_s hwid;
500         hubinfo_t hubinfo;
501         int is_xswitch;
502         nodepda_t       *npdap;
503         struct semaphore *peer_sema = 0;
504         uint32_t        widget_partnum;
505
506         npdap = NODEPDA(cnodeid);
507
508         /*
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
514          */
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);
517
518         ASSERT(hubv != GRAPH_VERTEX_NONE);
519
520         /* 
521          * If nothing connected to this hub's xtalk port, we're done.
522          */
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);
526                 return;
527                 /* NOTREACHED */
528         }
529
530         /* 
531          * attach our hub_provider information to hubv,
532          * so we can use it as a crosstalk provider "master"
533          * vertex.
534          */
535         xtalk_provider_register(hubv, &hub_provider);
536         xtalk_provider_startup(hubv);
537
538         /*
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.
543          *
544          * Crosstalk Switch drivers "climb up" from their
545          * connection point to try and take over the switch
546          * point.
547          *
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.
552          */
553
554         (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
555
556         DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
557
558         ASSERT(switchv != GRAPH_VERTEX_NONE);
559
560         (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
561
562         DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
563
564         /*
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.
568          */
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;
573
574         if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
575                         (widget_partnum == XXBOW_WIDGET_PART_NUM) ||
576                         (widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
577                 /* 
578                  * Xbow control register does not have the widget ID field.
579                  * So, hard code the widget ID to be zero.
580                  */
581                 DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
582                 npdap->basew_id = 0;
583
584         } else {
585                 void    *bridge;
586
587                 bridge = (void *)NODE_SWIN_BASE(cnodeid_to_nasid(cnodeid), 0);
588                 npdap->basew_id = pcireg_bridge_control_get(bridge) & WIDGET_WIDGET_ID;
589
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);
591                 return;
592         }
593         {
594                 char widname[10];
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);
599         }
600         
601         nodepda->basew_xc = widgetv;
602
603         is_xswitch = xwidget_hwid_is_xswitch(&hwid);
604
605         /* 
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
610          * masters.
611          */
612         if (device_master_set(widgetv, hubv) == 0) {
613
614                 /* Only one hub (thread) per Crosstalk device or switch makes
615                  * it to here.
616                  */
617
618                 /* 
619                  * Initialize whatever xwidget is hanging off our hub.
620                  * Whatever it is, it's accessible through widgetnum 0.
621                  */
622                 hubinfo_get(hubv, &hubinfo);
623
624                 (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid);
625
626                 /* 
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
634                  */
635
636                 volunteer_for_widgets(switchv, hubv);
637
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);
643                 }
644
645                 assign_widgets_to_volunteers(switchv, hubv);
646
647                 /* Signal that we're done */
648                 if (peer_sema) {
649                         up(peer_sema);
650                 }
651                 
652         }
653         else {
654             /* Wait 'til master is done assigning widgets. */
655             down(&npdap->xbow_sema);
656         }
657
658         /* Now both nodes can safely inititialize widgets */
659         io_init_xswitch_widgets(switchv, cnodeid);
660
661         DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
662 }
663
664 #include <asm/sn/ioerror_handling.h>
665
666 /*
667  * Initialize all I/O devices.  Starting closest to nodes, probe and
668  * initialize outward.
669  */
670 void
671 init_all_devices(void)
672 {
673         cnodeid_t cnodeid, active;
674
675         active = 0;
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);
679
680                 DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
681         }
682
683         for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
684                 /*
685                  * Update information generated by IO init.
686                  */
687                 update_node_information(cnodeid);
688         }
689 }
690
691 static
692 struct io_brick_map_s io_brick_tab[] = {
693
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      */
698         0,                                      /* 0x8            */
699         0,                                      /* 0x9            */
700         0, 0,                                   /* 0xa - 0xb      */
701         1,                                      /* 0xc            */
702         5,                                      /* 0xd            */
703         0,                                      /* 0xe            */
704         3                                       /* 0xf            */
705     }
706  },
707
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      */
712         0,                                      /* 0x8            */
713         0,                                      /* 0x9            */
714         0, 0,                                   /* 0xa - 0xb      */
715         0,                                      /* 0xc            */
716         0,                                      /* 0xd            */
717         0,                                      /* 0xe            */
718         1                                       /* 0xf            */
719     }
720  },
721
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      */
726         0,                                      /* 0x8            */
727         0,                                      /* 0x9            */
728         0, 0,                                   /* 0xa - 0xb      */
729         1,                                      /* 0xc            */
730         5,                                      /* 0xd            */
731         0,                                      /* 0xe            */
732         3                                       /* 0xf            */
733     }
734  },
735
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      */
740         0,                                      /* 0x8            */
741         0,                                      /* 0x9            */
742         0, 1,                                   /* 0xa - 0xb      */
743         0,                                      /* 0xc            */
744         0,                                      /* 0xd            */
745         0,                                      /* 0xe            */
746         0                                       /* 0xf            */
747      }
748  },
749 };
750
751 /*
752  * Use the brick's type to map a widget number to a meaningful int
753  */
754 int
755 io_brick_map_widget(int brick_type, int widget_num)
756 {
757         int num_bricks, i;
758
759         /* Calculate number of bricks in table */
760         num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
761
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];
766         }
767
768         return 0;
769
770 }