📄 pcibr_rrb.c
字号:
- delta_vchan0 - delta_vchan1; pcibr_soft->bs_rrb_res[pciio_slot] = 0; /* * Reserve enough RRBs so this slot's RRB configuration can be * reset to its boot-time default following a hot-plug shut-down */ res_rrbs = (pcibr_soft->bs_rrb_valid_dflt[pciio_slot] - pcibr_soft->bs_rrb_valid[pciio_slot]) + (pcibr_soft->bs_rrb_valid_dflt[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] - pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL]) + (pcibr_soft->bs_rrb_res_dflt[pciio_slot] - pcibr_soft->bs_rrb_res[pciio_slot]); if (res_rrbs > 0) { pcibr_soft->bs_rrb_res[pciio_slot] = res_rrbs; pcibr_soft->bs_rrb_avail[pciio_slot & 1] = pcibr_soft->bs_rrb_avail[pciio_slot & 1] - res_rrbs; } #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 long 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 devices. The evn_odd argument indicates whether * allocation is for the odd or even rrbs. The next group of four argument * pairs indicate the amount of rrbs to be assigned to each device. The first * argument of each pair indicate the total number of rrbs to allocate for that * device. The second argument of each pair indicates how many rrb's from the * first argument should be assigned to the virtual channel. The total of all * of the first arguments should be <= 8. The second argument should be <= the * first argument. * if even_odd = 0 the devices in order are 0, 2, 4, 6 * if even_odd = 1 the devices in order are 1, 3, 5, 7 * 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; pcibr_soft_t pcibr_soft = (pcibr_soft_t)0; 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 long 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]) { for( j = 0; j < virt[i]; j++) { 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 long 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);}/* * pcibr_slot_initial_rrb_alloc * Allocate a default number of rrbs for this slot on * the two channels. This is dictated by the rrb allocation * strategy routine defined per platform. */intpcibr_slot_initial_rrb_alloc(devfs_handle_t pcibr_vhdl, pciio_slot_t slot){ pcibr_soft_t pcibr_soft; pcibr_info_h pcibr_infoh; pcibr_info_t pcibr_info; bridge_t *bridge; int c0, c1, r; pcibr_soft = pcibr_soft_get(pcibr_vhdl); if (!pcibr_soft || !PCIBR_VALID_SLOT(slot)) return(EINVAL); bridge = pcibr_soft->bs_base; /* How may RRBs are on this slot? */ c0 = do_pcibr_rrb_count_valid(bridge, slot); c1 = do_pcibr_rrb_count_valid(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL);#if PCIBR_RRB_DEBUG printk( "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n", slot, c0, c1);#endif /* Do we really need any? */ pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos; pcibr_info = pcibr_infoh[0]; if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && !pcibr_soft->bs_slot[slot].has_host) { if (c0 > 0) do_pcibr_rrb_free(bridge, slot, c0); if (c1 > 0) do_pcibr_rrb_free(bridge, slot + PCIBR_RRB_SLOT_VIRTUAL, c1); pcibr_soft->bs_rrb_valid[slot] = 0x1000; pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = 0x1000; return(ENODEV); } pcibr_soft->bs_rrb_avail[slot & 1] -= c0 + c1; pcibr_soft->bs_rrb_valid[slot] = c0; pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL] = c1; pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); r = 3 - (c0 + c1); if (r > 0) { pcibr_soft->bs_rrb_res[slot] = r; pcibr_soft->bs_rrb_avail[slot & 1] -= r; }#if PCIBR_RRB_DEBUG printk("\t%d+%d+%d", 0xFFF & pcibr_soft->bs_rrb_valid[slot], 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], pcibr_soft->bs_rrb_res[slot]); printk("\n");#endif return(0);}/* * pcibr_initial_rrb * Assign an equal total number of RRBs to all candidate slots, * where the total is the sum of the number of RRBs assigned to * the normal channel, the number of RRBs assigned to the virtual * channel, and the number of RRBs assigned as reserved. * * A candidate slot is a populated slot on a non-SN1 system or * any existing (populated or empty) slot on an SN1 system. * Empty SN1 slots need RRBs to support hot-plug operations. */intpcibr_initial_rrb(devfs_handle_t pcibr_vhdl, pciio_slot_t first, pciio_slot_t last){ pcibr_soft_t pcibr_soft = pcibr_soft_get(pcibr_vhdl); bridge_t *bridge = pcibr_soft->bs_base; pciio_slot_t slot; int c0, c1; int have[2][3]; int res[2]; int eo; have[0][0] = have[0][1] = have[0][2] = 0; have[1][0] = have[1][1] = have[1][2] = 0; res[0] = res[1] = 0; for (slot = 0; slot < 8; ++slot) { /* Initial RRB management; give back RRBs in all non-existent slots */ (void) pcibr_slot_initial_rrb_alloc(pcibr_vhdl, slot); /* Base calculations only on existing slots */ if ((slot >= first) && (slot <= last)) { c0 = pcibr_soft->bs_rrb_valid[slot]; c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]; if ((c0 + c1) < 3) have[slot & 1][c0 + c1]++; } } /* Initialize even/odd slot available RRB counts */ pcibr_soft->bs_rrb_avail[0] = do_pcibr_rrb_count_avail(bridge, 0); pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(bridge, 1); /* * Calculate reserved RRBs for slots based on current RRB usage */ for (eo = 0; eo < 2; eo++) { if ((3 * have[eo][0] + 2 * have[eo][1] + have[eo][2]) <= pcibr_soft->bs_rrb_avail[eo]) res[eo] = 3; else if ((2 * have[eo][0] + have[eo][1]) <= pcibr_soft->bs_rrb_avail[eo]) res[eo] = 2; else if (have[eo][0] <= pcibr_soft->bs_rrb_avail[eo]) res[eo] = 1; else res[eo] = 0; } /* Assign reserved RRBs to existing slots */ for (slot = first; slot <= last; ++slot) { int r; c0 = pcibr_soft->bs_rrb_valid[slot]; c1 = pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL]; r = res[slot & 1] - (c0 + c1); if (r > 0) { pcibr_soft->bs_rrb_res[slot] = r; pcibr_soft->bs_rrb_avail[slot & 1] -= r; } }#if PCIBR_RRB_DEBUG printk("%v RRB MANAGEMENT: %d+%d free\n", pcibr_vhdl, pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]); for (slot = first; slot <= last; ++slot) printk("\tslot %d: %d+%d+%d", slot, 0xFFF & pcibr_soft->bs_rrb_valid[slot], 0xFFF & pcibr_soft->bs_rrb_valid[slot + PCIBR_RRB_SLOT_VIRTUAL], pcibr_soft->bs_rrb_res[slot]); printk("\n");#endif return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -