pcibr_rrb.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 888 行 · 第 1/2 页

C
888
字号
		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);    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;    /* 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)	    do_pcibr_rrb_free(pcibr_soft, pciio_slot, VCHAN0, -delta_vchan0);	if (delta_vchan1 < 0)	    do_pcibr_rrb_free(pcibr_soft, pciio_slot, VCHAN1, -delta_vchan1);	if (delta_vchan0 > 0)	    do_pcibr_rrb_alloc(pcibr_soft, pciio_slot, VCHAN0, delta_vchan0);	if (delta_vchan1 > 0)	    do_pcibr_rrb_alloc(pcibr_soft, 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;    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;    /* How many RRBs are on this slot? */    vchan_total = NUMBER_VCHANNELS;    for (vchan = 0; vchan < vchan_total; vchan++)         chan[vchan] = do_pcibr_rrb_count_valid(pcibr_soft, slot, vchan);    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]));    /* Do we really need any?     */    pcibr_infoh = pcibr_soft->bs_slot[slot].bss_infos;    pcibr_info = pcibr_infoh[0];    /*     * PIC BRINGUP WAR (PV# 856866, 859504, 861476, 861478):     * Don't free RRBs we allocated to device[2|3]--vchan3 as     * a WAR to those PVs mentioned above.  In pcibr_attach2     * we allocate RRB0,8,1,9 to device[2|3]--vchan3.     */    if (PCIBR_WAR_ENABLED(PV856866, 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(pcibr_soft, slot, vchan, 8);	    pcibr_soft->bs_rrb_valid[slot][vchan] = 0;	}        pcibr_soft->bs_rrb_valid[slot][3] = chan[3];        return -ENODEV;    }    if ((pcibr_info->f_vendor == PCIIO_VENDOR_ID_NONE) &&	!pcibr_soft->bs_slot[slot].has_host) {	do_pcibr_rrb_free_all(pcibr_soft, slot);        	/* Reserve RRBs for this empty slot for hot-plug */	for (vchan = 0; vchan < vchan_total; vchan++) 	    pcibr_soft->bs_rrb_valid[slot][vchan] = 0;	return -ENODEV;    }    for (vchan = 0; vchan < vchan_total; vchan++)        pcibr_soft->bs_rrb_valid[slot][vchan] = chan[vchan];    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 *      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);    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;    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 */        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(pcibr_soft, 0);    pcibr_soft->bs_rrb_avail[1] = do_pcibr_rrb_count_avail(pcibr_soft, 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;	if (pcibr_soft->bs_unused_slot & (1 << slot))	    continue;	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;        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]));        PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,                    "\tslot\tvchan0\tvchan1\tvchan2\tvchan3\treserved\n"));        for (slot=0; slot < PCIBR_NUM_SLOTS(pcibr_soft); slot++) {            PCIBR_DEBUG_ALWAYS((PCIBR_DEBUG_RRB, pcibr_soft->bs_vhdl,		    "\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]));        }    }}

⌨️ 快捷键说明

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