From c4331c507135838aaf803df6382b79327d10cf1c Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 10 Sep 2020 22:23:37 +0200 Subject: [PATCH] Update v4.19 patches Changes: - SAM: - Cleanup and restructuring. Links: - SAM: https://github.com/linux-surface/surface-aggregator-module/commit/84827e830e09cf4a7f38ecee63a6e7319bf22b9b - kernel: https://github.com/linux-surface/kernel/commit/f6bd6798d43e86b0fb0b6b3e6ae93fb306b1e09c --- patches/4.19/0001-surface3-power.patch | 2 +- .../0002-surface3-touchscreen-dma-fix.patch | 2 +- patches/4.19/0003-surface3-oemb.patch | 2 +- patches/4.19/0004-surface-buttons.patch | 2 +- patches/4.19/0005-suspend.patch | 2 +- patches/4.19/0006-ipts.patch | 2 +- patches/4.19/0007-wifi.patch | 2 +- patches/4.19/0008-surface-sam.patch | 1282 ++++++++--------- patches/4.19/0009-surface-sam-over-hid.patch | 2 +- patches/4.19/0010-surface-gpe.patch | 2 +- pkg/arch/kernel-lts/PKGBUILD | 20 +- 11 files changed, 613 insertions(+), 707 deletions(-) diff --git a/patches/4.19/0001-surface3-power.patch b/patches/4.19/0001-surface3-power.patch index d6441b682..b9dab072d 100644 --- a/patches/4.19/0001-surface3-power.patch +++ b/patches/4.19/0001-surface3-power.patch @@ -1,4 +1,4 @@ -From b422fc5ba72b16acef3b968747f059d6bdf98b8e Mon Sep 17 00:00:00 2001 +From 2b27645bad38762fcc16f4ac0a9f930be12dc56d Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Sep 2019 18:00:43 +0200 Subject: [PATCH 01/10] surface3-power diff --git a/patches/4.19/0002-surface3-touchscreen-dma-fix.patch b/patches/4.19/0002-surface3-touchscreen-dma-fix.patch index dc4648c9c..91bbdc0f6 100644 --- a/patches/4.19/0002-surface3-touchscreen-dma-fix.patch +++ b/patches/4.19/0002-surface3-touchscreen-dma-fix.patch @@ -1,4 +1,4 @@ -From b893f9530c82d2e1638c5d3a1ec68495ed074ae5 Mon Sep 17 00:00:00 2001 +From cc23a17bfdd6590e35ded6f3f74977f2ee555b9d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 5 Jul 2020 14:56:20 +0300 Subject: [PATCH 02/10] surface3-touchscreen-dma-fix diff --git a/patches/4.19/0003-surface3-oemb.patch b/patches/4.19/0003-surface3-oemb.patch index 800ce465b..3321cbffd 100644 --- a/patches/4.19/0003-surface3-oemb.patch +++ b/patches/4.19/0003-surface3-oemb.patch @@ -1,4 +1,4 @@ -From 43fa4088439b8bbc5f0da0294d0632daf93cea42 Mon Sep 17 00:00:00 2001 +From 2ecc50b1e97eb6e03da1573bc77579a959747720 Mon Sep 17 00:00:00 2001 From: Chih-Wei Huang Date: Tue, 18 Sep 2018 11:01:37 +0800 Subject: [PATCH 03/10] surface3-oemb diff --git a/patches/4.19/0004-surface-buttons.patch b/patches/4.19/0004-surface-buttons.patch index 9a2f6c3a6..6d328b2cd 100644 --- a/patches/4.19/0004-surface-buttons.patch +++ b/patches/4.19/0004-surface-buttons.patch @@ -1,4 +1,4 @@ -From 63f089ec36f3a1d2da9835e3cb2c7215f9502635 Mon Sep 17 00:00:00 2001 +From 066f906d44f16f19dd0db51f65e484e6ada3a746 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Jul 2019 17:51:37 +0200 Subject: [PATCH 04/10] surface-buttons diff --git a/patches/4.19/0005-suspend.patch b/patches/4.19/0005-suspend.patch index c63bdb6b8..eef1c7f31 100644 --- a/patches/4.19/0005-suspend.patch +++ b/patches/4.19/0005-suspend.patch @@ -1,4 +1,4 @@ -From 0aed72e4a7fedaa863fb959468368d58c512faea Mon Sep 17 00:00:00 2001 +From fc0c0dc8968fd830b9201665f8d22b9320ef576a Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Sat, 28 Sep 2019 17:48:21 +0200 Subject: [PATCH 05/10] suspend diff --git a/patches/4.19/0006-ipts.patch b/patches/4.19/0006-ipts.patch index 7fe314fb7..a8d945912 100644 --- a/patches/4.19/0006-ipts.patch +++ b/patches/4.19/0006-ipts.patch @@ -1,4 +1,4 @@ -From ba999a4990cd55ef2bb8f7ccb0859d7e9437ea0e Mon Sep 17 00:00:00 2001 +From 5e210179aa3805a2de1fbd962f8dbd41a7dec045 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Sep 2019 17:58:17 +0200 Subject: [PATCH 06/10] ipts diff --git a/patches/4.19/0007-wifi.patch b/patches/4.19/0007-wifi.patch index 224dc1268..86362182c 100644 --- a/patches/4.19/0007-wifi.patch +++ b/patches/4.19/0007-wifi.patch @@ -1,4 +1,4 @@ -From c888f3c6fccaee39aeb651af86e692a040136f4d Mon Sep 17 00:00:00 2001 +From 0ff2409216e886210e447368c88da0aa8498cf85 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 07/10] wifi diff --git a/patches/4.19/0008-surface-sam.patch b/patches/4.19/0008-surface-sam.patch index c9c788426..aa537973d 100644 --- a/patches/4.19/0008-surface-sam.patch +++ b/patches/4.19/0008-surface-sam.patch @@ -1,4 +1,4 @@ -From ab15e9bef7de01db4da1a967e4453641843fbd8b Mon Sep 17 00:00:00 2001 +From 8d0d4a3096e577659407cbd2e3c52bf43e938c8f Mon Sep 17 00:00:00 2001 From: qzed Date: Mon, 26 Aug 2019 01:15:40 +0200 Subject: [PATCH 08/10] surface-sam @@ -22,13 +22,12 @@ Subject: [PATCH 08/10] 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 ++ + .../surface_sam/clients/surface_sam_debugfs.c | 265 ++ .../clients/surface_sam_device_hub.c | 583 ++++ .../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 +++ @@ -46,10 +45,11 @@ Subject: [PATCH 08/10] surface-sam drivers/misc/surface_sam/ssh_request_layer.h | 136 + drivers/tty/serdev/core.c | 111 +- include/linux/mod_devicetable.h | 17 + - include/linux/surface_aggregator_module.h | 1715 ++++++++++++ + include/linux/surface_acpi_notify.h | 30 + + include/linux/surface_aggregator_module.h | 1740 ++++++++++++ scripts/mod/devicetable-offsets.c | 7 + scripts/mod/file2alias.c | 22 + - 45 files changed, 17563 insertions(+), 29 deletions(-) + 45 files changed, 17469 insertions(+), 29 deletions(-) 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 @@ -68,7 +68,6 @@ Subject: [PATCH 08/10] 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 @@ -85,6 +84,7 @@ Subject: [PATCH 08/10] 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 @@ -1797,10 +1797,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..15fd8d8d34898 +index 0000000000000..91d50dcef629e --- /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 @@ -1826,15 +1826,15 @@ index 0000000000000..15fd8d8d34898 + __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; +}; + @@ -1862,8 +1862,6 @@ index 0000000000000..15fd8d8d34898 + 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; @@ -1878,9 +1876,11 @@ index 0000000000000..15fd8d8d34898 + 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) { @@ -1889,19 +1889,19 @@ index 0000000000000..15fd8d8d34898 + 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) { @@ -1910,14 +1910,13 @@ index 0000000000000..15fd8d8d34898 + 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); @@ -1943,11 +1942,8 @@ index 0000000000000..15fd8d8d34898 + ret = tmp; + + // cleanup -+ if (pldbuf) -+ kfree(pldbuf); -+ -+ if (rspbuf) -+ kfree(rspbuf); ++ kfree(spec.payload); ++ kfree(rsp.pointer); + + return ret; +} @@ -1969,7 +1965,7 @@ index 0000000000000..15fd8d8d34898 + return ssam_dbgdev_request(file, arg); + + default: -+ return -EINVAL; ++ return -ENOIOCTLCMD; + } +} + @@ -2037,7 +2033,7 @@ index 0000000000000..15fd8d8d34898 +}; + +static struct platform_driver ssam_dbgdev_driver = { -+ .probe = ssam_dbgdev_probe, ++ .probe = ssam_dbgdev_probe, + .remove = ssam_dbgdev_remove, + .driver = { + .name = SSAM_DBGDEV_NAME, @@ -2058,14 +2054,13 @@ index 0000000000000..15fd8d8d34898 + + 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 "); @@ -3251,10 +3246,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. @@ -3273,7 +3268,7 @@ index 0000000000000..a47a5eb7391a1 +#include + +#include -+#include "surface_sam_san.h" ++#include + + +// TODO: vgaswitcheroo integration @@ -3346,6 +3341,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; @@ -3358,6 +3354,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 { @@ -4108,15 +4106,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; +} + @@ -4363,9 +4363,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; + } + } @@ -4385,6 +4385,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); @@ -4416,9 +4417,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) { @@ -4464,7 +4468,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); @@ -4499,7 +4503,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); @@ -4544,10 +4548,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. @@ -4560,57 +4564,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; @@ -4619,22 +4584,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 @@ -4642,8 +4941,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; + @@ -4669,375 +4968,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; + } + @@ -5047,49 +5020,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); @@ -5098,7 +5045,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 @@ -5114,12 +5063,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; +} + @@ -5130,13 +5078,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; @@ -5145,7 +5092,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 @@ -5154,20 +5101,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; @@ -5176,41 +5117,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; + } @@ -5227,22 +5167,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; @@ -5250,7 +5204,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; @@ -5276,94 +5230,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; @@ -5372,27 +5268,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; + } + @@ -5400,13 +5296,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; + @@ -5416,26 +5306,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); + + /* @@ -5444,19 +5329,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" }, + { }, +}; + @@ -5480,48 +5365,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. @@ -5566,28 +5415,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); +} + + @@ -5627,7 +5472,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; @@ -5647,7 +5492,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; + @@ -5676,7 +5521,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; + } @@ -5684,7 +5529,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; +} @@ -5692,7 +5537,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); +} + + @@ -16264,12 +16109,48 @@ index 610cdf8082f2e..d3b51c3488cba 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..5364764288f21 +index 0000000000000..bb37deb8836b3 --- /dev/null +++ b/include/linux/surface_aggregator_module.h -@@ -0,0 +1,1715 @@ +@@ -0,0 +1,1740 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Interface for Surface System Aggregator Module (SSAM) via Surface Serial @@ -17066,6 +16947,31 @@ index 0000000000000..5364764288f21 + 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. diff --git a/patches/4.19/0009-surface-sam-over-hid.patch b/patches/4.19/0009-surface-sam-over-hid.patch index e6b08168e..8fe8f3643 100644 --- a/patches/4.19/0009-surface-sam-over-hid.patch +++ b/patches/4.19/0009-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 7cbba449789e1256a45457876fec5b3e41b09785 Mon Sep 17 00:00:00 2001 +From f4f96f44e6610ddde9a4211e0ad05735c1161b07 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH 09/10] surface-sam-over-hid diff --git a/patches/4.19/0010-surface-gpe.patch b/patches/4.19/0010-surface-gpe.patch index 5f35b7d8e..32be72a2d 100644 --- a/patches/4.19/0010-surface-gpe.patch +++ b/patches/4.19/0010-surface-gpe.patch @@ -1,4 +1,4 @@ -From 59276f3647266b4e58b51a493a7afaef6576e652 Mon Sep 17 00:00:00 2001 +From 35261af143804010f415624ec5d5c813545862d3 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 16 Aug 2020 23:39:56 +0200 Subject: [PATCH 10/10] surface-gpe diff --git a/pkg/arch/kernel-lts/PKGBUILD b/pkg/arch/kernel-lts/PKGBUILD index 0c32961df..ee77e2127 100644 --- a/pkg/arch/kernel-lts/PKGBUILD +++ b/pkg/arch/kernel-lts/PKGBUILD @@ -41,16 +41,16 @@ sha256sums=('2a4335c66f0ea8cc49d89ab25e5e00d75fcb33fe638d5584855598b4b8f3038d' '4e68572e7cc4c5368f0236e0792660ae8498373988625dca46e509399a7eaea6' 'a13581d3c6dc595206e4fe7fcf6b542e7a1bdbe96101f0f010fc5be49f99baf2' 'd0fc46eebfb42efdde0b1b1a67f057b56222595b640274b240f5e1cdf36d40c3' - '9f8a60f8126c6e7c981703d2e0a7d103d52b6efb1b3143bf435df8b366890b3a' - '7a6d841e2a582e6be73020a7466bde3ec9fd4844fcea17132fe0bfcda6883d1f' - 'c9b3cfe6232601ae300a84e27442f8e142b68dffb9705f916701738de47e1106' - '120a086f499e0ca1243b036fdad6083988c903dd753aa7405f7159faeaa1c466' - '6e74d4d048a9a0c86b3c035ead610edce02cf151c8b541bd15effadc4d0fcf02' - 'e69e08011ca2dac4f0a23e943b882598eb315b5b59285f6f544223c33447c527' - '6fa55e170b6fef45c95d1dec00661ea58c6b49941cb8913899dcdbc217cdb3c4' - 'fdf3970e01a1f0ab2d5edfa878326d9c3ee499c05eb8afad104bd410a9fc9e80' - '7a241025ca99e12e3b681f3eb57c1dcdb4da73ecc03a82d6e894f8182a826b17' - 'a71e8bb9ef3c6db39f94b39c0794a795d8aa9e70eb1841114f7cb85da0b8abfd') + '1854aa50c52db18a22069a4fccdfe33326a0323a4aff31bc8f36f3cd1a4a2493' + 'd1c0e26c4d6e8cca663e6fd0ff550b69809bdda49e1a9b69499c1544373e1ece' + 'f69a3cabe5bc04242e08dd45cd57a1e56f05446f2ed454bea196ca1c86173dab' + '031d7e07ccb2cf359afc1bd014c1e12b65a74c57729403b53ce66eb0c6cfb0bd' + '011dcc0cd12c4448610b3a2891f07cc06bd790c2e85b8fc22810512a4de08c1f' + 'a340db858154cab193d2e4fcb2ab3681c3072bfd3d7e44b7c072ef85f77f808e' + '04a13708bdf6f1c42cd3c1bf6aa5f6f1852eee3faf7672992458ebf3943d186b' + '3a9627e69fab2027a09cd1d48f080d9973a60d25c49c2693f2d3a752051989c5' + '52e5dc499a634442279164deda93cd3ccae7ce4f963c532187cf1da132ac5fcb' + 'a797d8ca4840c39d4494d7a3b555d6374a332ed7d91a8411fe56d6a43118160d') export KBUILD_BUILD_HOST=archlinux export KBUILD_BUILD_USER=$pkgbase