📄 xbow.c
字号:
XEM_ADD_VAR(wid_err_lower); XEM_ADD_VAR(wid_err_addr); XEM_ADD_VAR(port); XEM_ADD_VAR(link_control); XEM_ADD_VAR(link_status); XEM_ADD_VAR(link_aux_status);#if !DEBUG }#endif /* caller will dump raw ioerror data * in DEBUG and kdebug kernels. */ return retval;}#endif /* LATER */voidxbow_update_perf_counters(devfs_handle_t vhdl){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; xbow_perf_link_t *xbow_plink = xbow_soft->xbow_perflink; xbow_perfcount_t perf_reg; unsigned long s; int link, i; for (i = 0; i < XBOW_PERF_COUNTERS; i++, xbow_perf++) { if (xbow_perf->xp_mode == XBOW_MONITOR_NONE) continue; s = mutex_spinlock(&xbow_soft->xbow_perf_lock); perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; link = perf_reg.xb_perf.link_select; (xbow_plink + link)->xlp_cumulative[xbow_perf->xp_curmode] += ((perf_reg.xb_perf.count - xbow_perf->xp_current) & XBOW_COUNTER_MASK); xbow_perf->xp_current = perf_reg.xb_perf.count; mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); } /* Do port /mode multiplexing here */#ifdef LATER (void) timeout(xbow_update_perf_counters, (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT);#endif}xbow_perf_link_t *xbow_get_perf_counters(devfs_handle_t vhdl){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_link_t *xbow_perf_link = xbow_soft->xbow_perflink; return xbow_perf_link;}intxbow_enable_perf_counter(devfs_handle_t vhdl, int link, int mode, int counter){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_perf_t *xbow_perf = xbow_soft->xbow_perfcnt; xbow_linkctrl_t xbow_link_ctrl; xbow_t *xbow = xbow_soft->base; xbow_perfcount_t perf_reg; unsigned long s; int i; link -= BASE_XBOW_PORT; if ((link < 0) || (link >= MAX_XBOW_PORTS)) return -1; if ((mode < XBOW_MONITOR_NONE) || (mode > XBOW_MONITOR_DEST_LINK)) return -1; if ((counter < 0) || (counter >= XBOW_PERF_COUNTERS)) return -1; s = mutex_spinlock(&xbow_soft->xbow_perf_lock); if ((xbow_perf + counter)->xp_mode && mode) { mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); return -1; } for (i = 0; i < XBOW_PERF_COUNTERS; i++) { if (i == counter) continue; if (((xbow_perf + i)->xp_link == link) && ((xbow_perf + i)->xp_mode)) { mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); return -1; } } xbow_perf += counter; xbow_perf->xp_curlink = xbow_perf->xp_link = link; xbow_perf->xp_curmode = xbow_perf->xp_mode = mode; xbow_link_ctrl.xbl_ctrlword = xbow->xb_link_raw[link].link_control; xbow_link_ctrl.xb_linkcontrol.perf_mode = mode; xbow->xb_link_raw[link].link_control = xbow_link_ctrl.xbl_ctrlword; perf_reg.xb_counter_val = *(xbowreg_t *) xbow_perf->xp_perf_reg; perf_reg.xb_perf.link_select = link; *(xbowreg_t *) xbow_perf->xp_perf_reg = perf_reg.xb_counter_val; xbow_perf->xp_current = perf_reg.xb_perf.count;#ifdef LATER (void) timeout(xbow_update_perf_counters, (void *) (__psunsigned_t) vhdl, XBOW_PERF_TIMEOUT);#endif mutex_spinunlock(&xbow_soft->xbow_perf_lock, s); return 0;}xbow_link_status_t *xbow_get_llp_status(devfs_handle_t vhdl){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; return xbow_llp_status;}voidxbow_update_llp_status(devfs_handle_t vhdl){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl); xbow_link_status_t *xbow_llp_status = xbow_soft->xbow_link_status; xbow_t *xbow; xbwX_stat_t lnk_sts; xbow_aux_link_status_t aux_sts; int link; devfs_handle_t xwidget_vhdl; char *xwidget_name; xbow = (xbow_t *) xbow_soft->base; for (link = 0; link < MAX_XBOW_PORTS; link++, xbow_llp_status++) { /* Get the widget name corresponding the current link. * Note : 0 <= link < MAX_XBOW_PORTS(8). * BASE_XBOW_PORT(0x8) <= xwidget number < MAX_PORT_NUM (0x10) */ xwidget_vhdl = xbow_widget_lookup(xbow_soft->busv,link+BASE_XBOW_PORT); xwidget_name = xwidget_name_get(xwidget_vhdl); aux_sts.aux_linkstatus = xbow->xb_link_raw[link].link_aux_status; lnk_sts.linkstatus = xbow->xb_link_raw[link].link_status_clr; if (lnk_sts.link_alive == 0) continue; xbow_llp_status->rx_err_count += aux_sts.xb_aux_linkstatus.rx_err_cnt; xbow_llp_status->tx_retry_count += aux_sts.xb_aux_linkstatus.tx_retry_cnt; if (lnk_sts.linkstatus & ~(XB_STAT_RCV_ERR | XB_STAT_XMT_RTRY_ERR | XB_STAT_LINKALIVE)) {#ifdef LATER PRINT_WARNING("link %d[%s]: bad status 0x%x\n", link, xwidget_name, lnk_sts.linkstatus);#endif } }#ifdef LATER if (xbow_soft->link_monitor) (void) timeout(xbow_update_llp_status, (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT);#endif}intxbow_disable_llp_monitor(devfs_handle_t vhdl){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl); int port; for (port = 0; port < MAX_XBOW_PORTS; port++) { xbow_soft->xbow_link_status[port].rx_err_count = 0; xbow_soft->xbow_link_status[port].tx_retry_count = 0; } xbow_soft->link_monitor = 0; return 0;}intxbow_enable_llp_monitor(devfs_handle_t vhdl){ xbow_soft_t xbow_soft = xbow_soft_get(vhdl);#ifdef LATER (void) timeout(xbow_update_llp_status, (void *) (__psunsigned_t) vhdl, XBOW_STATS_TIMEOUT);#endif xbow_soft->link_monitor = 1; return 0;}intxbow_reset_link(devfs_handle_t xconn_vhdl){ xwidget_info_t widget_info; xwidgetnum_t port; xbow_t *xbow; xbowreg_t ctrl; xbwX_stat_t stat; unsigned itick; unsigned dtick; static int ticks_per_ms = 0; if (!ticks_per_ms) { itick = get_timestamp(); us_delay(1000); ticks_per_ms = get_timestamp() - itick; } widget_info = xwidget_info_get(xconn_vhdl); port = xwidget_info_id_get(widget_info);#ifdef XBOW_K1PTR /* defined if we only have one xbow ... */ xbow = XBOW_K1PTR;#else { devfs_handle_t xbow_vhdl; xbow_soft_t xbow_soft; hwgraph_traverse(xconn_vhdl, ".master/xtalk/0/xbow", &xbow_vhdl); xbow_soft = xbow_soft_get(xbow_vhdl); xbow = xbow_soft->base; }#endif /* * This requires three PIOs (reset the link, check for the * reset, restore the control register for the link) plus * 10us to wait for the reset. We allow up to 1ms for the * widget to come out of reset before giving up and * returning a failure. */ ctrl = xbow->xb_link(port).link_control; xbow->xb_link(port).link_reset = 0; itick = get_timestamp(); while (1) { stat.linkstatus = xbow->xb_link(port).link_status; if (stat.link_alive) break; dtick = get_timestamp() - itick; if (dtick > ticks_per_ms) { return -1; /* never came out of reset */ } DELAY(2); /* don't beat on link_status */ } xbow->xb_link(port).link_control = ctrl; return 0;}/* * Dump xbow registers. * input parameter is either a pointer to * the xbow chip or the vertex handle for * an xbow vertex. */voididbg_xbowregs(int64_t regs){ xbow_t *xbow; int i; xb_linkregs_t *link;#ifdef LATER if (dev_is_vertex((devfs_handle_t) regs)) { devfs_handle_t vhdl = (devfs_handle_t) regs; xbow_soft_t soft = xbow_soft_get(vhdl); xbow = soft->base; } else#endif { xbow = (xbow_t *) regs; }#ifdef LATER qprintf("Printing xbow registers starting at 0x%x\n", xbow); qprintf("wid %x status %x erruppr %x errlower %x control %x timeout %x\n", xbow->xb_wid_id, xbow->xb_wid_stat, xbow->xb_wid_err_upper, xbow->xb_wid_err_lower, xbow->xb_wid_control, xbow->xb_wid_req_timeout); qprintf("intr uppr %x lower %x errcmd %x llp ctrl %x arb_reload %x\n", xbow->xb_wid_int_upper, xbow->xb_wid_int_lower, xbow->xb_wid_err_cmdword, xbow->xb_wid_llp, xbow->xb_wid_arb_reload);#endif for (i = 8; i <= 0xf; i++) { link = &xbow->xb_link(i);#ifdef LATER qprintf("Link %d registers\n", i); qprintf("\tctrl %x stat %x arbuppr %x arblowr %x auxstat %x\n", link->link_control, link->link_status, link->link_arb_upper, link->link_arb_lower, link->link_aux_status);#endif }}#define XBOW_ARB_RELOAD_TICKS 25 /* granularity: 4 MB/s, max: 124 MB/s */#define GRANULARITY ((100 * 1000000) / XBOW_ARB_RELOAD_TICKS)#define XBOW_BYTES_TO_GBR(BYTES_per_s) (int) (BYTES_per_s / GRANULARITY)#define XBOW_GBR_TO_BYTES(cnt) (bandwidth_t) ((cnt) * GRANULARITY)#define CEILING_BYTES_TO_GBR(gbr, bytes_per_sec) \ ((XBOW_GBR_TO_BYTES(gbr) < bytes_per_sec) ? gbr+1 : gbr)#define XBOW_ARB_GBR_MAX 31#define ABS(x) ((x > 0) ? (x) : (-1 * x)) /* absolute value */intxbow_bytes_to_gbr(bandwidth_t old_bytes_per_sec, bandwidth_t bytes_per_sec){ int gbr_granted; int new_total_gbr; int change_gbr; bandwidth_t new_total_bw;#ifdef GRIO_DEBUG printf("xbow_bytes_to_gbr: old_bytes_per_sec %lld bytes_per_sec %lld\n", old_bytes_per_sec, bytes_per_sec);#endif /* GRIO_DEBUG */ gbr_granted = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(old_bytes_per_sec)), old_bytes_per_sec); new_total_bw = old_bytes_per_sec + bytes_per_sec; new_total_gbr = CEILING_BYTES_TO_GBR((XBOW_BYTES_TO_GBR(new_total_bw)), new_total_bw); change_gbr = new_total_gbr - gbr_granted;#ifdef GRIO_DEBUG printf("xbow_bytes_to_gbr: gbr_granted %d new_total_gbr %d change_gbr %d\n", gbr_granted, new_total_gbr, change_gbr);#endif /* GRIO_DEBUG */ return (change_gbr);}/* Conversion from GBR to bytes */bandwidth_txbow_gbr_to_bytes(int gbr){ return (XBOW_GBR_TO_BYTES(gbr));}/* Given the vhdl for the desired xbow, the src and dest. widget ids * and the req_bw value, this xbow driver entry point accesses the * xbow registers and allocates the desired bandwidth if available. * * If bandwidth allocation is successful, return success else return failure. */intxbow_prio_bw_alloc(devfs_handle_t vhdl, xwidgetnum_t src_wid, xwidgetnum_t dest_wid, unsigned long long old_alloc_bw, unsigned long long req_bw){ xbow_soft_t soft = xbow_soft_get(vhdl); volatile xbowreg_t *xreg; xbowreg_t mask; unsigned long s; int error = 0; bandwidth_t old_bw_BYTES, req_bw_BYTES; xbowreg_t old_xreg; int old_bw_GBR, req_bw_GBR, new_bw_GBR;#ifdef GRIO_DEBUG printf("xbow_prio_bw_alloc: vhdl %d src_wid %d dest_wid %d req_bw %lld\n", (int) vhdl, (int) src_wid, (int) dest_wid, req_bw);#endif ASSERT(XBOW_WIDGET_IS_VALID(src_wid)); ASSERT(XBOW_WIDGET_IS_VALID(dest_wid)); s = mutex_spinlock(&soft->xbow_bw_alloc_lock); /* Get pointer to the correct register */ xreg = XBOW_PRIO_ARBREG_PTR(soft->base, dest_wid, src_wid); /* Get mask for GBR count value */ mask = XB_ARB_GBR_MSK << XB_ARB_GBR_SHFT(src_wid); req_bw_GBR = xbow_bytes_to_gbr(old_alloc_bw, req_bw); req_bw_BYTES = (req_bw_GBR < 0) ? (-1 * xbow_gbr_to_bytes(ABS(req_bw_GBR))) : xbow_gbr_to_bytes(req_bw_GBR);#ifdef GRIO_DEBUG printf("req_bw %lld req_bw_BYTES %lld req_bw_GBR %d\n", req_bw, req_bw_BYTES, req_bw_GBR);#endif /* GRIO_DEBUG */ old_bw_BYTES = soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS]; old_xreg = *xreg; old_bw_GBR = (((*xreg) & mask) >> XB_ARB_GBR_SHFT(src_wid));#ifdef GRIO_DEBUG ASSERT(XBOW_BYTES_TO_GBR(old_bw_BYTES) == old_bw_GBR); printf("old_bw_BYTES %lld old_bw_GBR %d\n", old_bw_BYTES, old_bw_GBR); printf("req_bw_BYTES %lld old_bw_BYTES %lld soft->bw_hiwm %lld\n", req_bw_BYTES, old_bw_BYTES, soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]); #endif /* GRIO_DEBUG */ /* Accept the request only if we don't exceed the destination * port HIWATER_MARK *AND* the max. link GBR arbitration count */ if (((old_bw_BYTES + req_bw_BYTES) <= soft->bw_hiwm[(int) dest_wid - MAX_XBOW_PORTS]) && (req_bw_GBR + old_bw_GBR <= XBOW_ARB_GBR_MAX)) { new_bw_GBR = (old_bw_GBR + req_bw_GBR); /* Set this in the xbow link register */ *xreg = (old_xreg & ~mask) | \ (new_bw_GBR << XB_ARB_GBR_SHFT(src_wid) & mask); soft->bw_cur_used[(int) dest_wid - MAX_XBOW_PORTS] = xbow_gbr_to_bytes(new_bw_GBR); } else { error = 1; } mutex_spinunlock(&soft->xbow_bw_alloc_lock, s); return (error);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -