/* * XXX - This won't work as written if we ever have more than two nodes * on a crossbow. In that case, we'll need an array or partners. */ int hub_check_pci_equiv(void *addra, void *addrb) { nasid_t nasida, nasidb; /* * This is for a permanent workaround that causes us to use a * big window in place of small window 0. */ if (!hub_check_window_equiv(addra, addrb)) return 0; /* If the offsets aren't the same, forget it. */ if (SWIN_WIDGETADDR((__psunsigned_t)addra) != (SWIN_WIDGETADDR((__psunsigned_t)addrb))) return 0; /* Now, check the nasids */ nasida = NASID_GET(addra); nasidb = NASID_GET(addrb); ASSERT(NASID_TO_COMPACT_NODEID(nasida) != INVALID_NASID); ASSERT(NASID_TO_COMPACT_NODEID(nasidb) != INVALID_NASID); /* * Either the NASIDs must be the same or they must be crossbow * partners (on the same crossbow). */ return (check_nasid_equiv(nasida, nasidb)); }
int request_bridge_irq(struct bridge_controller *bc, int pin) { struct hub_irq_data *hd; struct hub_data *hub; struct irq_desc *desc; int swlevel; int irq; hd = kzalloc(sizeof(*hd), GFP_KERNEL); if (!hd) return -ENOMEM; swlevel = alloc_level(); if (unlikely(swlevel < 0)) { kfree(hd); return -EAGAIN; } irq = swlevel + IP27_HUB_IRQ_BASE; hd->bc = bc; hd->bit = swlevel; hd->pin = pin; irq_set_chip_data(irq, hd); /* use CPU connected to nearest hub */ hub = hub_data(NASID_TO_COMPACT_NODEID(bc->nasid)); setup_hub_mask(hd, &hub->h_cpus); desc = irq_to_desc(irq); desc->irq_common_data.node = bc->nasid; cpumask_copy(desc->irq_common_data.affinity, &hub->h_cpus); return irq; }
int check_nasid_equiv(nasid_t nasida, nasid_t nasidb) { if ((nasida == nasidb) || (nasida == NODEPDA(NASID_TO_COMPACT_NODEID(nasidb))->xbow_peer)) return 1; else return 0; }
/* * hub_set_piomode() * * Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" * mode. To do this, we have to make absolutely sure that no PIOs * are in progress so we turn off access to all widgets for the duration * of the function. * * XXX - This code should really check what kind of widget we're talking * to. Bridges can only handle three requests, but XG will do more. * How many can crossbow handle to widget 0? We're assuming 1. * * XXX - There is a bug in the crossbow that link reset PIOs do not * return write responses. The easiest solution to this problem is to * leave widget 0 (xbow) in fire-and-forget mode at all times. This * only affects pio's to xbow registers, which should be rare. */ void hub_set_piomode(nasid_t nasid, int conveyor) { hubreg_t ii_iowa; int direct_connect; hubii_wcr_t ii_wcr; int prbnum; int s, cons_lock = 0; ASSERT(NASID_TO_COMPACT_NODEID(nasid) != INVALID_CNODEID); if (nasid == get_console_nasid()) { PUTBUF_LOCK(s); cons_lock = 1; } ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS); REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0); ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR); direct_connect = ii_wcr.iwcr_dir_con; if (direct_connect) { /* * Assume a bridge here. */ hub_setup_prb(nasid, 0, 3, conveyor); } else { /* * Assume a crossbow here. */ hub_setup_prb(nasid, 0, 1, conveyor); } for (prbnum = HUB_WIDGET_ID_MIN; prbnum <= HUB_WIDGET_ID_MAX; prbnum++) { /* * XXX - Here's where we should take the widget type into * when account assigning credits. */ /* Always set the PRBs in fire-and-forget mode */ hub_setup_prb(nasid, prbnum, 3, conveyor); } #ifdef IRIX /* * In direct connect mode, disable access to all widgets but 0. * Later, the prom will do this for us. */ if (direct_connect) ii_iowa = 1; #endif REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa); if (cons_lock) PUTBUF_UNLOCK(s); }
static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid) { cnodeid_t client_cnode; kern_vars_t *kvp; client_cnode = NASID_TO_COMPACT_NODEID(client_nasid); kvp = &hub_data(client_nasid)->kern_vars; KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp; kvp->kv_magic = KV_MAGIC; kvp->kv_ro_nasid = server_nasid; kvp->kv_rw_nasid = master_nasid; kvp->kv_ro_baseaddr = NODE_CAC_BASE(server_nasid); kvp->kv_rw_baseaddr = NODE_CAC_BASE(master_nasid); printk("REPLICATION: ON nasid %d, ktext from nasid %d, kdata from nasid %d\n", client_nasid, server_nasid, master_nasid); }
/* * Map the physical node id to a virtual node id (virtual node ids are contiguous). */ cnodeid_t get_compact_nodeid(void) { return NASID_TO_COMPACT_NODEID(get_nasid()); }
int hubiio_crb_error_handler(vertex_hdl_t hub_v, hubinfo_t hinfo) { cnodeid_t cnode; nasid_t nasid; ii_icrb0_a_u_t icrba; /* II CRB Register A */ ii_icrb0_b_u_t icrbb; /* II CRB Register B */ ii_icrb0_c_u_t icrbc; /* II CRB Register C */ ii_icrb0_d_u_t icrbd; /* II CRB Register D */ ii_icrb0_e_u_t icrbe; /* II CRB Register D */ int i; int num_errors = 0; /* Num of errors handled */ ioerror_t ioerror; int rc; nasid = hinfo->h_nasid; cnode = NASID_TO_COMPACT_NODEID(nasid); /* * XXX - Add locking for any recovery actions */ /* * Scan through all CRBs in the Hub, and handle the errors * in any of the CRBs marked. */ for (i = 0; i < IIO_NUM_CRBS; i++) { /* Check this crb entry to see if it is in error. */ icrbb.ii_icrb0_b_regval = REMOTE_HUB_L(nasid, IIO_ICRB_B(i)); if (icrbb.b_mark == 0) { continue; } icrba.ii_icrb0_a_regval = REMOTE_HUB_L(nasid, IIO_ICRB_A(i)); IOERROR_INIT(&ioerror); /* read other CRB error registers. */ icrbc.ii_icrb0_c_regval = REMOTE_HUB_L(nasid, IIO_ICRB_C(i)); icrbd.ii_icrb0_d_regval = REMOTE_HUB_L(nasid, IIO_ICRB_D(i)); icrbe.ii_icrb0_e_regval = REMOTE_HUB_L(nasid, IIO_ICRB_E(i)); IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); /* Check if this error is due to BTE operation, * and handle it separately. */ if (icrbd.d_bteop || ((icrbb.b_initiator == IIO_ICRB_INIT_BTE0 || icrbb.b_initiator == IIO_ICRB_INIT_BTE1) && (icrbb.b_imsgtype == IIO_ICRB_IMSGT_BTE || icrbb.b_imsgtype == IIO_ICRB_IMSGT_SN1NET))){ int bte_num; if (icrbd.d_bteop) bte_num = icrbc.c_btenum; else /* b_initiator bit 2 gives BTE number */ bte_num = (icrbb.b_initiator & 0x4) >> 2; hubiio_crb_free(hinfo, i); bte_crb_error_handler(hub_v, bte_num, i, &ioerror, icrbd.d_bteop); num_errors++; continue; } /* * XXX * Assuming the only other error that would reach here is * crosstalk errors. * If CRB times out on a message from Xtalk, it changes * the message type to CRB. * * If we get here due to other errors (SN0net/CRB) * what's the action ? */ /* * Pick out the useful fields in CRB, and * tuck them away into ioerror structure. */ IOERROR_SETVALUE(&ioerror,xtalkaddr,icrba.a_addr << IIO_ICRB_ADDR_SHFT); IOERROR_SETVALUE(&ioerror,widgetnum,icrba.a_sidn); if (icrba.a_iow){ /* * XXX We shouldn't really have BRIDGE-specific code * here, but alas.... * * The BRIDGE (or XBRIDGE) sets the upper bit of TNUM * to indicate a WRITE operation. It sets the next * bit to indicate an INTERRUPT operation. The bottom * 3 bits of TNUM indicate which device was responsible. */ IOERROR_SETVALUE(&ioerror,widgetdev, TNUM_TO_WIDGET_DEV(icrba.a_tnum)); /* * The encoding of TNUM (see comments above) is * different for PIC. So we'll save TNUM here and * deal with the differences later when we can * determine if we're using a Bridge or the PIC. * * XXX: We may be able to remove saving the widgetdev * above and just sort it out of TNUM later. */ IOERROR_SETVALUE(&ioerror, tnum, icrba.a_tnum); } if (icrbb.b_error) { /* * CRB 'i' has some error. Identify the type of error, * and try to handle it. * */ switch(icrbb.b_ecode) { case IIO_ICRB_ECODE_PERR: case IIO_ICRB_ECODE_WERR: case IIO_ICRB_ECODE_AERR: case IIO_ICRB_ECODE_PWERR: case IIO_ICRB_ECODE_TOUT: case IIO_ICRB_ECODE_XTERR: printk("Shub II CRB %d: error %s on hub cnodeid: %d", i, hubiio_crb_errors[icrbb.b_ecode], cnode); /* * Any sort of write error is mostly due * bad programming (Note it's not a timeout.) * So, invoke hub_iio_error_handler with * appropriate information. */ IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); /* Go through the error bit lookup phase */ if (error_state_set(hub_v, ERROR_STATE_LOOKUP) == ERROR_RETURN_CODE_CANNOT_SET_STATE) return(IOERROR_UNHANDLED); rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVERROR, &ioerror); if (rc == IOERROR_HANDLED) { rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVREENABLE, &ioerror); }else { printk("Unable to handle %s on hub %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /* panic; */ } /* Go to Next error */ print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); hubiio_crb_free(hinfo, i); continue; case IIO_ICRB_ECODE_PRERR: case IIO_ICRB_ECODE_DERR: printk("Shub II CRB %d: error %s on hub : %d", i, hubiio_crb_errors[icrbb.b_ecode], cnode); /* panic */ default: printk("Shub II CRB error (code : %d) on hub : %d", icrbb.b_ecode, cnode); /* panic */ } } /* * Error is not indicated via the errcode field * Check other error indications in this register. */ if (icrbb.b_xerr) { printk("Shub II CRB %d: Xtalk Packet with error bit set to hub %d", i, cnode); /* panic */ } if (icrbb.b_lnetuce) { printk("Shub II CRB %d: Uncorrectable data error detected on data " " from NUMAlink to node %d", i, cnode); /* panic */ } print_crb_fields(i, icrba, icrbb, icrbc, icrbd, icrbe); if (icrbb.b_error) { /* * CRB 'i' has some error. Identify the type of error, * and try to handle it. */ switch(icrbb.b_ecode) { case IIO_ICRB_ECODE_PERR: case IIO_ICRB_ECODE_WERR: case IIO_ICRB_ECODE_AERR: case IIO_ICRB_ECODE_PWERR: printk("%s on hub cnodeid: %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /* * Any sort of write error is mostly due * bad programming (Note it's not a timeout.) * So, invoke hub_iio_error_handler with * appropriate information. */ IOERROR_SETVALUE(&ioerror,errortype,icrbb.b_ecode); rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVERROR, &ioerror); if (rc == IOERROR_HANDLED) { rc = hub_ioerror_handler( hub_v, DMA_WRITE_ERROR, MODE_DEVREENABLE, &ioerror); ASSERT(rc == IOERROR_HANDLED); }else { panic("Unable to handle %s on hub %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /*NOTREACHED*/ } /* Go to Next error */ hubiio_crb_free(hinfo, i); continue; case IIO_ICRB_ECODE_PRERR: case IIO_ICRB_ECODE_TOUT: case IIO_ICRB_ECODE_XTERR: case IIO_ICRB_ECODE_DERR: panic("Fatal %s on hub : %d", hubiio_crb_errors[icrbb.b_ecode], cnode); /*NOTREACHED*/ default: panic("Fatal error (code : %d) on hub : %d", icrbb.b_ecode, cnode); /*NOTREACHED*/ } } /* if (icrbb.b_error) */ /* * Error is not indicated via the errcode field * Check other error indications in this register. */ if (icrbb.b_xerr) { panic("Xtalk Packet with error bit set to hub %d", cnode); /*NOTREACHED*/ } if (icrbb.b_lnetuce) { panic("Uncorrectable data error detected on data " " from Craylink to node %d", cnode); /*NOTREACHED*/ } }
/* * Initialize all I/O on the specified node. */ static void io_init_node(cnodeid_t cnodeid) { /*REFERENCED*/ vertex_hdl_t hubv, switchv, widgetv; struct xwidget_hwid_s hwid; hubinfo_t hubinfo; int is_xswitch; nodepda_t *npdap; struct semaphore *peer_sema = 0; uint32_t widget_partnum; cpuid_t c = 0; npdap = NODEPDA(cnodeid); /* * Get the "top" vertex for this node's hardware * graph; it will carry the per-hub hub-specific * data, and act as the crosstalk provider master. * It's canonical path is probably something of the * form /hw/module/%M/slot/%d/node */ hubv = cnodeid_to_vertex(cnodeid); DBG("io_init_node: Initialize IO for cnode %d hubv(node) 0x%p npdap 0x%p\n", cnodeid, hubv, npdap); ASSERT(hubv != GRAPH_VERTEX_NONE); /* * Read mfg info on this hub */ /* * If nothing connected to this hub's xtalk port, we're done. */ early_probe_for_widget(hubv, &hwid); if (hwid.part_num == XWIDGET_PART_NUM_NONE) { #ifdef PROBE_TEST if ((cnodeid == 1) || (cnodeid == 2)) { int index; for (index = 0; index < 600; index++) DBG("Interfering with device probing!!!\n"); } #endif /* io_init_done takes cpu cookie as 2nd argument * to do a restorenoderun for the setnoderun done * at the start of this thread */ DBG("**** io_init_node: Node's 0x%p hub widget has XWIDGET_PART_NUM_NONE ****\n", hubv); return; /* NOTREACHED */ } /* * attach our hub_provider information to hubv, * so we can use it as a crosstalk provider "master" * vertex. */ xtalk_provider_register(hubv, &hub_provider); xtalk_provider_startup(hubv); /* * Create a vertex to represent the crosstalk bus * attached to this hub, and a vertex to be used * as the connect point for whatever is out there * on the other side of our crosstalk connection. * * Crosstalk Switch drivers "climb up" from their * connection point to try and take over the switch * point. * * Of course, the edges and verticies may already * exist, in which case our net effect is just to * associate the "xtalk_" driver with the connection * point for the device. */ (void)hwgraph_path_add(hubv, EDGE_LBL_XTALK, &switchv); DBG("io_init_node: Created 'xtalk' entry to '../node/' xtalk vertex 0x%p\n", switchv); ASSERT(switchv != GRAPH_VERTEX_NONE); (void)hwgraph_edge_add(hubv, switchv, EDGE_LBL_IO); DBG("io_init_node: Created symlink 'io' from ../node/io to ../node/xtalk \n"); /* * We need to find the widget id and update the basew_id field * accordingly. In particular, SN00 has direct connected bridge, * and hence widget id is Not 0. */ widget_partnum = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + WIDGET_ID))) & WIDGET_PART_NUM) >> WIDGET_PART_NUM_SHFT; if (widget_partnum == BRIDGE_WIDGET_PART_NUM || widget_partnum == XBRIDGE_WIDGET_PART_NUM){ npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); DBG("io_init_node: Found XBRIDGE widget_partnum= 0x%x\n", widget_partnum); } else if ((widget_partnum == XBOW_WIDGET_PART_NUM) || (widget_partnum == XXBOW_WIDGET_PART_NUM) || (widget_partnum == PXBOW_WIDGET_PART_NUM) ) { /* * Xbow control register does not have the widget ID field. * So, hard code the widget ID to be zero. */ DBG("io_init_node: Found XBOW widget_partnum= 0x%x\n", widget_partnum); npdap->basew_id = 0; } else { npdap->basew_id = (((*(volatile int32_t *)(NODE_SWIN_BASE(COMPACT_TO_NASID_NODEID(cnodeid), 0) + BRIDGE_WID_CONTROL))) & WIDGET_WIDGET_ID); 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); /*NOTREACHED*/ } { char widname[10]; sprintf(widname, "%x", npdap->basew_id); (void)hwgraph_path_add(switchv, widname, &widgetv); DBG("io_init_node: Created '%s' to '..node/xtalk/' vertex 0x%p\n", widname, widgetv); ASSERT(widgetv != GRAPH_VERTEX_NONE); } nodepda->basew_xc = widgetv; is_xswitch = xwidget_hwid_is_xswitch(&hwid); /* * Try to become the master of the widget. If this is an xswitch * with multiple hubs connected, only one will succeed. Mastership * of an xswitch is used only when touching registers on that xswitch. * The slave xwidgets connected to the xswitch can be owned by various * masters. */ if (device_master_set(widgetv, hubv) == 0) { /* Only one hub (thread) per Crosstalk device or switch makes * it to here. */ /* * Initialize whatever xwidget is hanging off our hub. * Whatever it is, it's accessible through widgetnum 0. */ hubinfo_get(hubv, &hubinfo); (void)xwidget_register(&hwid, widgetv, npdap->basew_id, hubv, hubinfo->h_widgetid); if (!is_xswitch) { /* io_init_done takes cpu cookie as 2nd argument * to do a restorenoderun for the setnoderun done * at the start of this thread */ io_init_done(cnodeid,c); /* NOTREACHED */ } /* * Special handling for Crosstalk Switches (e.g. xbow). * We need to do things in roughly the following order: * 1) Initialize xswitch hardware (done above) * 2) Determine which hubs are available to be widget masters * 3) Discover which links are active from the xswitch * 4) Assign xwidgets hanging off the xswitch to hubs * 5) Initialize all xwidgets on the xswitch */ DBG("call volunteer_for_widgets\n"); volunteer_for_widgets(switchv, hubv); /* If there's someone else on this crossbow, recognize him */ if (npdap->xbow_peer != INVALID_NASID) { nodepda_t *peer_npdap = NODEPDA(NASID_TO_COMPACT_NODEID(npdap->xbow_peer)); peer_sema = &peer_npdap->xbow_sema; DBG("call volunteer_for_widgets again\n"); volunteer_for_widgets(switchv, peer_npdap->node_vertex); } assign_widgets_to_volunteers(switchv, hubv); /* Signal that we're done */ if (peer_sema) { up(peer_sema); } } else { /* Wait 'til master is done assigning widgets. */ down(&npdap->xbow_sema); } #ifdef PROBE_TEST if ((cnodeid == 1) || (cnodeid == 2)) { int index; for (index = 0; index < 500; index++) DBG("Interfering with device probing!!!\n"); } #endif /* Now both nodes can safely inititialize widgets */ io_init_xswitch_widgets(switchv, cnodeid); io_link_xswitch_widgets(switchv, cnodeid); /* io_init_done takes cpu cookie as 2nd argument * to do a restorenoderun for the setnoderun done * at the start of this thread */ io_init_done(cnodeid,c); DBG("\nio_init_node: DONE INITIALIZED ALL I/O FOR CNODEID %d\n\n", cnodeid); }
void io_xswitch_widget_init(vertex_hdl_t xswitchv, vertex_hdl_t hubv, xwidgetnum_t widgetnum) { xswitch_info_t xswitch_info; xwidgetnum_t hub_widgetid; vertex_hdl_t widgetv; cnodeid_t cnode; widgetreg_t widget_id; nasid_t nasid, peer_nasid; struct xwidget_hwid_s hwid; hubinfo_t hubinfo; /*REFERENCED*/ int rc; char pathname[128]; lboard_t *board = NULL; char buffer[16]; char bt; moduleid_t io_module; slotid_t get_widget_slotnum(int xbow, int widget); DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); /* * Verify that xswitchv is indeed an attached xswitch. */ xswitch_info = xswitch_info_get(xswitchv); ASSERT(xswitch_info != NULL); hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; cnode = NASID_TO_COMPACT_NODEID(nasid); hub_widgetid = hubinfo->h_widgetid; /* * Check that the widget is an io widget and is enabled * on this nasid or the `peer' nasid. The peer nasid * is the other hub/bedrock connected to the xbow. */ peer_nasid = NODEPDA(cnode)->xbow_peer; if (peer_nasid == INVALID_NASID) /* If I don't have a peer, use myself. */ peer_nasid = nasid; if (!xbow_port_io_enabled(nasid, widgetnum) && !xbow_port_io_enabled(peer_nasid, widgetnum)) { return; } if (xswitch_info_link_ok(xswitch_info, widgetnum)) { char name[4]; lboard_t dummy; /* * If the current hub is not supposed to be the master * for this widgetnum, then skip this widget. */ if (xswitch_info_master_assignment_get(xswitch_info, widgetnum) != hubv) { return; } board = find_lboard_class( (lboard_t *)KL_CONFIG_INFO(nasid), KLCLASS_IOBRICK); if (!board && NODEPDA(cnode)->xbow_peer != INVALID_NASID) { board = find_lboard_class( (lboard_t *)KL_CONFIG_INFO( NODEPDA(cnode)->xbow_peer), KLCLASS_IOBRICK); } if (board) { DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); } else { DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); board = &dummy; } /* Copy over the nodes' geoid info */ { lboard_t *brd; brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA); if ( brd != (lboard_t *)0 ) { board->brd_geoid = brd->brd_geoid; } } /* * Make sure we really want to say xbrick, pbrick, * etc. rather than XIO, graphics, etc. */ memset(buffer, 0, 16); format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d" "/%s" "/%s/%d", buffer, geo_slab(board->brd_geoid), (board->brd_type == KLTYPE_IBRICK) ? EDGE_LBL_IBRICK : (board->brd_type == KLTYPE_PBRICK) ? EDGE_LBL_PBRICK : (board->brd_type == KLTYPE_PXBRICK) ? EDGE_LBL_PXBRICK : (board->brd_type == KLTYPE_IXBRICK) ? EDGE_LBL_IXBRICK : (board->brd_type == KLTYPE_CGBRICK) ? EDGE_LBL_CGBRICK : (board->brd_type == KLTYPE_OPUSBRICK) ? EDGE_LBL_OPUSBRICK : (board->brd_type == KLTYPE_XBRICK) ? EDGE_LBL_XBRICK : "?brick", EDGE_LBL_XTALK, widgetnum); DBG("io_xswitch_widget_init: path= %s\n", pathname); rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); ASSERT(rc == GRAPH_SUCCESS); /* This is needed to let the user programs to map the * module,slot numbers to the corresponding widget numbers * on the crossbow. */ device_master_set(hwgraph_connectpt_get(widgetv), hubv); sprintf(name, "%d", widgetnum); DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); rc = hwgraph_edge_add(xswitchv, widgetv, name); /* * crosstalk switch code tracks which * widget is attached to each link. */ xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); /* * Peek at the widget to get its crosstalk part and * mfgr numbers, then present it to the generic xtalk * bus provider to have its driver attach routine * called (or not). */ widget_id = XWIDGET_ID_READ(nasid, widgetnum); hwid.part_num = XWIDGET_PART_NUM(widget_id); hwid.rev_num = XWIDGET_REV_NUM(widget_id); hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); /* Store some inventory information about * the xwidget in the hardware graph. */ xwidget_inventory_add(widgetv,board,hwid); (void)xwidget_register(&hwid, widgetv, widgetnum, hubv, hub_widgetid); ia64_sn_sysctl_iobrick_module_get(nasid, &io_module); if (io_module >= 0) { char buffer[16]; vertex_hdl_t to, from; char *brick_name; extern char *iobrick_L1bricktype_to_name(int type); memset(buffer, 0, 16); format_module_id(buffer, geo_module(board->brd_geoid), MODULE_FORMAT_BRIEF); if ( isupper(MODULE_GET_BTCHAR(io_module)) ) { bt = tolower(MODULE_GET_BTCHAR(io_module)); } else { bt = MODULE_GET_BTCHAR(io_module); } brick_name = iobrick_L1bricktype_to_name(bt); /* Add a helper vertex so xbow monitoring * can identify the brick type. It's simply * an edge from the widget 0 vertex to the * brick vertex. */ sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/" EDGE_LBL_NODE "/" EDGE_LBL_XTALK "/" "0", buffer, geo_slab(board->brd_geoid)); DBG("io_xswitch_widget_init: FROM path '%s'\n", pathname); from = hwgraph_path_to_vertex(pathname); ASSERT_ALWAYS(from); sprintf(pathname, EDGE_LBL_HW "/" EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLAB "/%d/" "%s", buffer, geo_slab(board->brd_geoid), brick_name); DBG("io_xswitch_widget_init: TO path '%s'\n", pathname); to = hwgraph_path_to_vertex(pathname); ASSERT_ALWAYS(to); rc = hwgraph_edge_add(from, to, EDGE_LBL_INTERCONNECT); if (rc == -EEXIST) goto link_done; if (rc != GRAPH_SUCCESS) { printk("%s: Unable to establish link" " for xbmon.", pathname); } link_done: } #ifdef SN0_USE_BTE bte_bpush_war(cnode, (void *)board); #endif } }
void io_xswitch_widget_init(devfs_handle_t xswitchv, devfs_handle_t hubv, xwidgetnum_t widgetnum, async_attach_t aa) { xswitch_info_t xswitch_info; xwidgetnum_t hub_widgetid; devfs_handle_t widgetv; cnodeid_t cnode; widgetreg_t widget_id; nasid_t nasid, peer_nasid; struct xwidget_hwid_s hwid; hubinfo_t hubinfo; /*REFERENCED*/ int rc; char pathname[128]; char new_name[64]; moduleid_t module; slotid_t slot; lboard_t *board = NULL; char buffer[16]; slotid_t get_widget_slotnum(int xbow, int widget); DBG("\nio_xswitch_widget_init: hubv 0x%p, xswitchv 0x%p, widgetnum 0x%x\n", hubv, xswitchv, widgetnum); /* * Verify that xswitchv is indeed an attached xswitch. */ xswitch_info = xswitch_info_get(xswitchv); ASSERT(xswitch_info != NULL); hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; cnode = NASID_TO_COMPACT_NODEID(nasid); hub_widgetid = hubinfo->h_widgetid; /* * Check that the widget is an io widget and is enabled * on this nasid or the `peer' nasid. The peer nasid * is the other hub/bedrock connected to the xbow. */ peer_nasid = NODEPDA(cnode)->xbow_peer; if (peer_nasid == INVALID_NASID) /* If I don't have a peer, use myself. */ peer_nasid = nasid; if (!xbow_port_io_enabled(nasid, widgetnum) && !xbow_port_io_enabled(peer_nasid, widgetnum)) { return; } if (xswitch_info_link_ok(xswitch_info, widgetnum)) { char name[4]; /* * If the current hub is not supposed to be the master * for this widgetnum, then skip this widget. */ if (xswitch_info_master_assignment_get(xswitch_info, widgetnum) != hubv) { return; } module = NODEPDA(cnode)->module_id; #ifdef XBRIDGE_REGS_SIM /* hardwire for now...could do this with something like: * xbow_soft_t soft = hwgraph_fastinfo_get(vhdl); * xbow_t xbow = soft->base; * xbowreg_t xwidget_id = xbow->xb_wid_id; * but I don't feel like figuring out vhdl right now.. * and I know for a fact the answer is 0x2d000049 */ DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); DBG("XWIDGET_PART_NUM(0x2d000049)= 0x%x\n", XWIDGET_PART_NUM(0x2d000049)); if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) #else if (nasid_has_xbridge(nasid)) #endif /* XBRIDGE_REGS_SIM */ { board = find_lboard_module_class( (lboard_t *)KL_CONFIG_INFO(nasid), module, KLTYPE_IOBRICK); DBG("io_xswitch_widget_init: Board 0x%p\n", board); { lboard_t dummy; if (board) { DBG("io_xswitch_widget_init: Found KLTYPE_IOBRICK Board 0x%p brd_type 0x%x\n", board, board->brd_type); } else { DBG("io_xswitch_widget_init: FIXME did not find IOBOARD\n"); board = &dummy; } } /* * Make sure we really want to say xbrick, pbrick, * etc. rather than XIO, graphics, etc. */ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" "%cbrick" "/%s/%d", NODEPDA(cnode)->module_id, #else memset(buffer, 0, 16); format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); sprintf(pathname, EDGE_LBL_MODULE "/%s/" "%cbrick" "/%s/%d", buffer, #endif (board->brd_type == KLTYPE_IBRICK) ? 'I' : (board->brd_type == KLTYPE_PBRICK) ? 'P' : (board->brd_type == KLTYPE_XBRICK) ? 'X' : '?', EDGE_LBL_XTALK, widgetnum); } DBG("io_xswitch_widget_init: path= %s\n", pathname); rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); ASSERT(rc == GRAPH_SUCCESS); /* This is needed to let the user programs to map the * module,slot numbers to the corresponding widget numbers * on the crossbow. */ rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); /* If we are looking at the global master io6 * then add information about the version of * the io6prom as a part of "detailed inventory" * information. */ if (is_master_baseio(nasid, NODEPDA(cnode)->module_id, get_widget_slotnum(0,widgetnum))) { extern void klhwg_baseio_inventory_add(devfs_handle_t, cnodeid_t); module = NODEPDA(cnode)->module_id; #ifdef XBRIDGE_REGS_SIM DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: reading xwidget id: hardwired to xbridge (0x2d000049).\n"); if (XWIDGET_PART_NUM(0x2d000049)==XXBOW_WIDGET_PART_NUM) #else if (nasid_has_xbridge(nasid)) #endif /* XBRIDGE_REGS_SIM */ { board = find_lboard_module( (lboard_t *)KL_CONFIG_INFO(nasid), module); /* * Change iobrick to correct i/o brick */ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" #else sprintf(pathname, EDGE_LBL_MODULE "/%x/" #endif "iobrick" "/%s/%d", NODEPDA(cnode)->module_id, EDGE_LBL_XTALK, widgetnum); } else { slot = get_widget_slotnum(0, widgetnum); board = get_board_name(nasid, module, slot, new_name); /* * Create the vertex for the widget, * using the decimal * widgetnum as the name of the primary edge. */ #ifdef SUPPORT_PRINTING_M_FORMAT sprintf(pathname, EDGE_LBL_MODULE "/%M/" EDGE_LBL_SLOT "/%s", NODEPDA(cnode)->module_id, new_name); #else memset(buffer, 0, 16); format_module_id(buffer, NODEPDA(cnode)->module_id, MODULE_FORMAT_BRIEF); sprintf(pathname, EDGE_LBL_MODULE "/%s/" EDGE_LBL_SLOT "/%s", buffer, new_name); #endif } rc = hwgraph_path_add(hwgraph_root, pathname, &widgetv); DBG("io_xswitch_widget_init: (2) path= %s\n", pathname); /* * This is a weird ass code needed for error injection * purposes. */ rc = device_master_set(hwgraph_connectpt_get(widgetv), hubv); klhwg_baseio_inventory_add(widgetv,cnode); } sprintf(name, "%d", widgetnum); DBG("io_xswitch_widget_init: FIXME hwgraph_edge_add %s xswitchv 0x%p, widgetv 0x%p\n", name, xswitchv, widgetv); rc = hwgraph_edge_add(xswitchv, widgetv, name); /* * crosstalk switch code tracks which * widget is attached to each link. */ xswitch_info_vhdl_set(xswitch_info, widgetnum, widgetv); /* * Peek at the widget to get its crosstalk part and * mfgr numbers, then present it to the generic xtalk * bus provider to have its driver attach routine * called (or not). */ #ifdef XBRIDGE_REGS_SIM widget_id = 0x2d000049; DBG("io_xswitch_widget_init: XBRIDGE_REGS_SIM FIXME: id hardwired to widget_id\n"); #else widget_id = XWIDGET_ID_READ(nasid, widgetnum); #endif /* XBRIDGE_REGS_SIM */ hwid.part_num = XWIDGET_PART_NUM(widget_id); hwid.rev_num = XWIDGET_REV_NUM(widget_id); hwid.mfg_num = XWIDGET_MFG_NUM(widget_id); /* Store some inventory information about * the xwidget in the hardware graph. */ xwidget_inventory_add(widgetv,board,hwid); (void)xwidget_register(&hwid, widgetv, widgetnum, hubv, hub_widgetid, aa); #ifdef SN0_USE_BTE bte_bpush_war(cnode, (void *)board); #endif }
/* * If this PIC is attached to two Cbricks ("dual-ported") then * attach each bus to opposite Cbricks. * * If successful, return a new vertex suitable for attaching the PIC bus. * If not successful, return zero and both buses will attach to the * vertex passed into pic_attach(). */ vertex_hdl_t pic_bus1_redist(nasid_t nasid, vertex_hdl_t conn_v) { cnodeid_t cnode = NASID_TO_COMPACT_NODEID(nasid); cnodeid_t xbow_peer = -1; char pathname[256], peer_path[256], tmpbuf[256]; char *p; int rc; vertex_hdl_t peer_conn_v; int pos; slabid_t slab; if (NODEPDA(cnode)->xbow_peer >= 0) { /* if dual-ported */ /* create a path for this widget on the peer Cbrick */ /* pcibr widget hw/module/001c11/slab/0/Pbrick/xtalk/12 */ /* sprintf(pathname, "%v", conn_v); */ xbow_peer = NASID_TO_COMPACT_NODEID(NODEPDA(cnode)->xbow_peer); pos = hwgfs_generate_path(conn_v, tmpbuf, 256); strcpy(pathname, &tmpbuf[pos]); p = pathname + strlen("hw/module/001c01/slab/0/"); memset(tmpbuf, 0, 16); format_module_id(tmpbuf, geo_module((NODEPDA(xbow_peer))->geoid), MODULE_FORMAT_BRIEF); slab = geo_slab((NODEPDA(xbow_peer))->geoid); sprintf(peer_path, "module/%s/slab/%d/%s", tmpbuf, (int)slab, p); /* Look for vertex for this widget on the peer Cbrick. * Expect GRAPH_NOT_FOUND. */ rc = hwgraph_traverse(hwgraph_root, peer_path, &peer_conn_v); if (GRAPH_SUCCESS == rc) printk("pic_attach: found unexpected vertex: 0x%lx\n", (uint64_t)peer_conn_v); else if (GRAPH_NOT_FOUND != rc) { printk("pic_attach: hwgraph_traverse unexpectedly" " returned 0x%x\n", rc); } else { /* try to add the widget vertex to the peer Cbrick */ rc = hwgraph_path_add(hwgraph_root, peer_path, &peer_conn_v); if (GRAPH_SUCCESS != rc) printk("pic_attach: hwgraph_path_add" " failed with 0x%x\n", rc); else { PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_ATTACH, conn_v, "pic_bus1_redist: added vertex %v\n", peer_conn_v)); /* Now hang appropiate stuff off of the new * vertex. We bail out if we cannot add something. * In that case, we don't remove the newly added * vertex but that should be safe and we don't * really expect the additions to fail anyway. */ #if 0 if (!pic_bus1_inventory_dup(conn_v, peer_conn_v)) return 0; pic_bus1_device_desc_dup(conn_v, peer_conn_v); #endif if (!pic_bus1_widget_info_dup(conn_v, peer_conn_v, xbow_peer)) return 0; return peer_conn_v; } } } return 0; }