From: Shih-Yuan Lee <fourdollars@debian.org>
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org,
Shih-Yuan Lee <fourdollars@debian.org>
Subject: [PATCH v3 1/3] Input: applespi - force PIO mode on MacBook8,1
Date: Sat, 11 Jul 2026 17:20:52 +0800 [thread overview]
Message-ID: <20260711092054.13818-2-fourdollars@debian.org> (raw)
In-Reply-To: <20260711092054.13818-1-fourdollars@debian.org>
On MacBook8,1 (early 2015 12" MacBook), the LPSS SPI controller's DMA
handshake and interrupt routing frequently fail or time out on boot,
causing the keyboard and trackpad to become unresponsive.
Address this by introducing a DMI quirk and a `force_pio` module
parameter. If either is true, override the SPI controller's `can_dma`
callback to a helper that always returns false. This forces all SPI
transfers to fall back to the reliable PIO mode.
To ensure correct timing and architectural safety:
1. Perform the override at the very beginning of applespi_probe() so
that all early initialization transfers use PIO.
2. In case of probe failures or module unload (remove), unconditionally
restore the original `can_dma` callback (even if it was NULL) to
prevent any execute-after-free or dangling pointer vulnerability in
the shared host controller.
Link: https://bugzilla.kernel.org/show_bug.cgi?id=108331
Signed-off-by: Shih-Yuan Lee <fourdollars@debian.org>
---
drivers/input/keyboard/applespi.c | 66 +++++++++++++++++++++++++------
1 file changed, 54 insertions(+), 12 deletions(-)
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
index b5ff71cd5a70..79e5cb5001c7 100644
--- a/drivers/input/keyboard/applespi.c
+++ b/drivers/input/keyboard/applespi.c
@@ -46,6 +46,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/efi.h>
+#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/ktime.h>
@@ -110,6 +111,10 @@ module_param_string(touchpad_dimensions, touchpad_dimensions,
sizeof(touchpad_dimensions), 0444);
MODULE_PARM_DESC(touchpad_dimensions, "The pixel dimensions of the touchpad, as XxY+W+H .");
+static bool applespi_force_pio;
+module_param_named(force_pio, applespi_force_pio, bool, 0444);
+MODULE_PARM_DESC(force_pio, "Force PIO mode (disables DMA) for SPI transfers. ([0] = disabled, 1 = enabled)");
+
/**
* struct keyboard_protocol - keyboard message.
* message.type = 0x0110, message.length = 0x000a
@@ -431,6 +436,10 @@ struct applespi_data {
int tp_dim_max_x;
int tp_dim_min_y;
int tp_dim_max_y;
+
+ bool (*original_can_dma)(struct spi_controller *controller,
+ struct spi_device *spi,
+ struct spi_transfer *xfer);
};
static const unsigned char applespi_scancodes[] = {
@@ -1605,6 +1614,13 @@ static void applespi_save_bl_level(struct applespi_data *applespi,
"Error saving backlight level to EFI vars: 0x%lx\n", sts);
}
+static bool applespi_can_not_dma(struct spi_controller *controller,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ return false;
+}
+
static int applespi_probe(struct spi_device *spi)
{
struct applespi_data *applespi;
@@ -1612,6 +1628,7 @@ static int applespi_probe(struct spi_device *spi)
acpi_status acpi_sts;
int sts, i;
unsigned long long gpe, usb_status;
+ bool override_dma = applespi_force_pio || dmi_match(DMI_PRODUCT_NAME, "MacBook8,1");
/* check if the USB interface is present and enabled already */
acpi_sts = acpi_evaluate_integer(spi_handle, "UIST", NULL, &usb_status);
@@ -1628,6 +1645,13 @@ static int applespi_probe(struct spi_device *spi)
applespi->spi = spi;
+ /* Save original can_dma and override if requested or needed */
+ applespi->original_can_dma = spi->controller->can_dma;
+ if (override_dma) {
+ dev_info(&spi->dev, "Disabling DMA for SPI to force PIO mode\n");
+ spi->controller->can_dma = applespi_can_not_dma;
+ }
+
INIT_WORK(&applespi->work, applespi_worker);
/* store the driver data */
@@ -1645,8 +1669,10 @@ static int applespi_probe(struct spi_device *spi)
GFP_KERNEL);
if (!applespi->tx_buffer || !applespi->tx_status ||
- !applespi->rx_buffer || !applespi->msg_buf)
- return -ENOMEM;
+ !applespi->rx_buffer || !applespi->msg_buf) {
+ sts = -ENOMEM;
+ goto err_restore_dma;
+ }
/* set up our spi messages */
applespi_setup_read_txfrs(applespi);
@@ -1658,7 +1684,8 @@ static int applespi_probe(struct spi_device *spi)
dev_err(&applespi->spi->dev,
"Failed to get SIEN ACPI method handle: %s\n",
acpi_format_exception(acpi_sts));
- return -ENODEV;
+ sts = -ENODEV;
+ goto err_restore_dma;
}
acpi_sts = acpi_get_handle(spi_handle, "SIST", &applespi->sist);
@@ -1666,23 +1693,26 @@ static int applespi_probe(struct spi_device *spi)
dev_err(&applespi->spi->dev,
"Failed to get SIST ACPI method handle: %s\n",
acpi_format_exception(acpi_sts));
- return -ENODEV;
+ sts = -ENODEV;
+ goto err_restore_dma;
}
/* switch on the SPI interface */
sts = applespi_setup_spi(applespi);
if (sts)
- return sts;
+ goto err_restore_dma;
sts = applespi_enable_spi(applespi);
if (sts)
- return sts;
+ goto err_restore_dma;
/* setup the keyboard input dev */
applespi->keyboard_input_dev = devm_input_allocate_device(&spi->dev);
- if (!applespi->keyboard_input_dev)
- return -ENOMEM;
+ if (!applespi->keyboard_input_dev) {
+ sts = -ENOMEM;
+ goto err_restore_dma;
+ }
applespi->keyboard_input_dev->name = "Apple SPI Keyboard";
applespi->keyboard_input_dev->phys = "applespi/input0";
@@ -1717,7 +1747,7 @@ static int applespi_probe(struct spi_device *spi)
if (sts) {
dev_err(&applespi->spi->dev,
"Unable to register keyboard input device (%d)\n", sts);
- return -ENODEV;
+ goto err_restore_dma;
}
/*
@@ -1729,7 +1759,8 @@ static int applespi_probe(struct spi_device *spi)
dev_err(&applespi->spi->dev,
"Failed to obtain GPE for SPI slave device: %s\n",
acpi_format_exception(acpi_sts));
- return -ENODEV;
+ sts = -ENODEV;
+ goto err_restore_dma;
}
applespi->gpe = (int)gpe;
@@ -1740,7 +1771,8 @@ static int applespi_probe(struct spi_device *spi)
dev_err(&applespi->spi->dev,
"Failed to install GPE handler for GPE %d: %s\n",
applespi->gpe, acpi_format_exception(acpi_sts));
- return -ENODEV;
+ sts = -ENODEV;
+ goto err_restore_dma;
}
applespi->suspended = false;
@@ -1751,7 +1783,8 @@ static int applespi_probe(struct spi_device *spi)
"Failed to enable GPE handler for GPE %d: %s\n",
applespi->gpe, acpi_format_exception(acpi_sts));
acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify);
- return -ENODEV;
+ sts = -ENODEV;
+ goto err_restore_dma;
}
/* trigger touchpad setup */
@@ -1789,6 +1822,11 @@ static int applespi_probe(struct spi_device *spi)
&applespi_tp_dim_fops);
return 0;
+
+err_restore_dma:
+ if (override_dma)
+ spi->controller->can_dma = applespi->original_can_dma;
+ return sts;
}
static void applespi_drain_writes(struct applespi_data *applespi)
@@ -1813,6 +1851,7 @@ static void applespi_drain_reads(struct applespi_data *applespi)
static void applespi_remove(struct spi_device *spi)
{
struct applespi_data *applespi = spi_get_drvdata(spi);
+ bool override_dma = applespi_force_pio || dmi_match(DMI_PRODUCT_NAME, "MacBook8,1");
applespi_drain_writes(applespi);
@@ -1822,6 +1861,9 @@ static void applespi_remove(struct spi_device *spi)
applespi_drain_reads(applespi);
+ if (override_dma)
+ spi->controller->can_dma = applespi->original_can_dma;
+
debugfs_remove_recursive(applespi->debugfs_root);
}
--
2.39.5
next prev parent reply other threads:[~2026-07-11 9:21 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-11 9:20 [PATCH v3 0/3] Input: applespi - fixes for DMA timeout, UAF, and NULL pointer dereference Shih-Yuan Lee
2026-07-11 9:20 ` Shih-Yuan Lee [this message]
2026-07-11 9:30 ` [PATCH v3 1/3] Input: applespi - force PIO mode on MacBook8,1 sashiko-bot
2026-07-11 9:20 ` [PATCH v3 2/3] Input: applespi - cancel pending work on driver remove Shih-Yuan Lee
2026-07-11 9:36 ` sashiko-bot
2026-07-11 9:20 ` [PATCH v3 3/3] Input: applespi - fix NULL pointer dereference in tp_dim open Shih-Yuan Lee
2026-07-11 9:39 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260711092054.13818-2-fourdollars@debian.org \
--to=fourdollars@debian.org \
--cc=dmitry.torokhov@gmail.com \
--cc=linux-input@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox