1 /* $Id$
2 *
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
5 * for more details.
6 *
7 * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
8 */
9
10 #include <linux/types.h>
11 #include <linux/slab.h>
12 #include <linux/ctype.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/sn_sal.h>
15 #include <asm/sn/io.h>
16 #include <asm/sn/sn_cpuid.h>
17 #include <asm/sn/iograph.h>
18 #include <asm/sn/invent.h>
19 #include <asm/sn/hcl.h>
20 #include <asm/sn/hcl_util.h>
21 #include <asm/sn/labelcl.h>
22 #include <asm/sn/xtalk/xbow.h>
23 #include <asm/sn/pci/bridge.h>
24 #include <asm/sn/klconfig.h>
25 #include <asm/sn/sn_private.h>
26 #include <asm/sn/pci/pcibr.h>
27 #include <asm/sn/xtalk/xtalk.h>
28 #include <asm/sn/xtalk/xswitch.h>
29 #include <asm/sn/xtalk/xwidget.h>
30 #include <asm/sn/xtalk/xtalk_private.h>
31 #include <asm/sn/xtalk/xtalkaddrs.h>
32
33 /* #define IOGRAPH_DEBUG */
34 #ifdef IOGRAPH_DEBUG
35 #define DBG(x...) printk(x)
36 #else
37 #define DBG(x...)
38 #endif /* IOGRAPH_DEBUG */
39
40 /* #define PROBE_TEST */
41
42 /* At most 2 hubs can be connected to an xswitch */
43 #define NUM_XSWITCH_VOLUNTEER 2
44
45 /*
46 * Track which hubs have volunteered to manage devices hanging off of
47 * a Crosstalk Switch (e.g. xbow). This structure is allocated,
48 * initialized, and hung off the xswitch vertex early on when the
49 * xswitch vertex is created.
50 */
51 typedef struct xswitch_vol_s {
52 struct semaphore xswitch_volunteer_mutex;
53 int xswitch_volunteer_count;
54 vertex_hdl_t xswitch_volunteer[NUM_XSWITCH_VOLUNTEER];
55 } *xswitch_vol_t;
56
57
58 void
xswitch_vertex_init(vertex_hdl_t xswitch)59 xswitch_vertex_init(vertex_hdl_t xswitch)
60 {
61 xswitch_vol_t xvolinfo;
62 int rc;
63
64 xvolinfo = snia_kmem_zalloc(sizeof(struct xswitch_vol_s));
65 init_MUTEX(&xvolinfo->xswitch_volunteer_mutex);
66 rc = hwgraph_info_add_LBL(xswitch,
67 INFO_LBL_XSWITCH_VOL,
68 (arbitrary_info_t)xvolinfo);
69 ASSERT(rc == GRAPH_SUCCESS); rc = rc;
70 }
71
72
73 /*
74 * When assignment of hubs to widgets is complete, we no longer need the
75 * xswitch volunteer structure hanging around. Destroy it.
76 */
77 static void
xswitch_volunteer_delete(vertex_hdl_t xswitch)78 xswitch_volunteer_delete(vertex_hdl_t xswitch)
79 {
80 xswitch_vol_t xvolinfo;
81 int rc;
82 extern void snia_kmem_free(void *ptr, size_t size);
83
84 rc = hwgraph_info_remove_LBL(xswitch,
85 INFO_LBL_XSWITCH_VOL,
86 (arbitrary_info_t *)&xvolinfo);
87 snia_kmem_free(xvolinfo, sizeof(struct xswitch_vol_s));
88 }
89 /*
90 * A Crosstalk master volunteers to manage xwidgets on the specified xswitch.
91 */
92 /* ARGSUSED */
93 static void
volunteer_for_widgets(vertex_hdl_t xswitch,vertex_hdl_t master)94 volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master)
95 {
96 xswitch_vol_t xvolinfo = NULL;
97 vertex_hdl_t hubv;
98 hubinfo_t hubinfo;
99
100 (void)hwgraph_info_get_LBL(xswitch,
101 INFO_LBL_XSWITCH_VOL,
102 (arbitrary_info_t *)&xvolinfo);
103 if (xvolinfo == NULL) {
104 if (!is_headless_node_vertex(master))
105 printk(KERN_WARNING
106 "volunteer for widgets: vertex 0x%p has no info label",
107 (void *)xswitch);
108 return;
109 }
110
111 down(&xvolinfo->xswitch_volunteer_mutex);
112 ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER);
113 xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master;
114 xvolinfo->xswitch_volunteer_count++;
115
116 /*
117 * if dual ported, make the lowest widgetid always be
118 * xswitch_volunteer[0].
119 */
120 if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) {
121 hubv = xvolinfo->xswitch_volunteer[0];
122 hubinfo_get(hubv, &hubinfo);
123 if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) {
124 xvolinfo->xswitch_volunteer[0] =
125 xvolinfo->xswitch_volunteer[1];
126 xvolinfo->xswitch_volunteer[1] = hubv;
127 }
128 }
129 up(&xvolinfo->xswitch_volunteer_mutex);
130 }
131
132 extern int xbow_port_io_enabled(nasid_t nasid, int widgetnum);
133
134 /*
135 * Assign all the xwidgets hanging off the specified xswitch to the
136 * Crosstalk masters that have volunteered for xswitch duty.
137 */
138 /* ARGSUSED */
139 static void
assign_widgets_to_volunteers(vertex_hdl_t xswitch,vertex_hdl_t hubv)140 assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv)
141 {
142 xswitch_info_t xswitch_info;
143 xswitch_vol_t xvolinfo = NULL;
144 xwidgetnum_t widgetnum;
145 int num_volunteer;
146 nasid_t nasid;
147 hubinfo_t hubinfo;
148 extern int iobrick_type_get_nasid(nasid_t);
149
150
151 hubinfo_get(hubv, &hubinfo);
152 nasid = hubinfo->h_nasid;
153
154 xswitch_info = xswitch_info_get(xswitch);
155 ASSERT(xswitch_info != NULL);
156
157 (void)hwgraph_info_get_LBL(xswitch,
158 INFO_LBL_XSWITCH_VOL,
159 (arbitrary_info_t *)&xvolinfo);
160 if (xvolinfo == NULL) {
161 if (!is_headless_node_vertex(hubv))
162 printk(KERN_WARNING
163 "assign_widgets_to_volunteers:vertex 0x%p has "
164 " no info label",
165 (void *)xswitch);
166 return;
167 }
168
169 num_volunteer = xvolinfo->xswitch_volunteer_count;
170 ASSERT(num_volunteer > 0);
171
172 /* Assign master hub for xswitch itself. */
173 if (HUB_WIDGET_ID_MIN > 0) {
174 hubv = xvolinfo->xswitch_volunteer[0];
175 xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv);
176 }
177
178 /*
179 * TBD: Use administrative information to alter assignment of
180 * widgets to hubs.
181 */
182 for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
183 int i;
184
185 /*
186 * Ignore disabled/empty ports.
187 */
188 if (!xbow_port_io_enabled(nasid, widgetnum))
189 continue;
190
191 /*
192 * If this is the master IO board, assign it to the same
193 * hub that owned it in the prom.
194 */
195 if (is_master_baseio_nasid_widget(nasid, widgetnum)) {
196 extern nasid_t snia_get_master_baseio_nasid(void);
197 for (i=0; i<num_volunteer; i++) {
198 hubv = xvolinfo->xswitch_volunteer[i];
199 hubinfo_get(hubv, &hubinfo);
200 nasid = hubinfo->h_nasid;
201 if (nasid == snia_get_master_baseio_nasid())
202 goto do_assignment;
203 }
204 panic("Nasid == %d, console nasid == %d",
205 nasid, snia_get_master_baseio_nasid());
206 }
207
208 /*
209 * Assuming that we're dual-hosted and that PCI cards
210 * are naturally placed left-to-right, alternate PCI
211 * buses across both Cbricks. For Pbricks, and Ibricks,
212 * io_brick_map_widget() returns the PCI bus number
213 * associated with the given brick type and widget number.
214 * For Xbricks, it returns the XIO slot number.
215 */
216
217 i = 0;
218 if (num_volunteer > 1) {
219 int bt;
220
221 bt = iobrick_type_get_nasid(nasid);
222 if (bt >= 0) {
223 i = io_brick_map_widget(bt, widgetnum) & 1;
224 }
225 }
226
227 hubv = xvolinfo->xswitch_volunteer[i];
228
229 do_assignment:
230 /*
231 * At this point, we want to make hubv the master of widgetnum.
232 */
233 xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv);
234 }
235
236 xswitch_volunteer_delete(xswitch);
237 }
238
239 /*
240 * Let boot processor know that we're done initializing our node's IO
241 * and then exit.
242 */
243 /* ARGSUSED */
244 static void
io_init_done(cnodeid_t cnodeid,cpuid_t c)245 io_init_done(cnodeid_t cnodeid,cpuid_t c)
246 {
247 /* Let boot processor know that we're done. */
248 }
249
250 /*
251 * Probe to see if this hub's xtalk link is active. If so,
252 * return the Crosstalk Identification of the widget that we talk to.
253 * This is called before any of the Crosstalk infrastructure for
254 * this hub is set up. It's usually called on the node that we're
255 * probing, but not always.
256 *
257 * TBD: Prom code should actually do this work, and pass through
258 * hwid for our use.
259 */
260 static void
early_probe_for_widget(vertex_hdl_t hubv,xwidget_hwid_t hwid)261 early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid)
262 {
263 hubreg_t llp_csr_reg;
264 nasid_t nasid;
265 hubinfo_t hubinfo;
266
267 hubinfo_get(hubv, &hubinfo);
268 nasid = hubinfo->h_nasid;
269
270 llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
271 /*
272 * If link is up, read the widget's part number.
273 * A direct connect widget must respond to widgetnum=0.
274 */
275 if (llp_csr_reg & IIO_LLP_CSR_IS_UP) {
276 /* TBD: Put hub into "indirect" mode */
277 /*
278 * We're able to read from a widget because our hub's
279 * WIDGET_ID was set up earlier.
280 */
281 widgetreg_t widget_id = *(volatile widgetreg_t *)
282 (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
283
284 DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id,
285 (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) );
286
287 hwid->part_num = XWIDGET_PART_NUM(widget_id);
288 hwid->rev_num = XWIDGET_REV_NUM(widget_id);
289 hwid->mfg_num = XWIDGET_MFG_NUM(widget_id);
290
291 /* TBD: link reset */
292 } else {
293
294 hwid->part_num = XWIDGET_PART_NUM_NONE;
295 hwid->rev_num = XWIDGET_REV_NUM_NONE;
296 hwid->mfg_num = XWIDGET_MFG_NUM_NONE;
297 }
298 }
299
300 /* Add inventory information to the widget vertex
301 * Right now (module,slot,revision) is being
302 * added as inventory information.
303 */
304 static void
xwidget_inventory_add(vertex_hdl_t widgetv,lboard_t * board,struct xwidget_hwid_s hwid)305 xwidget_inventory_add(vertex_hdl_t widgetv,
306 lboard_t *board,
307 struct xwidget_hwid_s hwid)
308 {
309 if (!board)
310 return;
311 /* Donot add inventory information for the baseio
312 * on a speedo with an xbox. It has already been
313 * taken care of in SN00_vmc.
314 * Speedo with xbox's baseio comes in at slot io1 (widget 9)
315 */
316 device_inventory_add(widgetv,INV_IOBD,board->brd_type,
317 geo_module(board->brd_geoid),
318 SLOTNUM_GETSLOT(board->brd_slot),
319 hwid.rev_num);
320 }
321
322 /*
323 * io_xswitch_widget_init
324 *
325 */
326
327 void
io_xswitch_widget_init(vertex_hdl_t xswitchv,vertex_hdl_t hubv,xwidgetnum_t widgetnum)328 io_xswitch_widget_init(vertex_hdl_t xswitchv,
329 vertex_hdl_t hubv,
330 xwidgetnum_t widgetnum)
331 {
332 xswitch_info_t xswitch_info;
333 xwidgetnum_t hub_widgetid;
334 vertex_hdl_t widgetv;
335 cnodeid_t cnode;
336 widgetreg_t widget_id;
337 nasid_t nasid, peer_nasid;
338 struct xwidget_hwid_s hwid;
339 hubinfo_t hubinfo;
340 /*REFERENCED*/
341 int rc;
342 char pathname[128];
343 lboard_t *board = NULL;
344 char buffer[16];
345 char bt;
346 moduleid_t io_module;
347 slotid_t get_widget_slotnum(int xbow, int widget);
348
349 DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum);
350
351 /*
352 * Verify that xswitchv is indeed an attached xswitch.
353 */
354 xswitch_info = xswitch_info_get(xswitchv);
355 ASSERT(xswitch_info != NULL);
356
357 hubinfo_get(hubv, &hubinfo);
358 nasid = hubinfo->h_nasid;
359 cnode = NASID_TO_COMPACT_NODEID(nasid);
360 hub_widgetid = hubinfo->h_widgetid;
361
362 /*
363 * Check that the widget is an io widget and is enabled
364 * on this nasid or the `peer' nasid. The peer nasid
365 * is the other hub/bedrock connected to the xbow.
366 */
367 peer_nasid = NODEPDA(cnode)->xbow_peer;
368 if (peer_nasid == INVALID_NASID)
369 /* If I don't have a peer, use myself. */
370 peer_nasid = nasid;
371 if (!xbow_port_io_enabled(nasid, widgetnum) &&
372 !xbow_port_io_enabled(peer_nasid, widgetnum)) {
373 return;
374 }
375
376 if (xswitch_info_link_ok(xswitch_info, widgetnum)) {
377 char name[4];
378 lboard_t dummy;
379
380
381 /*
382 * If the current hub is not supposed to be the master
383 * for this widgetnum, then skip this widget.
384 */
385
386 if (xswitch_info_master_assignment_get(xswitch_info, widgetnum) != hubv) {
387 return;
388 }
389
390 board = find_lboard_class(
391 (lboard_t *)KL_CONFIG_INFO(nasid),
392 KLCLASS_IOBRICK);
393 if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) {
394 board = find_lboard_class(
395 (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer),
396 KLCLASS_IOBRICK);
397 }
398
399 if (board) {
400 DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type);
401 } else {
402 DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n");
403 board = &dummy;
404 }
405
406
407 /* Copy over the nodes' geoid info */
408 {
409 lboard_t *brd;
410
411 brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
412 if ( brd != (lboard_t *)0 ) {
413 board->brd_geoid = brd->brd_geoid;
414 }
415 }
416
417 /*
418 * Make sure we really want to say xbrick, pbrick,
419 * etc. rather than XIO, graphics, etc.
420 */
421
422 memset(buffer, 0, 16);
423 format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
424
425 sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d",
426 buffer,
427 geo_slab(board->brd_geoid),
428 (board->brd_type == KLTYPE_IBRICK) ? EDGE_LBL_IBRICK :
429 (board->brd_type == KLTYPE_PBRICK) ? EDGE_LBL_PBRICK :
430 (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK :
431 (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK :
432 (board->brd_type == KLTYPE_CGBRICK) ? EDGE_LBL_CGBRICK :
433 (board->brd_type == KLTYPE_OPUSBRICK) ? EDGE_LBL_OPUSBRICK :
434 (board->brd_type == KLTYPE_XBRICK) ? EDGE_LBL_XBRICK : "?brick",
435 EDGE_LBL_XTALK, widgetnum);
436
437 DBG("io_xswitch_widget_init: path= %s\n", pathname);
438 rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv);
439
440 ASSERT(rc == GRAPH_SUCCESS);
441
442 /* This is needed to let the user programs to map the
443 * module,slot numbers to the corresponding widget numbers
444 * on the crossbow.
445 */
446 device_master_set(hwgraph_connectpt_get(widgetv), hubv);
447 sprintf(name, "%d", widgetnum);
448 DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv);
449 rc = hwgraph_edge_add(xswitchv, widgetv, name);
450
451 /*
452 * crosstalk switch code tracks which
453 * widget is attached to each link.
454 */
455 xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv);
456
457 /*
458 * Peek at the widget to get its crosstalk part and
459 * mfgr numbers, then present it to the generic xtalk
460 * bus provider to have its driver attach routine
461 * called (or not).
462 */
463 widget_id = XWIDGET_ID_READ(nasid, widgetnum);
464 hwid.part_num = XWIDGET_PART_NUM(widget_id);
465 hwid.rev_num = XWIDGET_REV_NUM(widget_id);
466 hwid.mfg_num = XWIDGET_MFG_NUM(widget_id);
467 /* Store some inventory information about
468 * the xwidget in the hardware graph.
469 */
470 xwidget_inventory_add(widgetv,board,hwid);
471
472 (void)xwidget_register(&hwid, widgetv, widgetnum,
473 hubv, hub_widgetid);
474
475 ia64_sn_sysctl_iobrick_module_get(nasid, &io_module);
476 if (io_module >= 0) {
477 char buffer[16];
478 vertex_hdl_t to, from;
479 char *brick_name;
480 extern char *iobrick_L1bricktype_to_name(int type);
481
482
483 memset(buffer, 0, 16);
484 format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF);
485
486 if ( isupper(MODULE_GET_BTCHAR(io_module)) ) {
487 bt = tolower(MODULE_GET_BTCHAR(io_module));
488 }
489 else {
490 bt = MODULE_GET_BTCHAR(io_module);
491 }
492
493 brick_name = iobrick_L1bricktype_to_name(bt);
494
495 /* Add a helper vertex so xbow monitoring
496 * can identify the brick type. It's simply
497 * an edge from the widget 0 vertex to the
498 * brick vertex.
499 */
500
501 sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/"
502 EDGE_LBL_SLAB "/%d/"
503 EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/"
504 "0",
505 buffer, geo_slab(board->brd_geoid));
506 DBG("io_xswitch_widget_init: FROM path '%s'\n", pathname);
507
508 from = hwgraph_path_to_vertex(pathname);
509 ASSERT_ALWAYS(from);
510
511 sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/"
512 EDGE_LBL_SLAB "/%d/"
513 "%s",
514 buffer, geo_slab(board->brd_geoid), brick_name);
515 DBG("io_xswitch_widget_init: TO path '%s'\n", pathname);
516 to = hwgraph_path_to_vertex(pathname);
517 ASSERT_ALWAYS(to);
518 rc = hwgraph_edge_add(from, to,
519 EDGE_LBL_INTERCONNECT);
520 if (rc == -EEXIST)
521 goto link_done;
522 if (rc != GRAPH_SUCCESS) {
523 printk("%s: Unable to establish link"
524 " for xbmon.", pathname);
525 }
526 link_done:
527 }
528
529 #ifdef SN0_USE_BTE
530 bte_bpush_war(cnode, (void *)board);
531 #endif
532 }
533 }
534
535
536 static void
io_init_xswitch_widgets(vertex_hdl_t xswitchv,cnodeid_t cnode)537 io_init_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnode)
538 {
539 xwidgetnum_t widgetnum;
540
541 DBG("io_init_xswitch_widgets: xswitchv 0x%p for cnode %d\n", xswitchv, cnode);
542
543 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
544 io_xswitch_widget_init(xswitchv, cnodeid_to_vertex(cnode), widgetnum);
545 }
546 }
547
548 /*
549 * For each PCI bridge connected to the xswitch, add a link from the
550 * board's klconfig info to the bridge's hwgraph vertex. This lets
551 * the FRU analyzer find the bridge without traversing the hardware
552 * graph and risking hangs.
553 */
554 static void
io_link_xswitch_widgets(vertex_hdl_t xswitchv,cnodeid_t cnodeid)555 io_link_xswitch_widgets(vertex_hdl_t xswitchv, cnodeid_t cnodeid)
556 {
557 xwidgetnum_t widgetnum;
558 char pathname[128];
559 vertex_hdl_t vhdl;
560 nasid_t nasid, peer_nasid;
561 lboard_t *board;
562
563
564
565 /* And its connected hub's nasids */
566 nasid = COMPACT_TO_NASID_NODEID(cnodeid);
567 peer_nasid = NODEPDA(cnodeid)->xbow_peer;
568
569 /*
570 * Look for paths matching "<widgetnum>/pci" under xswitchv.
571 * For every widget, init. its lboard's hwgraph link. If the
572 * board has a PCI bridge, point the link to it.
573 */
574 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX;
575 widgetnum++) {
576 sprintf(pathname, "%d", widgetnum);
577 if (hwgraph_traverse(xswitchv, pathname, &vhdl) !=
578 GRAPH_SUCCESS)
579 continue;
580
581 board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid),
582 NODEPDA(cnodeid)->geoid);
583 if (board == NULL && peer_nasid != INVALID_NASID) {
584 /*
585 * Try to find the board on our peer
586 */
587 board = find_lboard_module(
588 (lboard_t *)KL_CONFIG_INFO(peer_nasid),
589 NODEPDA(cnodeid)->geoid);
590 }
591 if (board == NULL) {
592 printk(KERN_WARNING "Could not find PROM info for vertex 0x%p, "
593 "FRU analyzer may fail",
594 (void *)vhdl);
595 return;
596 }
597
598 /* Check both buses */
599 sprintf(pathname, "%d/"EDGE_LBL_PCIX_0, widgetnum);
600 if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
601 board->brd_graph_link = vhdl;
602 else {
603 sprintf(pathname, "%d/"EDGE_LBL_PCIX_1, widgetnum);
604 if (hwgraph_traverse(xswitchv, pathname, &vhdl) == GRAPH_SUCCESS)
605 board->brd_graph_link = vhdl;
606 else
607 board->brd_graph_link = GRAPH_VERTEX_NONE;
608 }
609 }
610 }
611
612 /*
613 * Initialize all I/O on the specified node.
614 */
615 static void
io_init_node(cnodeid_t cnodeid)616 io_init_node(cnodeid_t cnodeid)
617 {
618 /*REFERENCED*/
619 vertex_hdl_t hubv, switchv, widgetv;
620 struct xwidget_hwid_s hwid;
621 hubinfo_t hubinfo;
622 int is_xswitch;
623 nodepda_t *npdap;
624 struct semaphore *peer_sema = 0;
625 uint32_t widget_partnum;
626 cpuid_t c = 0;
627
628 npdap = NODEPDA(cnodeid);
629
630 /*
631 * Get the "top" vertex for this node's hardware
632 * graph; it will carry the per-hub hub-specific
633 * data, and act as the crosstalk provider master.
634 * It's canonical path is probably something of the
635 * form /hw/module/%M/slot/%d/node
636 */
637 hubv = cnodeid_to_vertex(cnodeid);
638 DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap);
639
640 ASSERT(hubv != GRAPH_VERTEX_NONE);
641
642 /*
643 * Read mfg info on this hub
644 */
645
646 /*
647 * If nothing connected to this hub's xtalk port, we're done.
648 */
649 early_probe_for_widget(hubv, &hwid);
650 if (hwid.part_num == XWIDGET_PART_NUM_NONE) {
651 #ifdef PROBE_TEST
652 if ((cnodeid == 1) || (cnodeid == 2)) {
653 int index;
654
655 for (index = 0; index < 600; index++)
656 DBG("Interfering with device probing!!!\n");
657 }
658 #endif
659 /* io_init_done takes cpu cookie as 2nd argument
660 * to do a restorenoderun for the setnoderun done
661 * at the start of this thread
662 */
663
664 DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv);
665 return;
666 /* NOTREACHED */
667 }
668
669 /*
670 * attach our hub_provider information to hubv,
671 * so we can use it as a crosstalk provider "master"
672 * vertex.
673 */
674 xtalk_provider_register(hubv, &hub_provider);
675 xtalk_provider_startup(hubv);
676
677 /*
678 * Create a vertex to represent the crosstalk bus
679 * attached to this hub, and a vertex to be used
680 * as the connect point for whatever is out there
681 * on the other side of our crosstalk connection.
682 *
683 * Crosstalk Switch drivers "climb up" from their
684 * connection point to try and take over the switch
685 * point.
686 *
687 * Of course, the edges and verticies may already
688 * exist, in which case our net effect is just to
689 * associate the "xtalk_" driver with the connection
690 * point for the device.
691 */
692
693 (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv);
694
695 DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv);
696
697 ASSERT(switchv != GRAPH_VERTEX_NONE);
698
699 (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO);
700
701 DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n");
702
703 /*
704 * We need to find the widget id and update the basew_id field
705 * accordingly. In particular, SN00 has direct connected bridge,
706 * and hence widget id is Not 0.
707 */
708
709 widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT;
710
711 if (widget_partnum == BRIDGE_WIDGET_PART_NUM ||
712 widget_partnum == XBRIDGE_WIDGET_PART_NUM){
713 npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
714
715 DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum);
716
717 } else if ((widget_partnum == XBOW_WIDGET_PART_NUM) ||
718 (widget_partnum == XXBOW_WIDGET_PART_NUM) ||
719 (widget_partnum == PXBOW_WIDGET_PART_NUM) ) {
720 /*
721 * Xbow control register does not have the widget ID field.
722 * So, hard code the widget ID to be zero.
723 */
724 DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum);
725 npdap->basew_id = 0;
726
727 } else {
728 npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID);
729
730 panic(" ****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);
731
732 /*NOTREACHED*/
733 }
734 {
735 char widname[10];
736 sprintf(widname, "%x", npdap->basew_id);
737 (void)hwgraph_path_add(switchv, widname, &widgetv);
738 DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv);
739 ASSERT(widgetv != GRAPH_VERTEX_NONE);
740 }
741
742 nodepda->basew_xc = widgetv;
743
744 is_xswitch = xwidget_hwid_is_xswitch(&hwid);
745
746 /*
747 * Try to become the master of the widget. If this is an xswitch
748 * with multiple hubs connected, only one will succeed. Mastership
749 * of an xswitch is used only when touching registers on that xswitch.
750 * The slave xwidgets connected to the xswitch can be owned by various
751 * masters.
752 */
753 if (device_master_set(widgetv, hubv) == 0) {
754
755 /* Only one hub (thread) per Crosstalk device or switch makes
756 * it to here.
757 */
758
759 /*
760 * Initialize whatever xwidget is hanging off our hub.
761 * Whatever it is, it's accessible through widgetnum 0.
762 */
763 hubinfo_get(hubv, &hubinfo);
764
765 (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid);
766
767 if (!is_xswitch) {
768 /* io_init_done takes cpu cookie as 2nd argument
769 * to do a restorenoderun for the setnoderun done
770 * at the start of this thread
771 */
772 io_init_done(cnodeid,c);
773 /* NOTREACHED */
774 }
775
776 /*
777 * Special handling for Crosstalk Switches (e.g. xbow).
778 * We need to do things in roughly the following order:
779 * 1) Initialize xswitch hardware (done above)
780 * 2) Determine which hubs are available to be widget masters
781 * 3) Discover which links are active from the xswitch
782 * 4) Assign xwidgets hanging off the xswitch to hubs
783 * 5) Initialize all xwidgets on the xswitch
784 */
785
786 DBG("call volunteer_for_widgets\n");
787
788 volunteer_for_widgets(switchv, hubv);
789
790 /* If there's someone else on this crossbow, recognize him */
791 if (npdap->xbow_peer != INVALID_NASID) {
792 nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer));
793 peer_sema = &peer_npdap->xbow_sema;
794 DBG("call volunteer_for_widgets again\n");
795 volunteer_for_widgets(switchv, peer_npdap->node_vertex);
796 }
797
798 assign_widgets_to_volunteers(switchv, hubv);
799
800 /* Signal that we're done */
801 if (peer_sema) {
802 up(peer_sema);
803 }
804
805 }
806 else {
807 /* Wait 'til master is done assigning widgets. */
808 down(&npdap->xbow_sema);
809 }
810
811 #ifdef PROBE_TEST
812 if ((cnodeid == 1) || (cnodeid == 2)) {
813 int index;
814
815 for (index = 0; index < 500; index++)
816 DBG("Interfering with device probing!!!\n");
817 }
818 #endif
819 /* Now both nodes can safely inititialize widgets */
820 io_init_xswitch_widgets(switchv, cnodeid);
821 io_link_xswitch_widgets(switchv, cnodeid);
822
823 /* io_init_done takes cpu cookie as 2nd argument
824 * to do a restorenoderun for the setnoderun done
825 * at the start of this thread
826 */
827 io_init_done(cnodeid,c);
828
829 DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid);
830 }
831
832
833 #define IOINIT_STKSZ (16 * 1024)
834
835 #define __DEVSTR1 "/../.master/"
836 #define __DEVSTR2 "/target/"
837 #define __DEVSTR3 "/lun/0/disk/partition/"
838 #define __DEVSTR4 "/../ef"
839
840 /*
841 * ioconfig starts numbering SCSI's at NUM_BASE_IO_SCSI_CTLR.
842 */
843 #define NUM_BASE_IO_SCSI_CTLR 6
844 /*
845 * This tells ioconfig where it can start numbering scsi controllers.
846 * Below this base number, platform-specific handles the numbering.
847 * XXX Irix legacy..controller numbering should be part of devfsd's job
848 */
849 int num_base_io_scsi_ctlr = 2; /* used by syssgi */
850 vertex_hdl_t base_io_scsi_ctlr_vhdl[NUM_BASE_IO_SCSI_CTLR];
851
852 #include <asm/sn/ioerror_handling.h>
853 /* #endif */
854
855 /*
856 * Initialize all I/O devices. Starting closest to nodes, probe and
857 * initialize outward.
858 */
859 void
init_all_devices(void)860 init_all_devices(void)
861 {
862 /* Governor on init threads..bump up when safe
863 * (beware many devfs races)
864 */
865 cnodeid_t cnodeid, active;
866
867 active = 0;
868 for (cnodeid = 0; cnodeid < numnodes; cnodeid++) {
869 DBG("init_all_devices: Calling io_init_node() for cnode %d\n", cnodeid);
870 io_init_node(cnodeid);
871
872 DBG("init_all_devices: Done io_init_node() for cnode %d\n", cnodeid);
873 }
874
875 for (cnodeid = 0; cnodeid < numnodes; cnodeid++)
876 /*
877 * Update information generated by IO init.
878 */
879 update_node_information(cnodeid);
880
881 #if HWG_PRINT
882 hwgraph_print();
883 #endif
884
885 }
886
887 #define toint(x) ((int)(x) - (int)('0'))
888
889 void
devnamefromarcs(char * devnm)890 devnamefromarcs(char *devnm)
891 {
892 int val;
893 char tmpnm[MAXDEVNAME];
894 char *tmp1, *tmp2;
895
896 val = strncmp(devnm, "dks", 3);
897 if (val != 0)
898 return;
899 tmp1 = devnm + 3;
900 if (!isdigit(*tmp1))
901 return;
902
903 val = 0;
904 while (isdigit(*tmp1)) {
905 val = 10*val+toint(*tmp1);
906 tmp1++;
907 }
908
909 if(*tmp1 != 'd')
910 return;
911 else
912 tmp1++;
913
914 if ((val < 0) || (val >= num_base_io_scsi_ctlr)) {
915 int i;
916 int viable_found = 0;
917
918 DBG("Only controller numbers 0..%d are supported for\n", NUM_BASE_IO_SCSI_CTLR-1);
919 DBG("prom \"root\" variables of the form dksXdXsX.\n");
920 DBG("To use another disk you must use the full hardware graph path\n\n");
921 DBG("Possible controller numbers for use in 'dksXdXsX' on this system: ");
922 for (i=0; i<NUM_BASE_IO_SCSI_CTLR; i++) {
923 if (base_io_scsi_ctlr_vhdl[i] != GRAPH_VERTEX_NONE) {
924 DBG("%d ", i);
925 viable_found=1;
926 }
927 }
928 if (viable_found)
929 DBG("\n");
930 else
931 DBG("none found!\n");
932
933 udelay(15000000);
934 //prom_reboot();
935 panic("FIXME: devnamefromarcs: should call prom_reboot here.\n");
936 /* NOTREACHED */
937 }
938
939 ASSERT(base_io_scsi_ctlr_vhdl[val] != GRAPH_VERTEX_NONE);
940 vertex_to_name(base_io_scsi_ctlr_vhdl[val],
941 tmpnm,
942 MAXDEVNAME);
943 tmp2 = tmpnm + strlen(tmpnm);
944 strcpy(tmp2, __DEVSTR2);
945 tmp2 += strlen(__DEVSTR2);
946 while (*tmp1 != 's') {
947 if((*tmp2++ = *tmp1++) == '\0')
948 return;
949 }
950 tmp1++;
951 strcpy(tmp2, __DEVSTR3);
952 tmp2 += strlen(__DEVSTR3);
953 while ( (*tmp2++ = *tmp1++) )
954 ;
955 tmp2--;
956 *tmp2++ = '/';
957 strcpy(tmp2, EDGE_LBL_BLOCK);
958 strcpy(devnm,tmpnm);
959 }
960
961 static
962 struct io_brick_map_s io_brick_tab[] = {
963
964 /* Ibrick widget number to PCI bus number map */
965 { MODULE_IBRICK, /* Ibrick type */
966 /* PCI Bus # Widget # */
967 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
968 0, /* 0x8 */
969 0, /* 0x9 */
970 0, 0, /* 0xa - 0xb */
971 0, /* 0xc */
972 0, /* 0xd */
973 2, /* 0xe */
974 1 /* 0xf */
975 }
976 },
977
978 /* Pbrick widget number to PCI bus number map */
979 { MODULE_PBRICK, /* Pbrick type */
980 /* PCI Bus # Widget # */
981 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
982 2, /* 0x8 */
983 1, /* 0x9 */
984 0, 0, /* 0xa - 0xb */
985 5, /* 0xc */
986 6, /* 0xd */
987 4, /* 0xe */
988 3 /* 0xf */
989 }
990 },
991
992 /* PXbrick widget number to PCI bus number map */
993 { MODULE_PXBRICK, /* PXbrick type */
994 /* PCI Bus # Widget # */
995 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
996 0, /* 0x8 */
997 0, /* 0x9 */
998 0, 0, /* 0xa - 0xb */
999 1, /* 0xc */
1000 5, /* 0xd */
1001 0, /* 0xe */
1002 3 /* 0xf */
1003 }
1004 },
1005
1006 /* OPUSbrick widget number to PCI bus number map */
1007 { MODULE_OPUSBRICK, /* OPUSbrick type */
1008 /* PCI Bus # Widget # */
1009 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1010 0, /* 0x8 */
1011 0, /* 0x9 */
1012 0, 0, /* 0xa - 0xb */
1013 0, /* 0xc */
1014 0, /* 0xd */
1015 0, /* 0xe */
1016 1 /* 0xf */
1017 }
1018 },
1019
1020 /* IXbrick widget number to PCI bus number map */
1021 { MODULE_IXBRICK, /* IXbrick type */
1022 /* PCI Bus # Widget # */
1023 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1024 0, /* 0x8 */
1025 0, /* 0x9 */
1026 0, 0, /* 0xa - 0xb */
1027 1, /* 0xc */
1028 5, /* 0xd */
1029 0, /* 0xe */
1030 3 /* 0xf */
1031 }
1032 },
1033
1034 /* Xbrick widget to XIO slot map */
1035 { MODULE_XBRICK, /* Xbrick type */
1036 /* XIO Slot # Widget # */
1037 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1038 1, /* 0x8 */
1039 3, /* 0x9 */
1040 0, 0, /* 0xa - 0xb */
1041 2, /* 0xc */
1042 4, /* 0xd */
1043 0, /* 0xe */
1044 0 /* 0xf */
1045 }
1046 },
1047 /* CG brick widget number to PCI bus number map */
1048 { MODULE_CGBRICK, /* CG brick */
1049 /* PCI Bus # Widget # */
1050 { 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0 - 0x7 */
1051 0, /* 0x8 */
1052 0, /* 0x9 */
1053 0, 1, /* 0xa - 0xb */
1054 0, /* 0xc */
1055 0, /* 0xd */
1056 0, /* 0xe */
1057 0 /* 0xf */
1058 }
1059 }
1060 };
1061
1062 /*
1063 * Use the brick's type to map a widget number to a meaningful int
1064 */
1065 int
io_brick_map_widget(int brick_type,int widget_num)1066 io_brick_map_widget(int brick_type, int widget_num)
1067 {
1068 int num_bricks, i;
1069
1070 /* Calculate number of bricks in table */
1071 num_bricks = sizeof(io_brick_tab)/sizeof(io_brick_tab[0]);
1072
1073 /* Look for brick prefix in table */
1074 for (i = 0; i < num_bricks; i++) {
1075 if (brick_type == io_brick_tab[i].ibm_type)
1076 return(io_brick_tab[i].ibm_map_wid[widget_num]);
1077 }
1078
1079 return 0;
1080
1081 }
1082