⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcibr_rrb.c

📁 linux-2.4.29操作系统的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
     *     * 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;	pcibr_soft->bs_rrb_avail[pciio_slot & 1] =	    pcibr_soft->bs_rrb_avail[pciio_slot & 1]	    + pcibr_soft->bs_rrb_res[pciio_slot]	    - 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_res_dflt[pciio_slot] -		    pcibr_soft->bs_rrb_res[pciio_slot]);	for (vchan = 0; vchan < vchan_total; vchan++) {	    res_rrbs += (pcibr_soft->bs_rrb_valid_dflt[pciio_slot][vchan] -			 pcibr_soft->bs_rrb_valid[pciio_slot][vchan]);	}	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;        } 	pcibr_rrb_debug("pcibr_rrb_alloc", pcibr_soft);	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(vertex_hdl_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 = PCIBR_INFO_SLOT_GET_INT(pciio_info)) < PCIBR_NUM_SLOTS(pcibr_soft))) {	s = pcibr_lock(pcibr_soft);	if (count_vchan0)	    *count_vchan0 =		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN0];	if (count_vchan1)	    *count_vchan1 =		pcibr_soft->bs_rrb_valid[pciio_slot][VCHAN1];	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_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(vertex_hdl_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 		 vchan_total;    int			 vchan;    int                  chan[4];    pcibr_soft = pcibr_soft_get(pcibr_vhdl);    if (!pcibr_soft)	return(-EINVAL);    if (!PCIBR_VALID_SLOT(pcibr_soft, slot))	return(-EINVAL);    bridge = pcibr_soft->bs_base;    /* How many RRBs are on this slot? */    vchan_total = NUMBER_VCHANNELS(bridge);    for (vchan = 0; vchan < vchan_total; vchan++)         chan[vchan] = do_pcibr_rrb_count_valid(bridge, slot, vchan);    if (IS_PIC_SOFT(pcibr_soft)) { 	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d+%d+%d\n",	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 	    chan[VCHAN0], chan[VCHAN1], chan[VCHAN2], chan[VCHAN3]));    } else {	PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_vhdl,	    "pcibr_slot_initial_rrb_alloc: slot %d started with %d+%d\n",	    PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot), 	    chan[VCHAN0], chan[VCHAN1]));    }    /* Do we really need any?     */    pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;    pcibr_info = pcibr_infoh[0];    if (PCIBR_WAR_ENABLED(PV856866, pcibr_soft) && IS_PIC_SOFT(pcibr_soft) &&                        (slot == 2 || slot == 3) &&                        (pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&                        !pcibr_soft->bs_slot[slot].has_host) {        for (vchan = 0; vchan < 2; vchan++) {            do_pcibr_rrb_free(bridge, slot, vchan, 8);            pcibr_soft->bs_rrb_valid[slot][vchan] = 0;        }        pcibr_soft->bs_rrb_valid[slot][3] = chan[3];        return(-ENODEV);    }    /* Give back any assigned to empty slots */    if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) && !pcibr_soft->bs_slot[slot].has_host) {	do_pcibr_rrb_free_all(pcibr_soft, bridge, slot);	return(-ENODEV);    }    for (vchan = 0; vchan < vchan_total; vchan++)        pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan];    return(0);}voidrrb_reserved_free(pcibr_soft_t pcibr_soft, int slot){        int res = pcibr_soft->bs_rrb_res[slot];        if (res) {                 pcibr_soft->bs_rrb_avail[slot & 1] += res;                 pcibr_soft->bs_rrb_res[slot] = 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 *      channels, and the number of RRBs assigned as reserved.  * *      A candidate slot is any existing (populated or empty) slot. *      Empty SN1 slots need RRBs to support hot-plug operations. */intpcibr_initial_rrb(vertex_hdl_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			    rrb_total;    int			    vchan_total;    int			    vchan;    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;    vchan_total = NUMBER_VCHANNELS(bridge);    for (slot = pcibr_soft->bs_min_slot; 			slot < PCIBR_NUM_SLOTS(pcibr_soft); ++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)) {	    rrb_total = 0;	    for (vchan = 0; vchan < vchan_total; vchan++) 		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];            if (rrb_total < 3)                have[slot & 1][rrb_total]++;        }    }    /* 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;	rrb_total = 0;	for (vchan = 0; vchan < vchan_total; vchan++)		rrb_total += pcibr_soft->bs_rrb_valid[slot][vchan];        r = res[slot & 1] - (rrb_total);        if (r > 0) {            pcibr_soft->bs_rrb_res[slot] = r;            pcibr_soft->bs_rrb_avail[slot & 1] -= r;        }    }    pcibr_rrb_debug("pcibr_initial_rrb", pcibr_soft);    return 0;}/* * Dump the pcibr_soft_t RRB state variable */voidpcibr_rrb_debug(char *calling_func, pcibr_soft_t pcibr_soft){    pciio_slot_t slot;    char tmp_str[256];        if (pcibr_debug_mask & PCIBR_DEBUG_RRB) {        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,                    "%s: rrbs available, even=%d, odd=%d\n", calling_func,                    pcibr_soft->bs_rrb_avail[0], pcibr_soft->bs_rrb_avail[1]));        if (IS_PIC_SOFT(pcibr_soft)) {            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,                        "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n"));        } else {	    PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,		        "\tslot\tvchan0\tvchan1\treserved\n"));        }        for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) {	    /*             * The kernel only allows functions to have so many variable args,             * attempting to call PCIBR_DEBUG_ALWAYS() with more than 5 printf             * arguments fails so sprintf() it into a temporary string.             */	    if (IS_PIC_SOFT(pcibr_soft)) {                sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\t  %d\t  %d\n", 		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN2],                        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN3],                        pcibr_soft->bs_rrb_res[slot]);	    } else {	        sprintf(tmp_str, "\t %d\t  %d\t  %d\t  %d\n", 		        PCIBR_DEVICE_TO_SLOT(pcibr_soft, slot),		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN0],		        0xFFF & pcibr_soft->bs_rrb_valid[slot][VCHAN1],		        pcibr_soft->bs_rrb_res[slot]);	    }                PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,                        "%s", tmp_str));        }    }}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -