3 * This file is subject to the terms and conditions of the GNU General Public
4 * License. See the file "COPYING" in the main directory of this archive
7 * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
11 #include <linux/types.h>
12 #include <linux/config.h>
13 #include <linux/ctype.h>
14 #include <asm/sn/sgi.h>
15 #include <asm/sn/sn_sal.h>
16 #include <asm/sn/io.h>
17 #include <asm/sn/sn_cpuid.h>
18 #include <asm/sn/iograph.h>
19 #include <asm/sn/invent.h>
20 #include <asm/sn/hcl.h>
21 #include <asm/sn/labelcl.h>
22 #include <asm/sn/klconfig.h>
23 #include <asm/sn/nodepda.h>
24 #include <asm/sn/module.h>
25 #include <asm/sn/router.h>
26 #include <asm/sn/xtalk/xbow.h>
32 #define NIC_UNKNOWN ((nic_t) -1)
36 #define DBG(x...) printk(x)
39 #endif /* DEBUG_KLGRAPH */
41 static void sort_nic_names(lboard_t *) ;
43 u64 klgraph_addr[MAX_COMPACT_NODES];
46 find_lboard(lboard_t *start, unsigned char brd_type)
48 /* Search all boards stored on this node. */
50 if (start->brd_type == brd_type)
52 start = KLCF_NEXT(start);
56 return (lboard_t *)NULL;
60 find_lboard_class(lboard_t *start, unsigned char brd_type)
62 /* Search all boards stored on this node. */
64 if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
66 start = KLCF_NEXT(start);
70 return (lboard_t *)NULL;
74 find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
78 if (kli == (klinfo_t *)NULL) {
81 for (j = 0; j < KLCF_NUM_COMPS(brd); j++) {
82 if (kli == KLCF_COMP(brd, j))
86 if (index == KLCF_NUM_COMPS(brd)) {
87 DBG("find_component: Bad pointer: 0x%p\n", kli);
88 return (klinfo_t *)NULL;
90 index++; /* next component */
93 for (; index < KLCF_NUM_COMPS(brd); index++) {
94 kli = KLCF_COMP(brd, index);
95 DBG("find_component: brd %p kli %p request type = 0x%x kli type 0x%x\n", brd, kli, kli->struct_type, KLCF_COMP_TYPE(kli));
96 if (KLCF_COMP_TYPE(kli) == struct_type)
100 /* Didn't find it. */
101 return (klinfo_t *)NULL;
105 find_first_component(lboard_t *brd, unsigned char struct_type)
107 return find_component(brd, (klinfo_t *)NULL, struct_type);
111 find_lboard_modslot(lboard_t *start, moduleid_t mod, slotid_t slot)
113 /* Search all boards stored on this node. */
115 if (MODULE_MATCH(start->brd_module, mod) &&
116 (start->brd_slot == slot))
118 start = KLCF_NEXT(start);
121 /* Didn't find it. */
122 return (lboard_t *)NULL;
126 find_lboard_module(lboard_t *start, moduleid_t mod)
128 /* Search all boards stored on this node. */
130 if (MODULE_MATCH(start->brd_module, mod))
132 start = KLCF_NEXT(start);
135 /* Didn't find it. */
136 return (lboard_t *)NULL;
140 find_lboard_module_class(lboard_t *start, moduleid_t mod,
141 unsigned char brd_type)
145 DBG("find_lboard_module_class: lboard 0x%p, start->brd_module 0x%x, mod 0x%x, start->brd_type 0x%x, brd_type 0x%x\n", start, start->brd_module, mod, start->brd_type, brd_type);
147 if (MODULE_MATCH(start->brd_module, mod) &&
148 (KLCLASS(start->brd_type) == KLCLASS(brd_type)))
150 start = KLCF_NEXT(start);
153 /* Didn't find it. */
154 return (lboard_t *)NULL;
159 * Convert a NIC name to a name for use in the hardware graph.
162 nic_name_convert(char *old_name, char *new_name)
168 if ((old_name[0] == '\0') || (old_name[1] == '\0')) {
169 strcpy(new_name, EDGE_LBL_XWIDGET);
171 for (i = 0; i < strlen(old_name); i++) {
175 new_name[i] = tolower(c);
185 * Since a bunch of boards made it out with weird names like
186 * IO6-fibbbed and IO6P2, we need to look for IO6 in a name and
187 * replace it with "baseio" to avoid confusion in the field.
188 * We also have to make sure we don't report media_io instead of
192 /* Skip underscores at the beginning of the name */
193 for (compare_ptr = new_name; (*compare_ptr) == '_'; compare_ptr++)
197 * Check for some names we need to replace. Early boards
198 * had junk following the name so check only the first
201 if (!strncmp(new_name, "io6", 3) ||
202 !strncmp(new_name, "mio", 3) ||
203 !strncmp(new_name, "media_io", 8))
204 strcpy(new_name, "baseio");
205 else if (!strncmp(new_name, "divo", 4))
206 strcpy(new_name, "divo") ;
210 /* Check if the given board corresponds to the global
214 is_master_baseio(nasid_t nasid,moduleid_t module,slotid_t slot)
218 #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
219 /* If this works then look for callers of is_master_baseio()
220 * (e.g. iograph.c) and let them pass in a slot if they want
222 board = find_lboard_module((lboard_t *)KL_CONFIG_INFO(nasid), module);
224 board = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid), module, slot);
229 cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
231 if (!board && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
232 #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
233 board = find_lboard_module((lboard_t *)
234 KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
237 board = find_lboard_modslot((lboard_t *)
238 KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
245 return(board->brd_flags & GLOBAL_MASTER_IO6);
248 * Find the lboard structure and get the board name.
249 * If we can't find the structure or it's too low a revision,
253 get_board_name(nasid_t nasid, moduleid_t mod, slotid_t slot, char *name)
257 brd = find_lboard_modslot((lboard_t *)KL_CONFIG_INFO(nasid),
262 cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid);
264 if (!brd && (NODEPDA(cnode)->xbow_peer != INVALID_NASID))
265 brd = find_lboard_modslot((lboard_t *)
266 KL_CONFIG_INFO(NODEPDA(cnode)->xbow_peer),
271 if (!brd || (brd->brd_sversion < 2)) {
272 strcpy(name, EDGE_LBL_XWIDGET);
274 nic_name_convert(brd->brd_name, name);
279 * If the name is not 'baseio'
280 * get the lowest of all the names in the nic string.
281 * This is needed for boards like divo, which can have
282 * a bunch of daughter cards, but would like to be called
283 * divo. We could do this for baseio
284 * but it has some special case names that we would not
285 * like to disturb at this point.
288 /* gfx boards don't need any of this name scrambling */
289 if (brd && (KLCLASS(brd->brd_type) == KLCLASS_GFX)) {
293 if (!(!strcmp(name, "baseio") )) {
295 sort_nic_names(brd) ;
296 /* Convert to small case, '-' to '_' etc */
297 nic_name_convert(brd->brd_name, name) ;
307 * Completely disabled brds have their klconfig on
308 * some other nasid as they have no memory. But their
309 * actual nasid is hidden in the klconfig. Use this
310 * routine to get it. Works for normal boards too.
313 get_actual_nasid(lboard_t *brd)
318 return INVALID_NASID ;
320 /* find out if we are a completely disabled brd. */
322 hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
324 return INVALID_NASID ;
325 if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */
326 return hub->hub_info.physid ;
328 return brd->brd_nasid ;
332 xbow_port_io_enabled(nasid_t nasid, int link)
338 * look for boards that might contain an xbow or xbridge
340 brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW);
341 if (brd == NULL) return 0;
343 if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
347 if (!XBOW_PORT_TYPE_IO(xbow_p, link) || !XBOW_PORT_IS_ENABLED(xbow_p, link))
350 DBG("xbow_port_io_enabled: brd 0x%p xbow_p 0x%p \n", brd, xbow_p);
356 board_to_path(lboard_t *brd, char *path)
363 switch (KLCLASS(brd->brd_type)) {
366 board_name = EDGE_LBL_NODE;
369 if (brd->brd_type == KLTYPE_META_ROUTER) {
370 board_name = EDGE_LBL_META_ROUTER;
372 } else if (brd->brd_type == KLTYPE_REPEATER_ROUTER) {
373 board_name = EDGE_LBL_REPEATER_ROUTER;
376 board_name = EDGE_LBL_ROUTER;
378 case KLCLASS_MIDPLANE:
379 board_name = EDGE_LBL_MIDPLANE;
382 board_name = EDGE_LBL_IO;
384 case KLCLASS_IOBRICK:
385 if (brd->brd_type == KLTYPE_PBRICK)
386 board_name = EDGE_LBL_PBRICK;
387 else if (brd->brd_type == KLTYPE_IBRICK)
388 board_name = EDGE_LBL_IBRICK;
389 else if (brd->brd_type == KLTYPE_XBRICK)
390 board_name = EDGE_LBL_XBRICK;
392 board_name = EDGE_LBL_IOBRICK;
395 board_name = EDGE_LBL_UNKNOWN;
398 modnum = brd->brd_module;
400 ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE);
404 memset(buffer, 0, 16);
405 format_module_id(buffer, modnum, MODULE_FORMAT_BRIEF);
406 sprintf(path, EDGE_LBL_MODULE "/%s/%s", buffer, board_name);
409 sprintf(path, "%H/%s", modnum, board_name);
414 * Get the module number for a NASID.
417 get_module_id(nasid_t nasid)
421 brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
424 return INVALID_MODULE;
426 return brd->brd_module;
433 /* Get the canonical hardware graph name for the given pci component
434 * on the given io board.
437 device_component_canonical_name_get(lboard_t *brd,
447 /* Get the module number of this board */
448 modnum = brd->brd_module;
450 /* Convert the [ CLASS | TYPE ] kind of slotid
453 slot = brd->brd_slot;
454 ASSERT(modnum != MODULE_UNKNOWN && modnum != INVALID_MODULE);
456 /* Get the io board name */
457 if (!brd || (brd->brd_sversion < 2)) {
458 strcpy(name, EDGE_LBL_XWIDGET);
460 nic_name_convert(brd->brd_name, board_name);
463 /* Give out the canonical name of the pci device*/
465 "/dev/hw/"EDGE_LBL_MODULE "/%x/"EDGE_LBL_SLOT"/%s/"
467 modnum, board_name,KLCF_BRIDGE_W_ID(component));
471 * Get the serial number of the main component of a board
472 * Returns 0 if a valid serial number is found
474 * Assumptions: Nic manufacturing string has the following format
475 * *Serial:<serial_number>;*
478 component_serial_number_get(lboard_t *board,
479 klconf_off_t mfg_nic_offset,
484 char *mfg_nic_string;
485 char *serial_string,*str;
487 char *serial_pattern = "Serial:";
489 /* We have an error on a null mfg nic offset */
492 /* Get the hub's manufacturing nic information
493 * which is in the form of a pre-formatted string
496 (char *)NODE_OFFSET_TO_K0(NASID_GET(board),
498 /* There is no manufacturing nic info */
502 str = mfg_nic_string;
503 /* Look for the key pattern first (if it is specified)
504 * and then print the serial number corresponding to that.
506 if (strcmp(key_pattern,"") &&
507 !(str = strstr(mfg_nic_string,key_pattern)))
510 /* There is no serial number info in the manufacturing
513 if (!(serial_string = strstr(str,serial_pattern)))
516 serial_string = serial_string + strlen(serial_pattern);
517 /* Copy the serial number information from the klconfig */
519 while (serial_string[i] != ';') {
520 serial_number[i] = serial_string[i];
523 serial_number[i] = 0;
528 * Get the serial number of a board
529 * Returns 0 if a valid serial number is found
534 board_serial_number_get(lboard_t *board,char *serial_number)
536 ASSERT(board && serial_number);
537 if (!board || !serial_number)
540 strcpy(serial_number,"");
541 switch(KLCLASS(board->brd_type)) {
542 case KLCLASS_CPU: { /* Node board */
545 /* Get the hub component information */
546 hub = (klhub_t *)find_first_component(board,
548 /* If we don't have a hub component on an IP27
549 * then we have a weird klconfig.
553 /* Get the serial number information from
554 * the hub's manufacturing nic info
556 if (component_serial_number_get(board,
559 #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
563 /* Try with IP31 key if IP27 key fails */
564 if (component_serial_number_get(board,
568 #endif /* CONFIG_IA64_SGI_SN1 */
572 case KLCLASS_IO: { /* IO board */
573 if (KLTYPE(board->brd_type) == KLTYPE_TPU) {
574 /* Special case for TPU boards */
577 /* Get the tpu component information */
578 tpu = (kltpu_t *)find_first_component(board,
580 /* If we don't have a tpu component on a tpu board
581 * then we have a weird klconfig.
585 /* Get the serial number information from
586 * the tpu's manufacturing nic info
588 if (component_serial_number_get(board,
594 } else if ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ||
595 (KLTYPE(board->brd_type) == KLTYPE_GSN_B)) {
596 /* Special case for GSN boards */
599 /* Get the gsn component information */
600 gsn = (klgsn_t *)find_first_component(board,
601 ((KLTYPE(board->brd_type) == KLTYPE_GSN_A) ?
602 KLSTRUCT_GSN_A : KLSTRUCT_GSN_B));
603 /* If we don't have a gsn component on a gsn board
604 * then we have a weird klconfig.
608 /* Get the serial number information from
609 * the gsn's manufacturing nic info
611 if (component_serial_number_get(board,
620 /* Get the bridge component information */
621 bridge = (klbri_t *)find_first_component(board,
623 /* If we don't have a bridge component on an IO board
624 * then we have a weird klconfig.
628 /* Get the serial number information from
629 * the bridge's manufacturing nic info
631 if (component_serial_number_get(board,
639 case KLCLASS_ROUTER: { /* Router board */
642 /* Get the router component information */
643 router = (klrou_t *)find_first_component(board,
645 /* If we don't have a router component on a router board
646 * then we have a weird klconfig.
650 /* Get the serial number information from
651 * the router's manufacturing nic info
653 if (component_serial_number_get(board,
660 case KLCLASS_GFX: { /* Gfx board */
663 /* Get the graphics component information */
664 graphics = (klgfx_t *)find_first_component(board, KLSTRUCT_GFX);
665 /* If we don't have a gfx component on a gfx board
666 * then we have a weird klconfig.
670 /* Get the serial number information from
671 * the graphics's manufacturing nic info
673 if (component_serial_number_get(board,
674 graphics->gfx_mfg_nic,
681 strcpy(serial_number,"");
687 #include "asm/sn/sn_private.h"
690 nodevertex_widgetnum_get(devfs_handle_t node_vtx)
694 hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO,
695 (arbitrary_info_t *) &hubinfo_p);
696 return(hubinfo_p->h_widgetid);
700 nodevertex_xbow_peer_get(devfs_handle_t node_vtx)
703 nasid_t xbow_peer_nasid;
706 hwgraph_info_get_LBL(node_vtx, INFO_LBL_NODE_INFO,
707 (arbitrary_info_t *) &hubinfo_p);
708 xbow_peer_nasid = hubinfo_p->h_nodepda->xbow_peer;
709 if(xbow_peer_nasid == INVALID_NASID)
710 return ( (devfs_handle_t)-1);
711 xbow_peer = NASID_TO_COMPACT_NODEID(xbow_peer_nasid);
712 return(NODEPDA(xbow_peer)->node_vertex);
715 /* NIC Sorting Support */
717 #define MAX_NICS_PER_STRING 32
718 #define MAX_NIC_NAME_LEN 32
721 get_nic_string(lboard_t *lb)
725 klconf_off_t mfg_off = 0 ;
726 char *mfg_nic = NULL ;
728 for (i = 0; i < KLCF_NUM_COMPS(lb); i++) {
729 k = KLCF_COMP(lb, i) ;
730 switch(k->struct_type) {
732 mfg_off = ((klbri_t *)k)->bri_mfg_nic ;
736 mfg_off = ((klhub_t *)k)->hub_mfg_nic ;
740 mfg_off = ((klrou_t *)k)->rou_mfg_nic ;
744 mfg_off = ((klgfx_t *)k)->gfx_mfg_nic ;
748 mfg_off = ((kltpu_t *)k)->tpu_mfg_nic ;
753 mfg_off = ((klgsn_t *)k)->gsn_mfg_nic ;
757 mfg_off = ((klxthd_t *)k)->xthd_mfg_nic ;
768 if ((mfg_off) && (k))
769 mfg_nic = (char *)NODE_OFFSET_TO_K0(k->nasid, mfg_off) ;
775 get_first_string(char **ptrs, int n)
780 if ((ptrs == NULL) || (n == 0))
788 for (i = 0 ; i < n ; i++) {
789 if (strcmp(tmpptr, ptrs[i]) > 0)
797 get_ptrs(char *idata, char **ptrs, int n, char *label)
802 if ((ptrs == NULL) || (idata == NULL) || (label == NULL) || (n == 0))
805 while ( (tmp = strstr(tmp, label)) ){
806 tmp += strlen(label) ;
807 /* check for empty name field, and last NULL ptr */
808 if ((i < (n-1)) && (*tmp != ';')) {
821 * Does not really do sorting. Find the alphabetically lowest
822 * name among all the nic names found in a nic string.
829 * lb->brd_name gets the new name found
833 sort_nic_names(lboard_t *lb)
836 char *ptrs[MAX_NICS_PER_STRING] ;
837 char name[MAX_NIC_NAME_LEN] ;
842 /* Get the nic pointer from the lb */
844 if ((nic_str = get_nic_string(lb)) == NULL)
847 tmp = get_first_string(ptrs,
848 get_ptrs(nic_str, ptrs, MAX_NICS_PER_STRING, "Name:")) ;
853 if ( (tmp1 = strchr(tmp, ';')) ){
854 strlcpy(name, tmp, tmp1-tmp) ;
856 strlcpy(name, tmp, (sizeof(name))) ;
859 strlcpy(lb->brd_name, name, sizeof(lb->brd_name)) ;
864 char brick_types[MAX_BRICK_TYPES + 1] = "crikxdp789012345";
866 #if defined(CONFIG_IA64_SGI_SN1) || defined(CONFIG_IA64_GENERIC)
869 * Format a module id for printing.
872 format_module_id(char *buffer, moduleid_t m, int fmt)
877 rack = MODULE_GET_RACK(m);
878 ASSERT(MODULE_GET_BTYPE(m) < MAX_BRICK_TYPES);
879 brickchar = MODULE_GET_BTCHAR(m);
880 position = MODULE_GET_BPOS(m);
882 if (fmt == MODULE_FORMAT_BRIEF) {
883 /* Brief module number format, eg. 002c15 */
885 /* Decompress the rack number */
886 *buffer++ = '0' + RACK_GET_CLASS(rack);
887 *buffer++ = '0' + RACK_GET_GROUP(rack);
888 *buffer++ = '0' + RACK_GET_NUM(rack);
890 /* Add the brick type */
891 *buffer++ = brickchar;
893 else if (fmt == MODULE_FORMAT_LONG) {
894 /* Fuller hwgraph format, eg. rack/002/bay/15 */
896 strcpy(buffer, EDGE_LBL_RACK "/"); buffer += strlen(buffer);
898 *buffer++ = '0' + RACK_GET_CLASS(rack);
899 *buffer++ = '0' + RACK_GET_GROUP(rack);
900 *buffer++ = '0' + RACK_GET_NUM(rack);
902 strcpy(buffer, "/" EDGE_LBL_RPOS "/"); buffer += strlen(buffer);
905 /* Add the bay position, using at least two digits */
908 sprintf(buffer, "%d", position);
913 * Parse a module id, in either brief or long form.
914 * Returns < 0 on error.
915 * The long form does not include a brick type, so it defaults to 0 (CBrick)
918 parse_module_id(char *buffer)
920 unsigned int v, rack, bay, type, form;
924 if (strstr(buffer, EDGE_LBL_RACK "/") == buffer) {
925 form = MODULE_FORMAT_LONG;
926 buffer += strlen(EDGE_LBL_RACK "/");
928 /* A long module ID must be exactly 5 non-template chars. */
929 if (strlen(buffer) != strlen("/" EDGE_LBL_RPOS "/") + 5)
933 form = MODULE_FORMAT_BRIEF;
935 /* A brief module id must be exactly 6 characters */
936 if (strlen(buffer) != 6)
940 /* The rack number must be exactly 3 digits */
941 if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && isdigit(buffer[2])))
946 if (v > RACK_CLASS_MASK(rack) >> RACK_CLASS_SHFT(rack))
948 RACK_ADD_CLASS(rack, v);
951 if (v > RACK_GROUP_MASK(rack) >> RACK_GROUP_SHFT(rack))
953 RACK_ADD_GROUP(rack, v);
956 /* rack numbers are 1-based */
957 if (v-1 > RACK_NUM_MASK(rack) >> RACK_NUM_SHFT(rack))
959 RACK_ADD_NUM(rack, v);
961 if (form == MODULE_FORMAT_BRIEF) {
962 /* Next should be a module type character. Accept ucase or lcase. */
967 /* strchr() returns a pointer into brick_types[], or NULL */
968 type = (unsigned int)(strchr(brick_types, tolower(c)) - brick_types);
969 if (type > MODULE_BTYPE_MASK >> MODULE_BTYPE_SHFT)
973 /* Hardcode the module type, and skip over the boilerplate */
974 type = MODULE_CBRICK;
976 if (strstr(buffer, "/" EDGE_LBL_RPOS "/") != buffer)
979 buffer += strlen("/" EDGE_LBL_RPOS "/");
982 /* The bay number is last. Make sure it's exactly two digits */
984 if (!(isdigit(buffer[0]) && isdigit(buffer[1]) && !buffer[2]))
987 bay = 10 * (buffer[0] - '0') + (buffer[1] - '0');
989 if (bay > MODULE_BPOS_MASK >> MODULE_BPOS_SHFT)
992 m = RBT_TO_MODULE(rack, bay, type);
994 /* avoid sign extending the moduleid_t */
995 return (int)(unsigned short)m;
998 #else /* CONFIG_IA64_SGI_SN1 */
1001 * Format a module id for printing.
1004 format_module_id(char *buffer, moduleid_t m, int fmt)
1006 if (fmt == MODULE_FORMAT_BRIEF) {
1007 sprintf(buffer, "%d", m);
1009 else if (fmt == MODULE_FORMAT_LONG) {
1010 sprintf(buffer, EDGE_LBL_MODULE "/%d", m);
1015 * Parse a module id, in either brief or long form.
1016 * Returns < 0 on error.
1019 parse_module_id(char *buffer)
1024 if (strstr(buffer, EDGE_LBL_MODULE "/") == buffer)
1025 buffer += strlen(EDGE_LBL_MODULE "/");
1027 for (m = 0; *buffer; buffer++) {
1031 m = 10 * m + (c - '0');
1034 /* avoid sign extending the moduleid_t */
1035 return (int)(unsigned short)m;
1038 #endif /* CONFIG_IA64_SGI_SN1 */