提交 4eebd5a4 编写于 作者: B Bruno Prémont 提交者: Darren Hart

apple-gmux: lock iGP IO to protect from vgaarb changes

As GMUX depends on IO for iGP to be enabled and active, lock the IO at
vgaarb level. This should prevent GPU driver for dGPU to disable IO for
iGP while it tries to own legacy VGA IO.

This fixes usage of backlight control combined with closed nvidia
driver on some Apple dual-GPU (intel/nvidia) systems.

On those systems loading nvidia driver disables intel IO decoding,
disabling the gmux backlight controls as a side effect.
Prior to commits moving boot_vga from (optional) efifb to less optional
vgaarb this mis-behavior could be avoided by using right kernel config
(efifb enabled but vgaarb disabled).

This patch explicitly does not try to trigger vgaarb changes in order
to avoid confusing already running graphics drivers. If IO has been
mis-configured by vgaarb gmux will thus fail to probe.
It is expected to load/probe gmux prior to graphics drivers.

Fixes: ce027dac592c0ada241ce0f95ae65856828ac450 # nvidia interaction
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=86121Reported-by: NPetri Hodju <petrihodju@yahoo.com>
Tested-by: NPetri Hodju <petrihodju@yahoo.com>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Matthew Garrett <matthew.garrett@nebula.com>
Signed-off-by: NBruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: NDarren Hart <dvhart@linux.intel.com>
上级 0a63ca11
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/vga_switcheroo.h> #include <linux/vga_switcheroo.h>
#include <linux/vgaarb.h>
#include <acpi/video.h> #include <acpi/video.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -31,6 +32,7 @@ struct apple_gmux_data { ...@@ -31,6 +32,7 @@ struct apple_gmux_data {
bool indexed; bool indexed;
struct mutex index_lock; struct mutex index_lock;
struct pci_dev *pdev;
struct backlight_device *bdev; struct backlight_device *bdev;
/* switcheroo data */ /* switcheroo data */
...@@ -415,6 +417,23 @@ static int gmux_resume(struct device *dev) ...@@ -415,6 +417,23 @@ static int gmux_resume(struct device *dev)
return 0; return 0;
} }
static struct pci_dev *gmux_get_io_pdev(void)
{
struct pci_dev *pdev = NULL;
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev))) {
u16 cmd;
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_IO))
continue;
return pdev;
}
return NULL;
}
static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{ {
struct apple_gmux_data *gmux_data; struct apple_gmux_data *gmux_data;
...@@ -425,6 +444,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ...@@ -425,6 +444,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
int ret = -ENXIO; int ret = -ENXIO;
acpi_status status; acpi_status status;
unsigned long long gpe; unsigned long long gpe;
struct pci_dev *pdev = NULL;
if (apple_gmux_data) if (apple_gmux_data)
return -EBUSY; return -EBUSY;
...@@ -475,7 +495,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ...@@ -475,7 +495,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
ver_minor = (version >> 16) & 0xff; ver_minor = (version >> 16) & 0xff;
ver_release = (version >> 8) & 0xff; ver_release = (version >> 8) & 0xff;
} else { } else {
pr_info("gmux device not present\n"); pr_info("gmux device not present or IO disabled\n");
ret = -ENODEV; ret = -ENODEV;
goto err_release; goto err_release;
} }
...@@ -483,6 +503,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ...@@ -483,6 +503,23 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor, pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
ver_release, (gmux_data->indexed ? "indexed" : "classic")); ver_release, (gmux_data->indexed ? "indexed" : "classic"));
/*
* Apple systems with gmux are EFI based and normally don't use
* VGA. In addition changing IO+MEM ownership between IGP and dGPU
* disables IO/MEM used for backlight control on some systems.
* Lock IO+MEM to GPU with active IO to prevent switch.
*/
pdev = gmux_get_io_pdev();
if (pdev && vga_tryget(pdev,
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM)) {
pr_err("IO+MEM vgaarb-locking for PCI:%s failed\n",
pci_name(pdev));
ret = -EBUSY;
goto err_release;
} else if (pdev)
pr_info("locked IO for PCI:%s\n", pci_name(pdev));
gmux_data->pdev = pdev;
memset(&props, 0, sizeof(props)); memset(&props, 0, sizeof(props));
props.type = BACKLIGHT_PLATFORM; props.type = BACKLIGHT_PLATFORM;
props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS); props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
...@@ -574,6 +611,10 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) ...@@ -574,6 +611,10 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
err_notify: err_notify:
backlight_device_unregister(bdev); backlight_device_unregister(bdev);
err_release: err_release:
if (gmux_data->pdev)
vga_put(gmux_data->pdev,
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
pci_dev_put(pdev);
release_region(gmux_data->iostart, gmux_data->iolen); release_region(gmux_data->iostart, gmux_data->iolen);
err_free: err_free:
kfree(gmux_data); kfree(gmux_data);
...@@ -593,6 +634,11 @@ static void gmux_remove(struct pnp_dev *pnp) ...@@ -593,6 +634,11 @@ static void gmux_remove(struct pnp_dev *pnp)
&gmux_notify_handler); &gmux_notify_handler);
} }
if (gmux_data->pdev) {
vga_put(gmux_data->pdev,
VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM);
pci_dev_put(gmux_data->pdev);
}
backlight_device_unregister(gmux_data->bdev); backlight_device_unregister(gmux_data->bdev);
release_region(gmux_data->iostart, gmux_data->iolen); release_region(gmux_data->iostart, gmux_data->iolen);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册