From 6070a3cde49109177fb7f3b964942755c2d4cba4 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 10 Sep 2020 22:29:26 +0200 Subject: [PATCH] Update v5.8 patches Changes: - SAM: - Cleanup and restructuring. - GPE: - Cleanup and restructuring. Links: - SAM: https://github.com/linux-surface/surface-aggregator-module/commit/84827e830e09cf4a7f38ecee63a6e7319bf22b9b - GPE: https://github.com/linux-surface/surface-gpe/commit/829bacbe198978080a6f4844658393bbe431988a - kernel: https://github.com/linux-surface/kernel/commit/0d9bfdba18305a2ac9b7f4cb93dd837036d50b72 --- patches/5.8/0001-surface3-oemb.patch | 2 +- patches/5.8/0002-wifi.patch | 2 +- patches/5.8/0003-ipts.patch | 2 +- patches/5.8/0004-surface-sam.patch | 1637 +++++++++---------- patches/5.8/0005-surface-sam-over-hid.patch | 2 +- patches/5.8/0006-surface-gpe.patch | 146 +- pkg/arch/kernel/PKGBUILD | 12 +- 7 files changed, 875 insertions(+), 928 deletions(-) diff --git a/patches/5.8/0001-surface3-oemb.patch b/patches/5.8/0001-surface3-oemb.patch index f21fcc1ed..3e00efea7 100644 --- a/patches/5.8/0001-surface3-oemb.patch +++ b/patches/5.8/0001-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 7cd3be5c7f76a886083272c6dd562d7217dc0767 Mon Sep 17 00:00:00 2001 +From 066e779c7a5805e345f1a9dcdbcca1206b4ece67 Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Tue, 18 Sep 2018 11:01:37 +0800 Subject: [PATCH 1/6] surface3-oemb diff --git a/patches/5.8/0002-wifi.patch b/patches/5.8/0002-wifi.patch index 666574d6c..80759bb0d 100644 --- a/patches/5.8/0002-wifi.patch +++ b/patches/5.8/0002-wifi.patch @@ -1,4 +1,4 @@ -From 2a3ed3370f323ca5026a37f9ad2dedb23fd378ca Mon Sep 17 00:00:00 2001 +From ca3d192b0e00bebf0ff2352a00a9120d1a2e4e7c Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Thu, 20 Feb 2020 16:51:11 +0900 Subject: [PATCH 2/6] wifi diff --git a/patches/5.8/0003-ipts.patch b/patches/5.8/0003-ipts.patch index 63a0d4b4d..45a165ae8 100644 --- a/patches/5.8/0003-ipts.patch +++ b/patches/5.8/0003-ipts.patch @@ -1,4 +1,4 @@ -From ba612c1a501963c3b941275a4d5f2b3b215b8a5b Mon Sep 17 00:00:00 2001 +From 4ad6656739cd57b52360b9909af2ab762968a632 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH 3/6] ipts diff --git a/patches/5.8/0004-surface-sam.patch b/patches/5.8/0004-surface-sam.patch index cd5d7b281..3cfe2594f 100644 --- a/patches/5.8/0004-surface-sam.patch +++ b/patches/5.8/0004-surface-sam.patch @@ -1,4 +1,4 @@ -From cf006a00cf91c80ebf40bb250ffa00da2258fa3b Mon Sep 17 00:00:00 2001 +From 5d20062d20b656c3a28cbe838842b020179c7114 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 17 Aug 2020 01:23:20 +0200 Subject: [PATCH 4/6] surface-sam @@ -20,13 +20,12 @@ Subject: [PATCH 4/6] surface-sam drivers/misc/surface_sam/bus.h | 14 + drivers/misc/surface_sam/clients/Kconfig | 121 + drivers/misc/surface_sam/clients/Makefile | 11 + - .../surface_sam/clients/surface_sam_debugfs.c | 270 ++ - .../clients/surface_sam_device_hub.c | 583 ++++ + .../surface_sam/clients/surface_sam_debugfs.c | 265 ++ + .../clients/surface_sam_device_hub.c | 642 +++++ .../surface_sam/clients/surface_sam_dtx.c | 583 ++++ - .../surface_sam/clients/surface_sam_hps.c | 1287 +++++++++ - .../surface_sam/clients/surface_sam_san.c | 932 +++++++ - .../surface_sam/clients/surface_sam_san.h | 30 + - .../clients/surface_sam_sid_perfmode.c | 194 ++ + .../surface_sam/clients/surface_sam_hps.c | 1296 +++++++++ + .../surface_sam/clients/surface_sam_san.c | 813 ++++++ + .../clients/surface_sam_sid_perfmode.c | 190 ++ .../clients/surface_sam_sid_power.c | 1114 ++++++++ .../surface_sam/clients/surface_sam_sid_vhf.c | 498 ++++ .../surface_sam/clients/surface_sam_vhf.c | 334 +++ @@ -43,10 +42,11 @@ Subject: [PATCH 4/6] surface-sam drivers/misc/surface_sam/ssh_request_layer.c | 1246 +++++++++ drivers/misc/surface_sam/ssh_request_layer.h | 136 + include/linux/mod_devicetable.h | 17 + - include/linux/surface_aggregator_module.h | 1719 ++++++++++++ + include/linux/surface_acpi_notify.h | 30 + + include/linux/surface_aggregator_module.h | 1722 ++++++++++++ scripts/mod/devicetable-offsets.c | 7 + scripts/mod/file2alias.c | 22 + - 42 files changed, 17459 insertions(+) + 42 files changed, 17402 insertions(+) create mode 100644 Documentation/driver-api/ssam/client-api.rst create mode 100644 Documentation/driver-api/ssam/client.rst create mode 100644 Documentation/driver-api/ssam/index.rst @@ -65,7 +65,6 @@ Subject: [PATCH 4/6] surface-sam create mode 100644 drivers/misc/surface_sam/clients/surface_sam_dtx.c create mode 100644 drivers/misc/surface_sam/clients/surface_sam_hps.c create mode 100644 drivers/misc/surface_sam/clients/surface_sam_san.c - create mode 100644 drivers/misc/surface_sam/clients/surface_sam_san.h create mode 100644 drivers/misc/surface_sam/clients/surface_sam_sid_perfmode.c create mode 100644 drivers/misc/surface_sam/clients/surface_sam_sid_power.c create mode 100644 drivers/misc/surface_sam/clients/surface_sam_sid_vhf.c @@ -82,6 +81,7 @@ Subject: [PATCH 4/6] surface-sam create mode 100644 drivers/misc/surface_sam/ssh_protocol.h create mode 100644 drivers/misc/surface_sam/ssh_request_layer.c create mode 100644 drivers/misc/surface_sam/ssh_request_layer.h + create mode 100644 include/linux/surface_acpi_notify.h create mode 100644 include/linux/surface_aggregator_module.h diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst @@ -1729,10 +1729,10 @@ index 0000000000000..1db9db2f86252 +obj-$(CONFIG_SURFACE_SAM_DEVICE_HUB) += surface_sam_device_hub.o diff --git a/drivers/misc/surface_sam/clients/surface_sam_debugfs.c b/drivers/misc/surface_sam/clients/surface_sam_debugfs.c new file mode 100644 -index 0000000000000..9b7ffbe610b10 +index 0000000000000..191ae7eb9f996 --- /dev/null +++ b/drivers/misc/surface_sam/clients/surface_sam_debugfs.c -@@ -0,0 +1,270 @@ +@@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include @@ -1758,15 +1758,15 @@ index 0000000000000..9b7ffbe610b10 + __s16 status; + + struct { -+ __u8 __pad[6]; -+ __u16 length; + const __u8 __user *data; ++ __u16 length; ++ __u8 __pad[6]; + } payload; + + struct { -+ __u8 __pad[6]; -+ __u16 length; + __u8 __user *data; ++ __u16 length; ++ __u8 __pad[6]; + } response; +}; + @@ -1794,8 +1794,6 @@ index 0000000000000..9b7ffbe610b10 + struct ssam_dbgdev_request rqst; + struct ssam_request spec; + struct ssam_response rsp; -+ u8 *pldbuf = NULL; -+ u8 *rspbuf = NULL; + int status = 0, ret = 0, tmp; + + r = (struct ssam_dbgdev_request __user *)arg; @@ -1810,9 +1808,11 @@ index 0000000000000..9b7ffbe610b10 + spec.instance_id = rqst.instance_id; + spec.flags = rqst.flags; + spec.length = rqst.payload.length; ++ spec.payload = NULL; + + rsp.capacity = rqst.response.length; + rsp.length = 0; ++ rsp.pointer = NULL; + + // get request payload from user-space + if (spec.length) { @@ -1821,19 +1821,19 @@ index 0000000000000..9b7ffbe610b10 + goto out; + } + -+ pldbuf = kzalloc(spec.length, GFP_KERNEL); -+ if (!pldbuf) { ++ spec.payload = kzalloc(spec.length, GFP_KERNEL); ++ if (!spec.payload) { + status = -ENOMEM; + ret = -EFAULT; + goto out; + } + -+ if (copy_from_user(pldbuf, rqst.payload.data, spec.length)) { ++ if (copy_from_user((void *)spec.payload, rqst.payload.data, ++ spec.length)) { + ret = -EFAULT; + goto out; + } + } -+ spec.payload = pldbuf; + + // allocate response buffer + if (rsp.capacity) { @@ -1842,14 +1842,13 @@ index 0000000000000..9b7ffbe610b10 + goto out; + } + -+ rspbuf = kzalloc(rsp.capacity, GFP_KERNEL); -+ if (!rspbuf) { ++ rsp.pointer = kzalloc(rsp.capacity, GFP_KERNEL); ++ if (!rsp.pointer) { + status = -ENOMEM; + ret = -EFAULT; + goto out; + } + } -+ rsp.pointer = rspbuf; + + // perform request + status = ssam_request_sync(ddev->ctrl, &spec, &rsp); @@ -1875,11 +1874,8 @@ index 0000000000000..9b7ffbe610b10 + ret = tmp; + + // cleanup -+ if (pldbuf) -+ kfree(pldbuf); -+ -+ if (rspbuf) -+ kfree(rspbuf); ++ kfree(spec.payload); ++ kfree(rsp.pointer); + + return ret; +} @@ -1901,7 +1897,7 @@ index 0000000000000..9b7ffbe610b10 + return ssam_dbgdev_request(file, arg); + + default: -+ return -EINVAL; ++ return -ENOIOCTLCMD; + } +} + @@ -1969,7 +1965,7 @@ index 0000000000000..9b7ffbe610b10 +}; + +static struct platform_driver ssam_dbgdev_driver = { -+ .probe = ssam_dbgdev_probe, ++ .probe = ssam_dbgdev_probe, + .remove = ssam_dbgdev_remove, + .driver = { + .name = SSAM_DBGDEV_NAME, @@ -1990,14 +1986,13 @@ index 0000000000000..9b7ffbe610b10 + + return status; +} ++module_init(surface_sam_debugfs_init); + +static void __exit surface_sam_debugfs_exit(void) +{ + platform_driver_unregister(&ssam_dbgdev_driver); + platform_device_unregister(&ssam_dbgdev_device); +} -+ -+module_init(surface_sam_debugfs_init); +module_exit(surface_sam_debugfs_exit); + +MODULE_AUTHOR("Maximilian Luz "); @@ -2005,10 +2000,10 @@ index 0000000000000..9b7ffbe610b10 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_sam/clients/surface_sam_device_hub.c b/drivers/misc/surface_sam/clients/surface_sam_device_hub.c new file mode 100644 -index 0000000000000..7b56d5e6ca1e5 +index 0000000000000..d099def70d605 --- /dev/null +++ b/drivers/misc/surface_sam/clients/surface_sam_device_hub.c -@@ -0,0 +1,583 @@ +@@ -0,0 +1,642 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Surface Device Registry. @@ -2025,125 +2020,167 @@ index 0000000000000..7b56d5e6ca1e5 +#include + + -+/* -- Device registry structures. ------------------------------------------- */ -+ -+struct ssam_hub_cell { -+ struct ssam_device_uid uid; -+ void *data; -+}; -+ -+struct ssam_hub_desc { -+ const struct ssam_hub_cell *cells; -+ unsigned int num_cells; -+}; -+ -+ -+#define SSAM_DUID_HUB_MAIN SSAM_DUID(_HUB, 0x01, 0x00, 0x00) -+#define SSAM_DUID_HUB_BASE SSAM_DUID(_HUB, 0x02, 0x00, 0x00) -+ -+#define SSAM_DEFINE_HUB_DESC(__name, __cells) \ -+ struct ssam_hub_desc __name = { \ -+ .cells = __cells, \ -+ .num_cells = ARRAY_SIZE(__cells), \ -+ }; -+ -+#define SSAM_DEFINE_PLATFORM_HUB(__suffix) \ -+ static const SSAM_DEFINE_HUB_DESC(ssam_device_hub_##__suffix, \ -+ ssam_devices_##__suffix); \ -+ static const struct ssam_hub_cell ssam_platform_hubs_##__suffix[] = { \ -+ { SSAM_DUID_HUB_MAIN, (void *)&ssam_device_hub_##__suffix }, \ -+ }; \ -+ static const SSAM_DEFINE_HUB_DESC(ssam_platform_hub_##__suffix, \ -+ ssam_platform_hubs_##__suffix); \ -+ -+#define SSAM_DEFINE_PLATFORM_HUB_WITH_BASE(__suffix) \ -+ static const SSAM_DEFINE_HUB_DESC(ssam_device_hub_##__suffix, \ -+ ssam_devices_##__suffix); \ -+ static const SSAM_DEFINE_HUB_DESC(ssam_device_hub_##__suffix##_base, \ -+ ssam_devices_##__suffix##_base); \ -+ static const struct ssam_hub_cell ssam_platform_hubs_##__suffix[] = { \ -+ { SSAM_DUID_HUB_MAIN, (void *)&ssam_device_hub_##__suffix }, \ -+ { SSAM_DUID_HUB_BASE, (void *)&ssam_device_hub_##__suffix##_base },\ -+ }; \ -+ static const SSAM_DEFINE_HUB_DESC(ssam_platform_hub_##__suffix, \ -+ ssam_platform_hubs_##__suffix); \ -+ -+ +/* -- Device registry. ------------------------------------------------------ */ + -+#define SSAM_DUID_BAT_AC SSAM_DUID(BAT, 0x01, 0x01, 0x01) -+#define SSAM_DUID_BAT_MAIN SSAM_DUID(BAT, 0x01, 0x01, 0x00) -+#define SSAM_DUID_BAT_SB3BASE SSAM_DUID(BAT, 0x02, 0x01, 0x00) -+ -+#define SSAM_DUID_TMP_PERF SSAM_DUID(TMP, 0x01, 0x00, 0x02) -+ -+#define SSAM_DUID_HID_KEYBOARD SSAM_DUID(HID, 0x02, 0x01, 0x00) -+#define SSAM_DUID_HID_TOUCHPAD SSAM_DUID(HID, 0x02, 0x03, 0x00) -+#define SSAM_DUID_HID_IID5 SSAM_DUID(HID, 0x02, 0x05, 0x00) -+#define SSAM_DUID_HID_IID6 SSAM_DUID(HID, 0x02, 0x06, 0x00) -+ -+ -+static const struct ssam_hub_cell ssam_devices_sb2[] = { -+ { SSAM_DUID_TMP_PERF }, ++static const struct software_node ssam_node_root = { ++ .name = "ssam_platform_hub", +}; + -+static const struct ssam_hub_cell ssam_devices_sb3[] = { -+ { SSAM_DUID_TMP_PERF }, -+ { SSAM_DUID_BAT_AC }, -+ { SSAM_DUID_BAT_MAIN }, ++static const struct software_node ssam_node_hub_main = { ++ .name = "ssam:00:01:00:00", ++ .parent = &ssam_node_root, +}; + -+static const struct ssam_hub_cell ssam_devices_sb3_base[] = { -+ { SSAM_DUID_BAT_SB3BASE }, -+ { SSAM_DUID_HID_KEYBOARD }, -+ { SSAM_DUID_HID_TOUCHPAD }, -+ { SSAM_DUID_HID_IID5 }, -+ { SSAM_DUID_HID_IID6 }, ++static const struct software_node ssam_node_hub_base = { ++ .name = "ssam:00:02:00:00", ++ .parent = &ssam_node_root, +}; + -+static const struct ssam_hub_cell ssam_devices_sl1[] = { -+ { SSAM_DUID_TMP_PERF }, ++static const struct software_node ssam_node_bat_ac = { ++ .name = "ssam:02:01:01:01", ++ .parent = &ssam_node_hub_main, +}; + -+static const struct ssam_hub_cell ssam_devices_sl2[] = { -+ { SSAM_DUID_TMP_PERF }, ++static const struct software_node ssam_node_bat_main = { ++ .name = "ssam:02:01:01:00", ++ .parent = &ssam_node_hub_main, +}; + -+static const struct ssam_hub_cell ssam_devices_sl3[] = { -+ { SSAM_DUID_TMP_PERF }, -+ { SSAM_DUID_BAT_AC }, -+ { SSAM_DUID_BAT_MAIN }, -+ { SSAM_DUID_HID_KEYBOARD }, -+ { SSAM_DUID_HID_TOUCHPAD }, -+ { SSAM_DUID_HID_IID5 }, ++static const struct software_node ssam_node_bat_sb3base = { ++ .name = "ssam:02:02:01:00", ++ .parent = &ssam_node_hub_base, +}; + -+static const struct ssam_hub_cell ssam_devices_sp5[] = { -+ { SSAM_DUID_TMP_PERF }, ++static const struct software_node ssam_node_tmp_perf = { ++ .name = "ssam:03:01:00:02", ++ .parent = &ssam_node_hub_main, +}; + -+static const struct ssam_hub_cell ssam_devices_sp6[] = { -+ { SSAM_DUID_TMP_PERF }, ++static const struct software_node ssam_node_hid_main_keyboard = { ++ .name = "ssam:15:02:01:00", ++ .parent = &ssam_node_hub_main, +}; + -+static const struct ssam_hub_cell ssam_devices_sp7[] = { -+ { SSAM_DUID_TMP_PERF }, -+ { SSAM_DUID_BAT_AC }, -+ { SSAM_DUID_BAT_MAIN }, ++static const struct software_node ssam_node_hid_main_touchpad = { ++ .name = "ssam:15:02:03:00", ++ .parent = &ssam_node_hub_main, +}; + -+SSAM_DEFINE_PLATFORM_HUB(sb2); -+SSAM_DEFINE_PLATFORM_HUB_WITH_BASE(sb3); -+SSAM_DEFINE_PLATFORM_HUB(sl1); -+SSAM_DEFINE_PLATFORM_HUB(sl2); -+SSAM_DEFINE_PLATFORM_HUB(sl3); -+SSAM_DEFINE_PLATFORM_HUB(sp5); -+SSAM_DEFINE_PLATFORM_HUB(sp6); -+SSAM_DEFINE_PLATFORM_HUB(sp7); ++static const struct software_node ssam_node_hid_main_iid5 = { ++ .name = "ssam:15:02:05:00", ++ .parent = &ssam_node_hub_main, ++}; ++ ++static const struct software_node ssam_node_hid_base_keyboard = { ++ .name = "ssam:15:02:01:00", ++ .parent = &ssam_node_hub_base, ++}; ++ ++static const struct software_node ssam_node_hid_base_touchpad = { ++ .name = "ssam:15:02:03:00", ++ .parent = &ssam_node_hub_base, ++}; ++ ++static const struct software_node ssam_node_hid_base_iid5 = { ++ .name = "ssam:15:02:05:00", ++ .parent = &ssam_node_hub_base, ++}; ++ ++static const struct software_node ssam_node_hid_base_iid6 = { ++ .name = "ssam:15:02:05:00", ++ .parent = &ssam_node_hub_base, ++}; ++ ++ ++static const struct software_node *ssam_node_group_sb2[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sb3[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_hub_base, ++ &ssam_node_tmp_perf, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_bat_sb3base, ++ &ssam_node_hid_base_keyboard, ++ &ssam_node_hid_base_touchpad, ++ &ssam_node_hid_base_iid5, ++ &ssam_node_hid_base_iid6, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sl1[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sl2[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sl3[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ &ssam_node_hid_main_keyboard, ++ &ssam_node_hid_main_touchpad, ++ &ssam_node_hid_main_iid5, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sp5[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sp6[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ NULL, ++}; ++ ++static const struct software_node *ssam_node_group_sp7[] = { ++ &ssam_node_root, ++ &ssam_node_hub_main, ++ &ssam_node_tmp_perf, ++ &ssam_node_bat_ac, ++ &ssam_node_bat_main, ++ NULL, ++}; + + +/* -- Device registry helper functions. ------------------------------------- */ + ++static int ssam_uid_from_string(const char *str, struct ssam_device_uid *uid) ++{ ++ u8 tc, tid, iid, fn; ++ ++ if (sscanf(str, "ssam:%hhx:%hhx:%hhx:%hhx", &tc, &tid, &iid, &fn) != 4) ++ return -EINVAL; ++ ++ uid->category = tc; ++ uid->target = tid; ++ uid->instance = iid; ++ uid->function = fn; ++ ++ return 0; ++} ++ +static int ssam_hub_remove_devices_fn(struct device *dev, void *data) +{ + if (!is_ssam_device(dev)) @@ -2160,17 +2197,22 @@ index 0000000000000..7b56d5e6ca1e5 + +static int ssam_hub_add_device(struct device *parent, + struct ssam_controller *ctrl, -+ const struct ssam_hub_cell *cell) ++ struct fwnode_handle *node) +{ ++ struct ssam_device_uid uid; + struct ssam_device *sdev; + int status; + -+ sdev = ssam_device_alloc(ctrl, cell->uid); ++ status = ssam_uid_from_string(fwnode_get_name(node), &uid); ++ if (status) ++ return -ENODEV; ++ ++ sdev = ssam_device_alloc(ctrl, uid); + if (!sdev) + return -ENOMEM; + + sdev->dev.parent = parent; -+ sdev->dev.platform_data = cell->data; ++ sdev->dev.fwnode = node; + + status = ssam_device_add(sdev); + if (status) @@ -2181,13 +2223,14 @@ index 0000000000000..7b56d5e6ca1e5 + +static int ssam_hub_add_devices(struct device *parent, + struct ssam_controller *ctrl, -+ const struct ssam_hub_desc *desc) ++ struct fwnode_handle *node) +{ -+ int status, i; ++ struct fwnode_handle *child; ++ int status; + -+ for (i = 0; i < desc->num_cells; i++) { -+ status = ssam_hub_add_device(parent, ctrl, &desc->cells[i]); -+ if (status) ++ fwnode_for_each_child_node(node, child) { ++ status = ssam_hub_add_device(parent, ctrl, child); ++ if (status && status != -ENODEV) + goto err; + } + @@ -2202,12 +2245,12 @@ index 0000000000000..7b56d5e6ca1e5 + +static int ssam_hub_probe(struct ssam_device *sdev) +{ -+ const struct ssam_hub_desc *desc = dev_get_platdata(&sdev->dev); ++ struct fwnode_handle *node = dev_fwnode(&sdev->dev); + -+ if (!desc) ++ if (!node) + return -ENODEV; + -+ return ssam_hub_add_devices(&sdev->dev, sdev->ctrl, desc); ++ return ssam_hub_add_devices(&sdev->dev, sdev->ctrl, node); +} + +static void ssam_hub_remove(struct ssam_device *sdev) @@ -2241,7 +2284,6 @@ index 0000000000000..7b56d5e6ca1e5 + +struct ssam_base_hub { + struct ssam_device *sdev; -+ const struct ssam_hub_desc *devices; + + struct mutex lock; + enum ssam_base_hub_state state; @@ -2297,7 +2339,7 @@ index 0000000000000..7b56d5e6ca1e5 +} + +static struct device_attribute ssam_base_hub_attr_state = -+ __ATTR(state, S_IRUGO, ssam_base_hub_state_show, NULL); ++ __ATTR(state, 0444, ssam_base_hub_state_show, NULL); + +static struct attribute *ssam_base_hub_attrs[] = { + &ssam_base_hub_attr_state.attr, @@ -2313,6 +2355,7 @@ index 0000000000000..7b56d5e6ca1e5 + enum ssam_base_hub_state new) +{ + struct ssam_base_hub *hub = ssam_device_get_drvdata(sdev); ++ struct fwnode_handle *node = dev_fwnode(&sdev->dev); + int status = 0; + + mutex_lock(&hub->lock); @@ -2323,7 +2366,7 @@ index 0000000000000..7b56d5e6ca1e5 + hub->state = new; + + if (hub->state == SSAM_BASE_HUB_CONNECTED) -+ status = ssam_hub_add_devices(&sdev->dev, sdev->ctrl, hub->devices); ++ status = ssam_hub_add_devices(&sdev->dev, sdev->ctrl, node); + + if (hub->state != SSAM_BASE_HUB_CONNECTED || status) + ssam_hub_remove_devices(&sdev->dev); @@ -2388,25 +2431,15 @@ index 0000000000000..7b56d5e6ca1e5 + +static int ssam_base_hub_probe(struct ssam_device *sdev) +{ -+ const struct ssam_hub_desc *desc = dev_get_platdata(&sdev->dev); -+ const struct ssam_device_id *match; + enum ssam_base_hub_state state; + struct ssam_base_hub *hub; + int status; + -+ if (!desc) -+ return -ENODEV; -+ -+ match = ssam_device_get_match(sdev); -+ if (!match) -+ return -ENODEV; -+ + hub = devm_kzalloc(&sdev->dev, sizeof(*hub), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + hub->sdev = sdev; -+ hub->devices = desc; + hub->state = SSAM_BASE_HUB_UNINITIALIZED; + + // TODO: still need to verify registry @@ -2480,31 +2513,31 @@ index 0000000000000..7b56d5e6ca1e5 + +static const struct acpi_device_id ssam_platform_hub_match[] = { + /* Surface Pro 4, 5, and 6 */ -+ { "MSHW0081", (unsigned long)&ssam_platform_hub_sp5 }, ++ { "MSHW0081", (unsigned long)ssam_node_group_sp5 }, + + /* Surface Pro 6 (OMBR >= 0x10) */ -+ { "MSHW0111", (unsigned long)&ssam_platform_hub_sp6 }, ++ { "MSHW0111", (unsigned long)ssam_node_group_sp6 }, + + /* Surface Pro 7 */ -+ { "MSHW0116", (unsigned long)&ssam_platform_hub_sp7 }, ++ { "MSHW0116", (unsigned long)ssam_node_group_sp7 }, + + /* Surface Book 2 */ -+ { "MSHW0107", (unsigned long)&ssam_platform_hub_sb2 }, ++ { "MSHW0107", (unsigned long)ssam_node_group_sb2 }, + + /* Surface Book 3 */ -+ { "MSHW0117", (unsigned long)&ssam_platform_hub_sb3 }, ++ { "MSHW0117", (unsigned long)ssam_node_group_sb3 }, + + /* Surface Laptop 1 */ -+ { "MSHW0086", (unsigned long)&ssam_platform_hub_sl1 }, ++ { "MSHW0086", (unsigned long)ssam_node_group_sl1 }, + + /* Surface Laptop 2 */ -+ { "MSHW0112", (unsigned long)&ssam_platform_hub_sl2 }, ++ { "MSHW0112", (unsigned long)ssam_node_group_sl2 }, + + /* Surface Laptop 3 (13", Intel) */ -+ { "MSHW0114", (unsigned long)&ssam_platform_hub_sl3 }, ++ { "MSHW0114", (unsigned long)ssam_node_group_sl3 }, + + /* Surface Laptop 3 (15", AMD) */ -+ { "MSHW0110", (unsigned long)&ssam_platform_hub_sl3 }, ++ { "MSHW0110", (unsigned long)ssam_node_group_sl3 }, + + { }, +}; @@ -2512,12 +2545,13 @@ index 0000000000000..7b56d5e6ca1e5 + +static int ssam_platform_hub_probe(struct platform_device *pdev) +{ -+ const struct ssam_hub_desc *desc; ++ const struct software_node **nodes; + struct ssam_controller *ctrl; ++ struct fwnode_handle *root; + int status; + -+ desc = acpi_device_get_match_data(&pdev->dev); -+ if (!desc) ++ nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev); ++ if (!nodes) + return -ENODEV; + + /* @@ -2531,12 +2565,33 @@ index 0000000000000..7b56d5e6ca1e5 + if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; + -+ return ssam_hub_add_devices(&pdev->dev, ctrl, desc); ++ status = software_node_register_node_group(nodes); ++ if (status) ++ return status; ++ ++ root = software_node_fwnode(&ssam_node_root); ++ if (!root) ++ return -EFAULT; ++ ++ set_secondary_fwnode(&pdev->dev, root); ++ ++ status = ssam_hub_add_devices(&pdev->dev, ctrl, root); ++ if (status) { ++ software_node_unregister_node_group(nodes); ++ return status; ++ } ++ ++ platform_set_drvdata(pdev, nodes); ++ return 0; +} + +static int ssam_platform_hub_remove(struct platform_device *pdev) +{ ++ const struct software_node **nodes = platform_get_drvdata(pdev); ++ + ssam_hub_remove_devices(&pdev->dev); ++ set_secondary_fwnode(&pdev->dev, NULL); ++ software_node_unregister_node_group(nodes); + return 0; +} + @@ -2578,6 +2633,7 @@ index 0000000000000..7b56d5e6ca1e5 +err_platform: + return status; +} ++module_init(ssam_device_hub_init); + +static void __exit ssam_device_hub_exit(void) +{ @@ -2585,8 +2641,6 @@ index 0000000000000..7b56d5e6ca1e5 + ssam_device_driver_unregister(&ssam_hub_driver); + platform_driver_unregister(&ssam_platform_hub_driver); +} -+ -+module_init(ssam_device_hub_init); +module_exit(ssam_device_hub_exit); + +MODULE_AUTHOR("Maximilian Luz "); @@ -3183,10 +3237,10 @@ index 0000000000000..ff73f54328069 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_sam/clients/surface_sam_hps.c b/drivers/misc/surface_sam/clients/surface_sam_hps.c new file mode 100644 -index 0000000000000..a47a5eb7391a1 +index 0000000000000..3a72642d13da5 --- /dev/null +++ b/drivers/misc/surface_sam/clients/surface_sam_hps.c -@@ -0,0 +1,1287 @@ +@@ -0,0 +1,1296 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Surface dGPU hot-plug system driver. @@ -3205,7 +3259,7 @@ index 0000000000000..a47a5eb7391a1 +#include + +#include -+#include "surface_sam_san.h" ++#include + + +// TODO: vgaswitcheroo integration @@ -3278,6 +3332,7 @@ index 0000000000000..a47a5eb7391a1 + +struct shps_driver_data { + struct ssam_controller *ctrl; ++ struct platform_device *pdev; + + struct mutex lock; + struct pci_dev *dgpu_root_port; @@ -3290,6 +3345,8 @@ index 0000000000000..a47a5eb7391a1 + unsigned long state; + acpi_handle sgpc_handle; + struct shps_hardware_traits hardware_traits; ++ ++ struct notifier_block dgpu_nf; +}; + +struct shps_hardware_probe { @@ -4040,15 +4097,17 @@ index 0000000000000..a47a5eb7391a1 + return 0; +} + -+static int shps_dgpu_handle_rqsg(struct surface_sam_san_rqsg *rqsg, void *data) ++static int shps_dgpu_handle_rqsg(struct notifier_block *nb, unsigned long action, void *data) +{ -+ struct platform_device *pdev = data; ++ struct shps_driver_data *drvdata = container_of(nb, struct shps_driver_data, dgpu_nf); ++ struct platform_device *pdev = drvdata->pdev; ++ struct ssam_anf_dgpu_event *evt = data; + -+ if (rqsg->tc == SAM_DGPU_TC && rqsg->cid == SAM_DGPU_CID_POWERON) ++ if (evt->category == SAM_DGPU_TC && evt->command == SAM_DGPU_CID_POWERON) + return shps_dgpu_powered_on(pdev); + + dev_warn(&pdev->dev, "unimplemented dGPU request: RQSG(0x%02x, 0x%02x, 0x%02x)\n", -+ rqsg->tc, rqsg->cid, rqsg->iid); ++ evt->category, evt->command, evt->instance); + return 0; +} + @@ -4295,9 +4354,9 @@ index 0000000000000..a47a5eb7391a1 + + if (detected_traits.notification_method == SHPS_NOTIFICATION_METHOD_SAN) { + // link to SAN -+ status = surface_sam_san_consumer_register(&pdev->dev, 0); ++ status = ssam_anf_client_link(&pdev->dev); + if (status) { -+ dev_err(&pdev->dev, "failed to register with san consumer: %d\n", status); ++ dev_err(&pdev->dev, "failed to register as SAN client: %d\n", status); + return status == -ENXIO ? -EPROBE_DEFER : status; + } + } @@ -4317,6 +4376,7 @@ index 0000000000000..a47a5eb7391a1 + platform_set_drvdata(pdev, drvdata); + + drvdata->ctrl = ctrl; ++ drvdata->pdev = pdev; + drvdata->hardware_traits = detected_traits; + + drvdata->dgpu_root_port = shps_dgpu_dsm_get_pci_dev(pdev); @@ -4348,9 +4408,12 @@ index 0000000000000..a47a5eb7391a1 + goto err_devlink; + + if (detected_traits.notification_method == SHPS_NOTIFICATION_METHOD_SAN) { -+ status = surface_sam_san_set_rqsg_handler(shps_dgpu_handle_rqsg, pdev); ++ drvdata->dgpu_nf.priority = 1; ++ drvdata->dgpu_nf.notifier_call = shps_dgpu_handle_rqsg; ++ ++ status = ssam_anf_dgpu_notifier_register(&drvdata->dgpu_nf); + if (status) { -+ dev_err(&pdev->dev, "unable to set SAN notification handler (%d)\n", status); ++ dev_err(&pdev->dev, "unable to register SAN notification handler (%d)\n", status); + goto err_devlink; + } + } else if (detected_traits.notification_method == SHPS_NOTIFICATION_METHOD_SGCP) { @@ -4396,7 +4459,7 @@ index 0000000000000..a47a5eb7391a1 + if (detected_traits.notification_method == SHPS_NOTIFICATION_METHOD_SGCP) { + shps_remove_sgcp_notification(pdev); + } else if (detected_traits.notification_method == SHPS_NOTIFICATION_METHOD_SAN) { -+ surface_sam_san_set_rqsg_handler(NULL, NULL); ++ ssam_anf_dgpu_notifier_unregister(&drvdata->dgpu_nf); + } +err_devlink: + device_remove_groups(&pdev->dev, shps_power_groups); @@ -4431,7 +4494,7 @@ index 0000000000000..a47a5eb7391a1 + if (drvdata->hardware_traits.notification_method == SHPS_NOTIFICATION_METHOD_SGCP) { + shps_remove_sgcp_notification(pdev); + } else if (drvdata->hardware_traits.notification_method == SHPS_NOTIFICATION_METHOD_SAN) { -+ surface_sam_san_set_rqsg_handler(NULL, NULL); ++ ssam_anf_dgpu_notifier_unregister(&drvdata->dgpu_nf); + } + device_remove_groups(&pdev->dev, shps_power_groups); + shps_gpios_remove_irq(pdev); @@ -4476,10 +4539,10 @@ index 0000000000000..a47a5eb7391a1 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_sam/clients/surface_sam_san.c b/drivers/misc/surface_sam/clients/surface_sam_san.c new file mode 100644 -index 0000000000000..5b08a1068bb94 +index 0000000000000..ff3b59bcae554 --- /dev/null +++ b/drivers/misc/surface_sam/clients/surface_sam_san.c -@@ -0,0 +1,932 @@ +@@ -0,0 +1,813 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Surface ACPI Notify (SAN) and ACPI integration driver for SAM. @@ -4492,57 +4555,18 @@ index 0000000000000..5b08a1068bb94 +#include +#include +#include ++#include ++#include + +#include -+#include "surface_sam_san.h" ++#include + + -+#define SAN_RQST_RETRY 5 -+ -+#define SAN_DSM_REVISION 0 -+#define SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT 0x09 -+ -+static const guid_t SAN_DSM_UUID = -+ GUID_INIT(0x93b666c5, 0x70c6, 0x469f, 0xa2, 0x15, 0x3d, -+ 0x48, 0x7c, 0x91, 0xab, 0x3c); -+ -+#define SAM_EVENT_DELAY_PWR_ADAPTER msecs_to_jiffies(5000) -+#define SAM_EVENT_DELAY_PWR_BST msecs_to_jiffies(2500) -+ -+#define SAM_EVENT_PWR_CID_BIX 0x15 -+#define SAM_EVENT_PWR_CID_BST 0x16 -+#define SAM_EVENT_PWR_CID_ADAPTER 0x17 -+#define SAM_EVENT_PWR_CID_DPTF 0x4f -+ -+#define SAM_EVENT_TEMP_CID_NOTIFY_SENSOR_TRIP_POINT 0x0b -+ -+ -+struct san_acpi_consumer { -+ char *path; -+ bool required; -+ u32 flags; -+}; -+ -+struct san_handler_data { -+ struct acpi_connection_info info; // must be first -+}; -+ -+struct san_consumer_link { -+ const struct san_acpi_consumer *properties; -+ struct device_link *link; -+}; -+ -+struct san_consumers { -+ u32 num; -+ struct san_consumer_link *links; -+}; -+ +struct san_data { + struct device *dev; + struct ssam_controller *ctrl; + -+ struct san_handler_data context; -+ struct san_consumers consumers; ++ struct acpi_connection_info info; + + struct ssam_event_notifier nf_bat; + struct ssam_event_notifier nf_tmp; @@ -4551,22 +4575,356 @@ index 0000000000000..5b08a1068bb94 +#define to_san_data(ptr, member) \ + container_of(ptr, struct san_data, member) + ++ ++/* -- dGPU Notifier Interface. ---------------------------------------------- */ ++ ++struct san_rqsg_if { ++ struct rw_semaphore lock; ++ struct device *dev; ++ struct blocking_notifier_head nh; ++}; ++ ++static struct san_rqsg_if san_rqsg_if = { ++ .lock = __RWSEM_INITIALIZER(san_rqsg_if.lock), ++ .dev = NULL, ++ .nh = BLOCKING_NOTIFIER_INIT(san_rqsg_if.nh), ++}; ++ ++static int san_set_rqsg_interface_device(struct device *dev) ++{ ++ int status = 0; ++ ++ down_write(&san_rqsg_if.lock); ++ if (!san_rqsg_if.dev && dev) ++ san_rqsg_if.dev = dev; ++ else ++ status = -EBUSY; ++ up_write(&san_rqsg_if.lock); ++ ++ return status; ++} ++ ++int ssam_anf_client_link(struct device *client) ++{ ++ const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER; ++ struct device_link *link; ++ ++ down_read(&san_rqsg_if.lock); ++ ++ if (!san_rqsg_if.dev) { ++ up_read(&san_rqsg_if.lock); ++ return -ENXIO; ++ } ++ ++ link = device_link_add(client, san_rqsg_if.dev, flags); ++ if (!link) { ++ up_read(&san_rqsg_if.lock); ++ return -ENOMEM; ++ } ++ ++ if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) { ++ up_read(&san_rqsg_if.lock); ++ return -ENXIO; ++ } ++ ++ up_read(&san_rqsg_if.lock); ++ return 0; ++} ++EXPORT_SYMBOL_GPL(ssam_anf_client_link); ++ ++int ssam_anf_dgpu_notifier_register(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register(&san_rqsg_if.nh, nb); ++} ++EXPORT_SYMBOL_GPL(ssam_anf_dgpu_notifier_register); ++ ++int ssam_anf_dgpu_notifier_unregister(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister(&san_rqsg_if.nh, nb); ++} ++EXPORT_SYMBOL_GPL(ssam_anf_dgpu_notifier_unregister); ++ ++static int san_dgpu_notifier_call(struct ssam_anf_dgpu_event *evt) ++{ ++ int ret; ++ ++ ret = blocking_notifier_call_chain(&san_rqsg_if.nh, evt->command, evt); ++ return notifier_to_errno(ret); ++} ++ ++ ++/* -- ACPI _DSM event relay. ------------------------------------------------ */ ++ ++#define SAN_DSM_REVISION 0 ++ ++static const guid_t SAN_DSM_UUID = ++ GUID_INIT(0x93b666c5, 0x70c6, 0x469f, 0xa2, 0x15, 0x3d, ++ 0x48, 0x7c, 0x91, 0xab, 0x3c); ++ ++enum san_dsm_event_fn { ++ SAN_DSM_EVENT_FN_BAT1_STAT = 0x03, ++ SAN_DSM_EVENT_FN_BAT1_INFO = 0x04, ++ SAN_DSM_EVENT_FN_ADP1_STAT = 0x05, ++ SAN_DSM_EVENT_FN_ADP1_INFO = 0x06, ++ SAN_DSM_EVENT_FN_BAT2_STAT = 0x07, ++ SAN_DSM_EVENT_FN_BAT2_INFO = 0x08, ++ SAN_DSM_EVENT_FN_THERMAL = 0x09, ++ SAN_DSM_EVENT_FN_DPTF = 0x0a, ++}; ++ ++enum sam_event_cid_bat { ++ SAM_EVENT_CID_BAT_BIX = 0x15, ++ SAM_EVENT_CID_BAT_BST = 0x16, ++ SAM_EVENT_CID_BAT_ADP = 0x17, ++ SAM_EVENT_CID_BAT_PROT = 0x18, ++ SAM_EVENT_CID_BAT_DPTF = 0x4f, ++}; ++ ++enum sam_event_cid_tmp { ++ SAM_EVENT_CID_TMP_TRIP = 0x0b, ++}; ++ +struct san_event_work { + struct delayed_work work; + struct device *dev; -+ struct ssam_event event; // must be last ++ struct ssam_event event; // must be last +}; + ++static int san_acpi_notify_event(struct device *dev, u64 func, ++ union acpi_object *param) ++{ ++ acpi_handle san = ACPI_HANDLE(dev); ++ union acpi_object *obj; ++ int status = 0; ++ ++ if (!acpi_check_dsm(san, &SAN_DSM_UUID, SAN_DSM_REVISION, 1 << func)) ++ return 0; ++ ++ dev_dbg(dev, "notify event 0x%02llx\n", func); ++ ++ obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION, ++ func, param, ACPI_TYPE_BUFFER); ++ if (IS_ERR_OR_NULL(obj)) ++ return obj ? PTR_ERR(obj) : -ENXIO; ++ ++ if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { ++ dev_err(dev, "got unexpected result from _DSM\n"); ++ status = -EFAULT; ++ } ++ ++ ACPI_FREE(obj); ++ return status; ++} ++ ++static int san_evt_bat_adp(struct device *dev, const struct ssam_event *event) ++{ ++ int status; ++ ++ status = san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_ADP1_STAT, NULL); ++ if (status) ++ return status; ++ ++ /* ++ * Enusre that the battery states get updated correctly. ++ * When the battery is fully charged and an adapter is plugged in, it ++ * sometimes is not updated correctly, instead showing it as charging. ++ * Explicitly trigger battery updates to fix this. ++ */ ++ ++ status = san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_BAT1_STAT, NULL); ++ if (status) ++ return status; ++ ++ return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_BAT2_STAT, NULL); ++} ++ ++static int san_evt_bat_bix(struct device *dev, const struct ssam_event *event) ++{ ++ enum san_dsm_event_fn fn; ++ ++ if (event->instance_id == 0x02) ++ fn = SAN_DSM_EVENT_FN_BAT2_INFO; ++ else ++ fn = SAN_DSM_EVENT_FN_BAT1_INFO; ++ ++ return san_acpi_notify_event(dev, fn, NULL); ++} ++ ++static int san_evt_bat_bst(struct device *dev, const struct ssam_event *event) ++{ ++ enum san_dsm_event_fn fn; ++ ++ if (event->instance_id == 0x02) ++ fn = SAN_DSM_EVENT_FN_BAT2_STAT; ++ else ++ fn = SAN_DSM_EVENT_FN_BAT1_STAT; ++ ++ return san_acpi_notify_event(dev, fn, NULL); ++} ++ ++static int san_evt_bat_dptf(struct device *dev, const struct ssam_event *event) ++{ ++ union acpi_object payload; ++ ++ /* ++ * The Surface ACPI expects a buffer and not a package. It specifically ++ * checks for ObjectType (Arg3) == 0x03. This will cause a warning in ++ * acpica/nsarguments.c, but that warning can be safely ignored. ++ */ ++ payload.type = ACPI_TYPE_BUFFER; ++ payload.buffer.length = event->length; ++ payload.buffer.pointer = (u8 *)&event->data[0]; ++ ++ return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_DPTF, &payload); ++} ++ ++static unsigned long san_evt_bat_delay(u8 cid) ++{ ++ switch (cid) { ++ case SAM_EVENT_CID_BAT_ADP: ++ /* ++ * Wait for battery state to update before signalling adapter ++ * change. ++ */ ++ return msecs_to_jiffies(5000); ++ ++ case SAM_EVENT_CID_BAT_BST: ++ /* Ensure we do not miss anything important due to caching. */ ++ return msecs_to_jiffies(2000); ++ ++ default: ++ return 0; ++ } ++} ++ ++static bool san_evt_bat(const struct ssam_event *event, struct device *dev) ++{ ++ int status; ++ ++ switch (event->command_id) { ++ case SAM_EVENT_CID_BAT_BIX: ++ status = san_evt_bat_bix(dev, event); ++ break; ++ ++ case SAM_EVENT_CID_BAT_BST: ++ status = san_evt_bat_bst(dev, event); ++ break; ++ ++ case SAM_EVENT_CID_BAT_ADP: ++ status = san_evt_bat_adp(dev, event); ++ break; ++ ++ case SAM_EVENT_CID_BAT_PROT: ++ /* ++ * TODO: Implement support for battery protection status change ++ * event. ++ */ ++ return true; ++ ++ case SAM_EVENT_CID_BAT_DPTF: ++ status = san_evt_bat_dptf(dev, event); ++ break; ++ ++ default: ++ return false; ++ } ++ ++ if (status) ++ dev_err(dev, "error handling power event (cid = %x)\n", ++ event->command_id); ++ ++ return true; ++} ++ ++static void san_evt_bat_workfn(struct work_struct *work) ++{ ++ struct san_event_work *ev; ++ ++ ev = container_of(work, struct san_event_work, work.work); ++ san_evt_bat(&ev->event, ev->dev); ++ kfree(ev); ++} ++ ++static u32 san_evt_bat_nf(struct ssam_event_notifier *nf, ++ const struct ssam_event *event) ++{ ++ struct san_data *d = to_san_data(nf, nf_bat); ++ struct san_event_work *work; ++ unsigned long delay = san_evt_bat_delay(event->command_id); ++ ++ if (delay == 0) ++ return san_evt_bat(event, d->dev) ? SSAM_NOTIF_HANDLED : 0; ++ ++ work = kzalloc(sizeof(struct san_event_work) + event->length, GFP_KERNEL); ++ if (!work) ++ return ssam_notifier_from_errno(-ENOMEM); ++ ++ INIT_DELAYED_WORK(&work->work, san_evt_bat_workfn); ++ work->dev = d->dev; ++ ++ memcpy(&work->event, event, sizeof(struct ssam_event) + event->length); ++ ++ schedule_delayed_work(&work->work, delay); ++ return SSAM_NOTIF_HANDLED; ++} ++ ++static int san_evt_tmp_trip(struct device *dev, const struct ssam_event *event) ++{ ++ union acpi_object param; ++ ++ /* ++ * The Surface ACPI expects an integer and not a package. This will ++ * cause a warning in acpica/nsarguments.c, but that warning can be ++ * safely ignored. ++ */ ++ param.type = ACPI_TYPE_INTEGER; ++ param.integer.value = event->instance_id; ++ ++ return san_acpi_notify_event(dev, SAN_DSM_EVENT_FN_THERMAL, ¶m); ++} ++ ++static bool san_evt_tmp(const struct ssam_event *event, struct device *dev) ++{ ++ int status; ++ ++ switch (event->command_id) { ++ case SAM_EVENT_CID_TMP_TRIP: ++ status = san_evt_tmp_trip(dev, event); ++ break; ++ ++ default: ++ return false; ++ } ++ ++ if (status) { ++ dev_err(dev, "error handling thermal event (cid = %x)\n", ++ event->command_id); ++ } ++ ++ return true; ++} ++ ++static u32 san_evt_tmp_nf(struct ssam_event_notifier *nf, ++ const struct ssam_event *event) ++{ ++ struct san_data *d = to_san_data(nf, nf_bat); ++ ++ return san_evt_tmp(event, d->dev) ? SSAM_NOTIF_HANDLED : 0; ++} ++ ++ ++/* -- ACPI GSB OperationRegion Handler -------------------------------------- */ ++ +struct gsb_data_in { + u8 cv; +} __packed; + +struct gsb_data_rqsx { -+ u8 cv; // command value (should be 0x01 or 0x03) -+ u8 tc; // target controller -+ u8 tid; // transport channnel ID -+ u8 iid; // target sub-controller (e.g. primary vs. secondary battery) -+ u8 snc; // expect-response-flag ++ u8 cv; // command value (san_gsb_request_cv) ++ u8 tc; // target category ++ u8 tid; // target ID ++ u8 iid; // instance ID ++ u8 snc; // expect-response-flag? + u8 cid; // command ID + u16 cdl; // payload length + u8 pld[0]; // payload @@ -4574,8 +4932,8 @@ index 0000000000000..5b08a1068bb94 + +struct gsb_data_etwl { + u8 cv; // command value (should be 0x02) -+ u8 etw3; // ? -+ u8 etw4; // ? ++ u8 etw3; // unknown ++ u8 etw4; // unknown + u8 msg[0]; // error message (ASCIIZ) +} __packed; + @@ -4601,375 +4959,49 @@ index 0000000000000..5b08a1068bb94 +#define SAN_GSB_MAX_RQSX_PAYLOAD (U8_MAX - 2 - sizeof(struct gsb_data_rqsx)) +#define SAN_GSB_MAX_RESPONSE (U8_MAX - 2 - sizeof(struct gsb_data_out)) + -+#define san_request_sync_onstack(ctrl, rqst, rsp) \ -+ ssam_request_sync_onstack(ctrl, rqst, rsp, SAN_GSB_MAX_RQSX_PAYLOAD) ++#define SAN_GSB_COMMAND 0 + -+ -+enum san_pwr_event { -+ SAN_PWR_EVENT_BAT1_STAT = 0x03, -+ SAN_PWR_EVENT_BAT1_INFO = 0x04, -+ SAN_PWR_EVENT_ADP1_STAT = 0x05, -+ SAN_PWR_EVENT_ADP1_INFO = 0x06, -+ SAN_PWR_EVENT_BAT2_STAT = 0x07, -+ SAN_PWR_EVENT_BAT2_INFO = 0x08, -+ SAN_PWR_EVENT_DPTF = 0x0A, ++enum san_gsb_request_cv { ++ SAN_GSB_REQUEST_CV_RQST = 0x01, ++ SAN_GSB_REQUEST_CV_ETWL = 0x02, ++ SAN_GSB_REQUEST_CV_RQSG = 0x03, +}; + ++#define SAN_REQUEST_NUM_TRIES 5 + -+static int sam_san_default_rqsg_handler(struct surface_sam_san_rqsg *rqsg, void *data); -+ -+struct sam_san_rqsg_if { -+ struct mutex lock; -+ struct device *san_dev; -+ surface_sam_san_rqsg_handler_fn handler; -+ void *handler_data; -+}; -+ -+static struct sam_san_rqsg_if rqsg_if = { -+ .lock = __MUTEX_INITIALIZER(rqsg_if.lock), -+ .san_dev = NULL, -+ .handler = sam_san_default_rqsg_handler, -+ .handler_data = NULL, -+}; -+ -+int surface_sam_san_consumer_register(struct device *consumer, u32 flags) ++static acpi_status san_etwl(struct san_data *d, struct gsb_buffer *b) +{ -+ const u32 valid = DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE; -+ int status; ++ struct gsb_data_etwl *etwl = &b->data.etwl; + -+ if ((flags | valid) != valid) -+ return -EINVAL; -+ -+ flags |= DL_FLAG_AUTOREMOVE_CONSUMER; -+ -+ mutex_lock(&rqsg_if.lock); -+ if (rqsg_if.san_dev) -+ status = device_link_add(consumer, rqsg_if.san_dev, flags) ? 0 : -EINVAL; -+ else -+ status = -ENXIO; -+ mutex_unlock(&rqsg_if.lock); -+ return status; -+} -+EXPORT_SYMBOL_GPL(surface_sam_san_consumer_register); -+ -+int surface_sam_san_set_rqsg_handler(surface_sam_san_rqsg_handler_fn fn, void *data) -+{ -+ int status = -EBUSY; -+ -+ mutex_lock(&rqsg_if.lock); -+ -+ if (rqsg_if.handler == sam_san_default_rqsg_handler || !fn) { -+ rqsg_if.handler = fn ? fn : sam_san_default_rqsg_handler; -+ rqsg_if.handler_data = fn ? data : NULL; -+ status = 0; ++ if (b->len < sizeof(struct gsb_data_etwl)) { ++ dev_err(d->dev, "invalid ETWL package (len = %d)\n", b->len); ++ return AE_OK; + } + -+ mutex_unlock(&rqsg_if.lock); -+ return status; -+} -+EXPORT_SYMBOL_GPL(surface_sam_san_set_rqsg_handler); ++ dev_err(d->dev, "ETWL(0x%02x, 0x%02x): %.*s\n", etwl->etw3, etwl->etw4, ++ (unsigned int)(b->len - sizeof(struct gsb_data_etwl)), ++ (char *)etwl->msg); + -+int san_call_rqsg_handler(struct surface_sam_san_rqsg *rqsg) -+{ -+ int status; ++ // indicate success ++ b->status = 0x00; ++ b->len = 0x00; + -+ mutex_lock(&rqsg_if.lock); -+ status = rqsg_if.handler(rqsg, rqsg_if.handler_data); -+ mutex_unlock(&rqsg_if.lock); -+ -+ return status; ++ return AE_OK; +} + -+static int sam_san_default_rqsg_handler(struct surface_sam_san_rqsg *rqsg, void *data) ++static struct gsb_data_rqsx *san_validate_rqsx(struct device *dev, ++ const char *type, struct gsb_buffer *b) +{ -+ struct device *dev = rqsg_if.san_dev; ++ struct gsb_data_rqsx *rqsx = &b->data.rqsx; + -+ dev_warn(dev, "unhandled request: RQSG(0x%02x, 0x%02x, 0x%02x)\n", -+ rqsg->tc, rqsg->cid, rqsg->iid); -+ -+ return 0; -+} -+ -+ -+static bool san_acpi_can_notify(struct device *dev, u64 func) -+{ -+ acpi_handle san = ACPI_HANDLE(dev); -+ return acpi_check_dsm(san, &SAN_DSM_UUID, SAN_DSM_REVISION, 1 << func); -+} -+ -+static int san_acpi_notify_power_event(struct device *dev, enum san_pwr_event event) -+{ -+ acpi_handle san = ACPI_HANDLE(dev); -+ union acpi_object *obj; -+ -+ if (!san_acpi_can_notify(dev, event)) -+ return 0; -+ -+ dev_dbg(dev, "notify power event 0x%02x\n", event); -+ obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION, -+ event, NULL, ACPI_TYPE_BUFFER); -+ -+ if (IS_ERR_OR_NULL(obj)) -+ return obj ? PTR_ERR(obj) : -ENXIO; -+ -+ if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { -+ dev_err(dev, "got unexpected result from _DSM\n"); -+ return -EFAULT; -+ } -+ -+ ACPI_FREE(obj); -+ return 0; -+} -+ -+static int san_acpi_notify_sensor_trip_point(struct device *dev, u8 iid) -+{ -+ acpi_handle san = ACPI_HANDLE(dev); -+ union acpi_object *obj; -+ union acpi_object param; -+ -+ if (!san_acpi_can_notify(dev, SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT)) -+ return 0; -+ -+ param.type = ACPI_TYPE_INTEGER; -+ param.integer.value = iid; -+ -+ obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION, -+ SAN_DSM_FN_NOTIFY_SENSOR_TRIP_POINT, -+ ¶m, ACPI_TYPE_BUFFER); -+ -+ if (IS_ERR_OR_NULL(obj)) -+ return obj ? PTR_ERR(obj) : -ENXIO; -+ -+ if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { -+ dev_err(dev, "got unexpected result from _DSM\n"); -+ return -EFAULT; -+ } -+ -+ ACPI_FREE(obj); -+ return 0; -+} -+ -+ -+static inline int san_evt_power_adapter(struct device *dev, const struct ssam_event *event) -+{ -+ int status; -+ -+ status = san_acpi_notify_power_event(dev, SAN_PWR_EVENT_ADP1_STAT); -+ if (status) -+ return status; -+ -+ /* -+ * Enusre that the battery states get updated correctly. -+ * When the battery is fully charged and an adapter is plugged in, it -+ * sometimes is not updated correctly, instead showing it as charging. -+ * Explicitly trigger battery updates to fix this. -+ */ -+ -+ status = san_acpi_notify_power_event(dev, SAN_PWR_EVENT_BAT1_STAT); -+ if (status) -+ return status; -+ -+ return san_acpi_notify_power_event(dev, SAN_PWR_EVENT_BAT2_STAT); -+} -+ -+static inline int san_evt_power_bix(struct device *dev, const struct ssam_event *event) -+{ -+ enum san_pwr_event evcode; -+ -+ if (event->instance_id == 0x02) -+ evcode = SAN_PWR_EVENT_BAT2_INFO; -+ else -+ evcode = SAN_PWR_EVENT_BAT1_INFO; -+ -+ return san_acpi_notify_power_event(dev, evcode); -+} -+ -+static inline int san_evt_power_bst(struct device *dev, const struct ssam_event *event) -+{ -+ enum san_pwr_event evcode; -+ -+ if (event->instance_id == 0x02) -+ evcode = SAN_PWR_EVENT_BAT2_STAT; -+ else -+ evcode = SAN_PWR_EVENT_BAT1_STAT; -+ -+ return san_acpi_notify_power_event(dev, evcode); -+} -+ -+static inline int san_evt_power_dptf(struct device *dev, const struct ssam_event *event) -+{ -+ union acpi_object payload; -+ acpi_handle san = ACPI_HANDLE(dev); -+ union acpi_object *obj; -+ -+ if (!san_acpi_can_notify(dev, SAN_PWR_EVENT_DPTF)) -+ return 0; -+ -+ /* -+ * The Surface ACPI expects a buffer and not a package. It specifically -+ * checks for ObjectType (Arg3) == 0x03. This will cause a warning in -+ * acpica/nsarguments.c, but this can safely be ignored. -+ */ -+ payload.type = ACPI_TYPE_BUFFER; -+ payload.buffer.length = event->length; -+ payload.buffer.pointer = (u8 *)&event->data[0]; -+ -+ dev_dbg(dev, "notify power event 0x%02x\n", event->command_id); -+ obj = acpi_evaluate_dsm_typed(san, &SAN_DSM_UUID, SAN_DSM_REVISION, -+ SAN_PWR_EVENT_DPTF, &payload, -+ ACPI_TYPE_BUFFER); -+ -+ if (IS_ERR_OR_NULL(obj)) -+ return obj ? PTR_ERR(obj) : -ENXIO; -+ -+ if (obj->buffer.length != 1 || obj->buffer.pointer[0] != 0) { -+ dev_err(dev, "got unexpected result from _DSM\n"); -+ return -EFAULT; -+ } -+ -+ ACPI_FREE(obj); -+ return 0; -+} -+ -+static unsigned long san_evt_power_delay(u8 cid) -+{ -+ switch (cid) { -+ case SAM_EVENT_PWR_CID_ADAPTER: -+ /* -+ * Wait for battery state to update before signalling adapter change. -+ */ -+ return SAM_EVENT_DELAY_PWR_ADAPTER; -+ -+ case SAM_EVENT_PWR_CID_BST: -+ /* -+ * Ensure we do not miss anything important due to caching. -+ */ -+ return SAM_EVENT_DELAY_PWR_BST; -+ -+ case SAM_EVENT_PWR_CID_BIX: -+ case SAM_EVENT_PWR_CID_DPTF: -+ default: -+ return 0; -+ } -+} -+ -+static bool san_evt_power(const struct ssam_event *event, struct device *dev) -+{ -+ int status; -+ -+ switch (event->command_id) { -+ case SAM_EVENT_PWR_CID_BIX: -+ status = san_evt_power_bix(dev, event); -+ break; -+ -+ case SAM_EVENT_PWR_CID_BST: -+ status = san_evt_power_bst(dev, event); -+ break; -+ -+ case SAM_EVENT_PWR_CID_ADAPTER: -+ status = san_evt_power_adapter(dev, event); -+ break; -+ -+ case SAM_EVENT_PWR_CID_DPTF: -+ status = san_evt_power_dptf(dev, event); -+ break; -+ -+ default: -+ return false; -+ } -+ -+ if (status) -+ dev_err(dev, "error handling power event (cid = %x)\n", -+ event->command_id); -+ -+ return true; -+} -+ -+static void san_evt_power_workfn(struct work_struct *work) -+{ -+ struct san_event_work *ev = container_of(work, struct san_event_work, work.work); -+ -+ san_evt_power(&ev->event, ev->dev); -+ kfree(ev); -+} -+ -+ -+static u32 san_evt_power_nf(struct ssam_event_notifier *nf, const struct ssam_event *event) -+{ -+ struct san_data *d = to_san_data(nf, nf_bat); -+ struct san_event_work *work; -+ unsigned long delay = san_evt_power_delay(event->command_id); -+ -+ if (delay == 0) { -+ if (san_evt_power(event, d->dev)) -+ return SSAM_NOTIF_HANDLED; -+ else -+ return 0; -+ } -+ -+ work = kzalloc(sizeof(struct san_event_work) + event->length, GFP_KERNEL); -+ if (!work) -+ return ssam_notifier_from_errno(-ENOMEM); -+ -+ INIT_DELAYED_WORK(&work->work, san_evt_power_workfn); -+ work->dev = d->dev; -+ -+ memcpy(&work->event, event, sizeof(struct ssam_event) + event->length); -+ -+ schedule_delayed_work(&work->work, delay); -+ return SSAM_NOTIF_HANDLED; -+} -+ -+ -+static inline int san_evt_thermal_notify(struct device *dev, const struct ssam_event *event) -+{ -+ return san_acpi_notify_sensor_trip_point(dev, event->instance_id); -+} -+ -+static bool san_evt_thermal(const struct ssam_event *event, struct device *dev) -+{ -+ int status; -+ -+ switch (event->command_id) { -+ case SAM_EVENT_TEMP_CID_NOTIFY_SENSOR_TRIP_POINT: -+ status = san_evt_thermal_notify(dev, event); -+ break; -+ -+ default: -+ return false; -+ } -+ -+ if (status) { -+ dev_err(dev, "error handling thermal event (cid = %x)\n", -+ event->command_id); -+ } -+ -+ return true; -+} -+ -+static u32 san_evt_thermal_nf(struct ssam_event_notifier *nf, const struct ssam_event *event) -+{ -+ if (san_evt_thermal(event, to_san_data(nf, nf_tmp)->dev)) -+ return SSAM_NOTIF_HANDLED; -+ else -+ return 0; -+} -+ -+ -+static struct gsb_data_rqsx -+*san_validate_rqsx(struct device *dev, const char *type, struct gsb_buffer *buffer) -+{ -+ struct gsb_data_rqsx *rqsx = &buffer->data.rqsx; -+ -+ if (buffer->len < 8) { -+ dev_err(dev, "invalid %s package (len = %d)\n", -+ type, buffer->len); ++ if (b->len < sizeof(struct gsb_data_rqsx)) { ++ dev_err(dev, "invalid %s package (len = %d)\n", type, b->len); + return NULL; + } + -+ if (get_unaligned(&rqsx->cdl) != buffer->len - sizeof(struct gsb_data_rqsx)) { ++ if (get_unaligned(&rqsx->cdl) != b->len - sizeof(struct gsb_data_rqsx)) { + dev_err(dev, "bogus %s package (len = %d, cdl = %d)\n", -+ type, buffer->len, get_unaligned(&rqsx->cdl)); ++ type, b->len, get_unaligned(&rqsx->cdl)); + return NULL; + } + @@ -4979,49 +5011,23 @@ index 0000000000000..5b08a1068bb94 + return NULL; + } + -+ if (rqsx->tid != 0x01) { -+ dev_warn(dev, "unsupported %s package (tid = 0x%02x)\n", -+ type, rqsx->tid); -+ return NULL; -+ } -+ + return rqsx; +} + -+static acpi_status san_etwl(struct san_data *d, struct gsb_buffer *buffer) ++static void gsb_rqsx_response_error(struct gsb_buffer *gsb, int status) +{ -+ struct gsb_data_etwl *etwl = &buffer->data.etwl; -+ -+ if (buffer->len < 3) { -+ dev_err(d->dev, "invalid ETWL package (len = %d)\n", buffer->len); -+ return AE_OK; -+ } -+ -+ dev_err(d->dev, "ETWL(0x%02x, 0x%02x): %.*s\n", -+ etwl->etw3, etwl->etw4, -+ buffer->len - 3, (char *)etwl->msg); -+ -+ // indicate success -+ buffer->status = 0x00; -+ buffer->len = 0x00; -+ -+ return AE_OK; -+} -+ -+static void gsb_response_error(struct gsb_buffer *gsb, int status) -+{ -+ gsb->status = 0x00; -+ gsb->len = 0x02; ++ gsb->status = 0x00; ++ gsb->len = 0x02; + gsb->data.out.status = (u8)(-status); -+ gsb->data.out.len = 0x00; ++ gsb->data.out.len = 0x00; +} + -+static void gsb_response_success(struct gsb_buffer *gsb, u8 *ptr, size_t len) ++static void gsb_rqsx_response_success(struct gsb_buffer *gsb, u8 *ptr, size_t len) +{ -+ gsb->status = 0x00; -+ gsb->len = len + 2; ++ gsb->status = 0x00; ++ gsb->len = len + 2; + gsb->data.out.status = 0x00; -+ gsb->data.out.len = len; ++ gsb->data.out.len = len; + + if (len) + memcpy(&gsb->data.out.pld[0], ptr, len); @@ -5030,7 +5036,9 @@ index 0000000000000..5b08a1068bb94 +static acpi_status san_rqst_fixup_suspended(struct ssam_request *rqst, + struct gsb_buffer *gsb) +{ -+ if (rqst->target_category == 0x11 && rqst->command_id == 0x0D) { ++ if (rqst->target_category == SSAM_SSH_TC_BAS && rqst->command_id == 0x0D) { ++ u8 base_state = 1; ++ + /* Base state quirk: + * The base state may be queried from ACPI when the EC is still + * suspended. In this case it will return '-EPERM'. This query @@ -5046,12 +5054,11 @@ index 0000000000000..5b08a1068bb94 + * delay. + */ + -+ u8 base_state = 1; -+ gsb_response_success(gsb, &base_state, 1); ++ gsb_rqsx_response_success(gsb, &base_state, sizeof(base_state)); + return AE_OK; + } + -+ gsb_response_error(gsb, -ENXIO); ++ gsb_rqsx_response_error(gsb, -ENXIO); + return AE_OK; +} + @@ -5062,13 +5069,12 @@ index 0000000000000..5b08a1068bb94 + struct ssam_request rqst; + struct ssam_response rsp; + int status = 0; -+ int try; + -+ gsb_rqst = san_validate_rqsx(d->dev, "RQST", buffer); ++ gsb_rqst = san_validate_rqsx(d->dev, "RQST", buffer); + if (!gsb_rqst) + return AE_OK; + -+ rqst.target_category = gsb_rqst->tc; ++ rqst.target_category = gsb_rqst->tc; + rqst.target_id = gsb_rqst->tid; + rqst.command_id = gsb_rqst->cid; + rqst.instance_id = gsb_rqst->iid; @@ -5077,7 +5083,7 @@ index 0000000000000..5b08a1068bb94 + rqst.payload = &gsb_rqst->pld[0]; + + rsp.capacity = ARRAY_SIZE(rspbuf); -+ rsp.length = 0; ++ rsp.length = 0; + rsp.pointer = &rspbuf[0]; + + // handle suspended device @@ -5086,20 +5092,14 @@ index 0000000000000..5b08a1068bb94 + return san_rqst_fixup_suspended(&rqst, buffer); + } + -+ for (try = 0; try < SAN_RQST_RETRY; try++) { -+ if (try) -+ dev_warn(d->dev, "rqst: IO error, trying again\n"); -+ -+ status = san_request_sync_onstack(d->ctrl, &rqst, &rsp); -+ if (status != -ETIMEDOUT && status != -EREMOTEIO) -+ break; -+ } ++ status = ssam_retry(ssam_request_sync_onstack, SAN_REQUEST_NUM_TRIES, ++ d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD); + + if (!status) { -+ gsb_response_success(buffer, rsp.pointer, rsp.length); ++ gsb_rqsx_response_success(buffer, rsp.pointer, rsp.length); + } else { + dev_err(d->dev, "rqst: failed with error %d\n", status); -+ gsb_response_error(buffer, status); ++ gsb_rqsx_response_error(buffer, status); + } + + return AE_OK; @@ -5108,41 +5108,40 @@ index 0000000000000..5b08a1068bb94 +static acpi_status san_rqsg(struct san_data *d, struct gsb_buffer *buffer) +{ + struct gsb_data_rqsx *gsb_rqsg; -+ struct surface_sam_san_rqsg rqsg; ++ struct ssam_anf_dgpu_event evt; + int status; + + gsb_rqsg = san_validate_rqsx(d->dev, "RQSG", buffer); + if (!gsb_rqsg) + return AE_OK; + -+ rqsg.tc = gsb_rqsg->tc; -+ rqsg.cid = gsb_rqsg->cid; -+ rqsg.iid = gsb_rqsg->iid; -+ rqsg.cdl = get_unaligned(&gsb_rqsg->cdl); -+ rqsg.pld = &gsb_rqsg->pld[0]; ++ evt.category = gsb_rqsg->tc; ++ evt.target = gsb_rqsg->tid; ++ evt.command = gsb_rqsg->cid; ++ evt.instance = gsb_rqsg->iid; ++ evt.length = get_unaligned(&gsb_rqsg->cdl); ++ evt.payload = &gsb_rqsg->pld[0]; + -+ status = san_call_rqsg_handler(&rqsg); ++ status = san_dgpu_notifier_call(&evt); + if (!status) { -+ gsb_response_success(buffer, NULL, 0); ++ gsb_rqsx_response_success(buffer, NULL, 0); + } else { + dev_err(d->dev, "rqsg: failed with error %d\n", status); -+ gsb_response_error(buffer, status); ++ gsb_rqsx_response_error(buffer, status); + } + + return AE_OK; +} + -+ -+static acpi_status -+san_opreg_handler(u32 function, acpi_physical_address command, -+ u32 bits, u64 *value64, -+ void *opreg_context, void *region_context) ++static acpi_status san_opreg_handler(u32 function, ++ acpi_physical_address command, u32 bits, u64 *value64, ++ void *opreg_context, void *region_context) +{ -+ struct san_data *d = to_san_data(opreg_context, context); ++ struct san_data *d = to_san_data(opreg_context, info); + struct gsb_buffer *buffer = (struct gsb_buffer *)value64; -+ int accessor_type = (0xFFFF0000 & function) >> 16; ++ int accessor_type = (function & 0xFFFF0000) >> 16; + -+ if (command != 0) { ++ if (command != SAN_GSB_COMMAND) { + dev_warn(d->dev, "unsupported command: 0x%02llx\n", command); + return AE_OK; + } @@ -5159,22 +5158,36 @@ index 0000000000000..5b08a1068bb94 + } + + switch (buffer->data.in.cv) { -+ case 0x01: return san_rqst(d, buffer); -+ case 0x02: return san_etwl(d, buffer); -+ case 0x03: return san_rqsg(d, buffer); -+ } ++ case SAN_GSB_REQUEST_CV_RQST: ++ return san_rqst(d, buffer); + -+ dev_warn(d->dev, "unsupported SAN0 request (cv: 0x%02x)\n", buffer->data.in.cv); -+ return AE_OK; ++ case SAN_GSB_REQUEST_CV_ETWL: ++ return san_etwl(d, buffer); ++ ++ case SAN_GSB_REQUEST_CV_RQSG: ++ return san_rqsg(d, buffer); ++ ++ default: ++ dev_warn(d->dev, "unsupported SAN0 request (cv: 0x%02x)\n", ++ buffer->data.in.cv); ++ return AE_OK; ++ } +} + ++ ++/* -- Driver setup. --------------------------------------------------------- */ ++ ++struct san_acpi_consumer { ++ const char *path; ++}; ++ +static int san_events_register(struct platform_device *pdev) +{ + struct san_data *d = platform_get_drvdata(pdev); + int status; + + d->nf_bat.base.priority = 1; -+ d->nf_bat.base.fn = san_evt_power_nf; ++ d->nf_bat.base.fn = san_evt_bat_nf; + d->nf_bat.event.reg = SSAM_EVENT_REGISTRY_SAM; + d->nf_bat.event.id.target_category = SSAM_SSH_TC_BAT; + d->nf_bat.event.id.instance = 0; @@ -5182,7 +5195,7 @@ index 0000000000000..5b08a1068bb94 + d->nf_bat.event.flags = SSAM_EVENT_SEQUENCED; + + d->nf_tmp.base.priority = 1; -+ d->nf_tmp.base.fn = san_evt_thermal_nf; ++ d->nf_tmp.base.fn = san_evt_tmp_nf; + d->nf_tmp.event.reg = SSAM_EVENT_REGISTRY_SAM; + d->nf_tmp.event.id.target_category = SSAM_SSH_TC_TMP; + d->nf_tmp.event.id.instance = 0; @@ -5208,94 +5221,36 @@ index 0000000000000..5b08a1068bb94 + ssam_notifier_unregister(d->ctrl, &d->nf_tmp); +} + -+ +static int san_consumers_link(struct platform_device *pdev, -+ const struct san_acpi_consumer *cons, -+ struct san_consumers *out) ++ const struct san_acpi_consumer *cons) +{ -+ const struct san_acpi_consumer *con; -+ struct san_consumer_link *links, *link; -+ struct acpi_device *adev; -+ acpi_handle handle; -+ u32 max_links = 0; -+ int status; ++ const u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER; ++ const struct san_acpi_consumer *c; + -+ if (!cons) -+ return 0; ++ for (c = cons; c && c->path; ++c) { ++ struct acpi_device *adev; ++ acpi_handle handle; ++ int status; + -+ // count links -+ for (con = cons; con->path; ++con) -+ max_links += 1; -+ -+ // allocate -+ links = kcalloc(max_links, sizeof(struct san_consumer_link), GFP_KERNEL); -+ link = &links[0]; -+ -+ if (!links) -+ return -ENOMEM; -+ -+ // create links -+ for (con = cons; con->path; ++con) { -+ status = acpi_get_handle(NULL, con->path, &handle); -+ if (status) { -+ if (con->required || status != AE_NOT_FOUND) { -+ status = -ENXIO; -+ goto cleanup; -+ } else { -+ continue; -+ } -+ } ++ status = acpi_get_handle(NULL, (acpi_string)c->path, &handle); ++ if (status && status != AE_NOT_FOUND) ++ return -ENXIO; + + status = acpi_bus_get_device(handle, &adev); + if (status) -+ goto cleanup; ++ return status; + -+ link->link = device_link_add(&adev->dev, &pdev->dev, con->flags); -+ if (!(link->link)) { -+ status = -EFAULT; -+ goto cleanup; -+ } -+ link->properties = con; -+ -+ link += 1; ++ if (!device_link_add(&adev->dev, &pdev->dev, flags)) ++ return -EFAULT; + } + -+ out->num = link - links; -+ out->links = links; -+ + return 0; -+ -+cleanup: -+ for (link = link - 1; link >= links; --link) { -+ if (link->properties->flags & DL_FLAG_STATELESS) -+ device_link_del(link->link); -+ } -+ -+ return status; -+} -+ -+static void san_consumers_unlink(struct san_consumers *consumers) -+{ -+ u32 i; -+ -+ if (!consumers) -+ return; -+ -+ for (i = 0; i < consumers->num; ++i) { -+ if (consumers->links[i].properties->flags & DL_FLAG_STATELESS) -+ device_link_del(consumers->links[i].link); -+ } -+ -+ kfree(consumers->links); -+ -+ consumers->num = 0; -+ consumers->links = NULL; +} + +static int surface_sam_san_probe(struct platform_device *pdev) +{ + const struct san_acpi_consumer *cons; -+ acpi_handle san = ACPI_HANDLE(&pdev->dev); // _SAN device node ++ acpi_handle san = ACPI_HANDLE(&pdev->dev); + struct ssam_controller *ctrl; + struct san_data *data; + int status; @@ -5304,27 +5259,27 @@ index 0000000000000..5b08a1068bb94 + if (status) + return status == -ENXIO ? -EPROBE_DEFER : status; + -+ data = kzalloc(sizeof(struct san_data), GFP_KERNEL); ++ cons = acpi_device_get_match_data(&pdev->dev); ++ if (cons) { ++ status = san_consumers_link(pdev, cons); ++ if (status) ++ return status; ++ } ++ ++ data = devm_kzalloc(&pdev->dev, sizeof(struct san_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = &pdev->dev; + data->ctrl = ctrl; + -+ cons = acpi_device_get_match_data(&pdev->dev); -+ status = san_consumers_link(pdev, cons, &data->consumers); -+ if (status) -+ goto err_consumers; -+ + platform_set_drvdata(pdev, data); + -+ status = acpi_install_address_space_handler(san, -+ ACPI_ADR_SPACE_GSBUS, -+ &san_opreg_handler, -+ NULL, &data->context); ++ status = acpi_install_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, ++ &san_opreg_handler, NULL, &data->info); + + if (ACPI_FAILURE(status)) { -+ status = -ENODEV; ++ status = -ENXIO; + goto err_install_handler; + } + @@ -5332,13 +5287,7 @@ index 0000000000000..5b08a1068bb94 + if (status) + goto err_enable_events; + -+ mutex_lock(&rqsg_if.lock); -+ if (!rqsg_if.san_dev) -+ rqsg_if.san_dev = &pdev->dev; -+ else -+ status = -EBUSY; -+ mutex_unlock(&rqsg_if.lock); -+ ++ status = san_set_rqsg_interface_device(&pdev->dev); + if (status) + goto err_install_dev; + @@ -5348,26 +5297,21 @@ index 0000000000000..5b08a1068bb94 +err_install_dev: + san_events_unregister(pdev); +err_enable_events: -+ acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, &san_opreg_handler); ++ acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, ++ &san_opreg_handler); +err_install_handler: + platform_set_drvdata(san, NULL); -+ san_consumers_unlink(&data->consumers); -+err_consumers: -+ kfree(data); + return status; +} + +static int surface_sam_san_remove(struct platform_device *pdev) +{ -+ struct san_data *data = platform_get_drvdata(pdev); + acpi_handle san = ACPI_HANDLE(&pdev->dev); // _SAN device node + acpi_status status = AE_OK; + -+ mutex_lock(&rqsg_if.lock); -+ rqsg_if.san_dev = NULL; -+ mutex_unlock(&rqsg_if.lock); -+ -+ acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, &san_opreg_handler); ++ san_set_rqsg_interface_device(NULL); ++ acpi_remove_address_space_handler(san, ACPI_ADR_SPACE_GSBUS, ++ &san_opreg_handler); + san_events_unregister(pdev); + + /* @@ -5376,19 +5320,19 @@ index 0000000000000..5b08a1068bb94 + */ + flush_scheduled_work(); + -+ san_consumers_unlink(&data->consumers); -+ kfree(data); -+ + platform_set_drvdata(pdev, NULL); + return status; +} + -+ ++/* ++ * ACPI devices that make use of the SAM EC via the SAN interface. Link them ++ * to the SAN device to try and enforce correct suspend/resume orderding. ++ */ +static const struct san_acpi_consumer san_mshw0091_consumers[] = { -+ { "\\_SB.SRTC", true, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, -+ { "\\ADP1", true, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, -+ { "\\_SB.BAT1", true, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, -+ { "\\_SB.BAT2", false, DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS }, ++ { "\\_SB.SRTC" }, ++ { "\\ADP1" }, ++ { "\\_SB.BAT1" }, ++ { "\\_SB.BAT2" }, + { }, +}; + @@ -5412,48 +5356,12 @@ index 0000000000000..5b08a1068bb94 +MODULE_AUTHOR("Maximilian Luz "); +MODULE_DESCRIPTION("Surface ACPI Notify Driver for 5th Generation Surface Devices"); +MODULE_LICENSE("GPL"); -diff --git a/drivers/misc/surface_sam/clients/surface_sam_san.h b/drivers/misc/surface_sam/clients/surface_sam_san.h -new file mode 100644 -index 0000000000000..3408dde964b3c ---- /dev/null -+++ b/drivers/misc/surface_sam/clients/surface_sam_san.h -@@ -0,0 +1,30 @@ -+/* SPDX-License-Identifier: GPL-2.0-or-later */ -+/* -+ * Interface for Surface ACPI/Notify (SAN). -+ * -+ * The SAN is the main interface between the Surface Serial Hub (SSH) and the -+ * Surface/System Aggregator Module (SAM). It allows requests to be translated -+ * from ACPI to SSH/SAM. It also interfaces with the discrete GPU hot-plug -+ * driver. -+ */ -+ -+#ifndef _SURFACE_SAM_SAN_H -+#define _SURFACE_SAM_SAN_H -+ -+#include -+ -+ -+struct surface_sam_san_rqsg { -+ u8 tc; // target category -+ u8 cid; // command ID -+ u8 iid; // instance ID -+ u16 cdl; // command data length (length of payload) -+ u8 *pld; // pointer to payload of length cdl -+}; -+ -+typedef int (*surface_sam_san_rqsg_handler_fn)(struct surface_sam_san_rqsg *rqsg, void *data); -+ -+int surface_sam_san_consumer_register(struct device *consumer, u32 flags); -+int surface_sam_san_set_rqsg_handler(surface_sam_san_rqsg_handler_fn fn, void *data); -+ -+#endif /* _SURFACE_SAM_SAN_H */ diff --git a/drivers/misc/surface_sam/clients/surface_sam_sid_perfmode.c b/drivers/misc/surface_sam/clients/surface_sam_sid_perfmode.c new file mode 100644 -index 0000000000000..24907e15c47ae +index 0000000000000..44f5d31709b22 --- /dev/null +++ b/drivers/misc/surface_sam/clients/surface_sam_sid_perfmode.c -@@ -0,0 +1,194 @@ +@@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Surface Performance Mode Driver. @@ -5498,28 +5406,24 @@ index 0000000000000..24907e15c47ae + __le16 unknown2; +} __packed; + -+static SSAM_DEFINE_SYNC_REQUEST_R(ssam_tmp_perf_mode_get, struct ssam_perf_info, { ++static SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_tmp_perf_mode_get, struct ssam_perf_info, { + .target_category = SSAM_SSH_TC_TMP, -+ .target_id = 0x01, + .command_id = 0x02, -+ .instance_id = 0x00, +}); + -+static SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, { ++static SSAM_DEFINE_SYNC_REQUEST_CL_W(__ssam_tmp_perf_mode_set, __le32, { + .target_category = SSAM_SSH_TC_TMP, -+ .target_id = 0x01, + .command_id = 0x03, -+ .instance_id = 0x00, +}); + -+static int ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, u32 mode) ++static int ssam_tmp_perf_mode_set(struct ssam_device *sdev, u32 mode) +{ + __le32 mode_le = cpu_to_le32(mode); + + if (mode < __SAM_PERF_MODE__START || mode > __SAM_PERF_MODE__END) + return -EINVAL; + -+ return __ssam_tmp_perf_mode_set(ctrl, &mode_le); ++ return __ssam_tmp_perf_mode_set(sdev, &mode_le); +} + + @@ -5559,7 +5463,7 @@ index 0000000000000..24907e15c47ae + struct ssam_perf_info info; + int status; + -+ status = ssam_tmp_perf_mode_get(sdev->ctrl, &info); ++ status = ssam_tmp_perf_mode_get(sdev, &info); + if (status) { + dev_err(dev, "failed to get current performance mode: %d\n", status); + return -EIO; @@ -5579,7 +5483,7 @@ index 0000000000000..24907e15c47ae + if (status) + return status; + -+ status = ssam_tmp_perf_mode_set(sdev->ctrl, perf_mode); ++ status = ssam_tmp_perf_mode_set(sdev, perf_mode); + if (status) + return status; + @@ -5608,7 +5512,7 @@ index 0000000000000..24907e15c47ae + + // set initial perf_mode + if (param_perf_mode_init != SID_PARAM_PERF_MODE_AS_IS) { -+ status = ssam_tmp_perf_mode_set(sdev->ctrl, param_perf_mode_init); ++ status = ssam_tmp_perf_mode_set(sdev, param_perf_mode_init); + if (status) + return status; + } @@ -5616,7 +5520,7 @@ index 0000000000000..24907e15c47ae + // register perf_mode attribute + status = sysfs_create_file(&sdev->dev.kobj, &dev_attr_perf_mode.attr); + if (status) -+ ssam_tmp_perf_mode_set(sdev->ctrl, param_perf_mode_exit); ++ ssam_tmp_perf_mode_set(sdev, param_perf_mode_exit); + + return status; +} @@ -5624,7 +5528,7 @@ index 0000000000000..24907e15c47ae +static void surface_sam_sid_perfmode_remove(struct ssam_device *sdev) +{ + sysfs_remove_file(&sdev->dev.kobj, &dev_attr_perf_mode.attr); -+ ssam_tmp_perf_mode_set(sdev->ctrl, param_perf_mode_exit); ++ ssam_tmp_perf_mode_set(sdev, param_perf_mode_exit); +} + + @@ -16043,12 +15947,48 @@ index e14cbe444afcc..82c8660a5c869 100644 +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ +diff --git a/include/linux/surface_acpi_notify.h b/include/linux/surface_acpi_notify.h +new file mode 100644 +index 0000000000000..37be101afdd95 +--- /dev/null ++++ b/include/linux/surface_acpi_notify.h +@@ -0,0 +1,30 @@ ++/* SPDX-License-Identifier: GPL-2.0-or-later */ ++/* ++ * Interface for Surface ACPI/Notify (SAN). ++ * ++ * The SAN is the main interface between the Surface Serial Hub (SSH) and the ++ * Surface/System Aggregator Module (SAM). It allows requests to be translated ++ * from ACPI to SSH/SAM. It also interfaces with the discrete GPU hot-plug ++ * driver. ++ */ ++ ++#ifndef _SURFACE_SAM_SAN_H ++#define _SURFACE_SAM_SAN_H ++ ++#include ++ ++ ++struct ssam_anf_dgpu_event { ++ u8 category; // target category ++ u8 target; // target ID ++ u8 command; // command ID ++ u8 instance; // instance ID ++ u16 length; // command data length (length of payload) ++ u8 *payload; // pointer to payload of length cdl ++}; ++ ++int ssam_anf_client_link(struct device *client); ++int ssam_anf_dgpu_notifier_register(struct notifier_block *nb); ++int ssam_anf_dgpu_notifier_unregister(struct notifier_block *nb); ++ ++#endif /* _SURFACE_SAM_SAN_H */ diff --git a/include/linux/surface_aggregator_module.h b/include/linux/surface_aggregator_module.h new file mode 100644 -index 0000000000000..ab57517c8bfe9 +index 0000000000000..8cf14038a89a4 --- /dev/null +++ b/include/linux/surface_aggregator_module.h -@@ -0,0 +1,1719 @@ +@@ -0,0 +1,1722 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Interface for Surface System Aggregator Module (SSAM) via Surface Serial @@ -16849,6 +16789,31 @@ index 0000000000000..ab57517c8bfe9 + ssam_request_sync_with_buffer(ctrl, rqst, rsp, &__buf); \ + }) + ++/** ++ * ssam_retry - Retry request in case of I/O errors or timeouts. ++ * @request: The request function to execute. Must return an integer. ++ * @n: Number of tries. ++ * @args: Arguments for the request function. ++ * ++ * Executes the given request function, i.e. calls @request. In case the ++ * request returns %-EREMOTEIO (indicates I/O error) or -%ETIMEDOUT (request ++ * or underlying packet timed out), @request will be re-executed again, up to ++ * @n times in total. ++ * ++ * Return: Returns the return value of the last execution of @request. ++ */ ++#define ssam_retry(request, n, args...) \ ++ ({ \ ++ int __i, __s = 0; \ ++ \ ++ for (__i = (n); __i > 0; __i--) { \ ++ __s = request(args); \ ++ if (__s != -ETIMEDOUT && __s != -EREMOTEIO) \ ++ break; \ ++ } \ ++ __s; \ ++ }) ++ + +/** + * struct ssam_request_spec - Blue-print specification of SAM request. @@ -17411,28 +17376,6 @@ index 0000000000000..ab57517c8bfe9 + u8 function; +}; + -+/** -+ * SSAM_DUID() - Define a &struct ssam_device_uid. -+ * @cat: Target category of the device. -+ * @tid: Target ID of the device. -+ * @iid: Instance ID of the device. -+ * @fun: Sub-function of the (virtual) device. -+ * -+ * Return: The &struct ssam_device_uid specified by the given parameters. -+ */ -+#define SSAM_DUID(cat, tid, iid, fun) \ -+ ((struct ssam_device_uid) { \ -+ .category = SSAM_SSH_TC_##cat, \ -+ .target = (tid), \ -+ .instance = (iid), \ -+ .function = (fun) \ -+ }) -+ -+/* -+ * SSAM_DUID_NULL - Null device UID. -+ */ -+#define SSAM_DUID_NULL ((struct ssam_device_uid) { 0 }) -+ +/* + * Special values for device matching. + */ diff --git a/patches/5.8/0005-surface-sam-over-hid.patch b/patches/5.8/0005-surface-sam-over-hid.patch index d7b437fbb..eb67544ff 100644 --- a/patches/5.8/0005-surface-sam-over-hid.patch +++ b/patches/5.8/0005-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 06d09ff5e8976c38cee7a3989461e5f0c6192a13 Mon Sep 17 00:00:00 2001 +From 2c2d6aff72e97d6ce46164d42de267cf3e0dce2d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH 5/6] surface-sam-over-hid diff --git a/patches/5.8/0006-surface-gpe.patch b/patches/5.8/0006-surface-gpe.patch index 42fc0254f..93307a891 100644 --- a/patches/5.8/0006-surface-gpe.patch +++ b/patches/5.8/0006-surface-gpe.patch @@ -1,4 +1,4 @@ -From dfe3b509e98f3f8b1df867927490e3862655b7a4 Mon Sep 17 00:00:00 2001 +From 9ec51d0d15ab736230deeeb6a9699163666e159e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 16 Aug 2020 23:39:56 +0200 Subject: [PATCH 6/6] surface-gpe @@ -6,8 +6,8 @@ Subject: [PATCH 6/6] surface-gpe --- drivers/platform/x86/Kconfig | 9 + drivers/platform/x86/Makefile | 1 + - drivers/platform/x86/surface_gpe.c | 299 +++++++++++++++++++++++++++++ - 3 files changed, 309 insertions(+) + drivers/platform/x86/surface_gpe.c | 303 +++++++++++++++++++++++++++++ + 3 files changed, 313 insertions(+) create mode 100644 drivers/platform/x86/surface_gpe.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig @@ -44,10 +44,10 @@ index 5156523b58639..ef0c3fcab3194 100644 obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o diff --git a/drivers/platform/x86/surface_gpe.c b/drivers/platform/x86/surface_gpe.c new file mode 100644 -index 0000000000000..4c141fef7a5f4 +index 0000000000000..10e563f253b9e --- /dev/null +++ b/drivers/platform/x86/surface_gpe.c -@@ -0,0 +1,299 @@ +@@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Surface GPE/Lid driver to enable wakeup from suspend via the lid by @@ -60,29 +60,36 @@ index 0000000000000..4c141fef7a5f4 +#include +#include + ++/* ++ * Note: The GPE numbers for the lid devices found below have been obtained ++ * from ACPI/the DSDT table, specifically from the GPE handler for the ++ * lid. ++ */ + -+struct surface_lid_device { -+ u32 gpe_number; ++static const struct property_entry lid_device_props_l17[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x17), ++ {}, +}; + -+static const struct surface_lid_device lid_device_l17 = { -+ .gpe_number = 0x17, ++static const struct property_entry lid_device_props_l4D[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x4D), ++ {}, +}; + -+static const struct surface_lid_device lid_device_l4D = { -+ .gpe_number = 0x4D, ++static const struct property_entry lid_device_props_l4F[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x4F), ++ {}, +}; + -+static const struct surface_lid_device lid_device_l4F = { -+ .gpe_number = 0x4F, ++static const struct property_entry lid_device_props_l57[] = { ++ PROPERTY_ENTRY_U32("gpe", 0x57), ++ {}, +}; + -+static const struct surface_lid_device lid_device_l57 = { -+ .gpe_number = 0x57, -+}; -+ -+ -+// Note: When changing this don't forget to change the MODULE_ALIAS below. ++/* ++ * Note: When changing this, don't forget to check that the MODULE_ALIAS below ++ * still fits. ++ */ +static const struct dmi_system_id dmi_lid_device_table[] = { + { + .ident = "Surface Pro 4", @@ -90,7 +97,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, -+ .driver_data = (void *)&lid_device_l17, ++ .driver_data = (void *)lid_device_props_l17, + }, + { + .ident = "Surface Pro 5", @@ -102,7 +109,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, -+ .driver_data = (void *)&lid_device_l4F, ++ .driver_data = (void *)lid_device_props_l4F, + }, + { + .ident = "Surface Pro 5 (LTE)", @@ -114,7 +121,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, -+ .driver_data = (void *)&lid_device_l4F, ++ .driver_data = (void *)lid_device_props_l4F, + }, + { + .ident = "Surface Pro 6", @@ -122,7 +129,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, -+ .driver_data = (void *)&lid_device_l4F, ++ .driver_data = (void *)lid_device_props_l4F, + }, + { + .ident = "Surface Pro 7", @@ -130,7 +137,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 7"), + }, -+ .driver_data = (void *)&lid_device_l4D, ++ .driver_data = (void *)lid_device_props_l4D, + }, + { + .ident = "Surface Book 1", @@ -138,7 +145,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, -+ .driver_data = (void *)&lid_device_l17, ++ .driver_data = (void *)lid_device_props_l17, + }, + { + .ident = "Surface Book 2", @@ -146,7 +153,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, -+ .driver_data = (void *)&lid_device_l17, ++ .driver_data = (void *)lid_device_props_l17, + }, + { + .ident = "Surface Book 3", @@ -154,7 +161,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 3"), + }, -+ .driver_data = (void *)&lid_device_l4D, ++ .driver_data = (void *)lid_device_props_l4D, + }, + { + .ident = "Surface Laptop 1", @@ -162,7 +169,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, -+ .driver_data = (void *)&lid_device_l57, ++ .driver_data = (void *)lid_device_props_l57, + }, + { + .ident = "Surface Laptop 2", @@ -170,7 +177,7 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, -+ .driver_data = (void *)&lid_device_l57, ++ .driver_data = (void *)lid_device_props_l57, + }, + { + .ident = "Surface Laptop 3 (Intel 13\")", @@ -182,16 +189,18 @@ index 0000000000000..4c141fef7a5f4 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Laptop_3_1867:1868"), + }, -+ .driver_data = (void *)&lid_device_l4D, ++ .driver_data = (void *)lid_device_props_l4D, + }, + { } +}; + ++struct surface_lid_device { ++ u32 gpe_number; ++}; + -+static int surface_lid_enable_wakeup(struct device *dev, -+ const struct surface_lid_device *lid, -+ bool enable) ++static int surface_lid_enable_wakeup(struct device *dev, bool enable) +{ ++ const struct surface_lid_device *lid = dev_get_drvdata(dev); + int action = enable ? ACPI_GPE_ENABLE : ACPI_GPE_DISABLE; + acpi_status status; + @@ -204,50 +213,52 @@ index 0000000000000..4c141fef7a5f4 + return 0; +} + -+ +static int surface_gpe_suspend(struct device *dev) +{ -+ const struct surface_lid_device *lid; -+ -+ lid = dev_get_platdata(dev); -+ return surface_lid_enable_wakeup(dev, lid, true); ++ return surface_lid_enable_wakeup(dev, true); +} + +static int surface_gpe_resume(struct device *dev) +{ -+ const struct surface_lid_device *lid; -+ -+ lid = dev_get_platdata(dev); -+ return surface_lid_enable_wakeup(dev, lid, false); ++ return surface_lid_enable_wakeup(dev, false); +} + +static SIMPLE_DEV_PM_OPS(surface_gpe_pm, surface_gpe_suspend, surface_gpe_resume); + -+ +static int surface_gpe_probe(struct platform_device *pdev) +{ -+ const struct surface_lid_device *lid; ++ struct surface_lid_device *lid; ++ u32 gpe_number; + int status; + -+ lid = dev_get_platdata(&pdev->dev); -+ if (!lid) ++ status = device_property_read_u32(&pdev->dev, "gpe", &gpe_number); ++ if (status) + return -ENODEV; + -+ status = acpi_mark_gpe_for_wake(NULL, lid->gpe_number); ++ status = acpi_mark_gpe_for_wake(NULL, gpe_number); + if (status) { + dev_err(&pdev->dev, "failed to mark GPE for wake: %d\n", status); + return -EINVAL; + } + -+ status = acpi_enable_gpe(NULL, lid->gpe_number); ++ status = acpi_enable_gpe(NULL, gpe_number); + if (status) { + dev_err(&pdev->dev, "failed to enable GPE: %d\n", status); + return -EINVAL; + } + -+ status = surface_lid_enable_wakeup(&pdev->dev, lid, false); ++ lid = devm_kzalloc(&pdev->dev, sizeof(struct surface_lid_device), ++ GFP_KERNEL); ++ if (!lid) ++ return -ENOMEM; ++ ++ lid->gpe_number = gpe_number; ++ platform_set_drvdata(pdev, lid); ++ ++ status = surface_lid_enable_wakeup(&pdev->dev, false); + if (status) { -+ acpi_disable_gpe(NULL, lid->gpe_number); ++ acpi_disable_gpe(NULL, gpe_number); ++ platform_set_drvdata(pdev, NULL); + return status; + } + @@ -256,12 +267,13 @@ index 0000000000000..4c141fef7a5f4 + +static int surface_gpe_remove(struct platform_device *pdev) +{ -+ struct surface_lid_device *lid = dev_get_platdata(&pdev->dev); ++ struct surface_lid_device *lid = dev_get_drvdata(&pdev->dev); + + /* restore default behavior without this module */ -+ surface_lid_enable_wakeup(&pdev->dev, lid, false); ++ surface_lid_enable_wakeup(&pdev->dev, false); + acpi_disable_gpe(NULL, lid->gpe_number); + ++ platform_set_drvdata(pdev, NULL); + return 0; +} + @@ -275,14 +287,14 @@ index 0000000000000..4c141fef7a5f4 + }, +}; + -+ +static struct platform_device *surface_gpe_device; + +static int __init surface_gpe_init(void) +{ + const struct dmi_system_id *match; -+ const struct surface_lid_device *lid; ++ const struct property_entry *props; + struct platform_device *pdev; ++ struct fwnode_handle *fwnode; + int status; + + match = dmi_first_match(dmi_lid_device_table); @@ -291,7 +303,7 @@ index 0000000000000..4c141fef7a5f4 + return 0; + } + -+ lid = match->driver_data; ++ props = match->driver_data; + + status = platform_driver_register(&surface_gpe_driver); + if (status) @@ -303,13 +315,15 @@ index 0000000000000..4c141fef7a5f4 + return -ENOMEM; + } + -+ status = platform_device_add_data(pdev, lid, sizeof(*lid)); -+ if (status) { ++ fwnode = fwnode_create_software_node(props, NULL); ++ if (IS_ERR(fwnode)) { + platform_device_put(pdev); + platform_driver_unregister(&surface_gpe_driver); -+ return status; ++ return PTR_ERR(fwnode); + } + ++ pdev->dev.fwnode = fwnode; ++ + status = platform_device_add(pdev); + if (status) { + platform_device_put(pdev); @@ -320,33 +334,23 @@ index 0000000000000..4c141fef7a5f4 + surface_gpe_device = pdev; + return 0; +} ++module_init(surface_gpe_init); + +static void __exit surface_gpe_exit(void) +{ + if (!surface_gpe_device) + return; + ++ fwnode_remove_software_node(surface_gpe_device->dev.fwnode); + platform_device_unregister(surface_gpe_device); + platform_driver_unregister(&surface_gpe_driver); +} -+ -+module_init(surface_gpe_init); +module_exit(surface_gpe_exit); + +MODULE_AUTHOR("Maximilian Luz "); +MODULE_DESCRIPTION("Surface GPE/Lid Driver"); +MODULE_LICENSE("GPL"); -+ -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfacePro:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfacePro4:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfacePro6:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfacePro7:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfaceBook:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfaceBook2:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfaceBook3:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfaceLaptop:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfaceLaptop2:*"); -+MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurfaceLaptop3:*"); ++MODULE_ALIAS("dmi:*:svnMicrosoftCorporation:pnSurface*:*"); -- 2.28.0 diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index 0956a74dd..10bbf6850 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -40,12 +40,12 @@ sha256sums=('d82def15bf6c77f1a420be2fd2609f67b08e17795952fe014cb888259181feb4' '181330a9cf4517abbbe29b93165bc859ad8ca14a43582f4e1d69aae2b5ecc2c9' '1f65b3f042db87952468e99be3f1f688f62dda18401bf9716cb734f5571288b5' '8dbaa21d2c03621b0c5d96c4fbcc7a839bea5a34a5f2279a409c3b404756e753' - 'a4077505868f3ce12601948e01c42e6486d022681019702238c5ef2f73ce7b41' - 'db1a236a5f3ee524ae13c410561962a663660b33156d79a60bd71b4b5f094677' - '984be5bde800d60d1c64c7018a65b0931cd74335919b393429646685e18ce7bc' - '91c5bd34b2d9bbb981720296e81fd47914c327c1fc83a3501471f298a7b27c11' - '14bd1b3e74af2b6e60afae9bc008d59f789ffd4d1e9e9721ed0e950c2d48585a' - 'b07f659bdbf60a1992657cfc581fa3b4a97d1caca2c26d54f252f722e8ae6c46') + '119fb1a8af1dd4f96cd6ce111be8b97c6269a47ee06ae4c2f7eef41ec20729aa' + '313546bef7d4b3744ec64652411e67ea3460e47c8036c6b616f510d68a1deb55' + '4459f22b346b14bca1f856666e92e2c771d0d844b8c1a709a7ab10e22564a075' + '951710d7a544a8bd6f8750ead837a62b4b5f3cb7751d703208f74defe75eec95' + '1d1f9a5c527f87d47fb417b4968d71e1b3cc57abb673a39c8248c3681d2cc978' + '5a8be55468498b00c77fe7c777d750a86ee7379c1a0baeaa6d4e14d6fc26c5d4') export KBUILD_BUILD_HOST=archlinux