Skip to content

Commit d143908

Browse files
committed
platform/x86: apple-gmux: Add apple_gmux_detect() helper
Add a new (static inline) apple_gmux_detect() helper to apple-gmux.h which can be used for gmux detection instead of apple_gmux_present(). The latter is not really reliable since an ACPI device with a HID of APP000B is present on some devices without a gmux at all, as well as on devices with a newer (unsupported) MMIO based gmux model. This causes apple_gmux_present() to return false-positives on a number of different Apple laptop models. This new helper uses the same probing as the actual apple-gmux driver, so that it does not return false positives. To avoid code duplication the gmux_probe() function of the actual driver is also moved over to using the new apple_gmux_detect() helper. This avoids false positives (vs _HID + IO region detection) on: MacBookPro5,4 https://pastebin.com/8Xjq7RhS MacBookPro8,1 https://linux-hardware.org/?probe=e513cfbadb&log=dmesg MacBookPro9,2 https://bugzilla.kernel.org/attachment.cgi?id=278961 MacBookPro10,2 https://lkml.org/lkml/2014/9/22/657 MacBookPro11,2 https://forums.fedora-fr.org/viewtopic.php?id=70142 MacBookPro11,4 https://raw.githubusercontent.com/im-0/investigate-card-reader-suspend-problem-on-mbp11.4/master/test-16/dmesg Fixes: 21245df ("ACPI: video: Add Apple GMUX brightness control detection") Link: https://lore.kernel.org/platform-driver-x86/[email protected]/ Reported-by: Emmanouil Kouroupakis <[email protected]> Signed-off-by: Hans de Goede <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 39f5a81 commit d143908

File tree

2 files changed

+102
-54
lines changed

2 files changed

+102
-54
lines changed

drivers/platform/x86/apple-gmux.c

Lines changed: 18 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -226,23 +226,6 @@ static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
226226
gmux_pio_write32(gmux_data, port, val);
227227
}
228228

229-
static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
230-
{
231-
u16 val;
232-
233-
outb(0xaa, gmux_data->iostart + 0xcc);
234-
outb(0x55, gmux_data->iostart + 0xcd);
235-
outb(0x00, gmux_data->iostart + 0xce);
236-
237-
val = inb(gmux_data->iostart + 0xcc) |
238-
(inb(gmux_data->iostart + 0xcd) << 8);
239-
240-
if (val == 0x55aa)
241-
return true;
242-
243-
return false;
244-
}
245-
246229
/**
247230
* DOC: Backlight control
248231
*
@@ -582,60 +565,43 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
582565
int ret = -ENXIO;
583566
acpi_status status;
584567
unsigned long long gpe;
568+
bool indexed = false;
569+
u32 version;
585570

586571
if (apple_gmux_data)
587572
return -EBUSY;
588573

574+
if (!apple_gmux_detect(pnp, &indexed)) {
575+
pr_info("gmux device not present\n");
576+
return -ENODEV;
577+
}
578+
589579
gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
590580
if (!gmux_data)
591581
return -ENOMEM;
592582
pnp_set_drvdata(pnp, gmux_data);
593583

594584
res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
595-
if (!res) {
596-
pr_err("Failed to find gmux I/O resource\n");
597-
goto err_free;
598-
}
599-
600585
gmux_data->iostart = res->start;
601586
gmux_data->iolen = resource_size(res);
602587

603-
if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
604-
pr_err("gmux I/O region too small (%lu < %u)\n",
605-
gmux_data->iolen, GMUX_MIN_IO_LEN);
606-
goto err_free;
607-
}
608-
609588
if (!request_region(gmux_data->iostart, gmux_data->iolen,
610589
"Apple gmux")) {
611590
pr_err("gmux I/O already in use\n");
612591
goto err_free;
613592
}
614593

615-
/*
616-
* Invalid version information may indicate either that the gmux
617-
* device isn't present or that it's a new one that uses indexed
618-
* io
619-
*/
620-
621-
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
622-
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
623-
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
624-
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
625-
if (gmux_is_indexed(gmux_data)) {
626-
u32 version;
627-
mutex_init(&gmux_data->index_lock);
628-
gmux_data->indexed = true;
629-
version = gmux_read32(gmux_data,
630-
GMUX_PORT_VERSION_MAJOR);
631-
ver_major = (version >> 24) & 0xff;
632-
ver_minor = (version >> 16) & 0xff;
633-
ver_release = (version >> 8) & 0xff;
634-
} else {
635-
pr_info("gmux device not present\n");
636-
ret = -ENODEV;
637-
goto err_release;
638-
}
594+
if (indexed) {
595+
mutex_init(&gmux_data->index_lock);
596+
gmux_data->indexed = true;
597+
version = gmux_read32(gmux_data, GMUX_PORT_VERSION_MAJOR);
598+
ver_major = (version >> 24) & 0xff;
599+
ver_minor = (version >> 16) & 0xff;
600+
ver_release = (version >> 8) & 0xff;
601+
} else {
602+
ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
603+
ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
604+
ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
639605
}
640606
pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
641607
ver_release, (gmux_data->indexed ? "indexed" : "classic"));

