📄 pcibr.c
字号:
#if PCIBR_RRB_DEBUG printk("pcibr_rrb_alloc: slot %d set to %d+%d; %d+%d free\n", pciio_slot, final_vchan0, final_vchan1, pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]); for (pciio_slot = 0; pciio_slot < 8; ++pciio_slot) printk("\t%d+%d+%d", 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot], 0xFFF & pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL], pcibr_soft->bs_rrb_res[pciio_slot]); printk("\n");#endif error = 0; } pcibr_unlock(pcibr_soft, s); return error;}/* * Device driver interface to check the current state * of the RRB allocations. * * pconn_vhdl is your PCI connection point (specifies which * PCI bus and which slot). * * count_vchan0 points to where to return the number of RRBs * assigned to the primary DMA channel, used by all DMA * that does not explicitly ask for the alternate virtual * channel. * * count_vchan1 points to where to return the number of RRBs * assigned to the secondary DMA channel, used when * PCIBR_VCHAN1 and PCIIO_DMA_A64 are specified. * * count_reserved points to where to return the number of RRBs * that have been automatically reserved for your device at * startup, but which have not been assigned to a * channel. RRBs must be assigned to a channel to be used; * this can be done either with an explicit pcibr_rrb_alloc * call, or automatically by the infrastructure when a DMA * translation is constructed. Any call to pcibr_rrb_alloc * will release any unassigned reserved RRBs back to the * free pool. * * count_pool points to where to return the number of RRBs * that are currently unassigned and unreserved. This * number can (and will) change as other drivers make calls * to pcibr_rrb_alloc, or automatically allocate RRBs for * DMA beyond their initial reservation. * * NULL may be passed for any of the return value pointers * the caller is not interested in. * * The return value is "0" if all went well, or "-1" if * there is a problem. Additionally, if the wrong vertex * is passed in, one of the subsidiary support functions * could panic with a "bad pciio fingerprint." */intpcibr_rrb_check(devfs_handle_t pconn_vhdl, int *count_vchan0, int *count_vchan1, int *count_reserved, int *count_pool){ pciio_info_t pciio_info; pciio_slot_t pciio_slot; pcibr_soft_t pcibr_soft; unsigned s; int error = -1; if ((pciio_info = pciio_info_get(pconn_vhdl)) && (pcibr_soft = (pcibr_soft_t) pciio_info_mfast_get(pciio_info)) && ((pciio_slot = pciio_info_slot_get(pciio_info)) < 8)) { s = pcibr_lock(pcibr_soft); if (count_vchan0) *count_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot]; if (count_vchan1) *count_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]; if (count_reserved) *count_reserved = pcibr_soft->bs_rrb_res[pciio_slot]; if (count_pool) *count_pool = pcibr_soft->bs_rrb_avail[pciio_slot & 1]; error = 0; pcibr_unlock(pcibr_soft, s); } return error;}/* pcibr_alloc_all_rrbs allocates all the rrbs available in the quantities * requested for each of the devies. The evn_odd argument indicates whether * allcoation for the odd or even rrbs is requested and next group of four pairse * are the amount to assign to each device (they should sum to <= 8) and * whether to set the viritual bit for that device (1 indictaes yes, 0 indicates no) * the devices in order are either 0, 2, 4, 6 or 1, 3, 5, 7 * if even_odd is even we alloc even rrbs else we allocate odd rrbs * returns 0 if no errors else returns -1 */intpcibr_alloc_all_rrbs(devfs_handle_t vhdl, int even_odd, int dev_1_rrbs, int virt1, int dev_2_rrbs, int virt2, int dev_3_rrbs, int virt3, int dev_4_rrbs, int virt4){ devfs_handle_t pcibr_vhdl;#ifdef colin pcibr_soft_t pcibr_soft;#else pcibr_soft_t pcibr_soft = NULL;#endif bridge_t *bridge = NULL; uint32_t rrb_setting = 0; int rrb_shift = 7; uint32_t cur_rrb; int dev_rrbs[4]; int virt[4]; int i, j; unsigned s; if (GRAPH_SUCCESS == hwgraph_traverse(vhdl, EDGE_LBL_PCI, &pcibr_vhdl)) { pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (pcibr_soft) bridge = pcibr_soft->bs_base; hwgraph_vertex_unref(pcibr_vhdl); } if (bridge == NULL) bridge = (bridge_t *) xtalk_piotrans_addr (vhdl, NULL, 0, sizeof(bridge_t), 0); even_odd &= 1; dev_rrbs[0] = dev_1_rrbs; dev_rrbs[1] = dev_2_rrbs; dev_rrbs[2] = dev_3_rrbs; dev_rrbs[3] = dev_4_rrbs; virt[0] = virt1; virt[1] = virt2; virt[2] = virt3; virt[3] = virt4; if ((dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs) > 8) { return -1; } if ((dev_1_rrbs < 0) || (dev_2_rrbs < 0) || (dev_3_rrbs < 0) || (dev_4_rrbs < 0)) { return -1; } /* walk through rrbs */ for (i = 0; i < 4; i++) { if (virt[i]) { cur_rrb = i | 0xc; cur_rrb = cur_rrb << (rrb_shift * 4); rrb_shift--; rrb_setting = rrb_setting | cur_rrb; dev_rrbs[i] = dev_rrbs[i] - 1; } for (j = 0; j < dev_rrbs[i]; j++) { cur_rrb = i | 0x8; cur_rrb = cur_rrb << (rrb_shift * 4); rrb_shift--; rrb_setting = rrb_setting | cur_rrb; } } if (pcibr_soft) s = pcibr_lock(pcibr_soft); bridge->b_rrb_map[even_odd].reg = rrb_setting; if (pcibr_soft) { pcibr_soft->bs_rrb_fixed |= 0x55 << even_odd; /* since we've "FIXED" the allocations * for these slots, we probably can dispense * with tracking avail/res/valid data, but * keeping it up to date helps debugging. */ pcibr_soft->bs_rrb_avail[even_odd] = 8 - (dev_1_rrbs + dev_2_rrbs + dev_3_rrbs + dev_4_rrbs); pcibr_soft->bs_rrb_res[even_odd + 0] = 0; pcibr_soft->bs_rrb_res[even_odd + 2] = 0; pcibr_soft->bs_rrb_res[even_odd + 4] = 0; pcibr_soft->bs_rrb_res[even_odd + 6] = 0; pcibr_soft->bs_rrb_valid[even_odd + 0] = dev_1_rrbs - virt1; pcibr_soft->bs_rrb_valid[even_odd + 2] = dev_2_rrbs - virt2; pcibr_soft->bs_rrb_valid[even_odd + 4] = dev_3_rrbs - virt3; pcibr_soft->bs_rrb_valid[even_odd + 6] = dev_4_rrbs - virt4; pcibr_soft->bs_rrb_valid[even_odd + 0 + PCIBR_RRB_SLOT_VIRTUAL] = virt1; pcibr_soft->bs_rrb_valid[even_odd + 2 + PCIBR_RRB_SLOT_VIRTUAL] = virt2; pcibr_soft->bs_rrb_valid[even_odd + 4 + PCIBR_RRB_SLOT_VIRTUAL] = virt3; pcibr_soft->bs_rrb_valid[even_odd + 6 + PCIBR_RRB_SLOT_VIRTUAL] = virt4; pcibr_unlock(pcibr_soft, s); } return 0;}/* * pcibr_rrb_flush: chase down all the RRBs assigned * to the specified connection point, and flush * them. */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 pciio_slot = pciio_info_slot_get(pciio_info); bridge_t *bridge = pcibr_soft->bs_base; unsigned s; reg_p rrbp; unsigned rrbm; int i; int rrbn; unsigned sval; unsigned mask; sval = BRIDGE_RRB_EN | (pciio_slot >> 1); mask = BRIDGE_RRB_EN | BRIDGE_RRB_PDEV; rrbn = pciio_slot & 1; rrbp = &bridge->b_rrb_map[rrbn].reg; s = pcibr_lock(pcibr_soft); rrbm = *rrbp; for (i = 0; i < 8; ++i) { if ((rrbm & mask) == sval) do_pcibr_rrb_flush(bridge, rrbn); rrbm >>= 4; rrbn += 2; } pcibr_unlock(pcibr_soft, s);}/* ===================================================================== * Device(x) register management *//* pcibr_try_set_device: attempt to modify Device(x) * for the specified slot on the specified bridge * as requested in flags, limited to the specified * bits. Returns which BRIDGE bits were in conflict, * or ZERO if everything went OK. * * Caller MUST hold pcibr_lock when calling this function. */LOCAL intpcibr_try_set_device(pcibr_soft_t pcibr_soft, pciio_slot_t slot, unsigned flags, bridgereg_t mask){ bridge_t *bridge; pcibr_soft_slot_t slotp; bridgereg_t old; bridgereg_t new; bridgereg_t chg; bridgereg_t bad; bridgereg_t badpmu; bridgereg_t badd32; bridgereg_t badd64; bridgereg_t fix; unsigned s; bridgereg_t xmask; xmask = mask; if (pcibr_soft->bs_xbridge) { if (mask == BRIDGE_DEV_PMU_BITS) xmask = XBRIDGE_DEV_PMU_BITS; if (mask == BRIDGE_DEV_D64_BITS) xmask = XBRIDGE_DEV_D64_BITS; } slotp = &pcibr_soft->bs_slot[slot]; s = pcibr_lock(pcibr_soft); bridge = pcibr_soft->bs_base; old = slotp->bss_device; /* figure out what the desired * Device(x) bits are based on * the flags specified. */ new = old; /* Currently, we inherit anything that * the new caller has not specified in * one way or another, unless we take * action here to not inherit. * * This is needed for the "swap" stuff, * since it could have been set via * pcibr_endian_set -- altho note that * any explicit PCIBR_BYTE_STREAM or * PCIBR_WORD_VALUES will freely override * the effect of that call (and vice * versa, no protection either way). * * I want to get rid of pcibr_endian_set * in favor of tracking DMA endianness * using the flags specified when DMA * channels are created. */#define BRIDGE_DEV_WRGA_BITS (BRIDGE_DEV_PMU_WRGA_EN | BRIDGE_DEV_DIR_WRGA_EN)#define BRIDGE_DEV_SWAP_BITS (BRIDGE_DEV_SWAP_PMU | BRIDGE_DEV_SWAP_DIR) /* Do not use Barrier, Write Gather, * or Prefetch unless asked. * Leave everything else as it * was from the last time. */ new = new & ~BRIDGE_DEV_BARRIER & ~BRIDGE_DEV_WRGA_BITS & ~BRIDGE_DEV_PREF ; /* Generic macro flags */ if (flags & PCIIO_DMA_DATA) {#ifdef colin new = new & ~BRIDGE_DEV_BARRIER /* barrier off */ | BRIDGE_DEV_PREF; /* prefetch on */#else new = (new & ~BRIDGE_DEV_BARRIER) /* barrier off */ | BRIDGE_DEV_PREF; /* prefetch on */#endif } if (flags & PCIIO_DMA_CMD) {#ifdef colin new = new & ~BRIDGE_DEV_PREF /* prefetch off */ & ~BRIDGE_DEV_WRGA_BITS /* write gather off */ | BRIDGE_DEV_BARRIER; /* barrier on */#else new = ((new & ~BRIDGE_DEV_PREF) /* prefetch off */ & ~BRIDGE_DEV_WRGA_BITS) /* write gather off */ | BRIDGE_DEV_BARRIER; /* barrier on */#endif } /* Generic detail flags */ if (flags & PCIIO_WRITE_GATHER) new |= BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_NOWRITE_GATHER) new &= ~BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_PREFETCH) new |= BRIDGE_DEV_PREF; if (flags & PCIIO_NOPREFETCH) new &= ~BRIDGE_DEV_PREF; if (flags & PCIBR_WRITE_GATHER) new |= BRIDGE_DEV_WRGA_BITS; if (flags & PCIBR_NOWRITE_GATHER) new &= ~BRIDGE_DEV_WRGA_BITS; if (flags & PCIIO_BYTE_STREAM) new |= (pcibr_soft->bs_xbridge) ? BRIDGE_DEV_SWAP_DIR : BRIDGE_DEV_SWAP_BITS; if (flags & PCIIO_WORD_VALUES) new &= (pcibr_soft->bs_xbridge) ? ~BRIDGE_DEV_SWAP_DIR : ~BRIDGE_DEV_SWAP_BITS; /* Provider-specific flags */ if (flags & PCIBR_PREFETCH) new |= BRIDGE_DEV_PREF; if (flags & PCIBR_NOPREFETCH) new &= ~BRIDGE_DEV_PREF; if (flags & PCIBR_PRECISE) new |= BRIDGE_DEV_PRECISE; if (flags & PCIBR_NOPRECISE) new &= ~BRIDGE_DEV_PRECISE; if (flags & PCIBR_BARRIER) new |= BRIDGE_DEV_BARRIER; if (flags & PCIBR_NOBARRIER) new &= ~BRIDGE_DEV_BARRIER; if (flags & PCIBR_64BIT) new |= BRIDGE_DEV_DEV_SIZE; if (flags & PCIBR_NO64BIT) new &= ~BRIDGE_DEV_DEV_SIZE; chg = old ^ new; /* what are we changing, */ chg &= xmask; /* of the interesting bits */ if (chg) { badd32 = slotp->bss_d32_uctr ? (BRIDGE_DEV_D32_BITS & chg) : 0; if (pcibr_soft->bs_xbridge) { badpmu = slotp->bss_pmu_uctr ? (XBRIDGE_DEV_PMU_BITS & chg) : 0; badd64 = slotp->bss_d64_uctr ? (XBRIDGE_DEV_D64_BITS & chg) : 0; } else { badpmu = slotp->bss_pmu_uctr ? (BRIDGE_DEV_PMU_BITS & chg) : 0; badd64 = slotp->bss_d64_uctr ? (BRIDGE_DEV_D64_BITS & chg) : 0; } bad = badpmu | badd32 | badd64;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -