FreeBSD/sys/dev/pci/pci_pci.c
/*
 * Attempt to grow a window to make room for a given resource request.
 */
Attempt to grow a window to make room for a given resource request.
Attempt to grow a window to make room for a given resource request .
static int
pcib_grow_window(struct pcib_softc *sc, struct pcib_window *w, int type,
    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
{
	rman_res_t align, start_free, end_free, front, back, wmask;
	int error;
	if (!w->valid)
		return (EINVAL);
	if (sc->bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 &&
	    start < 65536)
		start = 65536;
	if (end > w->rman.rm_end)
		end = w->rman.rm_end;
	if (start + count - 1 > end || start + count < start)
		return (EINVAL);
	wmask = ((rman_res_t)1 << w->step) - 1;
	if (w->res == NULL) {
		error = pcib_alloc_new_window(sc, w, type, start, end, count,
		    flags);
		if (error) {
			if (bootverbose)
				device_printf(sc->dev,
		    "failed to allocate initial %s window (%#jx-%#jx,%#jx)\n",
				    w->name, start, end, count);
			return (error);
		}
		if (bootverbose)
			device_printf(sc->dev,
			    "allocated initial %s window of %#jx-%#jx\n",
			    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
		goto updatewin;
	}
	if (bootverbose)
		device_printf(sc->dev,
		    "attempting to grow %s window for (%#jx-%#jx,%#jx)\n",
		    w->name, start, end, count);
	align = (rman_res_t)1 << RF_ALIGNMENT(flags);
	if (start < w->base) {
		if (rman_first_free_region(&w->rman, &start_free, &end_free) !=
		    0 || start_free != w->base)
			end_free = w->base;
		if (end_free > end)
			end_free = end + 1;
		end_free &= ~(align - 1);
		end_free--;
		front = end_free - (count - 1);
		if (front >= start && front <= end_free) {
			if (bootverbose)
				printf("\tfront candidate range: %#jx-%#jx\n",
				    front, end_free);
			front &= ~wmask;
			front = w->base - front;
		} else
			front = 0;
	} else
		front = 0;
	if (end > w->limit) {
		if (rman_last_free_region(&w->rman, &start_free, &end_free) !=
		    0 || end_free != w->limit)
			start_free = w->limit + 1;
		if (start_free < start)
			start_free = start;
		start_free = roundup2(start_free, align);
		back = start_free + count - 1;
		if (back <= end && start_free <= back) {
			if (bootverbose)
				printf("\tback candidate range: %#jx-%#jx\n",
				    start_free, back);
			back |= wmask;
			back -= w->limit;
		} else
			back = 0;
	} else
		back = 0;
	error = ENOSPC;
	while (front != 0 || back != 0) {
		if (front != 0 && (front <= back || back == 0)) {
			error = pcib_expand_window(sc, w, type, w->base - front,
			    w->limit);
			if (error == 0)
				break;
			front = 0;
		} else {
			error = pcib_expand_window(sc, w, type, w->base,
			    w->limit + back);
			if (error == 0)
				break;
			back = 0;
		}
	}
	if (error)
		return (error);
	if (bootverbose)
		device_printf(sc->dev, "grew %s window to %#jx-%#jx\n",
		    w->name, (uintmax_t)w->base, (uintmax_t)w->limit);
updatewin:
	KASSERT((w->base & wmask) == 0, ("start address is not aligned"));
	KASSERT((w->limit & wmask) == wmask, ("end address is not aligned"));
	pcib_write_windows(sc, w->mask);
	return (0);
}
static int pcib_grow_window ( struct pcib_softc * sc , struct pcib_window * w , int type , rman_res_t start , rman_res_t end , rman_res_t count , u_int flags ) { rman_res_t align , start_free , end_free , front , back , wmask ; int error ; if ( ! w -> valid ) return ( EINVAL ) ; if ( sc -> bridgectl & PCIB_BCR_ISA_ENABLE && count > 0x100 && start < 65536 ) start = 65536 ; if ( end > w -> rman . rm_end ) end = w -> rman . rm_end ; if ( start + count - 1 > end || start + count < start ) return ( EINVAL ) ; wmask = ( ( rman_res_t ) 1 << w -> step ) - 1 ; if ( w -> res == NULL ) { error = pcib_alloc_new_window ( sc , w , type , start , end , count , flags ) ; if ( error ) { if ( bootverbose ) device_printf ( sc -> dev , " \n " , w -> name , start , end , count ) ; return ( error ) ; } if ( bootverbose ) device_printf ( sc -> dev , " \n " , w -> name , ( uintmax_t ) w -> base , ( uintmax_t ) w -> limit ) ; goto updatewin ; } if ( bootverbose ) device_printf ( sc -> dev , " \n " , w -> name , start , end , count ) ; align = ( rman_res_t ) 1 << RF_ALIGNMENT ( flags ) ; if ( start < w -> base ) { if ( rman_first_free_region ( & w -> rman , & start_free , & end_free ) != 0 || start_free != w -> base ) end_free = w -> base ; if ( end_free > end ) end_free = end + 1 ; end_free &= ~ ( align - 1 ) ; end_free -- ; front = end_free - ( count - 1 ) ; if ( front >= start && front <= end_free ) { if ( bootverbose ) printf ( " \t \n " , front , end_free ) ; front &= ~ wmask ; front = w -> base - front ; } else front = 0 ; } else front = 0 ; if ( end > w -> limit ) { if ( rman_last_free_region ( & w -> rman , & start_free , & end_free ) != 0 || end_free != w -> limit ) start_free = w -> limit + 1 ; if ( start_free < start ) start_free = start ; start_free = roundup2 ( start_free , align ) ; back = start_free + count - 1 ; if ( back <= end && start_free <= back ) { if ( bootverbose ) printf ( " \t \n " , start_free , back ) ; back |= wmask ; back -= w -> limit ; } else back = 0 ; } else back = 0 ; error = ENOSPC ; while ( front != 0 || back != 0 ) { if ( front != 0 && ( front <= back || back == 0 ) ) { error = pcib_expand_window ( sc , w , type , w -> base - front , w -> limit ) ; if ( error == 0 ) break ; front = 0 ; } else { error = pcib_expand_window ( sc , w , type , w -> base , w -> limit + back ) ; if ( error == 0 ) break ; back = 0 ; } } if ( error ) return ( error ) ; if ( bootverbose ) device_printf ( sc -> dev , " \n " , w -> name , ( uintmax_t ) w -> base , ( uintmax_t ) w -> limit ) ; updatewin : KASSERT ( ( w -> base & wmask ) == 0 , ( " " ) ) ; KASSERT ( ( w -> limit & wmask ) == wmask , ( " " ) ) ; pcib_write_windows ( sc , w -> mask ) ; return ( 0 ) ; }
Attempt to grow a window to make room for a given resource request.
Attempt to grow a window to make room for a given resource request .
/*
	 * Clamp the desired resource range to the maximum address
	 * this window supports.  Reject impossible requests.
	 *
	 * For I/O port requests behind a bridge with the ISA enable
	 * bit set, force large allocations to start above 64k.
	 */ /*
	 * If there is no resource at all, just try to allocate enough
	 * aligned space for this resource.
	 */ /*
	 * See if growing the window would help.  Compute the minimum
	 * amount of address space needed on both the front and back
	 * ends of the existing window to satisfy the allocation.
	 *
	 * For each end, build a candidate region adjusting for the
	 * required alignment, etc.  If there is a free region at the
	 * edge of the window, grow from the inner edge of the free
	 * region.  Otherwise grow from the window boundary.
	 *
	 * Growing an I/O window below 64k for a bridge with the ISA
	 * enable bit doesn't require any special magic as the step
	 * size of an I/O window (1k) always includes multiple
	 * non-alias ranges when it is grown in either direction.
	 *
	 * XXX: Special case: if w->res is completely empty and the
	 * request size is larger than w->res, we should find the
	 * optimal aligned buffer containing w->res and allocate that.
	 */ /* Move end_free down until it is properly aligned. */ /*
		 * The resource would now be allocated at (front,
		 * end_free).  Ensure that fits in the (start, end)
		 * bounds.  end_free is checked above.  If 'front' is
		 * ok, ensure it is properly aligned for this window.
		 * Also check for underflow.
		 */ /* Move start_free up until it is properly aligned. */ /*
		 * The resource would now be allocated at (start_free,
		 * back).  Ensure that fits in the (start, end)
		 * bounds.  start_free is checked above.  If 'back' is
		 * ok, ensure it is properly aligned for this window.
		 * Also check for overflow.
		 */ /*
	 * Try to allocate the smallest needed region first.
	 * If that fails, fall back to the other region.
	 */ /* Write the new window. */