/* ARGSUSED */ static void volunteer_for_widgets(devfs_handle_t xswitch, devfs_handle_t master) { xswitch_vol_t xvolinfo = NULL; devfs_handle_t hubv; hubinfo_t hubinfo; (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { return; } mutex_lock(&xvolinfo->xswitch_volunteer_mutex); ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; xvolinfo->xswitch_volunteer_count++; /* * if dual ported, make the lowest widgetid always be * xswitch_volunteer[0]. */ if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) { hubv = xvolinfo->xswitch_volunteer[0]; hubinfo_get(hubv, &hubinfo); if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) { xvolinfo->xswitch_volunteer[0] = xvolinfo->xswitch_volunteer[1]; xvolinfo->xswitch_volunteer[1] = hubv; } } mutex_unlock(&xvolinfo->xswitch_volunteer_mutex); }
cnodeid_t hubdev_cnodeid_get(devfs_handle_t hub) { hubinfo_t hinfo = NULL; hubinfo_get(hub, &hinfo); ASSERT(hinfo); return hinfo->h_cnodeid; }
/* * Given a hub vertex, return the base address of the Hspec space * for that hub. */ caddr_t hubdev_prombase_get(devfs_handle_t hub) { hubinfo_t hinfo = NULL; hubinfo_get(hub, &hinfo); ASSERT(hinfo); return ((caddr_t)NODE_RBOOT_BASE(hinfo->h_nasid)); }
/* * copy xwidget_info_t from conn_v to peer_conn_v */ static int pic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v, cnodeid_t xbow_peer, char *peer_path) { xwidget_info_t widget_info, peer_widget_info; vertex_hdl_t peer_hubv; hubinfo_t peer_hub_info; /* get the peer hub's widgetid */ peer_hubv = NODEPDA(xbow_peer)->node_vertex; peer_hub_info = NULL; hubinfo_get(peer_hubv, &peer_hub_info); if (peer_hub_info == NULL) return 0; if (hwgraph_info_get_LBL(conn_v, INFO_LBL_XWIDGET, (arbitrary_info_t *)&widget_info) == GRAPH_SUCCESS) { peer_widget_info = kmalloc(sizeof (*(peer_widget_info)), GFP_KERNEL); if ( !peer_widget_info ) { return -ENOMEM; } memset(peer_widget_info, 0, sizeof (*(peer_widget_info))); peer_widget_info->w_fingerprint = widget_info_fingerprint; peer_widget_info->w_vertex = peer_conn_v; peer_widget_info->w_id = widget_info->w_id; peer_widget_info->w_master = peer_hubv; peer_widget_info->w_masterid = peer_hub_info->h_widgetid; /* structure copy */ peer_widget_info->w_hwid = widget_info->w_hwid; peer_widget_info->w_efunc = 0; peer_widget_info->w_einfo = 0; peer_widget_info->w_name = kmalloc(strlen(peer_path) + 1, GFP_KERNEL); if (!peer_widget_info->w_name) { kfree(peer_widget_info); return -ENOMEM; } strcpy(peer_widget_info->w_name, peer_path); if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_XWIDGET, (arbitrary_info_t)peer_widget_info) != GRAPH_SUCCESS) { kfree(peer_widget_info->w_name); kfree(peer_widget_info); return 0; } xwidget_info_set(peer_conn_v, peer_widget_info); return 1; } printk("pic_bus1_widget_info_dup: " "cannot get INFO_LBL_XWIDGET from 0x%lx\n", (uint64_t)conn_v); return 0; }
void hubii_eint_init(cnodeid_t cnode) { int bit, rv; ii_iidsr_u_t hubio_eint; hubinfo_t hinfo; cpuid_t intr_cpu; devfs_handle_t hub_v; ii_ilcsr_u_t ilcsr; int bit_pos_to_irq(int bit); int synergy_intr_connect(int bit, int cpuid); hub_v = (devfs_handle_t)cnodeid_to_vertex(cnode); ASSERT_ALWAYS(hub_v); hubinfo_get(hub_v, &hinfo); ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { /* * HUB II link is not up. * Just disable LLP, and don't connect any interrupts. */ ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); return; } /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ intr_cpu = intr_heuristic(hub_v,0,INTRCONNECT_ANYBIT,II_ERRORINT,hub_v, "HUB IO error interrupt",&bit); if (intr_cpu == CPU_NONE) { printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); return; } rv = intr_connect_level(intr_cpu, bit, 0, NULL); synergy_intr_connect(bit, intr_cpu); request_irq(bit_pos_to_irq(bit) + (intr_cpu << 8), hubii_eint_handler, 0, "SN hub error", (void *)hub_v); ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); }
/* * hub_device_inquiry * Find out the xtalk widget related information stored in this * hub's II. */ void hub_device_inquiry(devfs_handle_t xbus_vhdl, xwidgetnum_t widget) { devfs_handle_t xconn, hub_vhdl; char widget_name[8]; hubreg_t ii_iidem,ii_iiwa, ii_iowa; hubinfo_t hubinfo; nasid_t nasid; int d; sprintf(widget_name, "%d", widget); if (hwgraph_traverse(xbus_vhdl, widget_name, &xconn) != GRAPH_SUCCESS) return; hub_vhdl = device_master_get(xconn); if (hub_vhdl == GRAPH_VERTEX_NONE) return; hubinfo_get(hub_vhdl, &hubinfo); if (!hubinfo) return; nasid = hubinfo->h_nasid; ii_iidem = REMOTE_HUB_L(nasid, IIO_IIDEM); ii_iiwa = REMOTE_HUB_L(nasid, IIO_IIWA); ii_iowa = REMOTE_HUB_L(nasid, IIO_IOWA); #if defined(SUPPORT_PRINTING_V_FORMAT) cmn_err(CE_CONT, "Inquiry Info for %v\n", xconn); #else cmn_err(CE_CONT, "Inquiry Info for 0x%p\n", &xconn); #endif cmn_err(CE_CONT,"\tDevices shutdown [ "); for (d = 0 ; d <= 7 ; d++) if (!(ii_iidem & (IIO_IIDEM_WIDGETDEV_MASK(widget,d)))) cmn_err(CE_CONT, " %d", d); cmn_err(CE_CONT,"]\n"); cmn_err(CE_CONT, "\tInbound access ? %s\n", ii_iiwa & IIO_IIWA_WIDGET(widget) ? "yes" : "no"); cmn_err(CE_CONT, "\tOutbound access ? %s\n", ii_iowa & IIO_IOWA_WIDGET(widget) ? "yes" : "no"); }
void hubii_eint_init(cnodeid_t cnode) { int bit, rv; ii_iidsr_u_t hubio_eint; hubinfo_t hinfo; cpuid_t intr_cpu; vertex_hdl_t hub_v; int bit_pos_to_irq(int bit); ii_ilcsr_u_t ilcsr; hub_v = (vertex_hdl_t)cnodeid_to_vertex(cnode); ASSERT_ALWAYS(hub_v); hubinfo_get(hub_v, &hinfo); ASSERT(hinfo); ASSERT(hinfo->h_cnodeid == cnode); ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); if ((ilcsr.ii_ilcsr_fld_s.i_llp_stat & 0x2) == 0) { /* * HUB II link is not up. Disable LLP. Clear old errors. * Enable interrupts to handle BTE errors. */ ilcsr.ii_ilcsr_fld_s.i_llp_en = 0; REMOTE_HUB_S(hinfo->h_nasid, IIO_ILCSR, ilcsr.ii_ilcsr_regval); } /* Select a possible interrupt target where there is a free interrupt * bit and also reserve the interrupt bit for this IO error interrupt */ intr_cpu = intr_heuristic(hub_v,0,SGI_II_ERROR,0,hub_v, "HUB IO error interrupt",&bit); if (intr_cpu == CPU_NONE) { printk("hubii_eint_init: intr_reserve_level failed, cnode %d", cnode); return; } rv = intr_connect_level(intr_cpu, SGI_II_ERROR, 0, NULL); request_irq(SGI_II_ERROR, hubii_eint_handler, SA_SHIRQ, "SN_hub_error", (void *)hub_v); irq_desc(bit)->status |= SN2_IRQ_PER_HUB; ASSERT_ALWAYS(rv >= 0); hubio_eint.ii_iidsr_regval = 0; hubio_eint.ii_iidsr_fld_s.i_enable = 1; hubio_eint.ii_iidsr_fld_s.i_level = bit;/* Take the least significant bits*/ hubio_eint.ii_iidsr_fld_s.i_node = COMPACT_TO_NASID_NODEID(cnode); hubio_eint.ii_iidsr_fld_s.i_pi_id = cpuid_to_subnode(intr_cpu); REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, hubio_eint.ii_iidsr_regval); }
/* * copy xwidget_info_t from conn_v to peer_conn_v */ int pic_bus1_widget_info_dup(vertex_hdl_t conn_v, vertex_hdl_t peer_conn_v, cnodeid_t xbow_peer) { xwidget_info_t widget_info, peer_widget_info; char peer_path[256]; vertex_hdl_t peer_hubv; hubinfo_t peer_hub_info; /* get the peer hub's widgetid */ peer_hubv = NODEPDA(xbow_peer)->node_vertex; peer_hub_info = NULL; hubinfo_get(peer_hubv, &peer_hub_info); if (peer_hub_info == NULL) return 0; if (hwgraph_info_get_LBL(conn_v, INFO_LBL_XWIDGET, (arbitrary_info_t *)&widget_info) == GRAPH_SUCCESS) { NEW(peer_widget_info); peer_widget_info->w_vertex = peer_conn_v; peer_widget_info->w_id = widget_info->w_id; peer_widget_info->w_master = peer_hubv; peer_widget_info->w_masterid = peer_hub_info->h_widgetid; /* structure copy */ peer_widget_info->w_hwid = widget_info->w_hwid; peer_widget_info->w_efunc = 0; peer_widget_info->w_einfo = 0; peer_widget_info->w_name = kmalloc(strlen(peer_path) + 1, GFP_KERNEL); strcpy(peer_widget_info->w_name, peer_path); if (hwgraph_info_add_LBL(peer_conn_v, INFO_LBL_XWIDGET, (arbitrary_info_t)peer_widget_info) != GRAPH_SUCCESS) { DEL(peer_widget_info); return 0; } xwidget_info_set(peer_conn_v, peer_widget_info); return 1; } printk("pic_bus1_widget_info_dup: " "cannot get INFO_LBL_XWIDGET from 0x%lx\n", (uint64_t)conn_v); return 0; }
/* * Setup pio structures needed for a particular hub. */ static void hub_pio_init(devfs_handle_t hubv) { xwidgetnum_t widget; hubinfo_t hubinfo; nasid_t nasid; int bigwin; hub_piomap_t hub_piomap; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; /* Initialize small window piomaps for this hub */ for (widget=0; widget <= HUB_WIDGET_ID_MAX; widget++) { hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); hub_piomap->hpio_xtalk_info.xp_target = widget; hub_piomap->hpio_xtalk_info.xp_xtalk_addr = 0; hub_piomap->hpio_xtalk_info.xp_mapsz = SWIN_SIZE; hub_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_SWIN_BASE(nasid, widget); hub_piomap->hpio_hub = hubv; hub_piomap->hpio_flags = HUB_PIOMAP_IS_VALID; } /* Initialize big window piomaps for this hub */ for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { hub_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin); hub_piomap->hpio_xtalk_info.xp_mapsz = BWIN_SIZE; hub_piomap->hpio_hub = hubv; hub_piomap->hpio_holdcnt = 0; hub_piomap->hpio_flags = HUB_PIOMAP_IS_BIGWINDOW; IIO_ITTE_DISABLE(nasid, bigwin); } #ifdef BRINGUP hub_set_piomode(nasid, HUB_PIO_CONVEYOR); #else /* Set all the xwidgets in fire-and-forget mode * by default */ hub_set_piomode(nasid, HUB_PIO_FIRE_N_FORGET); #endif /* BRINGUP */ sv_init(&hubinfo->h_bwwait, SV_FIFO, "bigwin"); spinlock_init(&hubinfo->h_bwlock, "bigwin"); }
/* * hub_piomap_free destroys a caddr_t-to-xtalk pio mapping and frees * any associated mapping resources. * * If this * piomap was handled with a small window, or if it was handled * in a big window that's still in use by someone else, then there's * nothing to do. On the other hand, if this mapping was handled * with a big window, AND if we were the final user of that mapping, * then destroy the mapping. */ void hub_piomap_free(hub_piomap_t hub_piomap) { devfs_handle_t hubv; hubinfo_t hubinfo; nasid_t nasid; int s; /* * Small windows are permanently mapped to corresponding widgets, * so there're no resources to free. */ if (!(hub_piomap->hpio_flags & HUB_PIOMAP_IS_BIGWINDOW)) return; ASSERT(hub_piomap->hpio_flags & HUB_PIOMAP_IS_VALID); ASSERT(hub_piomap->hpio_holdcnt > 0); hubv = hub_piomap->hpio_hub; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; s = mutex_spinlock(&hubinfo->h_bwlock); /* * If this is the last hold on this mapping, free it. */ if (--hub_piomap->hpio_holdcnt == 0) { IIO_ITTE_DISABLE(nasid, hub_piomap->hpio_bigwin_num ); if (hub_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED) { hub_piomap->hpio_flags &= ~(HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED); hubinfo->h_num_big_window_fixed--; ASSERT(hubinfo->h_num_big_window_fixed >= 0); } else hub_piomap->hpio_flags &= ~HUB_PIOMAP_IS_VALID; (void)sv_signal(&hubinfo->h_bwwait); } mutex_spinunlock(&hubinfo->h_bwlock, s); }
/* ARGSUSED */ caddr_t hub_piotrans_addr( devfs_handle_t dev, /* translate to this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* Crosstalk address */ size_t byte_count, /* map this many bytes */ unsigned flags) /* (currently unused) */ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); devfs_handle_t hubv = xwidget_info_master_get(widget_info); hub_piomap_t hub_piomap; hubinfo_t hubinfo; hubinfo_get(hubv, &hubinfo); if (xtalk_addr + byte_count <= SWIN_SIZE) { hub_piomap = hubinfo_swin_piomap_get(hubinfo, (int)widget); return(hub_piomap_addr(hub_piomap, xtalk_addr, byte_count)); } else return(0); }
/* * Probe to see if this hub's xtalk link is active. If so, * return the Crosstalk Identification of the widget that we talk to. * This is called before any of the Crosstalk infrastructure for * this hub is set up. It's usually called on the node that we're * probing, but not always. * * TBD: Prom code should actually do this work, and pass through * hwid for our use. */ static void early_probe_for_widget(devfs_handle_t hubv, xwidget_hwid_t hwid) { hubreg_t llp_csr_reg; nasid_t nasid; hubinfo_t hubinfo; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); /* * If link is up, read the widget's part number. * A direct connect widget must respond to widgetnum=0. */ if (llp_csr_reg & IIO_LLP_CSR_IS_UP) { /* TBD: Put hub into "indirect" mode */ /* * We're able to read from a widget because our hub's * WIDGET_ID was set up earlier. */ widgetreg_t widget_id = *(volatile widgetreg_t *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID); DBG("early_probe_for_widget: Hub Vertex 0x%p is UP widget_id = 0x%x Register 0x%p\n", hubv, widget_id, (volatile widgetreg_t *)(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID) ); hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); /* TBD: link reset */ } else { hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; } }
/* ARGSUSED */ static void volunteer_for_widgets(vertex_hdl_t xswitch, vertex_hdl_t master) { xswitch_vol_t xvolinfo = NULL; vertex_hdl_t hubv; hubinfo_t hubinfo; (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { if (!is_headless_node_vertex(master)) { char name[MAXDEVNAME]; printk(KERN_WARNING "volunteer for widgets: vertex %s has no info label", vertex_to_name(xswitch, name, MAXDEVNAME)); } return; } down(&xvolinfo->xswitch_volunteer_mutex); ASSERT(xvolinfo->xswitch_volunteer_count < NUM_XSWITCH_VOLUNTEER); xvolinfo->xswitch_volunteer[xvolinfo->xswitch_volunteer_count] = master; xvolinfo->xswitch_volunteer_count++; /* * if dual ported, make the lowest widgetid always be * xswitch_volunteer[0]. */ if (xvolinfo->xswitch_volunteer_count == NUM_XSWITCH_VOLUNTEER) { hubv = xvolinfo->xswitch_volunteer[0]; hubinfo_get(hubv, &hubinfo); if (hubinfo->h_widgetid != XBOW_HUBLINK_LOW) { xvolinfo->xswitch_volunteer[0] = xvolinfo->xswitch_volunteer[1]; xvolinfo->xswitch_volunteer[1] = hubv; } } up(&xvolinfo->xswitch_volunteer_mutex); }
int hubii_ixtt_get(devfs_handle_t widget_vhdl, ii_ixtt_u_t *ixtt) { xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; int s; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex */ hubinfo_get(hub_vhdl, &hub_info); /* Being over cautious by grabbing a lock */ s = mutex_spinlock(&hub_info->h_bwlock); nasid = hub_info->h_nasid; ixtt->ii_ixtt_regval = REMOTE_HUB_L(nasid, IIO_IXTT); mutex_spinunlock(&hub_info->h_bwlock, s); return 0; }
/* * Probe to see if this hub's xtalk link is active. If so, * return the Crosstalk Identification of the widget that we talk to. * This is called before any of the Crosstalk infrastructure for * this hub is set up. It's usually called on the node that we're * probing, but not always. * * TBD: Prom code should actually do this work, and pass through * hwid for our use. */ static void early_probe_for_widget(vertex_hdl_t hubv, xwidget_hwid_t hwid) { nasid_t nasid; hubinfo_t hubinfo; hubreg_t llp_csr_reg; widgetreg_t widget_id; int result = 0; hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; llp_csr_reg = REMOTE_HUB_L(nasid, IIO_LLP_CSR); if (!(llp_csr_reg & IIO_LLP_CSR_IS_UP)) return; /* Read the Cross-Talk Widget Id on the other end */ result = snia_badaddr_val((volatile void *) (RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID), 4, (void *) &widget_id); if (result == 0) { /* Found something connected */ hwid->part_num = XWIDGET_PART_NUM(widget_id); hwid->rev_num = XWIDGET_REV_NUM(widget_id); hwid->mfg_num = XWIDGET_MFG_NUM(widget_id); /* TBD: link reset */ } else { hwid->part_num = XWIDGET_PART_NUM_NONE; hwid->rev_num = XWIDGET_REV_NUM_NONE; hwid->mfg_num = XWIDGET_MFG_NUM_NONE; } }
/* Interface to allow special drivers to set hub specific * device flags. * Return 0 on failure , 1 on success */ int hub_device_flags_set(devfs_handle_t widget_vhdl, hub_widget_flags_t flags) { xwidget_info_t widget_info = xwidget_info_get(widget_vhdl); xwidgetnum_t widget_num = xwidget_info_id_get(widget_info); devfs_handle_t hub_vhdl = xwidget_info_master_get(widget_info); hubinfo_t hub_info = 0; nasid_t nasid; int s,rv; /* Use the nasid from the hub info hanging off the hub vertex * and widget number from the widget vertex */ hubinfo_get(hub_vhdl, &hub_info); /* Being over cautious by grabbing a lock */ s = mutex_spinlock(&hub_info->h_bwlock); nasid = hub_info->h_nasid; rv = hub_widget_flags_set(nasid,widget_num,flags); mutex_spinunlock(&hub_info->h_bwlock, s); return rv; }
/* * First part error handler. This is called whenever any error CRB interrupt * is generated by the II. */ void bte_crb_error_handler(vertex_hdl_t hub_v, int btenum, int crbnum, ioerror_t * ioe, int bteop) { hubinfo_t hinfo; struct bteinfo_s *bte; hubinfo_get(hub_v, &hinfo); bte = &hinfo->h_nodepda->bte_if[btenum]; /* * The caller has already figured out the error type, we save that * in the bte handle structure for the thread excercising the * interface to consume. */ bte->bh_error = ioe->ie_errortype + BTEFAIL_OFFSET; bte->bte_error_count++; BTE_PRINTK(("Got an error on cnode %d bte %d: HW error type 0x%x\n", bte->bte_cnode, bte->bte_num, ioe->ie_errortype)); bte_error_handler((unsigned long) hinfo->h_nodepda); }
/* * 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); }
/*ARGSUSED*/ irqreturn_t hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) { vertex_hdl_t hub_v; hubinfo_t hinfo; ii_wstat_u_t wstat; hubreg_t idsr; ii_ilcsr_u_t ilcsr; /* two levels of casting avoids compiler warning.!! */ hub_v = (vertex_hdl_t)(long)(arg); ASSERT(hub_v); hubinfo_get(hub_v, &hinfo); idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_ICMR); #if 0 if (idsr & 0x1) { /* ICMR bit is set .. we are getting into "Spurious Interrupts condition. */ printk("Cnode %d II has seen the ICMR condition\n", hinfo->h_cnodeid); printk("***** Please file PV with the above messages *****\n"); /* panic("We have to panic to prevent further unknown states ..\n"); */ } #endif /* * Identify the reason for error. */ wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); if (wstat.ii_wstat_fld_s.w_crazy) { char *reason; /* * We can do a couple of things here. * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check * which of these caused the CRAZY bit to be set. * You may be able to check if the Link is up really. */ if (wstat.ii_wstat_fld_s.w_tx_mx_rty) reason = "Micro Packet Retry Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_tail_to) reason = "Crosstalk Tail Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_crd_to) reason = "Crosstalk Credit Timeout"; else { hubreg_t hubii_imem; /* * Check if widget 0 has been marked as shutdown, or * if BTE 0/1 has been marked. */ hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); if (hubii_imem & IIO_IMEM_W0ESD) reason = "Hub Widget 0 has been Shutdown"; else if (hubii_imem & IIO_IMEM_B0ESD) reason = "BTE 0 has been shutdown"; else if (hubii_imem & IIO_IMEM_B1ESD) reason = "BTE 1 has been shutdown"; else reason = "Unknown"; } /* * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ ilcsr.ii_ilcsr_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_ILCSR); if (ilcsr.ii_ilcsr_fld_s.i_llp_en == 1) { /* Link is enabled */ printk("Hub %d, cnode %d to Xtalk Link failed (II_ECRAZY) Reason: %s", hinfo->h_nasid, hinfo->h_cnodeid, reason); } } /* * Before processing any interrupt related information, clear all * error indication and reenable interrupts. This will prevent * lost interrupts due to the interrupt handler scanning past a PRB/CRB * which has not errorred yet and then the PRB/CRB goes into error. * Note, PRB errors are cleared individually. */ REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xff0000); idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); /* * It's a toss as to which one among PRB/CRB to check first. * Current decision is based on the severity of the errors. * IO CRB errors tend to be more severe than PRB errors. * * It is possible for BTE errors to have been handled already, so we * may not see any errors handled here. */ (void)hubiio_crb_error_handler(hub_v, hinfo); (void)hubiio_prb_error_handler(hub_v, hinfo); return IRQ_HANDLED; }
/* ARGSUSED */ static void assign_widgets_to_volunteers(vertex_hdl_t xswitch, vertex_hdl_t hubv) { xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; xwidgetnum_t widgetnum; int num_volunteer; nasid_t nasid; hubinfo_t hubinfo; extern int iobrick_type_get_nasid(nasid_t); hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; xswitch_info = xswitch_info_get(xswitch); ASSERT(xswitch_info != NULL); (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { if (!is_headless_node_vertex(hubv)) printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%p has " " no info label", (void *)xswitch); return; } num_volunteer = xvolinfo->xswitch_volunteer_count; ASSERT(num_volunteer > 0); /* Assign master hub for xswitch itself. */ if (HUB_WIDGET_ID_MIN > 0) { hubv = xvolinfo->xswitch_volunteer[0]; xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); } /* * TBD: Use administrative information to alter assignment of * widgets to hubs. */ for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { int i; /* * Ignore disabled/empty ports. */ if (!xbow_port_io_enabled(nasid, widgetnum)) continue; /* * If this is the master IO board, assign it to the same * hub that owned it in the prom. */ if (is_master_baseio_nasid_widget(nasid, widgetnum)) { extern nasid_t snia_get_master_baseio_nasid(void); for (i=0; i<num_volunteer; i++) { hubv = xvolinfo->xswitch_volunteer[i]; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; if (nasid == snia_get_master_baseio_nasid()) goto do_assignment; } panic("Nasid == %d, console nasid == %d", nasid, snia_get_master_baseio_nasid()); } /* * Assuming that we're dual-hosted and that PCI cards * are naturally placed left-to-right, alternate PCI * buses across both Cbricks. For Pbricks, and Ibricks, * io_brick_map_widget() returns the PCI bus number * associated with the given brick type and widget number. * For Xbricks, it returns the XIO slot number. */ i = 0; if (num_volunteer > 1) { int bt; bt = iobrick_type_get_nasid(nasid); if (bt >= 0) { i = io_brick_map_widget(bt, widgetnum) & 1; } } hubv = xvolinfo->xswitch_volunteer[i]; do_assignment: /* * At this point, we want to make hubv the master of widgetnum. */ xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); } xswitch_volunteer_delete(xswitch); }
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 }
/*ARGSUSED*/ void hubii_eint_handler (int irq, void *arg, struct pt_regs *ep) { devfs_handle_t hub_v; hubinfo_t hinfo; ii_wstat_u_t wstat; hubreg_t idsr; panic("Hubii interrupt\n"); #ifdef ajm /* * If the NI has a problem, everyone has a problem. We shouldn't * even attempt to handle other errors when an NI error is present. */ if (check_ni_errors()) { hubni_error_handler("II interrupt", 1); /* NOTREACHED */ } /* two levels of casting avoids compiler warning.!! */ hub_v = (devfs_handle_t)(long)(arg); ASSERT(hub_v); hubinfo_get(hub_v, &hinfo); /* * Identify the reason for error. */ wstat.ii_wstat_regval = REMOTE_HUB_L(hinfo->h_nasid, IIO_WSTAT); if (wstat.ii_wstat_fld_s.w_crazy) { char *reason; /* * We can do a couple of things here. * Look at the fields TX_MX_RTY/XT_TAIL_TO/XT_CRD_TO to check * which of these caused the CRAZY bit to be set. * You may be able to check if the Link is up really. */ if (wstat.ii_wstat_fld_s.w_tx_mx_rty) reason = "Micro Packet Retry Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_tail_to) reason = "Crosstalk Tail Timeout"; else if (wstat.ii_wstat_fld_s.w_xt_crd_to) reason = "Crosstalk Credit Timeout"; else { hubreg_t hubii_imem; /* * Check if widget 0 has been marked as shutdown, or * if BTE 0/1 has been marked. */ hubii_imem = REMOTE_HUB_L(hinfo->h_nasid, IIO_IMEM); if (hubii_imem & IIO_IMEM_W0ESD) reason = "Hub Widget 0 has been Shutdown"; else if (hubii_imem & IIO_IMEM_B0ESD) reason = "BTE 0 has been shutdown"; else if (hubii_imem & IIO_IMEM_B1ESD) reason = "BTE 1 has been shutdown"; else reason = "Unknown"; } /* * Note: we may never be able to print this, if the II talking * to Xbow which hosts the console is dead. */ printk("Hub %d to Xtalk Link failed (II_ECRAZY) Reason: %s", hinfo->h_cnodeid, reason); } /* * It's a toss as to which one among PRB/CRB to check first. * Current decision is based on the severity of the errors. * IO CRB errors tend to be more severe than PRB errors. * * It is possible for BTE errors to have been handled already, so we * may not see any errors handled here. */ (void)hubiio_crb_error_handler(hub_v, hinfo); (void)hubiio_prb_error_handler(hub_v, hinfo); /* * If we reach here, it indicates crb/prb handlers successfully * handled the error. So, re-enable II to send more interrupt * and return. */ REMOTE_HUB_S(hinfo->h_nasid, IIO_IECLR, 0xffffff); idsr = REMOTE_HUB_L(hinfo->h_nasid, IIO_IIDSR) & ~IIO_IIDSR_SENT_MASK; REMOTE_HUB_S(hinfo->h_nasid, IIO_IIDSR, idsr); #endif /* ajm */ }
/* ARGSUSED */ static void assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) { xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; xwidgetnum_t widgetnum; int num_volunteer; nasid_t nasid; hubinfo_t hubinfo; extern int iobrick_type_get_nasid(nasid_t); hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; xswitch_info = xswitch_info_get(xswitch); ASSERT(xswitch_info != NULL); (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { return; } num_volunteer = xvolinfo->xswitch_volunteer_count; ASSERT(num_volunteer > 0); /* Assign master hub for xswitch itself. */ if (HUB_WIDGET_ID_MIN > 0) { hubv = xvolinfo->xswitch_volunteer[0]; xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); } /* * TBD: Use administrative information to alter assignment of * widgets to hubs. */ for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { int i; /* * Ignore disabled/empty ports. */ if (!xbow_port_io_enabled(nasid, widgetnum)) continue; /* * If this is the master IO board, assign it to the same * hub that owned it in the prom. */ if (is_master_nasid_widget(nasid, widgetnum)) { for (i=0; i<num_volunteer; i++) { hubv = xvolinfo->xswitch_volunteer[i]; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; if (nasid == get_console_nasid()) goto do_assignment; } } /* * Assuming that we're dual-hosted and that PCI cards * are naturally placed left-to-right, alternate PCI * buses across both Cbricks. For Pbricks, and Ibricks, * io_brick_map_widget() returns the PCI bus number * associated with the given brick type and widget number. * For Xbricks, it returns the XIO slot number. */ i = 0; if (num_volunteer > 1) { int bt; bt = iobrick_type_get_nasid(nasid); if (bt >= 0) { /* * PXBRICK has two busses per widget so this * algorithm wouldn't work (all busses would * be assigned to one volunteer). Change the * bricktype to PBRICK whose mapping is setup * suchthat 2 of the PICs will be assigned to * one volunteer and the other one will be * assigned to the other volunteer. */ if (bt == MODULE_PXBRICK) bt = MODULE_PBRICK; i = io_brick_map_widget(bt, widgetnum) & 1; } } hubv = xvolinfo->xswitch_volunteer[i]; do_assignment: /* * At this point, we want to make hubv the master of widgetnum. */ xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); } xswitch_volunteer_delete(xswitch); }
/* ARGSUSED */ hub_piomap_t hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, size_t byte_count_max, /* maximum size of a mapping */ unsigned flags) /* defined in sys/pio.h */ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); devfs_handle_t hubv = xwidget_info_master_get(widget_info); hubinfo_t hubinfo; hub_piomap_t bw_piomap; int bigwin, free_bw_index; nasid_t nasid; volatile hubreg_t junk; int s; /* sanity check */ if (byte_count_max > byte_count) return(NULL); hubinfo_get(hubv, &hubinfo); /* If xtalk_addr range is mapped by a small window, we don't have * to do much */ if (xtalk_addr + byte_count <= SWIN_SIZE) return(hubinfo_swin_piomap_get(hubinfo, (int)widget)); /* We need to use a big window mapping. */ /* * TBD: Allow requests that would consume multiple big windows -- * split the request up and use multiple mapping entries. * For now, reject requests that span big windows. */ if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE) return(NULL); /* Round xtalk address down for big window alignement */ xtalk_addr = xtalk_addr & ~(BWIN_SIZE-1); /* * Check to see if an existing big window mapping will suffice. */ tryagain: free_bw_index = -1; s = mutex_spinlock(&hubinfo->h_bwlock); for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { bw_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin); /* If mapping is not valid, skip it */ if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)) { free_bw_index = bigwin; continue; } /* * If mapping is UNFIXED, skip it. We don't allow sharing * of UNFIXED mappings, because this would allow starvation. */ if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED)) continue; if ( xtalk_addr == bw_piomap->hpio_xtalk_info.xp_xtalk_addr && widget == bw_piomap->hpio_xtalk_info.xp_target) { bw_piomap->hpio_holdcnt++; mutex_spinunlock(&hubinfo->h_bwlock, s); return(bw_piomap); } } /* * None of the existing big window mappings will work for us -- * we need to establish a new mapping. */ /* Insure that we don't consume all big windows with FIXED mappings */ if (flags & PIOMAP_FIXED) { if (hubinfo->h_num_big_window_fixed < HUB_NUM_BIG_WINDOW-1) { ASSERT(free_bw_index >= 0); hubinfo->h_num_big_window_fixed++; } else { bw_piomap = NULL; goto done; } } else { /* PIOMAP_UNFIXED */ if (free_bw_index < 0) { if (flags & PIOMAP_NOSLEEP) { bw_piomap = NULL; goto done; } sv_wait(&hubinfo->h_bwwait, PZERO, &hubinfo->h_bwlock, s); goto tryagain; } } /* OK! Allocate big window free_bw_index for this mapping. */ /* * The code below does a PIO write to setup an ITTE entry. * We need to prevent other CPUs from seeing our updated memory * shadow of the ITTE (in the piomap) until the ITTE entry is * actually set up; otherwise, another CPU might attempt a PIO * prematurely. * * Also, the only way we can know that an entry has been received * by the hub and can be used by future PIO reads/writes is by * reading back the ITTE entry after writing it. * * For these two reasons, we PIO read back the ITTE entry after * we write it. */ nasid = hubinfo->h_nasid; IIO_ITTE_PUT(nasid, free_bw_index, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); junk = HUB_L(IIO_ITTE_GET(nasid, free_bw_index)); bw_piomap = hubinfo_bwin_piomap_get(hubinfo, free_bw_index); bw_piomap->hpio_xtalk_info.xp_dev = dev; bw_piomap->hpio_xtalk_info.xp_target = widget; bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr; bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index); bw_piomap->hpio_holdcnt++; bw_piomap->hpio_bigwin_num = free_bw_index; if (flags & PIOMAP_FIXED) bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED; else bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID; done: mutex_spinunlock(&hubinfo->h_bwlock, s); return(bw_piomap); }
/* * >>> bte_crb_error_handler needs to be broken into two parts. The * first should cleanup the CRB. The second should wait until all bte * related CRB's are complete and then do the error reset. */ void bte_crb_error_handler(devfs_handle_t hub_v, int btenum, int crbnum, ioerror_t *ioe, int bteop) /* * Function: bte_crb_error_handler * Purpose: Process a CRB for a specific HUB/BTE * Parameters: hub_v - vertex of hub in HW graph * btenum - bte number on hub (0 == a, 1 == b) * crbnum - crb number being processed * Notes: * This routine assumes serialization at a higher level. A CRB * should not be processed more than once. The error recovery * follows the following sequence - if you change this, be real * sure about what you are doing. * */ { hubinfo_t hinfo; icrba_t crba; icrbb_t crbb; nasid_t n; hubreg_t iidsr, imem, ieclr; hubinfo_get(hub_v, &hinfo); n = hinfo->h_nasid; /* * The following 10 lines (or so) are adapted from IRIXs * bte_crb_error function. No clear documentation tells * why the crb needs to complete normally in order for * the BTE to resume normal operations. This first step * appears vital! */ /* * Zero error and error code to prevent error_dump complaining * about these CRBs. Copy the CRB to the notification line. * The crb address is in shub format (physical address shifted * right by cacheline size). */ crbb.ii_icrb0_b_regval = REMOTE_HUB_L(n, IIO_ICRB_B(crbnum)); crbb.b_error=0; crbb.b_ecode=0; REMOTE_HUB_S(n, IIO_ICRB_B(crbnum), crbb.ii_icrb0_b_regval); crba.ii_icrb0_a_regval = REMOTE_HUB_L(n, IIO_ICRB_A(crbnum)); crba.a_addr = TO_PHYS((u64)&nodepda->bte_if[btenum].notify) >> 3; crba.a_valid = 1; REMOTE_HUB_S(n, IIO_ICRB_A(crbnum), crba.ii_icrb0_a_regval); REMOTE_HUB_S(n, IIO_ICCR, IIO_ICCR_PENDING | IIO_ICCR_CMD_FLUSH | crbnum); while (REMOTE_HUB_L(n, IIO_ICCR) & IIO_ICCR_PENDING) ; /* Terminate the BTE. */ /* >>> The other bte transfer will need to be restarted. */ HUB_L((shubreg_t *)((nodepda->bte_if[btenum].bte_base_addr + IIO_IBCT0 - IIO_IBLS0))); imem = REMOTE_HUB_L(n, IIO_IMEM); ieclr = REMOTE_HUB_L(n, IIO_IECLR); if (btenum == 0) { imem |= IIO_IMEM_W0ESD | IIO_IMEM_B0ESD; ieclr|= IECLR_BTE0; } else { imem |= IIO_IMEM_W0ESD | IIO_IMEM_B1ESD; ieclr|= IECLR_BTE1; } REMOTE_HUB_S(n, IIO_IMEM, imem); REMOTE_HUB_S(n, IIO_IECLR, ieclr); iidsr = REMOTE_HUB_L(n, IIO_IIDSR); iidsr &= ~IIO_IIDSR_SENT_MASK; iidsr |= IIO_IIDSR_ENB_MASK; REMOTE_HUB_S(n, IIO_IIDSR, iidsr); bte_reset_nasid(n); *nodepda->bte_if[btenum].most_rcnt_na = IBLS_ERROR; }
/* * pci_bus_map_create() - Called by pci_bus_to_hcl_cvlink() to finish the job. * * Linux PCI Bus numbers are assigned from lowest module_id numbers * (rack/slot etc.) starting from HUB_WIDGET_ID_MAX down to * HUB_WIDGET_ID_MIN: * widgetnum 15 gets lower Bus Number than widgetnum 14 etc. * * Given 2 modules 001c01 and 001c02 we get the following mappings: * 001c01, widgetnum 15 = Bus number 0 * 001c01, widgetnum 14 = Bus number 1 * 001c02, widgetnum 15 = Bus number 3 * 001c02, widgetnum 14 = Bus number 4 * etc. * * The rational for starting Bus Number 0 with Widget number 15 is because * the system boot disks are always connected via Widget 15 Slot 0 of the * I-brick. Linux creates /dev/sd* devices(naming) strating from Bus Number 0 * Therefore, /dev/sda1 will be the first disk, on Widget 15 of the lowest * module id(Master Cnode) of the system. * */ static int pci_bus_map_create(devfs_handle_t xtalk) { devfs_handle_t master_node_vertex = NULL; devfs_handle_t xwidget = NULL; devfs_handle_t pci_bus = NULL; hubinfo_t hubinfo = NULL; xwidgetnum_t widgetnum; char pathname[128]; graph_error_t rv; /* * Loop throught this vertex and get the Xwidgets .. */ for (widgetnum = HUB_WIDGET_ID_MAX; widgetnum >= HUB_WIDGET_ID_MIN; widgetnum--) { #if 0 { int pos; char dname[256]; pos = devfs_generate_path(xtalk, dname, 256); printk("%s : path= %s\n", __FUNCTION__, &dname[pos]); } #endif sprintf(pathname, "%d", widgetnum); xwidget = NULL; /* * Example - /hw/module/001c16/Pbrick/xtalk/8 is the xwidget * /hw/module/001c16/Pbrick/xtalk/8/pci/1 is device */ rv = hwgraph_traverse(xtalk, pathname, &xwidget); if ( (rv != GRAPH_SUCCESS) ) { if (!xwidget) continue; } sprintf(pathname, "%d/"EDGE_LBL_PCI, widgetnum); pci_bus = NULL; if (hwgraph_traverse(xtalk, pathname, &pci_bus) != GRAPH_SUCCESS) if (!pci_bus) continue; /* * Assign the correct bus number and also the nasid of this * pci Xwidget. * * Should not be any race here ... */ num_bridges++; busnum_to_pcibr_vhdl[num_bridges - 1] = pci_bus; /* * Get the master node and from there get the NASID. */ master_node_vertex = device_master_get(xwidget); if (!master_node_vertex) { printk("WARNING: pci_bus_map_create: Unable to get .master for vertex 0x%p\n", (void *)xwidget); } hubinfo_get(master_node_vertex, &hubinfo); if (!hubinfo) { printk("WARNING: pci_bus_map_create: Unable to get hubinfo for master node vertex 0x%p\n", (void *)master_node_vertex); return(1); } else { busnum_to_nid[num_bridges - 1] = hubinfo->h_nasid; } /* * Pre assign DMA maps needed for 32 Bits Page Map DMA. */ busnum_to_atedmamaps[num_bridges - 1] = (void *) kmalloc( sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS, GFP_KERNEL); if (!busnum_to_atedmamaps[num_bridges - 1]) printk("WARNING: pci_bus_map_create: Unable to precreate ATE DMA Maps for busnum %d vertex 0x%p\n", num_bridges - 1, (void *)xwidget); memset(busnum_to_atedmamaps[num_bridges - 1], 0x0, sizeof(struct sn_dma_maps_s) * MAX_ATE_MAPS); } return(0); }
/* ARGSUSED */ static void assign_widgets_to_volunteers(devfs_handle_t xswitch, devfs_handle_t hubv) { int curr_volunteer, num_volunteer; xwidgetnum_t widgetnum; xswitch_info_t xswitch_info; xswitch_vol_t xvolinfo = NULL; nasid_t nasid; hubinfo_t hubinfo; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; xswitch_info = xswitch_info_get(xswitch); ASSERT(xswitch_info != NULL); (void)hwgraph_info_get_LBL(xswitch, INFO_LBL_XSWITCH_VOL, (arbitrary_info_t *)&xvolinfo); if (xvolinfo == NULL) { #ifdef LATER if (!is_headless_node_vertex(hubv)) { #if defined(SUPPORT_PRINTING_V_FORMAT) printk(KERN_WARNING "assign_widgets_to_volunteers:vertex %v has " " no info label", xswitch); #else printk(KERN_WARNING "assign_widgets_to_volunteers:vertex 0x%x has " " no info label", xswitch); #endif } #endif /* LATER */ return; } num_volunteer = xvolinfo->xswitch_volunteer_count; ASSERT(num_volunteer > 0); curr_volunteer = 0; /* Assign master hub for xswitch itself. */ if (HUB_WIDGET_ID_MIN > 0) { hubv = xvolinfo->xswitch_volunteer[0]; xswitch_info_master_assignment_set(xswitch_info, (xwidgetnum_t)0, hubv); } /* * TBD: Use administrative information to alter assignment of * widgets to hubs. */ for (widgetnum=HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) { /* * Ignore disabled/empty ports. */ if (!xbow_port_io_enabled(nasid, widgetnum)) continue; /* * If this is the master IO board, assign it to the same * hub that owned it in the prom. */ if (is_master_nasid_widget(nasid, widgetnum)) { int i; for (i=0; i<num_volunteer; i++) { hubv = xvolinfo->xswitch_volunteer[i]; hubinfo_get(hubv, &hubinfo); nasid = hubinfo->h_nasid; if (nasid == get_console_nasid()) goto do_assignment; } #ifdef LATER PRINT_PANIC("Nasid == %d, console nasid == %d", nasid, get_console_nasid()); #endif } /* * Do a round-robin assignment among the volunteer nodes. */ hubv = xvolinfo->xswitch_volunteer[curr_volunteer]; curr_volunteer = (curr_volunteer + 1) % num_volunteer; /* fall through */ do_assignment: /* * At this point, we want to make hubv the master of widgetnum. */ xswitch_info_master_assignment_set(xswitch_info, widgetnum, hubv); } xswitch_volunteer_delete(xswitch); }