include/linux/apple-gmux.h

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#define LINUX_APPLE_GMUX_H
99

1010
#include <linux/acpi.h>
11+
#include <linux/io.h>
12+
#include <linux/pnp.h>
1113

1214
#define GMUX_ACPI_HID "APP000B"
1315

@@ -35,14 +37,89 @@
3537
#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
3638

3739
#if IS_ENABLED(CONFIG_APPLE_GMUX)
40+
static inline bool apple_gmux_is_indexed(unsigned long iostart)
41+
{
42+
u16 val;
43+
44+
outb(0xaa, iostart + 0xcc);
45+
outb(0x55, iostart + 0xcd);
46+
outb(0x00, iostart + 0xce);
47+
48+
val = inb(iostart + 0xcc) | (inb(iostart + 0xcd) << 8);
49+
if (val == 0x55aa)
50+
return true;
51+
52+
return false;
53+
}
3854

3955
/**
40-
* apple_gmux_present() - detect if gmux is built into the machine
56+
* apple_gmux_detect() - detect if gmux is built into the machine
57+
*
58+
* @pnp_dev: Device to probe or NULL to use the first matching device
59+
* @indexed_ret: Returns (by reference) if the gmux is indexed or not
60+
*
61+
* Detect if a supported gmux device is present by actually probing it.
62+
* This avoids the false positives returned on some models by
63+
* apple_gmux_present().
64+
*
65+
* Return: %true if a supported gmux ACPI device is detected and the kernel
66+
* was configured with CONFIG_APPLE_GMUX, %false otherwise.
67+
*/
68+
static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, bool *indexed_ret)
69+
{
70+
u8 ver_major, ver_minor, ver_release;
71+
struct device *dev = NULL;
72+
struct acpi_device *adev;
73+
struct resource *res;
74+
bool indexed = false;
75+
bool ret = false;
76+
77+
if (!pnp_dev) {
78+
adev = acpi_dev_get_first_match_dev(GMUX_ACPI_HID, NULL, -1);
79+
if (!adev)
80+
return false;
81+
82+
dev = get_device(acpi_get_first_physical_node(adev));
83+
acpi_dev_put(adev);
84+
if (!dev)
85+
return false;
86+
87+
pnp_dev = to_pnp_dev(dev);
88+
}
89+
90+
res = pnp_get_resource(pnp_dev, IORESOURCE_IO, 0);
91+
if (!res || resource_size(res) < GMUX_MIN_IO_LEN)
92+
goto out;
93+
94+
/*
95+
* Invalid version information may indicate either that the gmux
96+
* device isn't present or that it's a new one that uses indexed io.
97+
*/
98+
ver_major = inb(res->start + GMUX_PORT_VERSION_MAJOR);
99+
ver_minor = inb(res->start + GMUX_PORT_VERSION_MINOR);
100+
ver_release = inb(res->start + GMUX_PORT_VERSION_RELEASE);
101+
if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
102+
indexed = apple_gmux_is_indexed(res->start);
103+
if (!indexed)
104+
goto out;
105+
}
106+
107+
if (indexed_ret)
108+
*indexed_ret = indexed;
109+
110+
ret = true;
111+
out:
112+
put_device(dev);
113+
return ret;
114+
}
115+
116+
/**
117+
* apple_gmux_present() - check if gmux ACPI device is present
41118
*
42119
* Drivers may use this to activate quirks specific to dual GPU MacBook Pros
43120
* and Mac Pros, e.g. for deferred probing, runtime pm and backlight.
44121
*
45-
* Return: %true if gmux is present and the kernel was configured
122+
* Return: %true if gmux ACPI device is present and the kernel was configured
46123
* with CONFIG_APPLE_GMUX, %false otherwise.
47124
*/
48125
static inline bool apple_gmux_present(void)
@@ -57,6 +134,11 @@ static inline bool apple_gmux_present(void)
57134
return false;
58135
}
59136

137+
static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, bool *indexed_ret)
138+
{
139+
return false;
140+
}
141+
60142
#endif /* !CONFIG_APPLE_GMUX */
61143

62144
#endif /* LINUX_APPLE_GMUX_H */

0 commit comments

Comments
 (0)