Fixing X220 Video The Right Way
John Baldwin
jhb at freebsd.org
Thu Feb 28 17:09:56 UTC 2013
On Thursday, February 28, 2013 8:15:46 am matt wrote:
> On 02/27/13 12:27, John Baldwin wrote:
> > On Wednesday, February 27, 2013 1:35:43 pm matt wrote:
> >> On 02/27/13 09:00, John Baldwin wrote:
> >>> If that is true, it's because your BIOS is lying. Do you have a URL to
> >>> your ASL lying around already?
> >> Too big for pastebin :( +500k
> >>
> >> https://docs.google.com/file/d/0B6YlMzJxarGbVnotLUdNWWNTVG8/edit?usp=sharing
> > Here is where I find _DOD and _DOS methods:
> >
> > Device (PCI0)
> > Device (VID)
> > Name (_ADR, 0x00020000) // _ADR: Address
> > Method (_DOS, 1, NotSerialized) // _DOS: Disable Output Switching
> > Method (_DOD, 0, NotSerialized) // _DOD: Display Output Devices
> > Device (PEG)
> > Name (_ADR, 0x00010000) // _ADR: Address
> > Device (VID)
> > Name (_ADR, 0x00) // _ADR: Address
> > Method (_DOS, 1, NotSerialized) // _DOS: Disable Output Switching
> > Method (_DOD, 0, NotSerialized) // _DOD: Display Output Devices
> >
> > PCI0.VID is a PCI device at pci0:0:2:0.
> > PCI0.PEG would be a PCI-PCI bridge at pci0:0:1:0.
> > It would have a child device at 0:0 that would be PCI0.PEG.VID. Does the X220
> > have a switchable GPU (e.g. it has built-in Intel graphics, but also has an
> > Nvidia GPU or some such?). If so, I imagine that PCI0.VID is the Intel graphics
> > and PEG is the non-Intel. The output of 'pciconf -lcv' would be useful to determine
> > that. If both PCI devices exist you shoudl have both acpi_video0 and acpi_video1.
> > However, it may be that the acpi_video driver doesn't cope well with having multiple
> > devices.
> Only Intel graphics, there is no option for switchable graphics.
> I initially thought that PEG was for Optimus usage, and left in the bios
> by accident (i.e. Lenovo using a generic DSDT for many machines)
>
> Here is pciconf -lcf, truncated
> hostb0 at pci0:0:0:0: class=0x060000 card=0x21da17aa chip=0x01048086
> rev=0x09 hdr=0x00
> vendor = 'Intel Corporation'
> device = '2nd Generation Core Processor Family DRAM Controller'
> class = bridge
> subclass = HOST-PCI
> cap 09[e0] = vendor (length 12) Intel cap 0 version 1
> vgapci0 at pci0:0:2:0: class=0x030000 card=0x21da17aa chip=0x01268086
> rev=0x09 hdr=0x00
> vendor = 'Intel Corporation'
> device = '2nd Generation Core Processor Family Integrated
> Graphics Controller'
> class = display
> subclass = VGA
> cap 05[90] = MSI supports 1 message enabled with 1 message
> cap 01[d0] = powerspec 2 supports D0 D3 current D0
> cap 13[a4] = PCI Advanced Features: FLR TP
> none0 at pci0:0:22:0: class=0x078000 card=0x21da17aa chip=0x1c3a8086
> rev=0x04 hdr=0x00
> vendor = 'Intel Corporation'
>
> As you can see there is no device at pci0:0:1:0. So no dev_t with for
> acpi_video to probe or attach to.
>
> Nonetheless, only PEGs ACPI methods work, which is quite broken. This is
> true for a large number of Lenovo devices, back to x61 (non-attaching
> AGP adr) and probably including some other x series and t series.
>
> Unfortunately the ASL will not compile which makes fixing the DSDT an
> exercise in fixing broken ACPI.
>
> What I find interesting is that as far as I can tell, there's no special
> case handling for this device in Linux, yet backlight controls work out
> of the box since about 3.0. Installing Linux as the OSI via loader.conf
> is not the issue, unfortunately, nor Windows 2006 (/WVIS) or Windows
> 2009 (/WIN7). I get correct (for platform) behavior when I call PEGs
> _BCM... :(
>
> Is Linux getting this to work by doing it wrong, essentially?
Yes. I think the best way to fix this is to add a way to specify a
hint to override the ACPI path associated with a PCI device. Something
like:
hw.pci0.0.2.0.handle="\_SB_.PCI0.PEG.VID"
I think this patch should do the trick:
Index: sys/dev/acpica/acpi_pci.c
===================================================================
--- acpi_pci.c (revision 247320)
+++ acpi_pci.c (working copy)
@@ -264,6 +264,40 @@ acpi_pci_save_handle(ACPI_HANDLE handle, UINT32 le
return_ACPI_STATUS (AE_OK);
}
+static void
+acpi_pci_override_handles(device_t dev)
+{
+ struct acpi_pci_devinfo *dinfo;
+ device_t *devlist;
+ int error, i, numdevs;
+ char tunable_name[64], *path;
+ ACPI_HANDLE handle;
+
+ error = device_get_children(dev, &devlist, &numdevs);
+ if (error)
+ return;
+ for (i = 0; i < numdevs; i++) {
+ dinfo = device_get_ivars(devlist[i]);
+ snprintf(tunable_name, sizeof(tunable_name),
+ "hw.pci%d.%d.%d.%d.handle", dinfo->ap_dinfo.cfg.domain,
+ dinfo->ap_dinfo.cfg.bus, dinfo->ap_dinfo.cfg.slot,
+ dinfo->ap_dinfo.cfg.func);
+ path = getenv(tunable_name);
+ if (path == NULL)
+ continue;
+ if (ACPI_SUCCESS(AcpiGetHandle(NULL, path, &handle))) {
+ device_printf(dev,
+ "Forcing device at %d.%d to use path %s\n",
+ dinfo->ap_dinfo.cfg.slot,
+ dinfo->ap_dinfo.cfg.func, path);
+ dinfo->ap_handle = handle;
+ acpi_pci_update_device(handle, devlist[i]);
+ }
+ freeenv(path);
+ }
+ free(devlist, M_TEMP);
+}
+
static int
acpi_pci_probe(device_t dev)
{
@@ -306,5 +340,10 @@ acpi_pci_attach(device_t dev)
AcpiWalkNamespace(ACPI_TYPE_DEVICE, acpi_get_handle(dev), 1,
acpi_pci_save_handle, NULL, dev, NULL);
+ /*
+ * Perform another pass over child devices to allow their
+ * handles to be overridden via a hint from the user.
+ */
+ acpi_pci_override_handles(dev);
return (bus_generic_attach(dev));
}
--
John Baldwin
More information about the freebsd-current
mailing list