Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 2 May 2014 14:05:32 -0400
From:      John Baldwin <jhb@freebsd.org>
To:        Don Lewis <dl-kvmr@catspoiler.org>
Cc:        stable@freebsd.org
Subject:   Re: Thinkpad R60 hangs when booting recent 8.4-STABLE
Message-ID:  <201405021405.32570.jhb@freebsd.org>
In-Reply-To: <201405020939.s429dJVq039239@gw.catspoiler.org>
References:  <201405020939.s429dJVq039239@gw.catspoiler.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Friday, May 02, 2014 5:39:19 am Don Lewis wrote:
> On  1 May, John Baldwin wrote:
> > On Thursday, May 01, 2014 1:55:41 am Don Lewis wrote:
> >> On 30 Apr, John Baldwin wrote:
> >> 
> >> > Are you up for doing some printf sleuthing?  There are two odd things that I 
> >> > see so far:
> >> > 
> >> > 1) the base address of 0.  The question here is if pci_add_map() in 
> >> > sys/dev/pci/pci.c decides to set start to 0 explicitly, or if it happens 
> >> > further up the callchain (should be bus_alloc_resource calls in 
> >> > sys/dev/acpica/acpi_pcib_acpi.c, sys/x86/x86/nexus.c and then in the
> >> > rman code itself in sys/kern/subr_rman.c)
> >> > 
> >> > 2) The 'reserved' printfs during boot probe.  Those come from a printf in 
> >> > pci_alloc_resource() in sys/dev/pci/pci.c.  However, that should not be called 
> >> > until a driver attaches to a device and calls bus_alloc_resource().  It should 
> >> > not be called from pci_add_child() as it seems to be now.
> >> 
> >> The call graph for the four earlier ones that you previously pointed
> >> out (not hostb0) is:
> >> 	pci_add_child()
> >> 		pci_add_resources()
> >> 			*_early_takeover()
> >> 				[I suspect]
> >> 				bus_alloc_resource_any()
> >> 					pci_alloc_resource()
> >> 					
> >> These are the three system uhci controllers and the system ehci
> >> controller, which apparently pass this test:
> >> 	pci_get_class(dev) == PCIC_SERIALBUS &&
> >> 	pci_get_subclass(dev) == PCIS_SERIALBUS_USB
> > 
> > Oh, ok.  That is fine, and that explains why it was selective in the past (and
> > only for I/O resources).  That just leaves 1) then.  It would be especially good
> > to know what pci_add_map() does when it sees this BAR during the bus probe.
> 
> In either case after reading the BAR, base=0xd0000000,
> testval=0xf0000008. and the following gets printed:
>         map[10]: type Prefetchable Memory, range 32, base 0xd0000000, size 28, enabled
> Then we call resource_list_add(..., d0000000, dfffffff, 10000000)
> 
> When we don't pass the size in flags (w/o r262226),
> resource_list_alloc() eventually calls nexus_alloc_resource() with the
> expected start, end, and count values.  After returning from
> pci_add_map, we write 0xd0000000 to the BAR.
> 
> If we *do* pass the size in flags (with r262226), then
> resource_list_alloc() never calls nexus_alloc_resource(), but it does
> return a non-NULL value.  We then write 0 to the BAR.
> 
> Digging into resource_list_alloc(), I see start, count, and end having
> the expected values before the second call to BUS_ALLOC_RESOURCE()
> but afterwards rman_get_start(rle->res) is 0 and rman_get_end(rle->res)
> is 0xfffffff.  We don't call nexus_alloc_resource(). Setting flags to 0
> for this specific call to BUS_ALLOC_RESOURCE() based on the value of
> start fixes the problem.
> 
> The culprit appears to be the call to rman_reserve_resource() in
> acpi_alloc_resource().  With r262226 it "succeeds", but the returned
> resource has the wrong start and end addresses.  Without r262226,
> rman_reserve_resource returns NULL and we call BUS_ALLOC_RESOURCE(),
> which calls nexus_alloc_resource(), which returns the expected range.
> 
> I enabled debug.rman_debug and saw the following:
> 
> rman_reserve_resource_bound: <ACPI I/O memory addresses> request:
> [0xd0000000, 0xdfffffff], length 0x10000000, flags 28736, device (null)
> considering [0xfec00000, 0xffffffff]
> truncated region: [0, 0xdfffffff]; size 0xe0000000 (requested
> 0x10000000)
> candidate region [0, 0xdfffffff], size 0xe0000000
> allocating at the end
> 
> This is with subr_rman.c from HEAD.
> 
> This expression will overflow:
> 		if (s->r_start + count - 1 > end) {
> I don't understand the point of this test.  Is it an optimization to
> exit the loop early based on an assumption about the ordering of
> elements in the list?

Yes.  The elements in an rman list are supposed to be sorted.

> This expression will also overflow:
> 			rstart = (rstart + amask) & ~amask;
> which is where I think the start address is getting set to 0.
> 
> 
> After reverting subr_rman.c and applying the following patch, I see:
> considering [0xfec00000, 0xffffffff]
> no unshared regions found
> Then nexus_alloc_resource() gets called and I see
> considering [0x3ff60000, 0xfebfffff]
> and then all the right stuff happens.
> 
> 
> Index: sys/kern/subr_rman.c
> ===================================================================
> --- sys/kern/subr_rman.c	(revision 262226)
> +++ sys/kern/subr_rman.c	(working copy)
> @@ -468,11 +468,9 @@
>  	 */
>  	for (s = r; s; s = TAILQ_NEXT(s, r_link)) {
>  		DPRINTF(("considering [%#lx, %#lx]\n", s->r_start, s->r_end));
> -		if (s->r_start + count - 1 > end) {
> -			DPRINTF(("s->r_start (%#lx) + count - 1> end (%#lx)\n",
> -			    s->r_start, end));
> -			break;
> -		}
> +		if (s->r_end < start + count - 1 ||
> +		    s->r_start > end - count + 1)
> +			continue;
>  		if (s->r_flags & RF_ALLOCATED) {
>  			DPRINTF(("region is allocated\n"));
>  			continue;
> 
> 

I think this looks good.

> I have no idea why 9.2-STABLE was able to boot on this machine ...

acpi_alloc_resource() works differently in 9.x and later.  It only
tries the internal rmans if nexus_alloc_resource() fails.  In 8.x it
tries the internal rmans first.  That change was made in r216674.

-- 
John Baldwin



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405021405.32570.jhb>