Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Nov 2017 19:19:19 +0100
From:      =?UTF-8?Q?Harald_B=c3=b6hm?= <harald.boehm@fau.de>
To:        freebsd-hackers@freebsd.org
Subject:   Re: ACPICA missing support for device I/O port ranges
Message-ID:  <a8cf7cf8-98be-3e62-4f18-8c5f6e626bc2@fau.de>
In-Reply-To: <2497671.hb7Q7Esj6H@ralph.baldwin.cx>
References:  <e8699d73-f38b-3825-67ef-8d8f973e4ce0@fau.de> <2497671.hb7Q7Esj6H@ralph.baldwin.cx>

next in thread | previous in thread | raw e-mail | index | archive | help

> IO ranges are not supposed to be in _CRS.  An IO range is used for relocatable
> resources and would be in _PRS to say "you can use I/O ports at addresses, A,
> B, or C".  Specifically, the "Range" of an I/O port is the range of the
> starting addresses.  Normal I/O addresses in _CRS are set to a fixed range
> with the same values for Range Min and Range Max.  For example:
> 
>                 IO (Decode16,
>                     0x0CF8,             // Range Minimum
>                     0x0CF8,             // Range Maximum
>                     0x01,               // Alignment
>                     0x08,               // Length
>                     )
> 
> This says it uses the '8' (Length) I/O ports starting at 0xcf8 and that they
> are fixed at 0xcf8 because the starting address has to be >= 0xcf8 (range min)
> and <= 0xcf8 (range max).  The _CRS blob from your dump says that it wants to
> allocate 255 I/O ports with a starting address of 0x700, 0x701, 0x702, 0x703,
> .... , 0x7fd, 0x7fe, or 0x7ff, but it doesn't tell us _which_ of those ranges
> it is actually using (e.g. is it using 0x700 -> 0x7ff or is it using 0x780 ->
> 0x88f, etc.).  

Thanks for the explanation, after reading it and having a look at the
ACPI spec everyhing makes much more sense now. :)

> Probably it's just a bug in your BIOS and it means to use
> 0x700 -> 0x7ff and the BIOS author doesn't understand what Range Maximum means.
> It is not the end address of the full I/O port addresses reserved, but the
> maximum starting address (I agree this is a bit odd, but this is what the
> spec says).

>From what I know about the device so far, this seems to be true. The
device only uses I/O ports in the range between 0x700 and 0x7FF, that's
why I was confused in the first place. It also seems to be the only
device that has this buggy port description in my BIOS, all other device
entries look like the example you gave.

The affected Laptop is a MacBook Pro 11,3. The device should be present
in Apple computers with two graphics cards, it is used to switch between
GPUs. So, if anyone else is using a Mac with two graphics cards, it
would be interesting to see, whether this bug is also present in other
machines (acpidump -td and search for GMUX).

> Assuming the BIOS is buggy, we can add a hack for iorange that adds the
> resource if max == min + length and emit a warning under bootverbose about
> the BIOS being buggy.
> 

That would be great. Alternatively, I could read the _CRS in the
driver's code directly. I already wrote a patch, adapting your idea,
below is the output of diff -u, does this look reasonable?

--- acpi_resource.c	2017-11-25 17:17:02.083043000 +0100
+++ acpi_resource.c.patch	2017-11-25 17:20:57.223232000 +0100
@@ -35,6 +35,7 @@
 #include <sys/limits.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/reboot.h>

 #include <machine/bus.h>
 #include <machine/resource.h>
@@ -525,7 +526,26 @@

     if (cp == NULL)
 	return;
-    device_printf(dev, "I/O range not supported\n");
+
+    /*
+     * The CRS is not supposed to contain io ranges for relocatable
+     * resources. If the resource's length is equal to the address
+     * range between low and high, it indicates that the BIOS author
+     * probably meant that the device uses I/O ports from low to
+     * high. Therefore, we set the resources here, so drivers are
+     * able allocate them correctly.
+     */
+    if (high == (low+length)) {
+	if (boothowto & RB_VERBOSE) {
+	    device_printf(dev,
+		"warning: Device's _CRS contains an invalid I/O port range\n");
+	}
+
+	bus_set_resource(dev, SYS_RES_IOPORT, cp->ar_nio++, low,
+	    length);
+    } else {
+	device_printf(dev, "I/O range not supported\n");
+    }
 }

 static void



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?a8cf7cf8-98be-3e62-4f18-8c5f6e626bc2>