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

📄 pcibr.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
void                    pcibr_provider_startup(devfs_handle_t);void                    pcibr_provider_shutdown(devfs_handle_t);int                     pcibr_reset(devfs_handle_t);pciio_endian_t          pcibr_endian_set(devfs_handle_t, pciio_endian_t, pciio_endian_t);int                     pcibr_priority_bits_set(pcibr_soft_t, pciio_slot_t, pciio_priority_t);pciio_priority_t        pcibr_priority_set(devfs_handle_t, pciio_priority_t);int                     pcibr_device_flags_set(devfs_handle_t, pcibr_device_flags_t);LOCAL cfg_p             pcibr_config_addr(devfs_handle_t, unsigned);uint64_t                pcibr_config_get(devfs_handle_t, unsigned, unsigned);LOCAL uint64_t          do_pcibr_config_get(cfg_p, unsigned, unsigned);void                    pcibr_config_set(devfs_handle_t, unsigned, unsigned, uint64_t);LOCAL void              do_pcibr_config_set(cfg_p, unsigned, unsigned, uint64_t);LOCAL pcibr_hints_t     pcibr_hints_get(devfs_handle_t, int);void                    pcibr_hints_fix_rrbs(devfs_handle_t);void                    pcibr_hints_dualslot(devfs_handle_t, pciio_slot_t, pciio_slot_t);void			pcibr_hints_intr_bits(devfs_handle_t, pcibr_intr_bits_f *);void                    pcibr_set_rrb_callback(devfs_handle_t, rrb_alloc_funct_t);void                    pcibr_hints_handsoff(devfs_handle_t);void                    pcibr_hints_subdevs(devfs_handle_t, pciio_slot_t, uint64_t);LOCAL int		pcibr_slot_reset(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_info_init(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_info_free(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_addr_space_init(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_device_init(devfs_handle_t, pciio_slot_t);LOCAL int		pcibr_slot_guest_info_init(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_initial_rrb_alloc(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_call_device_attach(devfs_handle_t,pciio_slot_t);LOCAL int		pcibr_slot_call_device_detach(devfs_handle_t,pciio_slot_t);int			pcibr_slot_powerup(devfs_handle_t,pciio_slot_t);int			pcibr_slot_shutdown(devfs_handle_t,pciio_slot_t);int			pcibr_slot_inquiry(devfs_handle_t,pciio_slot_t);		/* ===================================================================== *    RRB management */#define LSBIT(word)		((word) &~ ((word)-1))#define PCIBR_RRB_SLOT_VIRTUAL	8LOCAL voiddo_pcibr_rrb_clear(bridge_t *bridge, int rrb){    bridgereg_t             status;    /* bridge_lock must be held;     * this RRB must be disabled.     */    /* 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? */	}    }}LOCAL voiddo_pcibr_rrb_flush(bridge_t *bridge, int rrbn){    reg_p                   rrbp = &bridge->b_rrb_map[rrbn & 1].reg;    bridgereg_t             rrbv;    int                     shft = 4 * (rrbn >> 1);    unsigned                ebit = BRIDGE_RRB_EN << shft;    rrbv = *rrbp;    if (rrbv & ebit)	*rrbp = rrbv & ~ebit;    do_pcibr_rrb_clear(bridge, rrbn);    if (rrbv & ebit)	*rrbp = rrbv;}/* *    pcibr_rrb_count_valid: count how many RRBs are *      marked valid for the specified PCI slot on this *      bridge. * *      NOTE: The "slot" parameter for all pcibr_rrb *      management routines must include the "virtual" *      bit; when manageing both the normal and the *      virtual channel, separate calls to these *      routines must be made. To denote the virtual *      channel, add PCIBR_RRB_SLOT_VIRTUAL to the slot *      number. * *      IMPL NOTE: The obvious algorithm is to iterate *      through the RRB fields, incrementing a count if *      the RRB is valid and matches the slot. However, *      it is much simpler to use an algorithm derived *      from the "partitioned add" idea. First, XOR in a *      pattern such that the fields that match this *      slot come up "all ones" and all other fields *      have zeros in the mismatching bits. Then AND *      together the bits in the field, so we end up *      with one bit turned on for each field that *      matched. Now we need to count these bits. This *      can be done either with a series of shift/add *      instructions or by using "tmp % 15"; I expect *      that the cascaded shift/add will be faster. */LOCAL intdo_pcibr_rrb_count_valid(bridge_t *bridge,			 pciio_slot_t slot){    bridgereg_t             tmp;    tmp = bridge->b_rrb_map[slot & 1].reg;    tmp ^= 0x11111111 * (7 - slot / 2);    tmp &= (0xCCCCCCCC & tmp) >> 2;    tmp &= (0x22222222 & tmp) >> 1;    tmp += tmp >> 4;    tmp += tmp >> 8;    tmp += tmp >> 16;    return tmp & 15;}/* *    do_pcibr_rrb_count_avail: count how many RRBs are *      available to be allocated for the specified slot. * *      IMPL NOTE: similar to the above, except we are *      just counting how many fields have the valid bit *      turned off. */LOCAL intdo_pcibr_rrb_count_avail(bridge_t *bridge,			 pciio_slot_t slot){    bridgereg_t             tmp;    tmp = bridge->b_rrb_map[slot & 1].reg;    tmp = (0x88888888 & ~tmp) >> 3;    tmp += tmp >> 4;    tmp += tmp >> 8;    tmp += tmp >> 16;    return tmp & 15;}/* *    do_pcibr_rrb_alloc: allocate some additional RRBs *      for the specified slot. Returns -1 if there were *      insufficient free RRBs to satisfy the request, *      or 0 if the request was fulfilled. * *      Note that if a request can be partially filled, *      it will be, even if we return failure. * *      IMPL NOTE: again we avoid iterating across all *      the RRBs; instead, we form up a word containing *      one bit for each free RRB, then peel the bits *      off from the low end. */LOCAL intdo_pcibr_rrb_alloc(bridge_t *bridge,		   pciio_slot_t slot,		   int more){    int                     rv = 0;    bridgereg_t             reg, tmp, bit;    reg = bridge->b_rrb_map[slot & 1].reg;    tmp = (0x88888888 & ~reg) >> 3;    while (more-- > 0) {	bit = LSBIT(tmp);	if (!bit) {	    rv = -1;	    break;	}	tmp &= ~bit;	reg = ((reg & ~(bit * 15)) | (bit * (8 + slot / 2)));    }    bridge->b_rrb_map[slot & 1].reg = reg;    return rv;}/* *    do_pcibr_rrb_free: release some of the RRBs that *      have been allocated for the specified *      slot. Returns zero for success, or negative if *      it was unable to free that many RRBs. * *      IMPL NOTE: We form up a bit for each RRB *      allocated to the slot, aligned with the VALID *      bitfield this time; then we peel bits off one at *      a time, releasing the corresponding RRB. */LOCAL intdo_pcibr_rrb_free(bridge_t *bridge,		  pciio_slot_t slot,		  int less){    int                     rv = 0;    bridgereg_t             reg, tmp, clr, bit;    int                     i;    clr = 0;    reg = bridge->b_rrb_map[slot & 1].reg;    /* This needs to be done otherwise the rrb's on the virtual channel     * for this slot won't be freed !!     */    tmp = reg & 0xbbbbbbbb;    tmp ^= (0x11111111 * (7 - slot / 2));    tmp &= (0x33333333 & tmp) << 2;    tmp &= (0x44444444 & tmp) << 1;    while (less-- > 0) {	bit = LSBIT(tmp);	if (!bit) {	    rv = -1;	    break;	}	tmp &= ~bit;	reg &= ~bit;	clr |= bit;    }    bridge->b_rrb_map[slot & 1].reg = reg;    for (i = 0; i < 8; i++)	if (clr & (8 << (4 * i)))	    do_pcibr_rrb_clear(bridge, (2 * i) + (slot & 1));    return rv;}LOCAL voiddo_pcibr_rrb_autoalloc(pcibr_soft_t pcibr_soft,		       int slot,		       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 & 7] > 0)	    pcibr_soft->bs_rrb_res[slot & 7]--;	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, 1) < 0)	    break;#if PCIBR_RRB_DEBUG	printk( "do_pcibr_rrb_autoalloc: add one to slot %d%s\n",		slot & 7, slot & 8 ? "v" : "");#endif	pcibr_soft->bs_rrb_valid[slot]++;    }#if PCIBR_RRB_DEBUG    printk("%s: %d+%d free RRBs. Allocation list:\n", pcibr_soft->bs_name,	    pcibr_soft->bs_rrb_avail[0],	    pcibr_soft->bs_rrb_avail[1]);    for (slot = 0; slot < 8; ++slot)	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}/* * 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 = pciio_info_slot_get(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);    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 = pciio_info_slot_get(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;    unsigned                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);    /* How many RRBs do we own? */    orig_vchan0 = pcibr_soft->bs_rrb_valid[pciio_slot];    orig_vchan1 = pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL];    /* 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, -delta_vchan0);	if (delta_vchan1 < 0)	    (void) do_pcibr_rrb_free(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, -delta_vchan1);	if (delta_vchan0 > 0)	    (void) do_pcibr_rrb_alloc(bridge, pciio_slot, delta_vchan0);	if (delta_vchan1 > 0)	    (void) do_pcibr_rrb_alloc(bridge, PCIBR_RRB_SLOT_VIRTUAL + pciio_slot, 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] = final_vchan0;	pcibr_soft->bs_rrb_valid[pciio_slot + PCIBR_RRB_SLOT_VIRTUAL] = 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;

⌨️ 快捷键说明

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