📄 pcibr_rrb.c
字号:
if ( is_pic(bridge) ) { /* wait until RRB has no outstanduing XIO packets. */ while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } /* if the RRB has data, drain it. */ if (status & BRIDGE_RRB_VALID(rrb)) { bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); /* wait until RRB is no longer valid. */ while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } } } else { if (io_get_sh_swapper(NASID_GET(bridge))) { while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_INUSE(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } /* if the RRB has data, drain it. */ if (status & BRIDGE_RRB_VALID(rrb)) { BRIDGE_REG_SET32((&bridge->b_resp_clear)) = __swab32(BRIDGE_RRB_CLEAR(rrb)); /* wait until RRB is no longer valid. */ while ((status = BRIDGE_REG_GET32((&bridge->b_resp_status))) & BRIDGE_RRB_VALID(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } } } else { /* io_get_sh_swapper(NASID_GET(bridge)) */ while ((status = bridge->b_resp_status) & BRIDGE_RRB_INUSE(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } /* if the RRB has data, drain it. */ if (status & BRIDGE_RRB_VALID(rrb)) { bridge->b_resp_clear = BRIDGE_RRB_CLEAR(rrb); /* wait until RRB is no longer valid. */ while ((status = bridge->b_resp_status) & BRIDGE_RRB_VALID(rrb)) { ; /* XXX- beats on bridge. bad idea? */ } } } }}/* * Flush the specified rrb by calling do_pcibr_rrb_clear(). This * routine is just a wrapper to make sure the rrb is disabled * before calling do_pcibr_rrb_clear(). */voiddo_pcibr_rrb_flush(bridge_t *bridge, int rrbn){ reg_p rrbp = &bridge->b_rrb_map[rrbn & 1].reg; bridgereg_t rrbv; int shft = (RRB_SIZE * (rrbn >> 1)); unsigned long ebit = RRB_ENABLE_BIT(bridge) << shft; if ( is_pic(bridge) ) { rrbv = *rrbp; } else { if (io_get_sh_swapper(NASID_GET(bridge))) { rrbv = BRIDGE_REG_GET32((&rrbp)); } else { rrbv = *rrbp; } } if (rrbv & ebit) { if ( is_pic(bridge) ) { *rrbp = rrbv & ~ebit; } else { if (io_get_sh_swapper(NASID_GET(bridge))) { BRIDGE_REG_SET32((&rrbp)) = __swab32((rrbv & ~ebit)); } else { *rrbp = rrbv & ~ebit; } } } do_pcibr_rrb_clear(bridge, rrbn); if (rrbv & ebit) { if ( is_pic(bridge) ) { *rrbp = rrbv; } else { if (io_get_sh_swapper(NASID_GET(bridge))) { BRIDGE_REG_SET32((&rrbp)) = __swab32(rrbv); } else { *rrbp = rrbv; } } }}voiddo_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft, int slot, int vchan, int more_rrbs){ bridge_t *bridge = pcibr_soft->bs_base; int got; for (got = 0; got < more_rrbs; ++got) { if (pcibr_soft->bs_rrb_res[slot] > 0) pcibr_soft->bs_rrb_res[slot]--; else if (pcibr_soft->bs_rrb_avail[slot & 1] > 0) pcibr_soft->bs_rrb_avail[slot & 1]--; else break; if (do_pcibr_rrb_alloc(bridge, slot, vchan, 1) < 0) break; pcibr_soft->bs_rrb_valid[slot][vchan]++; } PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl, "do_pcibr_rrb_autoalloc: added %d (of %d requested) RRBs " "to slot %d, vchan %d\n", got, more_rrbs, PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), vchan)); pcibr_rrb_debug("do_pcibr_rrb_autoalloc", pcibr_soft);}/* * Flush all the rrb's assigned to the specified connection point. */voidpcibr_rrb_flush(devfs_handle_t pconn_vhdl){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pcibr_soft_t pcibr_soft = (pcibr_soft_t)pciio_info_mfast_get(pciio_info); pciio_slot_t slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; bridgereg_t tmp; uint16_t enable_bit, pdev_bits, rrb_bits, rrb_mask; int rrb_index; unsigned long s; enable_bit = RRB_ENABLE_BIT(bridge); pdev_bits = SLOT_2_PDEV(bridge, slot); rrb_bits = enable_bit | pdev_bits; rrb_mask = enable_bit | ((NUM_PDEV_BITS(bridge) << 1) - 1); tmp = bridge->b_rrb_map[SLOT_2_RRB_REG(bridge, slot)].reg; s = pcibr_lock(pcibr_soft); for (rrb_index = 0; rrb_index < 8; rrb_index++) { int evn_odd = SLOT_2_RRB_REG(bridge, slot); if ((tmp & rrb_mask) == rrb_bits) do_pcibr_rrb_flush(bridge, (2 * rrb_index) + evn_odd); tmp = (tmp >> RRB_SIZE); } pcibr_unlock(pcibr_soft, s);}/* * Device driver interface to flush the write buffers for a specified * device hanging off the bridge. */intpcibr_wrb_flush(devfs_handle_t pconn_vhdl){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; volatile bridgereg_t *wrb_flush; wrb_flush = &(bridge->b_wr_req_buf[pciio_slot].reg); if ( IS_PIC_SOFT(pcibr_soft) ) { while (*wrb_flush) ; } else { if (io_get_sh_swapper(NASID_GET(bridge))) { while (BRIDGE_REG_GET32((wrb_flush))); } else { while (*wrb_flush) ; } } return(0);}/* * Device driver interface to request RRBs for a specified device * hanging off a Bridge. The driver requests the total number of * RRBs it would like for the normal channel (vchan0) and for the * "virtual channel" (vchan1). The actual number allocated to each * channel is returned. * * If we cannot allocate at least one RRB to a channel that needs * at least one, return -1 (failure). Otherwise, satisfy the request * as best we can and return 0. */intpcibr_rrb_alloc(devfs_handle_t pconn_vhdl, int *count_vchan0, int *count_vchan1){ pciio_info_t pciio_info = pciio_info_get(pconn_vhdl); pciio_slot_t pciio_slot = PCIBR_INFO_SLOT_GET_INT(pciio_info); pcibr_soft_t pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; int desired_vchan0; int desired_vchan1; int orig_vchan0; int orig_vchan1; int delta_vchan0; int delta_vchan1; int final_vchan0; int final_vchan1; int avail_rrbs; int res_rrbs; int vchan_total; int vchan; unsigned long s; int error; /* * TBD: temper request with admin info about RRB allocation, * and according to demand from other devices on this Bridge. * * One way of doing this would be to allocate two RRBs * for each device on the bus, before any drivers start * asking for extras. This has the weakness that one * driver might not give back an "extra" RRB until after * another driver has already failed to get one that * it wanted. */ s = pcibr_lock(pcibr_soft); vchan_total = NUMBER_VCHANNELS(bridge); /* Save the boot-time RRB configuration for this slot */ if (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][VCHAN0] < 0) { for (vchan = 0; vchan < vchan_total; vchan++) pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] = pcibr_soft->bs_rrb_valid[pciio_slot][vchan]; pcibr_soft->bs_rrb_res_dflt[pciio_slot] = pcibr_soft->bs_rrb_res[pciio_slot]; } /* How many RRBs do we own? */ orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0]; orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1]; /* How many RRBs do we want? */ desired_vchan0 = count_vchan0 ? *count_vchan0 : orig_vchan0; desired_vchan1 = count_vchan1 ? *count_vchan1 : orig_vchan1; /* How many RRBs are free? */ avail_rrbs = pcibr_soft->bs_rrb_avail[pciio_slot & 1] + pcibr_soft->bs_rrb_res[pciio_slot]; /* Figure desired deltas */ delta_vchan0 = desired_vchan0 - orig_vchan0; delta_vchan1 = desired_vchan1 - orig_vchan1; /* Trim back deltas to something * that we can actually meet, by * decreasing the ending allocation * for whichever channel wants * more RRBs. If both want the same * number, cut the second channel. * NOTE: do not change the allocation for * a channel that was passed as NULL. */ while ((delta_vchan0 + delta_vchan1) > avail_rrbs) { if (count_vchan0 && (!count_vchan1 || ((orig_vchan0 + delta_vchan0) > (orig_vchan1 + delta_vchan1)))) delta_vchan0--; else delta_vchan1--; } /* Figure final RRB allocations */ final_vchan0 = orig_vchan0 + delta_vchan0; final_vchan1 = orig_vchan1 + delta_vchan1; /* If either channel wants RRBs but our actions * would leave it with none, declare an error, * but DO NOT change any RRB allocations. */ if ((desired_vchan0 && !final_vchan0) || (desired_vchan1 && !final_vchan1)) { error = -1; } else { /* Commit the allocations: free, then alloc. */ if (delta_vchan0 < 0) (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN0, -delta_vchan0); if (delta_vchan1 < 0) (void) do_pcibr_rrb_free(bridge, pciio_slot, VCHAN1, -delta_vchan1); if (delta_vchan0 > 0) (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN0, delta_vchan0); if (delta_vchan1 > 0) (void) do_pcibr_rrb_alloc(bridge, pciio_slot, VCHAN1, delta_vchan1); /* Return final values to caller. */ if (count_vchan0) *count_vchan0 = final_vchan0; if (count_vchan1) *count_vchan1 = final_vchan1; /* prevent automatic changes to this slot's RRBs */ pcibr_soft->bs_rrb_fixed |= 1 << pciio_slot; /* Track the actual allocations, release * any further reservations, and update the * number of available RRBs. */ pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0] = final_vchan0; pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1] = final_vchan1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -