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