From b4964cbc542f544f31674933e951e1113739e0cb Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Tue, 24 Nov 2020 16:48:41 +0100 Subject: [PATCH] Update v5.9 patches Changes: - SAM: - Add serial I/O transmission timeout - Fix memory leak in error case - Clean up code and fix typos - Other fixes Links: - SAM: https://github.com/linux-surface/surface-aggregator-module/commit/19ddacd0d3882736d2c494143592df6fd4e8537c - kernel: https://github.com/linux-surface/kernel/commit/7732f52d7d7b3af69fb3364d0928398668df466d --- patches/5.9/0001-surface3-oemb.patch | 2 +- patches/5.9/0002-wifi.patch | 24 +- patches/5.9/0003-ipts.patch | 6 +- patches/5.9/0004-surface-gpe.patch | 2 +- patches/5.9/0005-surface-sam-over-hid.patch | 4 +- patches/5.9/0006-surface-sam.patch | 1341 ++++++++++--------- patches/5.9/0007-surface-typecover.patch | 2 +- pkg/arch/kernel/PKGBUILD | 14 +- 8 files changed, 760 insertions(+), 635 deletions(-) diff --git a/patches/5.9/0001-surface3-oemb.patch b/patches/5.9/0001-surface3-oemb.patch index b865c4b3d..daff83434 100644 --- a/patches/5.9/0001-surface3-oemb.patch +++ b/patches/5.9/0001-surface3-oemb.patch @@ -1,4 +1,4 @@ -From bcc470a5c0698f5706378ff82eedda63ccd35d1a Mon Sep 17 00:00:00 2001 +From ceab7ae053318d9fb5c2571070e7a6b21d5e5c18 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 18 Oct 2020 16:42:44 +0900 Subject: [PATCH] (surface3-oemb) add DMI matches for Surface 3 with broken DMI diff --git a/patches/5.9/0002-wifi.patch b/patches/5.9/0002-wifi.patch index bc171fea7..b54d76086 100644 --- a/patches/5.9/0002-wifi.patch +++ b/patches/5.9/0002-wifi.patch @@ -1,4 +1,4 @@ -From 74c77b82a0a8af9fd8c87bc401fab7c06c5ec796 Mon Sep 17 00:00:00 2001 +From 97625fe44e3b5841372a5a005ad5bf8abe7829f5 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Thu, 24 Sep 2020 18:02:06 +0900 Subject: [PATCH] mwifiex: pcie: skip cancel_work_sync() on reset failure path @@ -156,7 +156,7 @@ index fc59b522f670..048f4db6027a 100644 -- 2.29.2 -From 17333080602c7f3054d13254737445325430f4a2 Mon Sep 17 00:00:00 2001 +From 8a0fbe6b7e2e07f69dd93decf906e0792aff5cda Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Mon, 28 Sep 2020 17:46:49 +0900 Subject: [PATCH] mwifiex: pcie: add DMI-based quirk impl for Surface devices @@ -364,7 +364,7 @@ index 000000000000..5326ae7e5671 -- 2.29.2 -From 50f22e019a84229ef1a49485dc5d1e22da542fff Mon Sep 17 00:00:00 2001 +From a5c4c15fb7384a4fda273e93ac3af9488eaf4c88 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Tue, 29 Sep 2020 17:25:22 +0900 Subject: [PATCH] mwifiex: pcie: add reset_d3cold quirk for Surface gen4+ @@ -565,7 +565,7 @@ index 5326ae7e5671..8b9dcb5070d8 100644 -- 2.29.2 -From 43d1be085eae6527618151ea56eea4a0223be5f6 Mon Sep 17 00:00:00 2001 +From 58abf2d704a4c2acd806b0e2cd3229e938420d03 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Tue, 29 Sep 2020 17:32:22 +0900 Subject: [PATCH] mwifiex: pcie: add reset_wsid quirk for Surface 3 @@ -744,7 +744,7 @@ index 8b9dcb5070d8..3ef7440418e3 100644 -- 2.29.2 -From 757d1414fb52417e869dcdeff717439ce6b4b432 Mon Sep 17 00:00:00 2001 +From 49f96b3886f2d6e5b44e38bc4d7d28a73d7d4d9e Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Wed, 30 Sep 2020 18:08:24 +0900 Subject: [PATCH] mwifiex: pcie: (OEMB) add quirk for Surface 3 with broken DMI @@ -806,7 +806,7 @@ index f0a6fa0a7ae5..34dcd84f02a6 100644 -- 2.29.2 -From 5ce9a0a3f4164ac8a374f439ae5cf2ee6b259238 Mon Sep 17 00:00:00 2001 +From 0f6308694a660583998eaaf4b085c6d9f542faa9 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Thu, 24 Sep 2020 01:56:29 +0900 Subject: [PATCH] mwifiex: fix mwifiex_shutdown_sw() causing sw reset failure @@ -883,7 +883,7 @@ index 9ee5600351a7..5965999f1b9b 100644 -- 2.29.2 -From 3fb13d88addf81f89182c277a3465900eb955cdd Mon Sep 17 00:00:00 2001 +From a6920350cb750a102f41188d8cc5593aca8022a1 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Thu, 24 Sep 2020 01:56:34 +0900 Subject: [PATCH] mwifiex: pcie: use shutdown_sw()/reinit_sw() on @@ -1025,7 +1025,7 @@ index daae572ce94e..b46d56389c3b 100644 -- 2.29.2 -From 15266dbbcdfb49760b51416a83fb368e22d23385 Mon Sep 17 00:00:00 2001 +From 9273f2393ed6db40a1fd976403ece9efa43765b5 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Mon, 24 Aug 2020 17:11:35 +0900 Subject: [PATCH] mwifiex: pcie: add enable_device_dump module parameter @@ -1074,7 +1074,7 @@ index b46d56389c3b..1847a0274991 100644 -- 2.29.2 -From 06ae6b1caeacd400f1f351ac743648a9899ea7e7 Mon Sep 17 00:00:00 2001 +From 2f6a82518dc5d79343ecca57f95ce191fd8025d7 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:11:49 +0900 Subject: [PATCH] mwifiex: pcie: disable bridge_d3 for Surface gen4+ @@ -1229,7 +1229,7 @@ index 3ef7440418e3..a95ebac06e13 100644 -- 2.29.2 -From bd8188fb5deb2c7682ca1a1f2b985b8f8b8be5cf Mon Sep 17 00:00:00 2001 +From 9615589c153464b82d3a8d2c7063067dc8e65210 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:25:48 +0900 Subject: [PATCH] mwifiex: add allow_ps_mode module parameter @@ -1291,7 +1291,7 @@ index 96848fa0e417..786f7a197613 100644 -- 2.29.2 -From c84f1c874ea9ca6a2642f68722911cd8d9418b05 Mon Sep 17 00:00:00 2001 +From 4bf302343a4b198e67e4adb0865305e2ead3e910 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:38:48 +0900 Subject: [PATCH] mwifiex: print message when changing ps_mode @@ -1326,7 +1326,7 @@ index 786f7a197613..8f4b8bc5ff03 100644 -- 2.29.2 -From 467aba47a776ffd89200bee48be4cc566d115bee Mon Sep 17 00:00:00 2001 +From 07b0b38626bd636aeb4b19372f8fe7c498720121 Mon Sep 17 00:00:00 2001 From: Tsuchiya Yuto Date: Sun, 4 Oct 2020 00:59:37 +0900 Subject: [PATCH] mwifiex: disable ps_mode explicitly by default instead diff --git a/patches/5.9/0003-ipts.patch b/patches/5.9/0003-ipts.patch index 540fdb768..1e270b78f 100644 --- a/patches/5.9/0003-ipts.patch +++ b/patches/5.9/0003-ipts.patch @@ -1,4 +1,4 @@ -From 0ea99c8b2b4a79c949f37715c2f79b0a8b944392 Mon Sep 17 00:00:00 2001 +From 4ea132628789feadce39cfbb79234c72b3a46acd Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Fri, 25 Sep 2020 18:06:05 +0200 Subject: [PATCH] mei: Remove client devices before shutting down @@ -27,7 +27,7 @@ index bcee77768b91..21ed765003e1 100644 -- 2.29.2 -From 2ebe25b7fdc5a710021ba1c2e2f301faf9153014 Mon Sep 17 00:00:00 2001 +From e50580ef381fbc3e30805396e169daf688c3f5c8 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 30 Jul 2020 13:21:53 +0200 Subject: [PATCH] misc: mei: Add missing IPTS device IDs @@ -65,7 +65,7 @@ index 1de9ef7a272b..e12484840f88 100644 -- 2.29.2 -From bbf5bba02ab30a66fc9f31ffe6a39558d6a6670a Mon Sep 17 00:00:00 2001 +From 1d11d7bd327f477295047f940b3a9ebda7a2b955 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Thu, 6 Aug 2020 11:20:41 +0200 Subject: [PATCH] misc: Add support for Intel Precise Touch & Stylus diff --git a/patches/5.9/0004-surface-gpe.patch b/patches/5.9/0004-surface-gpe.patch index edbe17c96..ea4ad6f92 100644 --- a/patches/5.9/0004-surface-gpe.patch +++ b/patches/5.9/0004-surface-gpe.patch @@ -1,4 +1,4 @@ -From f8a8b8e8f6eee845f60e7d56e648fc4fe0ebfd31 Mon Sep 17 00:00:00 2001 +From e45bc35ec79b38c1b042378ee8dea73958e9be0f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 16 Aug 2020 23:39:56 +0200 Subject: [PATCH] platform/x86: Add Driver to set up lid GPEs on MS Surface diff --git a/patches/5.9/0005-surface-sam-over-hid.patch b/patches/5.9/0005-surface-sam-over-hid.patch index e5596b9d2..d4158f78a 100644 --- a/patches/5.9/0005-surface-sam-over-hid.patch +++ b/patches/5.9/0005-surface-sam-over-hid.patch @@ -1,4 +1,4 @@ -From 9c8705d7445eee3ade8598bdfe6cfd1e749f7f06 Mon Sep 17 00:00:00 2001 +From 8a8d8edc71e8158cfa3fd635ab7b406c3f859c7e Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 Subject: [PATCH] i2c: acpi: Implement RawBytes read access @@ -109,7 +109,7 @@ index 37c510d9347a..aed579942436 100644 -- 2.29.2 -From 01ac18ee58fa541b8edaae9135e6763e35bb3ce3 Mon Sep 17 00:00:00 2001 +From 48d1d5ac3390729e19448a44d6c5ea9e57e521e7 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 6 Sep 2020 04:01:19 +0200 Subject: [PATCH] platform/x86: Add driver for Surface Book 1 dGPU switch diff --git a/patches/5.9/0006-surface-sam.patch b/patches/5.9/0006-surface-sam.patch index 33edfe212..254eefcda 100644 --- a/patches/5.9/0006-surface-sam.patch +++ b/patches/5.9/0006-surface-sam.patch @@ -1,4 +1,4 @@ -From 0b304873e92c778debadaabbbe19b69420d8faa8 Mon Sep 17 00:00:00 2001 +From fd2526a6e86754774d40a3729cf12d4343448325 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 29 Oct 2020 22:04:38 +0100 Subject: [PATCH] PCI: Allow D3cold for hot-plug ports on Surface Books @@ -30,7 +30,7 @@ Patchset: surface-sam 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c -index e39c5499770f..31d8811ee5c5 100644 +index b2fed944903e..e288e5058520 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2814,6 +2814,32 @@ static const struct dmi_system_id bridge_d3_blacklist[] = { @@ -83,7 +83,7 @@ index e39c5499770f..31d8811ee5c5 100644 -- 2.29.2 -From a5497a7cc5c0befecf73d65b6af83f45f08389f8 Mon Sep 17 00:00:00 2001 +From 0253be4dab53b5bb18ab137e561be619916ac71f Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 9 Nov 2020 14:23:00 +0100 Subject: [PATCH] PCI: Run platform power transition on initial D0 entry @@ -128,7 +128,7 @@ Patchset: surface-sam 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c -index 31d8811ee5c5..4d652c3abae8 100644 +index e288e5058520..d260c0fcf2d5 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1791,7 +1791,7 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) @@ -143,7 +143,7 @@ index 31d8811ee5c5..4d652c3abae8 100644 -- 2.29.2 -From 69f385511d829a997aabfe92a44416af6d5f9ada Mon Sep 17 00:00:00 2001 +From d0c37a5d6da4148fe5290f5463101c92210204d9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 31 Oct 2020 20:46:33 +0100 Subject: [PATCH] PCI: Add sysfs attribute for PCI device power state @@ -216,7 +216,7 @@ index 6d78df981d41..17f186ce8e87 100644 -- 2.29.2 -From 4046882cdbccb918c844d260e8594b4e753d6354 Mon Sep 17 00:00:00 2001 +From 60412fae510ff6932d49c9b7c213fc8463b035a9 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 17 Aug 2020 01:23:20 +0200 Subject: [PATCH] misc: surface_sam: Add file2alias support for Surface SAM @@ -318,7 +318,7 @@ index 2417dd1dee33..a6c583362b92 100644 -- 2.29.2 -From 16d3d210570364fe10baf6dd740cb09817097fa9 Mon Sep 17 00:00:00 2001 +From c1fbe3bacb995a86249a20f967f252b12e2aa51a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Mon, 17 Aug 2020 01:44:30 +0200 Subject: [PATCH] misc: Add support for Surface System Aggregator Module @@ -351,39 +351,39 @@ Patchset: surface-sam drivers/misc/Makefile | 1 + drivers/misc/surface_aggregator/Kconfig | 67 + drivers/misc/surface_aggregator/Makefile | 18 + - drivers/misc/surface_aggregator/bus.c | 424 +++ + drivers/misc/surface_aggregator/bus.c | 425 +++ drivers/misc/surface_aggregator/bus.h | 27 + .../misc/surface_aggregator/clients/Kconfig | 151 + .../misc/surface_aggregator/clients/Makefile | 11 + .../clients/surface_acpi_notify.c | 884 ++++++ .../clients/surface_aggregator_cdev.c | 299 ++ - .../clients/surface_aggregator_registry.c | 656 +++++ + .../clients/surface_aggregator_registry.c | 657 +++++ .../clients/surface_battery.c | 1192 ++++++++ - .../surface_aggregator/clients/surface_dtx.c | 1279 +++++++++ - .../surface_aggregator/clients/surface_hid.c | 922 ++++++ + .../surface_aggregator/clients/surface_dtx.c | 1278 ++++++++ + .../surface_aggregator/clients/surface_hid.c | 921 ++++++ .../clients/surface_hotplug.c | 269 ++ .../clients/surface_perfmode.c | 122 + - drivers/misc/surface_aggregator/controller.c | 2557 +++++++++++++++++ + drivers/misc/surface_aggregator/controller.c | 2572 +++++++++++++++++ drivers/misc/surface_aggregator/controller.h | 288 ++ - drivers/misc/surface_aggregator/core.c | 831 ++++++ - drivers/misc/surface_aggregator/ssh_msgb.h | 201 ++ - .../surface_aggregator/ssh_packet_layer.c | 2009 +++++++++++++ - .../surface_aggregator/ssh_packet_layer.h | 175 ++ + drivers/misc/surface_aggregator/core.c | 830 ++++++ + drivers/misc/surface_aggregator/ssh_msgb.h | 198 ++ + .../surface_aggregator/ssh_packet_layer.c | 2060 +++++++++++++ + .../surface_aggregator/ssh_packet_layer.h | 189 ++ drivers/misc/surface_aggregator/ssh_parser.c | 229 ++ drivers/misc/surface_aggregator/ssh_parser.h | 157 + - .../surface_aggregator/ssh_request_layer.c | 1254 ++++++++ + .../surface_aggregator/ssh_request_layer.c | 1264 ++++++++ .../surface_aggregator/ssh_request_layer.h | 142 + - drivers/misc/surface_aggregator/trace.h | 625 ++++ + drivers/misc/surface_aggregator/trace.h | 648 +++++ include/linux/mod_devicetable.h | 5 +- include/linux/surface_acpi_notify.h | 39 + include/linux/surface_aggregator/controller.h | 832 ++++++ include/linux/surface_aggregator/device.h | 430 +++ - include/linux/surface_aggregator/serial_hub.h | 659 +++++ + include/linux/surface_aggregator/serial_hub.h | 675 +++++ include/uapi/linux/surface_aggregator/cdev.h | 58 + include/uapi/linux/surface_aggregator/dtx.h | 150 + scripts/mod/devicetable-offsets.c | 3 +- scripts/mod/file2alias.c | 10 +- - 48 files changed, 18823 insertions(+), 7 deletions(-) + 48 files changed, 18948 insertions(+), 7 deletions(-) create mode 100644 Documentation/driver-api/surface_aggregator/client-api.rst create mode 100644 Documentation/driver-api/surface_aggregator/client.rst create mode 100644 Documentation/driver-api/surface_aggregator/clients/cdev.rst @@ -2476,10 +2476,10 @@ index 000000000000..b48ffc37ab52 +endif diff --git a/drivers/misc/surface_aggregator/bus.c b/drivers/misc/surface_aggregator/bus.c new file mode 100644 -index 000000000000..5e734bbd18cd +index 000000000000..231e41bc84e5 --- /dev/null +++ b/drivers/misc/surface_aggregator/bus.c -@@ -0,0 +1,424 @@ +@@ -0,0 +1,425 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface System Aggregator Module bus and device integration. @@ -2502,7 +2502,8 @@ index 000000000000..5e734bbd18cd +{ + struct ssam_device *sdev = to_ssam_device(dev); + -+ return snprintf(buf, PAGE_SIZE - 1, "ssam:d%02Xc%02Xt%02Xi%02xf%02X\n", ++ // FIXME: we should use sysfs_emit here, but that's not available on < 5.10 ++ return scnprintf(buf, PAGE_SIZE, "ssam:d%02Xc%02Xt%02Xi%02xf%02X\n", + sdev->uid.domain, sdev->uid.category, sdev->uid.target, + sdev->uid.instance, sdev->uid.function); +} @@ -2583,8 +2584,8 @@ index 000000000000..5e734bbd18cd + * @sdev: The SSAM client device to be added. + * + * Added client devices must be guaranteed to always have a valid and active -+ * controller. Thus, this function will fail with %-ENXIO if the controller of -+ * the device has not been initialized yet, has been suspended, or has been ++ * controller. Thus, this function will fail with %-ENODEV if the controller ++ * of the device has not been initialized yet, has been suspended, or has been + * shut down. + * + * The caller of this function should ensure that the corresponding call to @@ -2595,7 +2596,7 @@ index 000000000000..5e734bbd18cd + * By default, the controller device will become the parent of the newly + * created client device. The parent may be changed before ssam_device_add is + * called, but care must be taken that a) the correct suspend/resume ordering -+ * is guaranteed and b) the client device does not oultive the controller, ++ * is guaranteed and b) the client device does not outlive the controller, + * i.e. that the device is removed before the controller is being shut down. + * In case these guarantees have to be manually enforced, please refer to the + * ssam_client_link() and ssam_client_bind() functions, which are intended to @@ -2628,7 +2629,7 @@ index 000000000000..5e734bbd18cd + + if (sdev->ctrl->state != SSAM_CONTROLLER_STARTED) { + ssam_controller_stateunlock(sdev->ctrl); -+ return -ENXIO; ++ return -ENODEV; + } + + status = device_add(&sdev->dev); @@ -2757,7 +2758,7 @@ index 000000000000..5e734bbd18cd +EXPORT_SYMBOL_GPL(ssam_device_get_match); + +/** -+ * ssam_device_get_match_data() - Find the ID matching the device in hte ++ * ssam_device_get_match_data() - Find the ID matching the device in the + * ID table of the bound driver and return its ``driver_data`` member. + * @dev: The device for which to get the match data. + * @@ -2871,7 +2872,7 @@ index 000000000000..5e734bbd18cd + * @ctrl: The controller to remove all direct clients for. + * + * Remove all SSAM client devices registered as direct children under the -+ * given controller. Note that this only accounts for direct children ot the ++ * given controller. Note that this only accounts for direct children of the + * controller device. This does not take care of any client devices where the + * parent device has been manually set before calling ssam_device_add. Refer + * to ssam_device_add()/ssam_device_remove() for more details on those cases. @@ -3113,7 +3114,7 @@ index 000000000000..7320922ba755 +obj-$(CONFIG_SURFACE_PERFMODE) += surface_perfmode.o diff --git a/drivers/misc/surface_aggregator/clients/surface_acpi_notify.c b/drivers/misc/surface_aggregator/clients/surface_acpi_notify.c new file mode 100644 -index 000000000000..7a5b8f280036 +index 000000000000..c7fc3eb7ea0e --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_acpi_notify.c @@ -0,0 +1,884 @@ @@ -3199,7 +3200,7 @@ index 000000000000..7a5b8f280036 + * The link will be automatically removed once the client device's driver is + * unbound. + * -+ * Return: Returns zero on succes, %-ENXIO if the SAN interface has not been ++ * Return: Returns zero on success, %-ENXIO if the SAN interface has not been + * set up yet, and %-ENOMEM if device link creation failed. + */ +int san_client_link(struct device *client) @@ -3335,9 +3336,9 @@ index 000000000000..7a5b8f280036 + 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. ++ * Ensure 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. + */ + @@ -3393,7 +3394,7 @@ index 000000000000..7a5b8f280036 + switch (cid) { + case SAM_EVENT_CID_BAT_ADP: + /* -+ * Wait for battery state to update before signalling adapter ++ * Wait for battery state to update before signaling adapter + * change. + */ + return msecs_to_jiffies(5000); @@ -3922,9 +3923,9 @@ index 000000000000..7a5b8f280036 + acpi_status astatus; + int status; + -+ status = ssam_client_bind(&pdev->dev, &ctrl); -+ if (status) -+ return status == -ENXIO ? -EPROBE_DEFER : status; ++ ctrl = ssam_client_bind(&pdev->dev); ++ if (IS_ERR(ctrl)) ++ return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + status = san_consumer_links_setup(pdev); + if (status) @@ -4003,7 +4004,7 @@ index 000000000000..7a5b8f280036 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_aggregator/clients/surface_aggregator_cdev.c b/drivers/misc/surface_aggregator/clients/surface_aggregator_cdev.c new file mode 100644 -index 000000000000..f5e81cd67357 +index 000000000000..573f8a10b840 --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_aggregator_cdev.c @@ -0,0 +1,299 @@ @@ -4211,9 +4212,9 @@ index 000000000000..f5e81cd67357 + struct ssam_cdev *cdev; + int status; + -+ status = ssam_client_bind(&pdev->dev, &ctrl); -+ if (status) -+ return status == -ENXIO ? -EPROBE_DEFER : status; ++ ctrl = ssam_client_bind(&pdev->dev); ++ if (IS_ERR(ctrl)) ++ return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) @@ -4308,10 +4309,10 @@ index 000000000000..f5e81cd67357 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_aggregator/clients/surface_aggregator_registry.c b/drivers/misc/surface_aggregator/clients/surface_aggregator_registry.c new file mode 100644 -index 000000000000..77ef266b88f3 +index 000000000000..0c674ed2dd53 --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_aggregator_registry.c -@@ -0,0 +1,656 @@ +@@ -0,0 +1,657 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface System Aggregator Module (SSAM) client device registry. @@ -4658,7 +4659,8 @@ index 000000000000..77ef266b88f3 + connected = hub->state == SSAM_BASE_HUB_CONNECTED; + mutex_unlock(&hub->lock); + -+ return snprintf(buf, PAGE_SIZE - 1, "%d\n", connected); ++ // FIXME: we should use sysfs_emit here, but that's not available on < 5.10 ++ return scnprintf(buf, PAGE_SIZE, "%d\n", connected); +} + +static struct device_attribute ssam_base_hub_attr_state = @@ -4883,9 +4885,9 @@ index 000000000000..77ef266b88f3 + * controller is removed. This also guarantees proper ordering for + * suspend/resume of the devices on this hub. + */ -+ status = ssam_client_bind(&pdev->dev, &ctrl); -+ if (status) -+ return status == -ENXIO ? -EPROBE_DEFER : status; ++ ctrl = ssam_client_bind(&pdev->dev); ++ if (IS_ERR(ctrl)) ++ return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + status = software_node_register_node_group(nodes); + if (status) @@ -6168,10 +6170,10 @@ index 000000000000..7ed9ba3f98d7 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_aggregator/clients/surface_dtx.c b/drivers/misc/surface_aggregator/clients/surface_dtx.c new file mode 100644 -index 000000000000..346b54848b8f +index 000000000000..84308a0ed767 --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_dtx.c -@@ -0,0 +1,1279 @@ +@@ -0,0 +1,1278 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface Book (gen. 2 and later) detachment system (DTX) driver. @@ -7323,12 +7325,11 @@ index 000000000000..346b54848b8f +{ + struct ssam_controller *ctrl; + struct sdtx_device *ddev; -+ int status; + + // link to EC -+ status = ssam_client_bind(&pdev->dev, &ctrl); -+ if (status) -+ return status == -ENXIO ? -EPROBE_DEFER : status; ++ ctrl = ssam_client_bind(&pdev->dev); ++ if (IS_ERR(ctrl)) ++ return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + ddev = sdtx_device_setup(&pdev->dev, ctrl); + if (IS_ERR(ddev)) @@ -7453,10 +7454,10 @@ index 000000000000..346b54848b8f +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_aggregator/clients/surface_hid.c b/drivers/misc/surface_aggregator/clients/surface_hid.c new file mode 100644 -index 000000000000..033abc9aa95e +index 000000000000..f41b7a578fbb --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_hid.c -@@ -0,0 +1,922 @@ +@@ -0,0 +1,921 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface System Aggregator Module (SSAM) HID device driver. @@ -8289,12 +8290,11 @@ index 000000000000..033abc9aa95e +{ + struct ssam_controller *ctrl; + struct surface_hid_device *shid; -+ int status; + + // add device link to EC -+ status = ssam_client_bind(&pdev->dev, &ctrl); -+ if (status) -+ return status == -ENXIO ? -EPROBE_DEFER : status; ++ ctrl = ssam_client_bind(&pdev->dev); ++ if (IS_ERR(ctrl)) ++ return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl); + + shid = devm_kzalloc(&pdev->dev, sizeof(*shid), GFP_KERNEL); + if (!shid) @@ -8784,10 +8784,10 @@ index 000000000000..e13f4995b28b +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_aggregator/controller.c b/drivers/misc/surface_aggregator/controller.c new file mode 100644 -index 000000000000..feee7c7c5945 +index 000000000000..539e0db277bf --- /dev/null +++ b/drivers/misc/surface_aggregator/controller.c -@@ -0,0 +1,2557 @@ +@@ -0,0 +1,2572 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Main SSAM/SSH controller structure and functionality. @@ -8801,6 +8801,7 @@ index 000000000000..feee7c7c5945 +#include +#include +#include ++#include +#include +#include +#include @@ -8837,7 +8838,7 @@ index 000000000000..feee7c7c5945 + * ssh_seq_next() - Get next sequence ID. + * @c: The counter providing the sequence IDs. + * -+ * Return: Retunrs the next sequence ID of the counter. ++ * Return: Returns the next sequence ID of the counter. + */ +static u8 ssh_seq_next(struct ssh_seq_counter *c) +{ @@ -8888,32 +8889,31 @@ index 000000000000..feee7c7c5945 +/* + * The notifier system is based on linux/notifier.h, specifically the SRCU + * implementation. The difference to that is, that some bits of the notifier -+ * call return value can be tracked across multiple calls. This is done so that -+ * handling of events can be tracked and a warning can be issued in case an -+ * event goes unhandled. The idea of that waring is that it should help discover -+ * and identify new/currently unimplemented features. ++ * call return value can be tracked across multiple calls. This is done so ++ * that handling of events can be tracked and a warning can be issued in case ++ * an event goes unhandled. The idea of that warning is that it should help ++ * discover and identify new/currently unimplemented features. + */ + + +/** -+ * ssam_event_matches_notifier() - Test if an event matches a notifier; ++ * ssam_event_matches_notifier() - Test if an event matches a notifier. + * @notif: The event notifier to test against. + * @event: The event to test. + * + * Return: Returns %true iff the given event matches the given notifier + * according to the rules set in the notifier's event mask, %false otherwise. + */ -+static bool ssam_event_matches_notifier( -+ const struct ssam_event_notifier *notif, -+ const struct ssam_event *event) ++static bool ssam_event_matches_notifier(const struct ssam_event_notifier *n, ++ const struct ssam_event *event) +{ -+ bool match = notif->event.id.target_category == event->target_category; ++ bool match = n->event.id.target_category == event->target_category; + -+ if (notif->event.mask & SSAM_EVENT_MASK_TARGET) -+ match &= notif->event.reg.target_id == event->target_id; ++ if (n->event.mask & SSAM_EVENT_MASK_TARGET) ++ match &= n->event.reg.target_id == event->target_id; + -+ if (notif->event.mask & SSAM_EVENT_MASK_INSTANCE) -+ match &= notif->event.id.instance == event->instance_id; ++ if (n->event.mask & SSAM_EVENT_MASK_INSTANCE) ++ match &= n->event.id.instance == event->instance_id; + + return match; +} @@ -8969,17 +8969,17 @@ index 000000000000..feee7c7c5945 + * Note: This function must be synchronized by the caller with respect to other + * insert and/or remove calls. + * -+ * Return: Returns zero on success, %-EINVAL if the notifier block has already ++ * Return: Returns zero on success, %-EEXIST if the notifier block has already + * been registered. + */ +static int __ssam_nfblk_insert(struct ssam_nf_head *nh, struct ssam_notifier_block *nb) +{ + struct ssam_notifier_block **link = &nh->head; + -+ while ((*link) != NULL) { -+ if (unlikely((*link) == nb)) { ++ while (*link) { ++ if (unlikely(*link == nb)) { + WARN(1, "double register detected"); -+ return -EINVAL; ++ return -EEXIST; + } + + if (nb->priority > (*link)->priority) @@ -8996,7 +8996,7 @@ index 000000000000..feee7c7c5945 + +/** + * __ssam_nfblk_find_link() - Find a notifier block link on the given list. -+ * @nh: The notifier head on wich the search should be conducted. ++ * @nh: The notifier head on which the search should be conducted. + * @nb: The notifier block to search for. + * + * Note: This function must be synchronized by the caller with respect to @@ -9011,8 +9011,8 @@ index 000000000000..feee7c7c5945 +{ + struct ssam_notifier_block **link = &nh->head; + -+ while ((*link) != NULL) { -+ if ((*link) == nb) ++ while (*link) { ++ if (*link == nb) + return link; + + link = &((*link)->next); @@ -9105,7 +9105,7 @@ index 000000000000..feee7c7c5945 +}; + +/** -+ * struct ssam_nf_refcount_entry - RB-tree entry for referecnce counting event ++ * struct ssam_nf_refcount_entry - RB-tree entry for reference counting event + * activations. + * @node: The node of this entry in the rb-tree. + * @key: The key of the event. @@ -9131,9 +9131,14 @@ index 000000000000..feee7c7c5945 + * event type/ID, allocating a new entry for this event ID if necessary. A + * newly allocated entry will have a refcount of one. + * -+ * Return: Returns the refcount entry on success. Returns ``ERR_PTR(-ENOSPC)`` -+ * if there have already been %INT_MAX events of the specified ID and type -+ * registered, or ``ERR_PTR(-ENOMEM)`` if the entry could not be allocated. ++ * Note: Must be synchronized by the caller with regards to other ++ * ssam_nf_refcount_inc() and ssam_nf_refcount_dec() calls, e.g. via ++ * ``nf->lock``. Note that this lock should also be used to ensure the ++ * corresponding EC requests are sent, if necessary. ++ * ++ * Return: Returns the refcount entry on success. Returns an error pointer ++ * with %-ENOSPC if there have already been %INT_MAX events of the specified ++ * ID and type registered, or %-ENOMEM if the entry could not be allocated. + */ +static struct ssam_nf_refcount_entry *ssam_nf_refcount_inc( + struct ssam_nf *nf, struct ssam_event_registry reg, @@ -9189,6 +9194,11 @@ index 000000000000..feee7c7c5945 + * returning its entry. If the returned entry has a refcount of zero, the + * caller is responsible for freeing it using kfree(). + * ++ * Note: Must be synchronized by the caller with regards to other ++ * ssam_nf_refcount_inc() and ssam_nf_refcount_dec() calls, e.g. via ++ * ``nf->lock``. Note that this lock should also be used to ensure the ++ * corresponding EC requests are sent, if necessary. ++ * + * Return: Returns the refcount entry on success or %NULL if the entry has not + * been found. + */ @@ -9241,9 +9251,9 @@ index 000000000000..feee7c7c5945 + * @rqid: The request ID of the event. + * @event: The event provided to the callbacks. + * -+ * Executa registered callbacks in order of their priority until either no -+ * callback is left or a callback returned a value with the %SSAM_NOTIF_STOP -+ * bit set. Note that this bit is set automatically when converting non.zero ++ * Execute registered callbacks in order of their priority until either no ++ * callback is left or a callback returns a value with the %SSAM_NOTIF_STOP ++ * bit set. Note that this bit is set automatically when converting non-zero + * error values via ssam_notifier_from_errno() to notifier values. + * + * Also note that any callback that could handle an event should return a value @@ -9298,7 +9308,7 @@ index 000000000000..feee7c7c5945 + } + + if (status) { -+ for (i = i - 1; i >= 0; i--) ++ while (i--) + ssam_nf_head_destroy(&nf->head[i]); + + return status; @@ -9328,6 +9338,13 @@ index 000000000000..feee7c7c5945 +#define SSAM_CPLT_WQ_NAME "ssam_cpltq" + +/* ++ * SSAM_CPLT_WQ_BATCH - Maximum number of event item completions executed per ++ * work execution. Used to prevent livelocking of the workqueue. Value chosen ++ * via educated guess, may be adjusted. ++ */ ++#define SSAM_CPLT_WQ_BATCH 10 ++ ++/* + * SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN - Maximum payload length for a cached + * &struct ssam_event_item. + * @@ -9404,13 +9421,13 @@ index 000000000000..feee7c7c5945 + struct ssam_event_item *item; + + if (len <= SSAM_EVENT_ITEM_CACHE_PAYLOAD_LEN) { -+ item = kmem_cache_alloc(ssam_event_item_cache, GFP_KERNEL); ++ item = kmem_cache_alloc(ssam_event_item_cache, flags); + if (!item) + return NULL; + + item->ops.free = __ssam_event_item_free_cached; + } else { -+ item = kzalloc(sizeof(*item) + len, GFP_KERNEL); ++ item = kzalloc(struct_size(item, event.data, len), flags); + if (!item) + return NULL; + @@ -9503,7 +9520,7 @@ index 000000000000..feee7c7c5945 +} + +/** -+ * ssam_cplt_submit() - Submit a work item to the compeltion system workqueue. ++ * ssam_cplt_submit() - Submit a work item to the completion system workqueue. + * @cplt: The completion system. + * @work: The work item to submit. + */ @@ -9553,7 +9570,7 @@ index 000000000000..feee7c7c5945 + * This operation is only intended to, during normal operation prior to + * shutdown, try to complete most events and requests to get them out of the + * system while the system is still fully operational. It does not aim to -+ * provide any guraantee that all of them have been handled. ++ * provide any guarantee that all of them have been handled. + */ +static void ssam_cplt_flush(struct ssam_cplt *cplt) +{ @@ -9566,21 +9583,21 @@ index 000000000000..feee7c7c5945 + struct ssam_event_item *item; + struct ssam_nf *nf; + struct device *dev; -+ int i; ++ unsigned int iterations = SSAM_CPLT_WQ_BATCH; + + queue = container_of(work, struct ssam_event_queue, work); + nf = &queue->cplt->event.notif; + dev = queue->cplt->dev; + + // limit number of processed events to avoid livelocking -+ for (i = 0; i < 10; i++) { ++ do { + item = ssam_event_queue_pop(queue); -+ if (item == NULL) ++ if (!item) + return; + + ssam_nf_call(nf, dev, item->rqid, &item->event); + ssam_event_item_free(item); -+ } ++ } while (--iterations); + + if (!ssam_event_queue_is_empty(queue)) + ssam_cplt_submit(queue->cplt, &queue->work); @@ -9780,7 +9797,8 @@ index 000000000000..feee7c7c5945 + item->event.instance_id = cmd->iid; + memcpy(&item->event.data[0], data->ptr, data->len); + -+ WARN_ON(ssam_cplt_submit_event(&ctrl->cplt, item)); ++ if (WARN_ON(ssam_cplt_submit_event(&ctrl->cplt, item))) ++ ssam_event_item_free(item); +} + +static const struct ssh_rtl_ops ssam_rtl_ops = { @@ -9788,13 +9806,16 @@ index 000000000000..feee7c7c5945 +}; + + -+static bool ssam_notifier_empty(struct ssam_controller *ctrl); ++static bool ssam_notifier_is_empty(struct ssam_controller *ctrl); +static void ssam_notifier_unregister_all(struct ssam_controller *ctrl); + + +#define SSAM_SSH_DSM_REVISION 0 -+static const guid_t SSAM_SSH_DSM_GUID = GUID_INIT(0xd5e383e1, 0xd892, 0x4a76, -+ 0x89, 0xfc, 0xf6, 0xaa, 0xae, 0x7e, 0xd5, 0xb5); ++ ++/* d5e383e1-d892-4a76-89fc-f6aaae7ed5b5 */ ++static const guid_t SSAM_SSH_DSM_GUID = ++ GUID_INIT(0xd5e383e1, 0xd892, 0x4a76, ++ 0x89, 0xfc, 0xf6, 0xaa, 0xae, 0x7e, 0xd5, 0xb5); + +enum ssh_dsm_fn { + SSH_DSM_FN_SSH_POWER_PROFILE = 0x05, @@ -9819,12 +9840,12 @@ index 000000000000..feee7c7c5945 + SSAM_SSH_DSM_REVISION, 0, NULL, + ACPI_TYPE_BUFFER); + if (!obj) -+ return -EFAULT; ++ return -EIO; + + for (i = 0; i < obj->buffer.length && i < 8; i++) + mask |= (((u64)obj->buffer.pointer[i]) << (i * 8)); + -+ if (mask & 0x01) ++ if (mask & BIT(0)) + *funcs = mask; + + ACPI_FREE(obj); @@ -9843,7 +9864,7 @@ index 000000000000..feee7c7c5945 + SSAM_SSH_DSM_REVISION, func, NULL, + ACPI_TYPE_INTEGER); + if (!obj) -+ return -EFAULT; ++ return -EIO; + + val = obj->integer.value; + ACPI_FREE(obj); @@ -9875,11 +9896,11 @@ index 000000000000..feee7c7c5945 + int status; + + // set defaults -+ caps->ssh_power_profile = (u32)-1; -+ caps->screen_on_sleep_idle_timeout = (u32)-1; -+ caps->screen_off_sleep_idle_timeout = (u32)-1; ++ caps->ssh_power_profile = U32_MAX; ++ caps->screen_on_sleep_idle_timeout = U32_MAX; ++ caps->screen_off_sleep_idle_timeout = U32_MAX; + caps->d3_closes_handle = false; -+ caps->ssh_buffer_size = (u32)-1; ++ caps->ssh_buffer_size = U32_MAX; + + status = ssam_dsm_get_functions(handle, &funcs); + if (status) @@ -9985,9 +10006,9 @@ index 000000000000..feee7c7c5945 + * controller. + * @ctrl: The controller. + * -+ * Note: When this function is called, the controller shouldbe properly hooked -+ * up to the serdev core via &struct serdev_device_ops. Please refert to -+ * ssam_controller_init() for more details on controller initialization. ++ * Note: When this function is called, the controller should be properly ++ * hooked up to the serdev core via &struct serdev_device_ops. Please refer ++ * to ssam_controller_init() for more details on controller initialization. + * + * This function must be called from an exclusive context with regards to the + * state, if necessary, by locking the controller via ssam_controller_lock(). @@ -10012,6 +10033,16 @@ index 000000000000..feee7c7c5945 + return 0; +} + ++/* ++ * SSAM_CTRL_SHUTDOWN_FLUSH_TIMEOUT - Timeout for flushing requests during ++ * shutdown. ++ * ++ * Chosen to be larger than one full request timeout, including packets timing ++ * out. This value should give ample time to complete any outstanding requests ++ * during normal operation and account for the odd package timeout. ++ */ ++#define SSAM_CTRL_SHUTDOWN_FLUSH_TIMEOUT msecs_to_jiffies(5000) ++ +/** + * ssam_controller_shutdown() - Shut down the controller. + * @ctrl: The controller. @@ -10023,13 +10054,13 @@ index 000000000000..feee7c7c5945 + * + * In the course of this shutdown procedure, all currently registered + * notifiers will be unregistered. It is, however, strongly recommended to not -+ * rely on this behavior, and instead the party registring the notifier should -+ * unregister it before the controller gets shut down, e.g. via the SSAM bus -+ * which guarantees client devices to be removed before a shutdown. ++ * rely on this behavior, and instead the party registering the notifier ++ * should unregister it before the controller gets shut down, e.g. via the ++ * SSAM bus which guarantees client devices to be removed before a shutdown. + * -+ * Note that events may still be pending after this call, but due to the -+ * notifiers being unregistered, the will be dropped when the controller is -+ * subsequently being destroyed via ssam_controller_destroy(). ++ * Note that events may still be pending after this call, but, due to the ++ * notifiers being unregistered, these events will be dropped when the ++ * controller is subsequently destroyed via ssam_controller_destroy(). + * + * This function must be called from an exclusive context with regards to the + * state, if necessary, by locking the controller via ssam_controller_lock(). @@ -10043,7 +10074,7 @@ index 000000000000..feee7c7c5945 + return; + + // try to flush pending events and requests while everything still works -+ status = ssh_rtl_flush(&ctrl->rtl, msecs_to_jiffies(5000)); ++ status = ssh_rtl_flush(&ctrl->rtl, SSAM_CTRL_SHUTDOWN_FLUSH_TIMEOUT); + if (status) { + ssam_err(ctrl, "failed to flush request transport layer: %d\n", + status); @@ -10057,7 +10088,7 @@ index 000000000000..feee7c7c5945 + * driver that set them up at this point. If this warning occurs, some + * client driver has not done that... + */ -+ WARN_ON(!ssam_notifier_empty(ctrl)); ++ WARN_ON(!ssam_notifier_is_empty(ctrl)); + + /* + * Nevertheless, we should still take care of drivers that don't behave @@ -10084,7 +10115,7 @@ index 000000000000..feee7c7c5945 + * Ensures that all resources associated with the controller get freed. This + * function should only be called after the controller has been stopped via + * ssam_controller_shutdown(). In general, this function should not be called -+ * directly. The only valid place to call this function direclty is during ++ * directly. The only valid place to call this function directly is during + * initialization, before the controller has been fully initialized and passed + * to other processes. This function is called automatically when the + * reference count of the controller reaches zero. @@ -10320,7 +10351,7 @@ index 000000000000..feee7c7c5945 + +/** + * ssam_request_sync_free() - Free a synchronous request. -+ * @rqst: The request to free. ++ * @rqst: The request to be freed. + * + * Free a synchronous request and its corresponding buffer allocated with + * ssam_request_sync_alloc(). Do not use for requests allocated on the stack @@ -10398,7 +10429,7 @@ index 000000000000..feee7c7c5945 + */ + if (WARN_ON(READ_ONCE(ctrl->state) != SSAM_CONTROLLER_STARTED)) { + ssh_request_put(&rqst->base); -+ return -ENXIO; ++ return -ENODEV; + } + + status = ssh_rtl_submit(&ctrl->rtl, &rqst->base); @@ -10415,9 +10446,9 @@ index 000000000000..feee7c7c5945 + * @rsp: The response buffer. + * + * Allocates a synchronous request with its message data buffer on the heap -+ * via ssam_request_sync_alloc(), fully intializes it via the provided request -+ * specification, submits it, and finally waits for its completion before -+ * freeing it and returning its status. ++ * via ssam_request_sync_alloc(), fully initializes it via the provided ++ * request specification, submits it, and finally waits for its completion ++ * before freeing it and returning its status. + * + * Return: Returns the status of the request or any failure during setup. + */ @@ -10456,7 +10487,7 @@ index 000000000000..feee7c7c5945 + +/** + * ssam_request_sync_with_buffer() - Execute a synchronous request with the -+ * provided buffer as backend for the message buffer. ++ * provided buffer as back-end for the message buffer. + * @ctrl: The controller via which the request will be submitted. + * @spec: The request specification and payload. + * @rsp: The response buffer. @@ -10464,7 +10495,7 @@ index 000000000000..feee7c7c5945 + * + * Allocates a synchronous request struct on the stack, fully initializes it + * using the provided buffer as message data buffer, submits it, and then -+ * waits for its completion before returning its staus. The ++ * waits for its completion before returning its status. The + * SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required + * message buffer size. + * @@ -10558,25 +10589,9 @@ index 000000000000..feee7c7c5945 + +static_assert(sizeof(struct ssh_notification_params) == 5); + -+/** -+ * ssam_ssh_event_enable() - Enable SSH event. -+ * @ctrl: The controller for which to enable the event. -+ * @reg: The event registry describing what request to use for enabling and -+ * disabling the event. -+ * @id: The event identifier. -+ * @flags: The event flags. -+ * -+ * This is a wrapper for the raw SAM request to enable an event, thus it does -+ * not handle referecnce counting for enable/disable of events. If an event -+ * has already been enabled, the EC will ignore this request. -+ * -+ * Return: Returns the status of the executed SAM request (zero on success and -+ * negative on direct failure) or %-EPROTO if the request response indicates a -+ * failure. -+ */ -+static int ssam_ssh_event_enable(struct ssam_controller *ctrl, -+ struct ssam_event_registry reg, -+ struct ssam_event_id id, u8 flags) ++static int __ssam_ssh_event_request(struct ssam_controller *ctrl, ++ struct ssam_event_registry reg, u8 cid, ++ struct ssam_event_id id, u8 flags) +{ + struct ssh_notification_params params; + struct ssam_request rqst; @@ -10584,7 +10599,7 @@ index 000000000000..feee7c7c5945 + int status; + + u16 rqid = ssh_tc_to_rqid(id.target_category); -+ u8 buf[1] = { 0x00 }; ++ u8 buf = 0; + + // only allow RQIDs that lie within event spectrum + if (!ssh_rqid_is_event(rqid)) @@ -10597,34 +10612,62 @@ index 000000000000..feee7c7c5945 + + rqst.target_category = reg.target_category; + rqst.target_id = reg.target_id; -+ rqst.command_id = reg.cid_enable; ++ rqst.command_id = cid; + rqst.instance_id = 0x00; + rqst.flags = SSAM_REQUEST_HAS_RESPONSE; + rqst.length = sizeof(params); + rqst.payload = (u8 *)¶ms; + -+ result.capacity = ARRAY_SIZE(buf); ++ result.capacity = sizeof(buf); + result.length = 0; -+ result.pointer = buf; ++ result.pointer = &buf; + + status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result, + sizeof(params)); -+ if (status) { ++ ++ return status < 0 ? status : buf; ++} ++ ++/** ++ * ssam_ssh_event_enable() - Enable SSH event. ++ * @ctrl: The controller for which to enable the event. ++ * @reg: The event registry describing what request to use for enabling and ++ * disabling the event. ++ * @id: The event identifier. ++ * @flags: The event flags. ++ * ++ * Enables the specified event on the EC. This function does not manage ++ * reference counting of enabled events and is basically only a wrapper for ++ * the raw EC request. If the specified event is already enabled, the EC will ++ * ignore this request. ++ * ++ * Return: Returns the status of the executed SAM request (zero on success and ++ * negative on direct failure) or %-EPROTO if the request response indicates a ++ * failure. ++ */ ++static int ssam_ssh_event_enable(struct ssam_controller *ctrl, ++ struct ssam_event_registry reg, ++ struct ssam_event_id id, u8 flags) ++{ ++ int status; ++ ++ status = __ssam_ssh_event_request(ctrl, reg, reg.cid_enable, id, flags); ++ ++ if (status < 0 && status != -EINVAL) { + ssam_err(ctrl, "failed to enable event source (tc: 0x%02x, " + "iid: 0x%02x, reg: 0x%02x)\n", id.target_category, + id.instance, reg.target_category); + } + -+ if (buf[0] != 0x00) { ++ if (status > 0) { + ssam_err(ctrl, "unexpected result while enabling event source: " + "0x%02x (tc: 0x%02x, iid: 0x%02x, reg: 0x%02x)\n", -+ buf[0], id.target_category, id.instance, ++ status, id.target_category, id.instance, + reg.target_category); + return -EPROTO; + } + + return status; -+ +} + +/** @@ -10635,9 +10678,10 @@ index 000000000000..feee7c7c5945 + * @id: The event identifier. + * @flags: The event flags (likely ignored for disabling of events). + * -+ * This is a wrapper for the raw SAM request to disable an event, thus it does -+ * not handle reference counting for enable/disable of events. If an event has -+ * already been disabled, the EC will ignore this request. ++ * Disables the specified event on the EC. This function does not manage ++ * reference counting of enabled events and is basically only a wrapper for ++ * the raw EC request. If the specified event is already disabled, the EC will ++ * ignore this request. + * + * Return: Returns the status of the executed SAM request (zero on success and + * negative on direct failure) or %-EPROTO if the request response indicates a @@ -10647,47 +10691,20 @@ index 000000000000..feee7c7c5945 + struct ssam_event_registry reg, + struct ssam_event_id id, u8 flags) +{ -+ struct ssh_notification_params params; -+ struct ssam_request rqst; -+ struct ssam_response result; + int status; + -+ u16 rqid = ssh_tc_to_rqid(id.target_category); -+ u8 buf[1] = { 0x00 }; ++ status = __ssam_ssh_event_request(ctrl, reg, reg.cid_enable, id, flags); + -+ // only allow RQIDs that lie within event spectrum -+ if (!ssh_rqid_is_event(rqid)) -+ return -EINVAL; -+ -+ params.target_category = id.target_category; -+ params.instance_id = id.instance; -+ params.flags = flags; -+ put_unaligned_le16(rqid, ¶ms.request_id); -+ -+ rqst.target_category = reg.target_category; -+ rqst.target_id = reg.target_id; -+ rqst.command_id = reg.cid_disable; -+ rqst.instance_id = 0x00; -+ rqst.flags = SSAM_REQUEST_HAS_RESPONSE; -+ rqst.length = sizeof(params); -+ rqst.payload = (u8 *)¶ms; -+ -+ result.capacity = ARRAY_SIZE(buf); -+ result.length = 0; -+ result.pointer = buf; -+ -+ status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result, -+ sizeof(params)); -+ if (status) { ++ if (status < 0 && status != -EINVAL) { + ssam_err(ctrl, "failed to disable event source (tc: 0x%02x, " + "iid: 0x%02x, reg: 0x%02x)\n", id.target_category, + id.instance, reg.target_category); + } + -+ if (buf[0] != 0x00) { ++ if (status > 0) { + ssam_err(ctrl, "unexpected result while disabling event source: " + "0x%02x (tc: 0x%02x, iid: 0x%02x, reg: 0x%02x)\n", -+ buf[0], id.target_category, id.instance, ++ status, id.target_category, id.instance, + reg.target_category); + return -EPROTO; + } @@ -10737,8 +10754,8 @@ index 000000000000..feee7c7c5945 + * backlight will be turned off by this call. + * + * This function will only send the display-off notification command if -+ * display noticications are supported by the EC. Currently all known devices -+ * support these notification. ++ * display notifications are supported by the EC. Currently all known devices ++ * support these notifications. + * + * Use ssam_ctrl_notif_display_on() to reverse the effects of this function. + * @@ -10776,8 +10793,8 @@ index 000000000000..feee7c7c5945 + * reverse its effects, including resetting events to their default behavior. + * + * This function will only send the display-on notification command if display -+ * noticications are supported by the EC. Currently all known devices support -+ * these notification. ++ * notifications are supported by the EC. Currently all known devices support ++ * these notifications. + * + * See ssam_ctrl_notif_display_off() for more details. + * @@ -10815,7 +10832,7 @@ index 000000000000..feee7c7c5945 + * EC are currently unknown. + * + * This function will only send the D0-exit notification command if D0-state -+ * noticications are supported by the EC. Only newer Surface generations ++ * notifications are supported by the EC. Only newer Surface generations + * support these notifications. + * + * Use ssam_ctrl_notif_d0_entry() to reverse the effects of this function. @@ -10839,8 +10856,8 @@ index 000000000000..feee7c7c5945 + return status; + + if (response != 0) { -+ ssam_err(ctrl, "unexpected response from D0-exit notification:" -+ " 0x%02x\n", response); ++ ssam_err(ctrl, "unexpected response from D0-exit notification: 0x%02x\n", ++ response); + return -EPROTO; + } + @@ -10857,7 +10874,7 @@ index 000000000000..feee7c7c5945 + * currently unknown. + * + * This function will only send the D0-entry notification command if D0-state -+ * noticications are supported by the EC. Only newer Surface generations ++ * notifications are supported by the EC. Only newer Surface generations + * support these notifications. + * + * See ssam_ctrl_notif_d0_exit() for more details. @@ -10881,8 +10898,8 @@ index 000000000000..feee7c7c5945 + return status; + + if (response != 0) { -+ ssam_err(ctrl, "unexpected response from D0-entry notification:" -+ " 0x%02x\n", response); ++ ssam_err(ctrl, "unexpected response from D0-entry notification: 0x%02x\n", ++ response); + return -EPROTO; + } + @@ -10931,10 +10948,9 @@ index 000000000000..feee7c7c5945 + return PTR_ERR(entry); + } + -+ ssam_dbg(ctrl, "enabling event (reg: 0x%02x, tc: 0x%02x, iid: 0x%02x," -+ " rc: %d)\n", n->event.reg.target_category, -+ n->event.id.target_category, n->event.id.instance, -+ entry->refcount); ++ ssam_dbg(ctrl, "enabling event (reg: 0x%02x, tc: 0x%02x, iid: 0x%02x, rc: %d)\n", ++ n->event.reg.target_category, n->event.id.target_category, ++ n->event.id.instance, entry->refcount); + + status = __ssam_nfblk_insert(nf_head, &n->base); + if (status) { @@ -11016,10 +11032,9 @@ index 000000000000..feee7c7c5945 + return -ENOENT; + } + -+ ssam_dbg(ctrl, "disabling event (reg: 0x%02x, tc: 0x%02x, iid: 0x%02x," -+ " rc: %d)\n", n->event.reg.target_category, -+ n->event.id.target_category, n->event.id.instance, -+ entry->refcount); ++ ssam_dbg(ctrl, "disabling event (reg: 0x%02x, tc: 0x%02x, iid: 0x%02x, rc: %d)\n", ++ n->event.reg.target_category, n->event.id.target_category, ++ n->event.id.instance, entry->refcount); + + if (entry->flags != n->event.flags) { + ssam_warn(ctrl, "inconsistent flags when enabling event: got 0x%02x," @@ -11051,7 +11066,7 @@ index 000000000000..feee7c7c5945 + * (EC command failing), all previously disabled events will be restored and + * the error code returned. + * -+ * This function is intended to disable all events prior to hibenration entry. ++ * This function is intended to disable all events prior to hibernation entry. + * See ssam_notifier_restore_registered() to restore/re-enable all events + * disabled with this function. + * @@ -11126,13 +11141,13 @@ index 000000000000..feee7c7c5945 +} + +/** -+ * ssam_notifier_empty() - Check if there are any registered notifiers. ++ * ssam_notifier_is_empty() - Check if there are any registered notifiers. + * @ctrl: The controller to check on. + * + * Return: Returns %true if there are currently no notifiers registered on the + * controller, %false otherwise. + */ -+static bool ssam_notifier_empty(struct ssam_controller *ctrl) ++static bool ssam_notifier_is_empty(struct ssam_controller *ctrl) +{ + struct ssam_nf *nf = &ctrl->cplt.event.notif; + bool result; @@ -11150,7 +11165,7 @@ index 000000000000..feee7c7c5945 + * @ctrl: The controller to unregister the notifiers on. + * + * Unregisters all currently registered notifiers. This function is used to -+ * ensure that all notifiers will be unregistered and assocaited ++ * ensure that all notifiers will be unregistered and associated + * entries/resources freed when the controller is being shut down. + */ +static void ssam_notifier_unregister_all(struct ssam_controller *ctrl) @@ -11347,7 +11362,7 @@ index 000000000000..feee7c7c5945 +} diff --git a/drivers/misc/surface_aggregator/controller.h b/drivers/misc/surface_aggregator/controller.h new file mode 100644 -index 000000000000..96e2b87a25d9 +index 000000000000..cfb0f658d66c --- /dev/null +++ b/drivers/misc/surface_aggregator/controller.h @@ -0,0 +1,288 @@ @@ -11417,7 +11432,7 @@ index 000000000000..96e2b87a25d9 + * registration and deregistration. + * @refcount: The root of the RB-tree used for reference-counting enabled + * events/notifications. -+ * @head: The list of notifier heads for event/notifiaction callbacks. ++ * @head: The list of notifier heads for event/notification callbacks. + */ +struct ssam_nf { + struct mutex lock; @@ -11606,7 +11621,7 @@ index 000000000000..96e2b87a25d9 + */ +static inline void ssam_controller_write_wakeup(struct ssam_controller *ctrl) +{ -+ ssh_ptl_tx_wakeup(&ctrl->rtl.ptl); ++ ssh_ptl_tx_wakeup_transfer(&ctrl->rtl.ptl); +} + + @@ -11641,10 +11656,10 @@ index 000000000000..96e2b87a25d9 +#endif /* _SURFACE_AGGREGATOR_CONTROLLER_H */ diff --git a/drivers/misc/surface_aggregator/core.c b/drivers/misc/surface_aggregator/core.c new file mode 100644 -index 000000000000..6aaac82b9091 +index 000000000000..460569c5300b --- /dev/null +++ b/drivers/misc/surface_aggregator/core.c -@@ -0,0 +1,831 @@ +@@ -0,0 +1,830 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface Serial Hub (SSH) driver for communication with the Surface/System @@ -11721,7 +11736,7 @@ index 000000000000..6aaac82b9091 + * Set the main controller reference to the given pointer if the reference + * hasn't been set already. + * -+ * Return: Returns zero on success or %-EBUSY if the reference has already ++ * Return: Returns zero on success or %-EEXIST if the reference has already + * been set. + */ +static int ssam_try_set_controller(struct ssam_controller *ctrl) @@ -11732,7 +11747,7 @@ index 000000000000..6aaac82b9091 + if (!__ssam_controller) + __ssam_controller = ctrl; + else -+ status = -EBUSY; ++ status = -EEXIST; + spin_unlock(&__ssam_controller_lock); + + return status; @@ -11767,7 +11782,7 @@ index 000000000000..6aaac82b9091 + * The device link does not have to be destructed manually. It is removed + * automatically once the driver of the client device unbinds. + * -+ * Return: Returns zero on success, %-ENXIO if the controller is not ready or ++ * Return: Returns zero on success, %-ENODEV if the controller is not ready or + * going to be removed soon, or %-ENOMEM if the device link could not be + * created for other reasons. + */ @@ -11781,13 +11796,13 @@ index 000000000000..6aaac82b9091 + + if (c->state != SSAM_CONTROLLER_STARTED) { + ssam_controller_stateunlock(c); -+ return -ENXIO; ++ return -ENODEV; + } + + ctrldev = ssam_controller_device(c); + if (!ctrldev) { + ssam_controller_stateunlock(c); -+ return -ENXIO; ++ return -ENODEV; + } + + link = device_link_add(client, ctrldev, flags); @@ -11797,14 +11812,14 @@ index 000000000000..6aaac82b9091 + } + + /* -+ * Return -ENXIO if supplier driver is on its way to be removed. In this -+ * case, the controller won't be around for much longer and the device -+ * link is not going to save us any more, as unbinding is already in -+ * progress. ++ * Return -ENODEV if supplier driver is on its way to be removed. In ++ * this case, the controller won't be around for much longer and the ++ * device link is not going to save us any more, as unbinding is ++ * already in progress. + */ + if (READ_ONCE(link->status) == DL_STATE_SUPPLIER_UNBIND) { + ssam_controller_stateunlock(c); -+ return -ENXIO; ++ return -ENODEV; + } + + ssam_controller_stateunlock(c); @@ -11815,7 +11830,6 @@ index 000000000000..6aaac82b9091 +/** + * ssam_client_bind() - Bind an arbitrary client device to the controller. + * @client: The client device. -+ * @ctrl: A pointer to where the controller reference should be returned. + * + * Link an arbitrary client device to the controller by creating a device link + * between it as consumer and the main controller device as provider. This @@ -11825,10 +11839,10 @@ index 000000000000..6aaac82b9091 + * + * This function does essentially the same as ssam_client_link(), except that + * it first fetches the main controller reference, then creates the link, and -+ * finally returns this reference in the @ctrl parameter. Note that this -+ * function does not increment the reference counter of the controller, as, -+ * due to the link, the controller lifetime is assured as long as the driver -+ * of the client device is bound. ++ * finally returns this reference. Note that this function does not increment ++ * the reference counter of the controller, as, due to the link, the ++ * controller lifetime is assured as long as the driver of the client device ++ * is bound. + * + * It is not valid to use the controller reference obtained by this method + * outside of the driver bound to the client device at the time of calling @@ -11844,18 +11858,18 @@ index 000000000000..6aaac82b9091 + * The created device link does not have to be destructed manually. It is + * removed automatically once the driver of the client device unbinds. + * -+ * Return: Returns zero on success, %-ENXIO if the controller is not present, -+ * not ready or going to be removed soon, or %-ENOMEM if the device link could -+ * not be created for other reasons. ++ * Return: Returns the controller on success, an error pointer with %-ENODEV ++ * if the controller is not present, not ready or going to be removed soon, or ++ * %-ENOMEM if the device link could not be created for other reasons. + */ -+int ssam_client_bind(struct device *client, struct ssam_controller **ctrl) ++struct ssam_controller *ssam_client_bind(struct device *client) +{ + struct ssam_controller *c; + int status; + + c = ssam_get_controller(); + if (!c) -+ return -ENXIO; ++ return ERR_PTR(-ENODEV); + + status = ssam_client_link(c, client); + @@ -11868,8 +11882,7 @@ index 000000000000..6aaac82b9091 + */ + ssam_controller_put(c); + -+ *ctrl = status == 0 ? c : NULL; -+ return status; ++ return status >= 0 ? c : ERR_PTR(status); +} +EXPORT_SYMBOL_GPL(ssam_client_bind); + @@ -11930,13 +11943,14 @@ index 000000000000..6aaac82b9091 + b = ((version >> 8) & 0xffff); + c = version & 0xff; + -+ return snprintf(buf, PAGE_SIZE - 1, "%u.%u.%u\n", a, b, c); ++ // FIXME: we should use sysfs_emit here, but that's not available on < 5.10 ++ return scnprintf(buf, PAGE_SIZE, "%u.%u.%u\n", a, b, c); +} +static DEVICE_ATTR_RO(firmware_version); + +static struct attribute *ssam_sam_attrs[] = { + &dev_attr_firmware_version.attr, -+ NULL, ++ NULL +}; + +static const struct attribute_group ssam_sam_group = { @@ -11996,8 +12010,8 @@ index 000000000000..6aaac82b9091 + } + + if (status) { -+ dev_err(&serdev->dev, "setup: failed to set parity (value: 0x%02x," -+ " error: %d)\n", uart->parity, status); ++ dev_err(&serdev->dev, "setup: failed to set parity (value: 0x%02x, error: %d)\n", ++ uart->parity, status); + return AE_ERROR; + } + @@ -12052,9 +12066,9 @@ index 000000000000..6aaac82b9091 + /* + * Try to signal display-off, This will quiesce events. + * -+ * Note: Signalling display-off/display-on should normally be done from -+ * some sort of display state notifier. As that is not available, signal -+ * it here. ++ * Note: Signaling display-off/display-on should normally be done from ++ * some sort of display state notifier. As that is not available, ++ * signal it here. + */ + + status = ssam_ctrl_notif_display_off(c); @@ -12072,9 +12086,9 @@ index 000000000000..6aaac82b9091 + /* + * Try to signal display-on. This will restore events. + * -+ * Note: Signalling display-off/display-on should normally be done from -+ * some sort of display state notifier. As that is not available, signal -+ * it here. ++ * Note: Signaling display-off/display-on should normally be done from ++ * some sort of display state notifier. As that is not available, ++ * signal it here. + */ + + status = ssam_ctrl_notif_display_on(c); @@ -12124,9 +12138,9 @@ index 000000000000..6aaac82b9091 + * case of errors, log them and try to restore normal operation state + * as far as possible. + * -+ * Note: Signalling display-off/display-on should normally be done from -+ * some sort of display state notifier. As that is not available, signal -+ * it here. ++ * Note: Signaling display-off/display-on should normally be done from ++ * some sort of display state notifier. As that is not available, ++ * signal it here. + */ + + ssam_irq_disarm_wakeup(c); @@ -12478,10 +12492,10 @@ index 000000000000..6aaac82b9091 +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/surface_aggregator/ssh_msgb.h b/drivers/misc/surface_aggregator/ssh_msgb.h new file mode 100644 -index 000000000000..7c29e7d7028a +index 000000000000..1bfdf045b4a7 --- /dev/null +++ b/drivers/misc/surface_aggregator/ssh_msgb.h -@@ -0,0 +1,201 @@ +@@ -0,0 +1,198 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * SSH message builder functions. @@ -12591,17 +12605,16 @@ index 000000000000..7c29e7d7028a + */ +static inline void msgb_push_frame(struct msgbuf *msgb, u8 ty, u16 len, u8 seq) +{ -+ struct ssh_frame *frame = (struct ssh_frame *)msgb->ptr; -+ const u8 *const begin = msgb->ptr; ++ u8 *const begin = msgb->ptr; + -+ if (WARN_ON(msgb->ptr + sizeof(*frame) > msgb->end)) ++ if (WARN_ON(msgb->ptr + sizeof(struct ssh_frame) > msgb->end)) + return; + -+ frame->type = ty; -+ put_unaligned_le16(len, &frame->len); -+ frame->seq = seq; ++ put_unaligned(ty, begin + offsetof(struct ssh_frame, type)); ++ put_unaligned(len, begin + offsetof(struct ssh_frame, len)); ++ put_unaligned(seq, begin + offsetof(struct ssh_frame, seq)); + -+ msgb->ptr += sizeof(*frame); ++ msgb->ptr += sizeof(struct ssh_frame); + msgb_push_crc(msgb, begin, msgb->ptr - begin); +} + @@ -12648,47 +12661,45 @@ index 000000000000..7c29e7d7028a +static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid, + const struct ssam_request *rqst) +{ -+ struct ssh_command *cmd; -+ const u8 *cmd_begin; + const u8 type = SSH_FRAME_TYPE_DATA_SEQ; ++ u8 *p; + + // SYN + msgb_push_syn(msgb); + + // command frame + crc -+ msgb_push_frame(msgb, type, sizeof(*cmd) + rqst->length, seq); ++ msgb_push_frame(msgb, type, sizeof(struct ssh_command) + rqst->length, seq); + + // frame payload: command struct + payload -+ if (WARN_ON(msgb->ptr + sizeof(*cmd) > msgb->end)) ++ if (WARN_ON(msgb->ptr + sizeof(struct ssh_command) > msgb->end)) + return; + -+ cmd_begin = msgb->ptr; -+ cmd = (struct ssh_command *)msgb->ptr; ++ p = msgb->ptr; + -+ cmd->type = SSH_PLD_TYPE_CMD; -+ cmd->tc = rqst->target_category; -+ cmd->tid_out = rqst->target_id; -+ cmd->tid_in = 0x00; -+ cmd->iid = rqst->instance_id; -+ put_unaligned_le16(rqid, &cmd->rqid); -+ cmd->cid = rqst->command_id; ++ put_unaligned(SSH_PLD_TYPE_CMD, p + offsetof(struct ssh_command, type)); ++ put_unaligned(rqst->target_category, p + offsetof(struct ssh_command, tc)); ++ put_unaligned(rqst->target_id, p + offsetof(struct ssh_command, tid_out)); ++ put_unaligned(0x00, p + offsetof(struct ssh_command, tid_in)); ++ put_unaligned(rqst->instance_id, p + offsetof(struct ssh_command, iid)); ++ put_unaligned(rqid, p + offsetof(struct ssh_command, rqid)); ++ put_unaligned(rqst->command_id, p + offsetof(struct ssh_command, cid)); + -+ msgb->ptr += sizeof(*cmd); ++ msgb->ptr += sizeof(struct ssh_command); + + // command payload + msgb_push_buf(msgb, rqst->payload, rqst->length); + + // crc for command struct + payload -+ msgb_push_crc(msgb, cmd_begin, msgb->ptr - cmd_begin); ++ msgb_push_crc(msgb, p, msgb->ptr - p); +} + +#endif /* _SURFACE_AGGREGATOR_SSH_MSGB_H */ diff --git a/drivers/misc/surface_aggregator/ssh_packet_layer.c b/drivers/misc/surface_aggregator/ssh_packet_layer.c new file mode 100644 -index 000000000000..2d72e8c02842 +index 000000000000..7a5ed16b90d7 --- /dev/null +++ b/drivers/misc/surface_aggregator/ssh_packet_layer.c -@@ -0,0 +1,2009 @@ +@@ -0,0 +1,2060 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SSH packet transport layer. @@ -12754,16 +12765,16 @@ index 000000000000..2d72e8c02842 + * - the timeout work item. + * + * Normal operation is as follows: The initial reference of the packet is -+ * obtained by submitting the packet and queueing it. The receiver thread -+ * takes packets from the queue. By doing this, it does not increment the -+ * refcount but takes over the reference (removing it from the queue). If the -+ * packet is sequenced (i.e. needs to be ACKed by the client), the transmitter -+ * thread sets-up the timeout and adds the packet to the pending set before -+ * starting to transmit it. As the timeout is handled by a reaper task, no -+ * additional reference for it is needed. After the transmit is done, the -+ * reference held by the transmitter thread is dropped. If the packet is -+ * unsequenced (i.e. does not need an ACK), the packet is completed by the -+ * transmitter thread before dropping that reference. ++ * obtained by submitting the packet and queuing it. The receiver thread takes ++ * packets from the queue. By doing this, it does not increment the refcount ++ * but takes over the reference (removing it from the queue). If the packet is ++ * sequenced (i.e. needs to be ACKed by the client), the transmitter thread ++ * sets-up the timeout and adds the packet to the pending set before starting ++ * to transmit it. As the timeout is handled by a reaper task, no additional ++ * reference for it is needed. After the transmit is done, the reference held ++ * by the transmitter thread is dropped. If the packet is unsequenced (i.e. ++ * does not need an ACK), the packet is completed by the transmitter thread ++ * before dropping that reference. + * + * On receival of an ACK, the receiver thread removes and obtains the + * reference to the packet from the pending set. The receiver thread will then @@ -12854,8 +12865,13 @@ index 000000000000..2d72e8c02842 + * + * >> General Notes << + * -+ * To avoid deadlocks, if both queue and pending locks are required, the -+ * pending lock must be acquired before the queue lock. ++ * - To avoid deadlocks, if both queue and pending locks are required, the ++ * pending lock must be acquired before the queue lock. ++ * ++ * - The packet priority must be accessed only while holding the queue lock. ++ * ++ * - The packet timestamp must be accessed only while holding the pending ++ * lock. + */ + +/* @@ -12869,7 +12885,16 @@ index 000000000000..2d72e8c02842 +#define SSH_PTL_MAX_PACKET_TRIES 3 + +/* -+ * SSH_PTL_PACKET_TIMEOUT - Packet timeout. ++ * SSH_PTL_TX_TIMEOUT - Packet transmission timeout. ++ * ++ * Timeout in jiffies for packet transmission via the underlying serial ++ * device. If transmitting the packet takes longer than this timeout, the ++ * packet will be completed with -ETIMEDOUT. It will not be re-submitted. ++ */ ++#define SSH_PTL_TX_TIMEOUT HZ ++ ++/* ++ * SSH_PTL_PACKET_TIMEOUT - Packet response timeout. + * + * Timeout as ktime_t delta for ACKs. If we have not received an ACK in this + * time-frame after starting transmission, the packet will be re-submitted. @@ -12910,8 +12935,8 @@ index 000000000000..2d72e8c02842 + * ssh_ptl_should_drop_ack_packet() - Error injection hook to drop ACK packets. + * + * Useful to test detection and handling of automated re-transmits by the EC. -+ * Specifically of packets that the EC consideres not-ACKed but the driver -+ * already consideres ACKed (due to dropped ACK). In this case, the EC ++ * Specifically of packets that the EC considers not-ACKed but the driver ++ * already considers ACKed (due to dropped ACK). In this case, the EC + * re-transmits the packet-to-be-ACKed and the driver should detect it as + * duplicate/already handled. Note that the driver should still send an ACK + * for the re-transmitted packet. @@ -12962,7 +12987,7 @@ index 000000000000..2d72e8c02842 +ALLOW_ERROR_INJECTION(ssh_ptl_should_fail_write, ERRNO); + +/** -+ * ssh_ptl_should_corrupt_tx_data() - Error injection hook to simualte invalid ++ * ssh_ptl_should_corrupt_tx_data() - Error injection hook to simulate invalid + * data being sent to the EC. + * + * Hook to simulate corrupt/invalid data being sent from host (driver) to EC. @@ -13118,7 +13143,7 @@ index 000000000000..2d72e8c02842 + if (likely(!ssh_ptl_should_corrupt_rx_syn())) + return; + -+ trace_ssam_ei_rx_corrupt_syn("data_length", data->len); ++ trace_ssam_ei_rx_corrupt_syn(data->len); + + data->ptr[1] = 0xb3; // set second byte of SYN to "random" value +} @@ -13364,33 +13389,17 @@ index 000000000000..2d72e8c02842 + mod_delayed_work(system_wq, &ptl->rtx_timeout.reaper, delta); +} + -+static void ssh_ptl_timeout_start(struct ssh_packet *packet) -+{ -+ struct ssh_ptl *ptl = packet->ptl; -+ ktime_t timestamp = ktime_get_coarse_boottime(); -+ ktime_t timeout = ptl->rtx_timeout.timeout; -+ -+ if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state)) -+ return; -+ -+ WRITE_ONCE(packet->timestamp, timestamp); -+ /* -+ * Ensure timestamp is set before starting the reaper. Paired with -+ * implicit barrier following check on ssh_packet_get_expiration() in -+ * ssh_ptl_timeout_reap(). -+ */ -+ smp_mb__after_atomic(); -+ -+ ssh_ptl_timeout_reaper_mod(packet->ptl, timestamp, timestamp + timeout); -+} -+ -+ ++/* must be called with queue lock held */ +static void ssh_packet_next_try(struct ssh_packet *p) +{ -+ u8 priority = READ_ONCE(p->priority); -+ u8 base = ssh_packet_priority_get_base(priority); -+ u8 try = ssh_packet_priority_get_try(priority); ++ u8 base = ssh_packet_priority_get_base(p->priority); ++ u8 try = ssh_packet_priority_get_try(p->priority); + ++ /* ++ * Ensure that we write the priority in one go via WRITE_ONCE() so we ++ * can access it via READ_ONCE() for tracing. Note that other access ++ * is guarded by the queue lock, so no need to use READ_ONCE() there. ++ */ + WRITE_ONCE(p->priority, __SSH_PACKET_PRIORITY(base, try + 1)); +} + @@ -13398,40 +13407,39 @@ index 000000000000..2d72e8c02842 +static struct list_head *__ssh_ptl_queue_find_entrypoint(struct ssh_packet *p) +{ + struct list_head *head; -+ u8 priority = READ_ONCE(p->priority); ++ struct ssh_packet *q; + + /* -+ * We generally assume that there are less control (ACK/NAK) packets and -+ * re-submitted data packets as there are normal data packets (at least -+ * in situations in which many packets are queued; if there aren't many -+ * packets queued the decision on how to iterate should be basically -+ * irrellevant; the number of control/data packets is more or less -+ * limited via the maximum number of pending packets). Thus, when -+ * inserting a control or re-submitted data packet, (determined by their -+ * priority), we search from front to back. Normal data packets are, -+ * usually queued directly at the tail of the queue, so for those search -+ * from back to front. ++ * We generally assume that there are less control (ACK/NAK) packets ++ * and re-submitted data packets as there are normal data packets (at ++ * least in situations in which many packets are queued; if there ++ * aren't many packets queued the decision on how to iterate should be ++ * basically irrelevant; the number of control/data packets is more or ++ * less limited via the maximum number of pending packets). Thus, when ++ * inserting a control or re-submitted data packet, (determined by ++ * their priority), we search from front to back. Normal data packets ++ * are, usually queued directly at the tail of the queue, so for those ++ * search from back to front. + */ + -+ if (priority > SSH_PACKET_PRIORITY(DATA, 0)) { ++ if (p->priority > SSH_PACKET_PRIORITY(DATA, 0)) { + list_for_each(head, &p->ptl->queue.head) { -+ p = list_entry(head, struct ssh_packet, queue_node); ++ q = list_entry(head, struct ssh_packet, queue_node); + -+ if (READ_ONCE(p->priority) < priority) ++ if (q->priority < p->priority) + break; + } + } else { + list_for_each_prev(head, &p->ptl->queue.head) { -+ p = list_entry(head, struct ssh_packet, queue_node); ++ q = list_entry(head, struct ssh_packet, queue_node); + -+ if (READ_ONCE(p->priority) >= priority) { ++ if (q->priority >= p->priority) { + head = head->next; + break; + } + } + } + -+ + return head; +} + @@ -13445,7 +13453,7 @@ index 000000000000..2d72e8c02842 + if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state)) + return -ESHUTDOWN; + -+ // avoid further transitions when cancelling/completing ++ // avoid further transitions when canceling/completing + if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state)) + return -EINVAL; + @@ -13491,10 +13499,19 @@ index 000000000000..2d72e8c02842 +static void ssh_ptl_pending_push(struct ssh_packet *packet) +{ + struct ssh_ptl *ptl = packet->ptl; ++ const ktime_t timestamp = ktime_get_coarse_boottime(); ++ const ktime_t timeout = ptl->rtx_timeout.timeout; ++ ++ /* ++ * Note: We can get the time for the timestamp before acquiring the ++ * lock as this is the only place we're setting it and this function ++ * is called only from the transmitter thread. Thus it is not possible ++ * to overwrite the timestamp with an outdated value below. ++ */ + + spin_lock(&ptl->pending.lock); + -+ // if we are cancelling/completing this packet, do not add it ++ // if we are canceling/completing this packet, do not add it + if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &packet->state)) { + spin_unlock(&ptl->pending.lock); + return; @@ -13506,10 +13523,15 @@ index 000000000000..2d72e8c02842 + return; + } + ++ packet->timestamp = timestamp; ++ + atomic_inc(&ptl->pending.count); + list_add_tail(&ssh_packet_get(packet)->pending_node, &ptl->pending.head); + + spin_unlock(&ptl->pending.lock); ++ ++ // arm/update timeout reaper ++ ssh_ptl_timeout_reaper_mod(packet->ptl, timestamp, timestamp + timeout); +} + +static void ssh_ptl_pending_remove(struct ssh_packet *packet) @@ -13573,7 +13595,7 @@ index 000000000000..2d72e8c02842 + if (test_bit(SSH_PACKET_TY_FLUSH_BIT, &packet->state)) + return !atomic_read(&ptl->pending.count); + -+ // we can alwas process non-blocking packets ++ // we can always process non-blocking packets + if (!test_bit(SSH_PACKET_TY_BLOCKING_BIT, &packet->state)) + return true; + @@ -13593,7 +13615,7 @@ index 000000000000..2d72e8c02842 + spin_lock(&ptl->queue.lock); + list_for_each_entry_safe(p, n, &ptl->queue.head, queue_node) { + /* -+ * If we are cancelling or completing this packet, ignore it. ++ * If we are canceling or completing this packet, ignore it. + * It's going to be removed from this queue shortly. + */ + if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state)) @@ -13611,10 +13633,7 @@ index 000000000000..2d72e8c02842 + + /* + * We are allowed to change the state now. Remove it from the -+ * queue and mark it as being transmitted. Note that we cannot -+ * add it to the set of pending packets yet, as queue locks must -+ * always be acquired before packet locks (otherwise we might -+ * run into a deadlock). ++ * queue and mark it as being transmitted. + */ + + list_del(&p->queue_node); @@ -13624,6 +13643,15 @@ index 000000000000..2d72e8c02842 + smp_mb__before_atomic(); + clear_bit(SSH_PACKET_SF_QUEUED_BIT, &p->state); + ++ /* ++ * Update number of tries. This directly influences the ++ * priority in case the packet is re-submitted (e.g. via ++ * timeout/NAK). Note that all reads and writes to the ++ * priority after the first submission are guarded by the ++ * queue lock. ++ */ ++ ssh_packet_next_try(p); ++ + packet = p; + break; + } @@ -13643,19 +13671,10 @@ index 000000000000..2d72e8c02842 + if (test_bit(SSH_PACKET_TY_SEQUENCED_BIT, &p->state)) { + ptl_dbg(ptl, "ptl: transmitting sequenced packet %p\n", p); + ssh_ptl_pending_push(p); -+ ssh_ptl_timeout_start(p); + } else { + ptl_dbg(ptl, "ptl: transmitting non-sequenced packet %p\n", p); + } + -+ /* -+ * Update number of tries. This directly influences the priority in case -+ * the packet is re-submitted (e.g. via timeout/NAK). Note that this is -+ * the only place where we update the priority in-flight. As this runs -+ * only on the tx-thread, this read-modify-write procedure is safe. -+ */ -+ ssh_packet_next_try(p); -+ + return p; +} + @@ -13704,104 +13723,134 @@ index 000000000000..2d72e8c02842 + wake_up_all(&packet->ptl->tx.packet_wq); +} + -+static void ssh_ptl_tx_threadfn_wait(struct ssh_ptl *ptl) ++static long ssh_ptl_tx_wait_packet(struct ssh_ptl *ptl) +{ -+ wait_event_interruptible(ptl->tx.thread_wq, -+ READ_ONCE(ptl->tx.thread_signal) || kthread_should_stop()); -+ WRITE_ONCE(ptl->tx.thread_signal, false); ++ int status; ++ ++ status = wait_for_completion_interruptible(&ptl->tx.thread_cplt_pkt); ++ ++ reinit_completion(&ptl->tx.thread_cplt_pkt); ++ ++ /* ++ * Ensure completion is cleared before continuing to avoid lost update ++ * problems. ++ */ ++ smp_mb__after_atomic(); ++ ++ return status; ++} ++ ++static long ssh_ptl_tx_wait_transfer(struct ssh_ptl *ptl, long timeout) ++{ ++ long status; ++ ++ status = wait_for_completion_interruptible_timeout( ++ &ptl->tx.thread_cplt_tx, timeout); ++ ++ reinit_completion(&ptl->tx.thread_cplt_tx); ++ ++ /* ++ * Ensure completion is cleared before continuing to avoid lost update ++ * problems. ++ */ ++ smp_mb__after_atomic(); ++ ++ return status; ++} ++ ++static int ssh_ptl_tx_packet(struct ssh_ptl *ptl, struct ssh_packet *packet) ++{ ++ long timeout = SSH_PTL_TX_TIMEOUT; ++ size_t offset = 0; ++ ++ // note: flush-packets don't have any data ++ if (unlikely(!packet->data.ptr)) ++ return 0; ++ ++ // error injection: drop packet to simulate transmission problem ++ if (ssh_ptl_should_drop_packet(packet)) ++ return 0; ++ ++ // error injection: simulate invalid packet data ++ ssh_ptl_tx_inject_invalid_data(packet); ++ ++ ptl_dbg(ptl, "tx: sending data (length: %zu)\n", packet->data.len); ++ print_hex_dump_debug("tx: ", DUMP_PREFIX_OFFSET, 16, 1, ++ packet->data.ptr, packet->data.len, false); ++ ++ do { ++ ssize_t status, len; ++ u8 *buf; ++ ++ buf = packet->data.ptr + offset; ++ len = packet->data.len - offset; ++ ++ status = ssh_ptl_write_buf(ptl, packet, buf, len); ++ if (status < 0) ++ return status; ++ ++ if (status == len) ++ return 0; ++ ++ offset += status; ++ ++ timeout = ssh_ptl_tx_wait_transfer(ptl, timeout); ++ if (kthread_should_stop() || !atomic_read(&ptl->tx.running)) ++ return -ESHUTDOWN; ++ ++ if (timeout < 0) ++ return -EINTR; ++ ++ if (timeout == 0) ++ return -ETIMEDOUT; ++ } while (true); +} + +static int ssh_ptl_tx_threadfn(void *data) +{ + struct ssh_ptl *ptl = data; + -+ while (!kthread_should_stop()) { -+ unsigned char *buf; -+ bool drop = false; -+ size_t len = 0; -+ int status = 0; ++ while (!kthread_should_stop() && atomic_read(&ptl->tx.running)) { ++ struct ssh_packet *packet; ++ int status; + -+ // if we don't have a packet, get the next and add it to pending -+ if (IS_ERR_OR_NULL(ptl->tx.packet)) { -+ ptl->tx.packet = ssh_ptl_tx_next(ptl); -+ ptl->tx.offset = 0; ++ // try to get the next packet ++ packet = ssh_ptl_tx_next(ptl); + -+ // if no packet can be processed, we are done -+ if (IS_ERR(ptl->tx.packet)) { -+ ssh_ptl_tx_threadfn_wait(ptl); -+ continue; -+ } ++ // if no packet can be processed, we are done ++ if (IS_ERR(packet)) { ++ ssh_ptl_tx_wait_packet(ptl); ++ continue; + } + -+ // error injection: drop packet to simulate transmission problem -+ if (ptl->tx.offset == 0) -+ drop = ssh_ptl_should_drop_packet(ptl->tx.packet); ++ // transfer and complete packet ++ status = ssh_ptl_tx_packet(ptl, packet); ++ if (status) ++ ssh_ptl_tx_compl_error(packet, status); ++ else ++ ssh_ptl_tx_compl_success(packet); + -+ // error injection: simulate invalid packet data -+ if (ptl->tx.offset == 0 && !drop) -+ ssh_ptl_tx_inject_invalid_data(ptl->tx.packet); -+ -+ // note: flush-packets don't have any data -+ if (likely(ptl->tx.packet->data.ptr && !drop)) { -+ buf = ptl->tx.packet->data.ptr + ptl->tx.offset; -+ len = ptl->tx.packet->data.len - ptl->tx.offset; -+ -+ ptl_dbg(ptl, "tx: sending data (length: %zu)\n", len); -+ print_hex_dump_debug("tx: ", DUMP_PREFIX_OFFSET, 16, 1, -+ buf, len, false); -+ -+ status = ssh_ptl_write_buf(ptl, ptl->tx.packet, buf, len); -+ } -+ -+ if (status < 0) { -+ // complete packet with error -+ ssh_ptl_tx_compl_error(ptl->tx.packet, status); -+ ssh_packet_put(ptl->tx.packet); -+ ptl->tx.packet = NULL; -+ -+ } else if (status == len) { -+ // complete packet and/or mark as transmitted -+ ssh_ptl_tx_compl_success(ptl->tx.packet); -+ ssh_packet_put(ptl->tx.packet); -+ ptl->tx.packet = NULL; -+ -+ } else { // need more buffer space -+ ptl->tx.offset += status; -+ ssh_ptl_tx_threadfn_wait(ptl); -+ } -+ } -+ -+ // cancel active packet before we actually stop -+ if (!IS_ERR_OR_NULL(ptl->tx.packet)) { -+ ssh_ptl_tx_compl_error(ptl->tx.packet, -ESHUTDOWN); -+ ssh_packet_put(ptl->tx.packet); -+ ptl->tx.packet = NULL; ++ ssh_packet_put(packet); + } + + return 0; +} + +/** -+ * ssh_ptl_tx_wakeup() - Wake up packet transmitter thread. ++ * ssh_ptl_tx_wakeup_packet() - Wake up packet transmitter thread for new ++ * packet. + * @ptl: The packet transport layer. + * -+ * Wakes up the packet transmitter thread. If the packet transport layer has -+ * been shut down, calls to this function will be ignored. ++ * Wakes up the packet transmitter thread, notifying it that a new packet has ++ * arrived and is ready for transfer. If the packet transport layer has been ++ * shut down, calls to this function will be ignored. + */ -+void ssh_ptl_tx_wakeup(struct ssh_ptl *ptl) ++static void ssh_ptl_tx_wakeup_packet(struct ssh_ptl *ptl) +{ + if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state)) + return; + -+ WRITE_ONCE(ptl->tx.thread_signal, true); -+ /* -+ * Ensure that the signal is set before we wake the transmitter -+ * thread to prevent lost updates: If the signal is not set, -+ * when the thread checks it in ssh_ptl_tx_threadfn_wait(), it -+ * may go back to sleep. -+ */ -+ smp_mb__after_atomic(); -+ wake_up(&ptl->tx.thread_wq); ++ complete(&ptl->tx.thread_cplt_pkt); +} + +/** @@ -13812,8 +13861,9 @@ index 000000000000..2d72e8c02842 + */ +int ssh_ptl_tx_start(struct ssh_ptl *ptl) +{ -+ ptl->tx.thread = kthread_run(ssh_ptl_tx_threadfn, ptl, -+ "ssam_serial_hub-tx"); ++ atomic_set_release(&ptl->tx.running, 1); ++ ++ ptl->tx.thread = kthread_run(ssh_ptl_tx_threadfn, ptl, "ssam_serial_hub-tx"); + if (IS_ERR(ptl->tx.thread)) + return PTR_ERR(ptl->tx.thread); + @@ -13830,7 +13880,19 @@ index 000000000000..2d72e8c02842 +{ + int status = 0; + -+ if (ptl->tx.thread) { ++ if (!IS_ERR_OR_NULL(ptl->tx.thread)) { ++ /* Tell thread to stop. */ ++ atomic_set_release(&ptl->tx.running, 0); ++ ++ /* ++ * Wake up thread in case it is paused. Do not use wakeup ++ * helpers as this may be called when the shutdown bit has ++ * already been set. ++ */ ++ complete(&ptl->tx.thread_cplt_pkt); ++ complete(&ptl->tx.thread_cplt_tx); ++ ++ /* Finally, wait for thread to stop. */ + status = kthread_stop(ptl->tx.thread); + ptl->tx.thread = NULL; + } @@ -13893,7 +13955,6 @@ index 000000000000..2d72e8c02842 +static void ssh_ptl_acknowledge(struct ssh_ptl *ptl, u8 seq) +{ + struct ssh_packet *p; -+ int status = 0; + + p = ssh_ptl_ack_pop(ptl, seq); + if (IS_ERR(p)) { @@ -13920,9 +13981,11 @@ index 000000000000..2d72e8c02842 + * has not been updated from "transmitting" to "transmitted" yet. + * In that case, we need to wait for this transition to occur in order + * to determine between success or failure. ++ * ++ * On transmission failure, the packet will be locked after this call. ++ * On success, the transmitted bit will be set. + */ -+ if (test_bit(SSH_PACKET_SF_TRANSMITTING_BIT, &p->state)) -+ ssh_ptl_wait_until_transmitted(p); ++ ssh_ptl_wait_until_transmitted(p); + + /* + * The packet will already be locked in case of a transmission error or @@ -13930,20 +13993,18 @@ index 000000000000..2d72e8c02842 + * packet. + */ + if (unlikely(test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state))) { ++ if (unlikely(!test_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &p->state))) ++ ptl_err(ptl, "ptl: received ACK before packet had been fully transmitted\n"); ++ + ssh_packet_put(p); + return; + } + -+ if (unlikely(!test_bit(SSH_PACKET_SF_TRANSMITTED_BIT, &p->state))) { -+ ptl_err(ptl, "ptl: received ACK before packet had been fully transmitted\n"); -+ status = -EREMOTEIO; -+ } -+ -+ ssh_ptl_remove_and_complete(p, status); ++ ssh_ptl_remove_and_complete(p, 0); + ssh_packet_put(p); + + if (atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING) -+ ssh_ptl_tx_wakeup(ptl); ++ ssh_ptl_tx_wakeup_packet(ptl); +} + + @@ -13978,6 +14039,9 @@ index 000000000000..2d72e8c02842 + /* + * The ptl reference only gets set on or before the first submission. + * After the first submission, it has to be read-only. ++ * ++ * Note that ptl may already be set from upper-layer request ++ * submission, thus we cannot expect it to be NULL. + */ + ptl_old = READ_ONCE(p->ptl); + if (ptl_old == NULL) @@ -13991,20 +14055,39 @@ index 000000000000..2d72e8c02842 + + if (!test_bit(SSH_PACKET_TY_BLOCKING_BIT, &p->state) + || (atomic_read(&ptl->pending.count) < SSH_PTL_MAX_PENDING)) -+ ssh_ptl_tx_wakeup(ptl); ++ ssh_ptl_tx_wakeup_packet(ptl); + + return 0; +} + -+/* must be called with pending lock held */ ++/* ++ * __ssh_ptl_resubmit() - Re-submit a packet to the transport layer. ++ * @packet: The packet to re-submit. ++ * ++ * Re-submits the given packet: Checks if it can be re-submitted and queues it ++ * if it can, resetting the packet timestamp in the process. Must be called ++ * with the pending lock held. ++ * ++ * Return: Returns %-ECANCELED if the packet has exceeded its number of tries, ++ * %-EINVAL if the packet has been locked, %-EALREADY if the packet is already ++ * on the queue, and %-ESHUTDOWN if the transmission layer has been shut down. ++ */ +static int __ssh_ptl_resubmit(struct ssh_packet *packet) +{ + int status; ++ u8 try; + + trace_ssam_packet_resubmit(packet); + + spin_lock(&packet->ptl->queue.lock); + ++ /* Check if the packet is out of tries. */ ++ try = ssh_packet_priority_get_try(packet->priority); ++ if (try >= SSH_PTL_MAX_PACKET_TRIES) { ++ spin_unlock(&packet->ptl->queue.lock); ++ return -ECANCELED; ++ } ++ + status = __ssh_ptl_queue_push(packet); + if (status) { + /* @@ -14016,13 +14099,7 @@ index 000000000000..2d72e8c02842 + return status; + } + -+ /* -+ * Reset the timestamp. This must be called and executed before the -+ * pending lock is released. The lock release should be a sufficient -+ * barrier for this operation, thus there is no need to manually add -+ * one here. -+ */ -+ WRITE_ONCE(packet->timestamp, KTIME_MAX); ++ packet->timestamp = KTIME_MAX; + + spin_unlock(&packet->ptl->queue.lock); + return 0; @@ -14032,7 +14109,6 @@ index 000000000000..2d72e8c02842 +{ + struct ssh_packet *p; + bool resub = false; -+ u8 try; + + /* + * Note: We deliberately do not remove/attempt to cancel and complete @@ -14049,19 +14125,10 @@ index 000000000000..2d72e8c02842 + + // re-queue all pending packets + list_for_each_entry(p, &ptl->pending.head, pending_node) { -+ // avoid further transitions if locked -+ if (test_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state)) -+ continue; -+ -+ // do not re-schedule if packet is out of tries -+ try = ssh_packet_priority_get_try(READ_ONCE(p->priority)); -+ if (try >= SSH_PTL_MAX_PACKET_TRIES) -+ continue; -+ + /* -+ * Submission fails if the packet has been locked, is already -+ * queued, or the layer is being shut down. No need to -+ * re-schedule tx-thread in those cases. ++ * Re-submission fails if the packet is out of tries, has been ++ * locked, is already queued, or the layer is being shut down. ++ * No need to re-schedule tx-thread in those cases. + */ + if (!__ssh_ptl_resubmit(p)) + resub = true; @@ -14070,7 +14137,7 @@ index 000000000000..2d72e8c02842 + spin_unlock(&ptl->pending.lock); + + if (resub) -+ ssh_ptl_tx_wakeup(ptl); ++ ssh_ptl_tx_wakeup_packet(ptl); +} + +/** @@ -14081,11 +14148,11 @@ index 000000000000..2d72e8c02842 + * callbacks will be called. This may occur during execution of this function + * or may occur at any point later. + * -+ * Note that it is not guaranteed that the packet will actually be cancelled -+ * if the packet is concurrently completed by another process. The only -+ * guarantee of this function is that the packet will be completed (with -+ * success, failure, or cancellation) and released from the transport layer in -+ * a reasonable time-frame. ++ * Note that it is not guaranteed that the packet will actually be canceled if ++ * the packet is concurrently completed by another process. The only guarantee ++ * of this function is that the packet will be completed (with success, ++ * failure, or cancellation) and released from the transport layer in a ++ * reasonable time-frame. + * + * May be called before the packet has been submitted, in which case any later + * packet submission fails. @@ -14122,20 +14189,18 @@ index 000000000000..2d72e8c02842 + ssh_ptl_remove_and_complete(p, -ECANCELED); + + if (atomic_read(&p->ptl->pending.count) < SSH_PTL_MAX_PENDING) -+ ssh_ptl_tx_wakeup(p->ptl); ++ ssh_ptl_tx_wakeup_packet(p->ptl); + + } else if (!test_and_set_bit(SSH_PACKET_SF_COMPLETED_BIT, &p->state)) { + __ssh_ptl_complete(p, -ECANCELED); + } +} + -+ ++/* must be called with pending lock held */ +static ktime_t ssh_packet_get_expiration(struct ssh_packet *p, ktime_t timeout) +{ -+ ktime_t timestamp = READ_ONCE(p->timestamp); -+ -+ if (timestamp != KTIME_MAX) -+ return ktime_add(timestamp, timeout); ++ if (p->timestamp != KTIME_MAX) ++ return ktime_add(p->timestamp, timeout); + else + return KTIME_MAX; +} @@ -14149,8 +14214,9 @@ index 000000000000..2d72e8c02842 + ktime_t timeout = ptl->rtx_timeout.timeout; + ktime_t next = KTIME_MAX; + bool resub = false; ++ int status; + -+ trace_ssam_ptl_timeout_reap("pending", atomic_read(&ptl->pending.count)); ++ trace_ssam_ptl_timeout_reap(atomic_read(&ptl->pending.count)); + + /* + * Mark reaper as "not pending". This is done before checking any @@ -14169,7 +14235,6 @@ index 000000000000..2d72e8c02842 + + list_for_each_entry_safe(p, n, &ptl->pending.head, pending_node) { + ktime_t expires = ssh_packet_get_expiration(p, timeout); -+ u8 try; + + /* + * Check if the timeout hasn't expired yet. Find out next @@ -14180,21 +14245,21 @@ index 000000000000..2d72e8c02842 + continue; + } + -+ // check if we still have some tries left -+ try = ssh_packet_priority_get_try(READ_ONCE(p->priority)); -+ if (likely(try < SSH_PTL_MAX_PACKET_TRIES)) { -+ trace_ssam_packet_timeout(p); ++ trace_ssam_packet_timeout(p); + -+ /* -+ * Submission fails if the packet has been locked, is -+ * already queued, or the layer is being shut down. -+ * No need to re-schedule tx-thread in those cases. -+ */ -+ if (!__ssh_ptl_resubmit(p)) -+ resub = true; ++ status = __ssh_ptl_resubmit(p); + ++ /* ++ * Re-submission fails if the packet is out of tries, has been ++ * locked, is already queued, or the layer is being shut down. ++ * No need to re-schedule tx-thread in those cases. ++ */ ++ if (!status) ++ resub = true; ++ ++ /* Go to next packet if this packet is not out of tries. */ ++ if (status != -ECANCELED) + continue; -+ } + + // no more tries left: cancel the packet + @@ -14202,8 +14267,6 @@ index 000000000000..2d72e8c02842 + if (test_and_set_bit(SSH_PACKET_SF_LOCKED_BIT, &p->state)) + continue; + -+ trace_ssam_packet_timeout(p); -+ + /* + * We have now marked the packet as locked. Thus it cannot be + * added to the pending list again after we've removed it here. @@ -14239,7 +14302,7 @@ index 000000000000..2d72e8c02842 + ssh_ptl_timeout_reaper_mod(ptl, now, next); + + if (resub) -+ ssh_ptl_tx_wakeup(ptl); ++ ssh_ptl_tx_wakeup_packet(ptl); +} + + @@ -14256,7 +14319,7 @@ index 000000000000..2d72e8c02842 + return true; + } + -+ // update list of blocked seuence IDs ++ // update list of blocked sequence IDs + ptl->rx.blocked.seqs[ptl->rx.blocked.offset] = seq; + ptl->rx.blocked.offset = (ptl->rx.blocked.offset + 1) + % ARRAY_SIZE(ptl->rx.blocked.seqs); @@ -14348,12 +14411,12 @@ index 000000000000..2d72e8c02842 + * detected when handling data frames. + * - This path will also be executed on invalid CRCs: When an + * invalid CRC is encountered, the code below will skip data -+ * until direclty after the SYN. This causes the search for ++ * until directly after the SYN. This causes the search for + * the next SYN, which is generally not placed directly after + * the last one. + * + * Open question: Should we send this in case of invalid -+ * payload CRCs if the frame-type is nonsequential (current ++ * payload CRCs if the frame-type is non-sequential (current + * implementation) or should we drop that frame without + * telling the EC? + */ @@ -14492,7 +14555,7 @@ index 000000000000..2d72e8c02842 + * @n: Size of the data to push to the layer, in bytes. + * + * Pushes data from a lower-layer transport to the receiver fifo buffer of the -+ * packet layer and notifies the reveiver thread. Calls to this function are ++ * packet layer and notifies the receiver thread. Calls to this function are + * ignored once the packet layer has been shut down. + * + * Return: Returns the number of bytes transferred (positive or zero) on @@ -14539,7 +14602,7 @@ index 000000000000..2d72e8c02842 + * Ensure that the layer gets marked as shut-down before actually + * stopping it. In combination with the check in ssh_ptl_queue_push(), + * this guarantees that no new packets can be added and all already -+ * queued packets are properly cancelled. In combination with the check ++ * queued packets are properly canceled. In combination with the check + * in ssh_ptl_rx_rcvbuf(), this guarantees that received data is + * properly cut off. + */ @@ -14561,14 +14624,14 @@ index 000000000000..2d72e8c02842 + * and pending set. + * + * Note: We still need locks here because someone could still be -+ * cancelling packets. ++ * canceling packets. + * + * Note 2: We can re-use queue_node (or pending_node) if we mark the + * packet as locked an then remove it from the queue (or pending set -+ * respecitvely). Marking the packet as locked avoids re-queueing ++ * respectively). Marking the packet as locked avoids re-queuing + * (which should already be prevented by having stopped the treads...) + * and not setting QUEUED_BIT (or PENDING_BIT) prevents removal from a -+ * new list via other threads (e.g. canellation). ++ * new list via other threads (e.g. cancellation). + * + * Note 3: There may be overlap between complete_p and complete_q. + * This is handled via test_and_set_bit() on the "completed" flag @@ -14653,10 +14716,9 @@ index 000000000000..2d72e8c02842 + atomic_set_release(&ptl->pending.count, 0); + + ptl->tx.thread = NULL; -+ ptl->tx.thread_signal = false; -+ ptl->tx.packet = NULL; -+ ptl->tx.offset = 0; -+ init_waitqueue_head(&ptl->tx.thread_wq); ++ atomic_set(&ptl->tx.running, 0); ++ init_completion(&ptl->tx.thread_cplt_pkt); ++ init_completion(&ptl->tx.thread_cplt_tx); + init_waitqueue_head(&ptl->tx.packet_wq); + + ptl->rx.thread = NULL; @@ -14700,10 +14762,10 @@ index 000000000000..2d72e8c02842 +} diff --git a/drivers/misc/surface_aggregator/ssh_packet_layer.h b/drivers/misc/surface_aggregator/ssh_packet_layer.h new file mode 100644 -index 000000000000..f3d8a85389d5 +index 000000000000..fd9bd2aa2028 --- /dev/null +++ b/drivers/misc/surface_aggregator/ssh_packet_layer.h -@@ -0,0 +1,175 @@ +@@ -0,0 +1,189 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * SSH packet transport layer. @@ -14761,12 +14823,11 @@ index 000000000000..f3d8a85389d5 + * @pending.head: List-head of the pending set/list. + * @pending.count: Number of currently pending packets. + * @tx: Transmitter subsystem. -+ * @tx.thread_signal: Signal notifying transmitter thread of data to be sent. ++ * @tx.running: Flag indicating (desired) transmitter thread state. + * @tx.thread: Transmitter thread. -+ * @tx.thread_wq: Waitqueue-head for transmitter thread. ++ * @tx.thread_cplt_tx: Completion for transmitter thread waiting on transfer. ++ * @tx.thread_cplt_pkt: Completion for transmitter thread waiting on packets. + * @tx.packet_wq: Waitqueue-head for packet transmit completion. -+ * @tx.packet: Currently sent packet. -+ * @tx.offset: Data-offset into the packet currently being transmitted. + * @rx: Receiver subsystem. + * @rx.thread: Receiver thread. + * @rx.wq: Waitqueue-head for receiver thread. @@ -14776,7 +14837,7 @@ index 000000000000..f3d8a85389d5 + * @rx.blocked.seqs: Array of blocked sequence IDs. + * @rx.blocked.offset: Offset indicating where a new ID should be inserted. + * @rtx_timeout: Retransmission timeout subsystem. -+ * @rtx_timeout.timeout: Timeout inverval for retransmission. ++ * @rtx_timeout.timeout: Timeout interval for retransmission. + * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled. + * @rtx_timeout.reaper: Work performing timeout checks and subsequent actions. + * @ops: Packet layer operations. @@ -14797,12 +14858,11 @@ index 000000000000..f3d8a85389d5 + } pending; + + struct { -+ bool thread_signal; ++ atomic_t running; + struct task_struct *thread; -+ struct wait_queue_head thread_wq; ++ struct completion thread_cplt_tx; ++ struct completion thread_cplt_pkt; + struct wait_queue_head packet_wq; -+ struct ssh_packet *packet; -+ size_t offset; + } tx; + + struct { @@ -14829,8 +14889,8 @@ index 000000000000..f3d8a85389d5 + +#define __ssam_prcond(func, p, fmt, ...) \ + do { \ -+ if ((p)) \ -+ func((p), fmt, ##__VA_ARGS__); \ ++ if (p) \ ++ func(p, fmt, ##__VA_ARGS__); \ + } while (0) + +#define ptl_dbg(p, fmt, ...) dev_dbg(&(p)->serdev->dev, fmt, ##__VA_ARGS__) @@ -14870,7 +14930,23 @@ index 000000000000..f3d8a85389d5 +void ssh_ptl_cancel(struct ssh_packet *p); + +int ssh_ptl_rx_rcvbuf(struct ssh_ptl *ptl, const u8 *buf, size_t n); -+void ssh_ptl_tx_wakeup(struct ssh_ptl *ptl); ++ ++/** ++ * ssh_ptl_tx_wakeup_transfer() - Wake up packet transmitter thread for ++ * transfer. ++ * @ptl: The packet transport layer. ++ * ++ * Wakes up the packet transmitter thread, notifying it that the underlying ++ * transport has more space for data to be transmitted. If the packet ++ * transport layer has been shut down, calls to this function will be ignored. ++ */ ++static inline void ssh_ptl_tx_wakeup_transfer(struct ssh_ptl *ptl) ++{ ++ if (test_bit(SSH_PTL_SF_SHUTDOWN_BIT, &ptl->state)) ++ return; ++ ++ complete(&ptl->tx.thread_cplt_tx); ++} + +void ssh_packet_init(struct ssh_packet *packet, unsigned long type, + u8 priority, const struct ssh_packet_ops *ops); @@ -14881,7 +14957,7 @@ index 000000000000..f3d8a85389d5 +#endif /* _SURFACE_AGGREGATOR_SSH_PACKET_LAYER_H */ diff --git a/drivers/misc/surface_aggregator/ssh_parser.c b/drivers/misc/surface_aggregator/ssh_parser.c new file mode 100644 -index 000000000000..575cbc039ad7 +index 000000000000..0e52344bcc7a --- /dev/null +++ b/drivers/misc/surface_aggregator/ssh_parser.c @@ -0,0 +1,229 @@ @@ -14939,9 +15015,9 @@ index 000000000000..575cbc039ad7 + * + * Search for SSH SYN bytes in the given source span. If found, set the @rem + * span to the remaining data, starting with the first SYN bytes and capped by -+ * the source span length, and return %true. This function does not copy -+ * any data, but rather only sets pointers to the respecitve start addresses -+ * and length values. ++ * the source span length, and return %true. This function does not copy any ++ * data, but rather only sets pointers to the respective start addresses and ++ * length values. + * + * If no SSH SYN bytes could be found, set the @rem span to the zero-length + * span at the end of the source span and return %false. @@ -14951,7 +15027,7 @@ index 000000000000..575cbc039ad7 + * source span, and return %false. This function should then be re-run once + * more data is available. + * -+ * Return: Returns %true iff a complete SSG SYN sequence could be found, ++ * Return: Returns %true iff a complete SSH SYN sequence could be found, + * %false otherwise. + */ +bool sshp_find_syn(const struct ssam_span *src, struct ssam_span *rem) @@ -14999,7 +15075,7 @@ index 000000000000..575cbc039ad7 + * + * Return: Returns zero on success or if the frame is incomplete, %-ENOMSG if + * the start of the message is invalid, %-EBADMSG if any (frame-header or -+ * payload) CRC is ivnalid, or %-EMSGSIZE if the SSH message is bigger than ++ * payload) CRC is invalid, or %-EMSGSIZE if the SSH message is bigger than + * the maximum message length specified in the @maxlen parameter. + */ +int sshp_parse_frame(const struct device *dev, const struct ssam_span *source, @@ -15037,9 +15113,9 @@ index 000000000000..575cbc039ad7 + + // ensure packet does not exceed maximum length + sp.len = get_unaligned_le16(&((struct ssh_frame *)sf.ptr)->len); -+ if (unlikely(sp.len + SSH_MESSAGE_LENGTH(0) > maxlen)) { -+ dev_warn(dev, "rx: parser: frame too large: %u bytes\n", -+ ((struct ssh_frame *)sf.ptr)->len); ++ if (unlikely(SSH_MESSAGE_LENGTH(sp.len) > maxlen)) { ++ dev_warn(dev, "rx: parser: frame too large: %llu bytes\n", ++ SSH_MESSAGE_LENGTH(sp.len)); + return -EMSGSIZE; + } + @@ -15279,10 +15355,10 @@ index 000000000000..71c43ab07bf6 +#endif /* _SURFACE_AGGREGATOR_SSH_PARSER_h */ diff --git a/drivers/misc/surface_aggregator/ssh_request_layer.c b/drivers/misc/surface_aggregator/ssh_request_layer.c new file mode 100644 -index 000000000000..f47bd949b6c3 +index 000000000000..9188526278e2 --- /dev/null +++ b/drivers/misc/surface_aggregator/ssh_request_layer.c -@@ -0,0 +1,1254 @@ +@@ -0,0 +1,1264 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * SSH request transport layer. @@ -15295,6 +15371,7 @@ index 000000000000..f47bd949b6c3 +#include +#include +#include ++#include +#include +#include +#include @@ -15372,7 +15449,7 @@ index 000000000000..f47bd949b6c3 +static u32 ssh_request_get_rqid_safe(struct ssh_request *rqst) +{ + if (!rqst->packet.data.ptr) -+ return (u32)-1; ++ return U32_MAX; + + return ssh_request_get_rqid(rqst); +} @@ -15456,7 +15533,7 @@ index 000000000000..f47bd949b6c3 + + trace_ssam_request_complete(rqst, status); + -+ // rtl/ptl may not be set if we're cancelling before submitting ++ // rtl/ptl may not be set if we're canceling before submitting + rtl_dbg_cond(rtl, "rtl: completing request (rqid: 0x%04x, status: %d)\n", + ssh_request_get_rqid_safe(rqst), status); + @@ -15566,13 +15643,14 @@ index 000000000000..f47bd949b6c3 + } else if (status) { + /* + * If submitting the packet failed and the packet layer isn't -+ * shutting down, the packet has either been submmitted/queued -+ * before (-EALREADY, which cannot happen as we have guaranteed -+ * that requests cannot be re-submitted), or the packet was -+ * marked as locked (-EINVAL). To mark the packet locked at this -+ * stage, the request, and thus the packets itself, had to have -+ * been canceled. Simply drop the reference. Cancellation itself -+ * will remove it from the set of pending requests. ++ * shutting down, the packet has either been submitted/queued ++ * before (-EALREADY, which cannot happen as we have ++ * guaranteed that requests cannot be re-submitted), or the ++ * packet was marked as locked (-EINVAL). To mark the packet ++ * locked at this stage, the request, and thus the packets ++ * itself, had to have been canceled. Simply drop the ++ * reference. Cancellation itself will remove it from the set ++ * of pending requests. + */ + + WARN_ON(status != -EINVAL); @@ -15737,6 +15815,10 @@ index 000000000000..f47bd949b6c3 + if (test_bit(SSH_REQUEST_SF_LOCKED_BIT, &rqst->state)) + return; + ++ /* ++ * Note: The timestamp gets set only once. This happens on the packet ++ * callback. All other access to it is read-only. ++ */ + WRITE_ONCE(rqst->timestamp, timestamp); + /* + * Ensure timestamp is set before starting the reaper. Paired with @@ -15885,10 +15967,10 @@ index 000000000000..f47bd949b6c3 + * from the queue, where we are now guaranteed that the packet is or has + * been due to the critical section. + * -+ * Note that if the CMPXCHG fails, we are guaranteed that ptl has ++ * Note that if the cmpxchg() fails, we are guaranteed that ptl has + * been set and is non-NULL, as states can only be nonzero after this -+ * has been set. Also note that we need to fetch the static (type) flags -+ * to ensure that they don't cause the cmpxchg to fail. ++ * has been set. Also note that we need to fetch the static (type) ++ * flags to ensure that they don't cause the cmpxchg() to fail. + */ + fixed = READ_ONCE(r->state) & SSH_REQUEST_FLAGS_TY_MASK; + flags = cmpxchg(&r->state, fixed, SSH_REQUEST_SF_LOCKED_BIT); @@ -15914,10 +15996,10 @@ index 000000000000..f47bd949b6c3 + spin_lock(&rtl->queue.lock); + + /* -+ * Note: 1) Requests cannot be re-submitted. 2) If a request is queued, -+ * it cannot be "transmitting"/"pending" yet. Thus, if we successfully -+ * remove the request here, we have removed all its occurences in the -+ * system. ++ * Note: 1) Requests cannot be re-submitted. 2) If a request is ++ * queued, it cannot be "transmitting"/"pending" yet. Thus, if we ++ * successfully remove the request here, we have removed all its ++ * occurrences in the system. + */ + + remove = test_and_clear_bit(SSH_REQUEST_SF_QUEUED_BIT, &r->state); @@ -15948,7 +16030,7 @@ index 000000000000..f47bd949b6c3 + + /* + * Now that we have locked the packet, we have guaranteed that it can't -+ * be added to the system any more. If ptl is zero, the locked ++ * be added to the system any more. If ptl is NULL, the locked + * check in ssh_rtl_submit() has not been run and any submission, + * currently in progress or called later, won't add the packet. Thus we + * can directly complete it. @@ -16046,11 +16128,11 @@ index 000000000000..f47bd949b6c3 + return; + + /* -+ * The packet may get cancelled even though it has not been ++ * The packet may get canceled even though it has not been + * submitted yet. The request may still be queued. Check the + * queue and remove it if necessary. As the timeout would have -+ * been started in this function on success, there's no need to -+ * cancel it here. ++ * been started in this function on success, there's no need ++ * to cancel it here. + */ + ssh_rtl_queue_remove(r); + ssh_rtl_pending_remove(r); @@ -16068,6 +16150,10 @@ index 000000000000..f47bd949b6c3 + + // if we expect a response, we just need to start the timeout + if (test_bit(SSH_REQUEST_TY_HAS_RESPONSE_BIT, &r->state)) { ++ /* ++ * Note: This is the only place where the timestamp gets set, ++ * all other access to it is read-only. ++ */ + ssh_rtl_timeout_start(r); + return; + } @@ -16110,7 +16196,7 @@ index 000000000000..f47bd949b6c3 + ktime_t timeout = rtl->rtx_timeout.timeout; + ktime_t next = KTIME_MAX; + -+ trace_ssam_rtl_timeout_reap("pending", atomic_read(&rtl->pending.count)); ++ trace_ssam_rtl_timeout_reap(atomic_read(&rtl->pending.count)); + + /* + * Mark reaper as "not pending". This is done before checking any @@ -16402,8 +16488,8 @@ index 000000000000..f47bd949b6c3 + * a special flush packet, meaning that upon completion, also the underlying + * packet transport layer has been flushed. + * -+ * Flushing the request layer gurarantees that all previously submitted -+ * requests have been fully completed before this call returns. Additinally, ++ * Flushing the request layer guarantees that all previously submitted ++ * requests have been fully completed before this call returns. Additionally, + * flushing blocks execution of all later submitted requests until the flush + * has been completed. + * @@ -16472,9 +16558,9 @@ index 000000000000..f47bd949b6c3 + set_bit(SSH_RTL_SF_SHUTDOWN_BIT, &rtl->state); + /* + * Ensure that the layer gets marked as shut-down before actually -+ * stopping it. In combination with the check in ssh_rtl_sunmit(), this -+ * guarantees that no new requests can be added and all already queued -+ * requests are properly cancelled. ++ * stopping it. In combination with the check in ssh_rtl_submit(), ++ * this guarantees that no new requests can be added and all already ++ * queued requests are properly canceled. + */ + smp_mb__after_atomic(); + @@ -16506,9 +16592,9 @@ index 000000000000..f47bd949b6c3 + cancel_delayed_work_sync(&rtl->rtx_timeout.reaper); + + /* -+ * Shutting down the packet layer should also have caneled all requests. -+ * Thus the pending set should be empty. Attempt to handle this -+ * gracefully anyways, even though this should be dead code. ++ * Shutting down the packet layer should also have canceled all ++ * requests. Thus the pending set should be empty. Attempt to handle ++ * this gracefully anyways, even though this should be dead code. + */ + + pending = atomic_read(&rtl->pending.count); @@ -16539,7 +16625,7 @@ index 000000000000..f47bd949b6c3 +} diff --git a/drivers/misc/surface_aggregator/ssh_request_layer.h b/drivers/misc/surface_aggregator/ssh_request_layer.h new file mode 100644 -index 000000000000..e945e0532628 +index 000000000000..4fcdd0bda4d4 --- /dev/null +++ b/drivers/misc/surface_aggregator/ssh_request_layer.h @@ -0,0 +1,142 @@ @@ -16602,7 +16688,7 @@ index 000000000000..e945e0532628 + * @tx: Transmitter subsystem. + * @tx.work: Transmitter work item. + * @rtx_timeout: Retransmission timeout subsystem. -+ * @rtx_timeout.timeout: Timeout inverval for retransmission. ++ * @rtx_timeout.timeout: Timeout interval for retransmission. + * @rtx_timeout.expires: Time specifying when the reaper work is next scheduled. + * @rtx_timeout.reaper: Work performing timeout checks and subsequent actions. + * @ops: Request layer operations. @@ -16687,10 +16773,10 @@ index 000000000000..e945e0532628 +#endif /* _SURFACE_AGGREGATOR_SSH_REQUEST_LAYER_H */ diff --git a/drivers/misc/surface_aggregator/trace.h b/drivers/misc/surface_aggregator/trace.h new file mode 100644 -index 000000000000..232bf1142aae +index 000000000000..fdf415205089 --- /dev/null +++ b/drivers/misc/surface_aggregator/trace.h -@@ -0,0 +1,625 @@ +@@ -0,0 +1,648 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Trace points for SSAM/SSH. @@ -16803,6 +16889,8 @@ index 000000000000..232bf1142aae +{ + char buf[2 * sizeof(void *) + 1]; + ++ BUILD_BUG_ON(ARRAY_SIZE(buf) < SSAM_PTR_UID_LEN); ++ + snprintf(buf, ARRAY_SIZE(buf), "%p", ptr); + memcpy(uid_str, &buf[ARRAY_SIZE(buf) - SSAM_PTR_UID_LEN], + SSAM_PTR_UID_LEN); @@ -16858,8 +16946,8 @@ index 000000000000..232bf1142aae +#endif /* _SURFACE_AGGREGATOR_TRACE_HELPERS */ + +#define ssam_trace_get_command_field_u8(packet, field) \ -+ ((!packet || packet->data.len < SSH_COMMAND_MESSAGE_LENGTH(0)) \ -+ ? 0 : p->data.ptr[SSH_MSGOFFSET_COMMAND(field)]) ++ ((!(packet) || (packet)->data.len < SSH_COMMAND_MESSAGE_LENGTH(0)) \ ++ ? 0 : (packet)->data.ptr[SSH_MSGOFFSET_COMMAND(field)]) + +#define ssam_show_generic_u8_field(value) \ + __print_symbolic(value, \ @@ -17248,28 +17336,49 @@ index 000000000000..232bf1142aae + ) + + -+DECLARE_EVENT_CLASS(ssam_generic_uint_class, -+ TP_PROTO(const char *property, unsigned int value), ++DECLARE_EVENT_CLASS(ssam_pending_class, ++ TP_PROTO(unsigned int pending), + -+ TP_ARGS(property, value), ++ TP_ARGS(pending), + + TP_STRUCT__entry( -+ __field(unsigned int, value) -+ __string(property, property) ++ __field(unsigned int, pending) + ), + + TP_fast_assign( -+ __entry->value = value; -+ __assign_str(property, property); ++ __entry->pending = pending; + ), + -+ TP_printk("%s=%u", __get_str(property), __entry->value) ++ TP_printk("pending=%u", __entry->pending) +); + -+#define DEFINE_SSAM_GENERIC_UINT_EVENT(name) \ -+ DEFINE_EVENT(ssam_generic_uint_class, ssam_##name, \ -+ TP_PROTO(const char *property, unsigned int value), \ -+ TP_ARGS(property, value) \ ++#define DEFINE_SSAM_PENDING_EVENT(name) \ ++ DEFINE_EVENT(ssam_pending_class, ssam_##name, \ ++ TP_PROTO(unsigned int pending), \ ++ TP_ARGS(pending) \ ++ ) ++ ++ ++DECLARE_EVENT_CLASS(ssam_data_class, ++ TP_PROTO(size_t length), ++ ++ TP_ARGS(length), ++ ++ TP_STRUCT__entry( ++ __field(size_t, length) ++ ), ++ ++ TP_fast_assign( ++ __entry->length = length; ++ ), ++ ++ TP_printk("length=%zu", __entry->length) ++); ++ ++#define DEFINE_SSAM_DATA_EVENT(name) \ ++ DEFINE_EVENT(ssam_data_class, ssam_##name, \ ++ TP_PROTO(size_t length), \ ++ TP_ARGS(length) \ + ) + + @@ -17283,20 +17392,20 @@ index 000000000000..232bf1142aae +DEFINE_SSAM_PACKET_EVENT(packet_timeout); +DEFINE_SSAM_PACKET_EVENT(packet_cancel); +DEFINE_SSAM_PACKET_STATUS_EVENT(packet_complete); -+DEFINE_SSAM_GENERIC_UINT_EVENT(ptl_timeout_reap); ++DEFINE_SSAM_PENDING_EVENT(ptl_timeout_reap); + +DEFINE_SSAM_REQUEST_EVENT(request_submit); +DEFINE_SSAM_REQUEST_EVENT(request_timeout); +DEFINE_SSAM_REQUEST_EVENT(request_cancel); +DEFINE_SSAM_REQUEST_STATUS_EVENT(request_complete); -+DEFINE_SSAM_GENERIC_UINT_EVENT(rtl_timeout_reap); ++DEFINE_SSAM_PENDING_EVENT(rtl_timeout_reap); + +DEFINE_SSAM_PACKET_EVENT(ei_tx_drop_ack_packet); +DEFINE_SSAM_PACKET_EVENT(ei_tx_drop_nak_packet); +DEFINE_SSAM_PACKET_EVENT(ei_tx_drop_dsq_packet); +DEFINE_SSAM_PACKET_STATUS_EVENT(ei_tx_fail_write); +DEFINE_SSAM_PACKET_EVENT(ei_tx_corrupt_data); -+DEFINE_SSAM_GENERIC_UINT_EVENT(ei_rx_corrupt_syn); ++DEFINE_SSAM_DATA_EVENT(ei_rx_corrupt_syn); +DEFINE_SSAM_FRAME_EVENT(ei_rx_corrupt_data); +DEFINE_SSAM_REQUEST_EVENT(ei_rx_drop_response); + @@ -17386,7 +17495,7 @@ index 000000000000..8e3e86c7d78c +#endif /* _LINUX_SURFACE_ACPI_NOTIFY_H */ diff --git a/include/linux/surface_aggregator/controller.h b/include/linux/surface_aggregator/controller.h new file mode 100644 -index 000000000000..d128c68c04e0 +index 000000000000..75a6c6440cdc --- /dev/null +++ b/include/linux/surface_aggregator/controller.h @@ -0,0 +1,832 @@ @@ -17499,8 +17608,8 @@ index 000000000000..d128c68c04e0 + + +struct ssam_controller *ssam_get_controller(void); ++struct ssam_controller *ssam_client_bind(struct device *client); +int ssam_client_link(struct ssam_controller *ctrl, struct device *client); -+int ssam_client_bind(struct device *client, struct ssam_controller **ctrl); + +struct device *ssam_controller_device(struct ssam_controller *c); + @@ -17564,9 +17673,9 @@ index 000000000000..d128c68c04e0 + * @rqst: The request. + * @resp: The response buffer. + * -+ * Sets the response buffer ot a synchronous request. This buffer will store -+ * the response of the request after it has been completed. May be %NULL if -+ * no response is expected. ++ * Sets the response buffer of a synchronous request. This buffer will store ++ * the response of the request after it has been completed. May be %NULL if no ++ * response is expected. + */ +static inline void ssam_request_sync_set_resp(struct ssam_request_sync *rqst, + struct ssam_response *resp) @@ -17618,10 +17727,10 @@ index 000000000000..d128c68c04e0 + * @payload_len: The (maximum) request payload length. + * + * Allocates a synchronous request with specified payload length on the stack, -+ * fully intializes it via the provided request specification, submits it, and -+ * finally waits for its completion before returning its status. This helper -+ * macro essentially allocates the request message buffer on the stack and -+ * then calls ssam_request_sync_with_buffer(). ++ * fully initializes it via the provided request specification, submits it, ++ * and finally waits for its completion before returning its status. This ++ * helper macro essentially allocates the request message buffer on the stack ++ * and then calls ssam_request_sync_with_buffer(). + * + * Note: The @payload_len parameter specifies the maximum payload length, used + * for buffer allocation. The actual payload length may be smaller. @@ -17644,7 +17753,7 @@ index 000000000000..d128c68c04e0 + * @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 ++ * 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. + * @@ -18224,7 +18333,7 @@ index 000000000000..d128c68c04e0 +#endif /* _LINUX_SURFACE_AGGREGATOR_CONTROLLER_H */ diff --git a/include/linux/surface_aggregator/device.h b/include/linux/surface_aggregator/device.h new file mode 100644 -index 000000000000..64b1299d7bd8 +index 000000000000..fcbc9ed25433 --- /dev/null +++ b/include/linux/surface_aggregator/device.h @@ -0,0 +1,430 @@ @@ -18255,7 +18364,7 @@ index 000000000000..64b1299d7bd8 +/** + * enum ssam_device_domain - SAM device domain. + * @SSAM_DOMAIN_VIRTUAL: Virtual device. -+ * @SSAM_DOMAIN_SERIALHUB: Physical dovice connected via Surface Serial Hub. ++ * @SSAM_DOMAIN_SERIALHUB: Physical device connected via Surface Serial Hub. + */ +enum ssam_device_domain { + SSAM_DOMAIN_VIRTUAL = 0x00, @@ -18548,8 +18657,8 @@ index 000000000000..64b1299d7bd8 + * @drv: The driver managed by this module. + * + * Helper macro to register a SSAM device driver via module_init() and -+ * module_exit(). This macro may only be used once per module and replaces -+ * the afforementioned definitions. ++ * module_exit(). This macro may only be used once per module and replaces the ++ * aforementioned definitions. + */ +#define module_ssam_device_driver(drv) \ + module_driver(drv, ssam_device_driver_register, \ @@ -18660,10 +18769,10 @@ index 000000000000..64b1299d7bd8 +#endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */ diff --git a/include/linux/surface_aggregator/serial_hub.h b/include/linux/surface_aggregator/serial_hub.h new file mode 100644 -index 000000000000..376313f402b2 +index 000000000000..7b3fa4d34cc4 --- /dev/null +++ b/include/linux/surface_aggregator/serial_hub.h -@@ -0,0 +1,659 @@ +@@ -0,0 +1,675 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Surface Serial Hub (SSH) protocol and communication interface. @@ -18711,8 +18820,8 @@ index 000000000000..376313f402b2 +enum ssh_frame_type { + SSH_FRAME_TYPE_DATA_SEQ = 0x80, + SSH_FRAME_TYPE_DATA_NSQ = 0x00, -+ SSH_FRAME_TYPE_ACK = 0x40, -+ SSH_FRAME_TYPE_NAK = 0x04, ++ SSH_FRAME_TYPE_ACK = 0x40, ++ SSH_FRAME_TYPE_NAK = 0x04, +}; + +/** @@ -18799,7 +18908,7 @@ index 000000000000..376313f402b2 +#define SSH_MSG_LEN_CTRL SSH_MSG_LEN_BASE + +/** -+ * SSH_MESSAGE_LENGTH() - Comute length of SSH message. ++ * SSH_MESSAGE_LENGTH() - Compute length of SSH message. + * @payload_size: Length of the payload inside the SSH frame. + * + * Return: Returns the length of a SSH message with payload of specified size. @@ -18822,7 +18931,8 @@ index 000000000000..376313f402b2 + * @field: The field for which the offset should be computed. + * + * Return: Returns the offset of the specified &struct ssh_frame field in the -+ * raw SSH message data as. ++ * raw SSH message data as. Takes SYN bytes (u16) preceding the frame into ++ * account. + */ +#define SSH_MSGOFFSET_FRAME(field) \ + (sizeof(u16) + offsetof(struct ssh_frame, field)) @@ -18833,7 +18943,8 @@ index 000000000000..376313f402b2 + * @field: The field for which the offset should be computed. + * + * Return: Returns the offset of the specified &struct ssh_command field in -+ * the raw SSH message data. ++ * the raw SSH message data. Takes SYN bytes (u16) preceding the frame and the ++ * frame CRC (u16) between frame and command into account. + */ +#define SSH_MSGOFFSET_COMMAND(field) \ + (2ull * sizeof(u16) + sizeof(struct ssh_frame) \ @@ -18944,8 +19055,18 @@ index 000000000000..376313f402b2 + size_t len; +}; + ++/* ++ * Known SSH/EC target categories. ++ * ++ * List of currently known target category values; "Known" as in we know they ++ * exist and are valid on at least some device/model. Detailed functionality ++ * or the full category name is only known for some of these categories and ++ * is detailed in the respective comment below. ++ * ++ * These values and abbreviations have been extracted from strings inside the ++ * Windows driver. ++ */ +enum ssam_ssh_tc { -+ /* Known SSH/EC target categories. */ + // category 0x00 is invalid for EC use + SSAM_SSH_TC_SAM = 0x01, // generic system functionality, real-time clock + SSAM_SSH_TC_BAT = 0x02, // battery/power subsystem @@ -18979,7 +19100,7 @@ index 000000000000..376313f402b2 + SSAM_SSH_TC_AUD = 0x1e, + SSAM_SSH_TC_SMC = 0x1f, + SSAM_SSH_TC_KPD = 0x20, -+ SSAM_SSH_TC_REG = 0x21, ++ SSAM_SSH_TC_REG = 0x21, // extended event registry +}; + + @@ -18988,7 +19109,7 @@ index 000000000000..376313f402b2 +/** + * enum ssh_packet_base_priority - Base priorities for &struct ssh_packet. + * @SSH_PACKET_PRIORITY_FLUSH: Base priority for flush packets. -+ * @SSH_PACKET_PRIORITY_DATA: Base priority for normal data paackets. ++ * @SSH_PACKET_PRIORITY_DATA: Base priority for normal data packets. + * @SSH_PACKET_PRIORITY_NAK: Base priority for NAK packets. + * @SSH_PACKET_PRIORITY_ACK: Base priority for ACK packets. + */ @@ -19108,7 +19229,8 @@ index 000000000000..376313f402b2 + * (or enclosing request) has not been submitted yet. + * @refcnt: Reference count of the packet. + * @priority: Priority of the packet. Must be computed via -+ * SSH_PACKET_PRIORITY(). ++ * SSH_PACKET_PRIORITY(). Must only be accessed while holding the ++ * queue lock after first submission. + * @data: Raw message data. + * @data.len: Length of the raw message data. + * @data.ptr: Pointer to the raw message data buffer. @@ -19118,7 +19240,8 @@ index 000000000000..376313f402b2 + * @timestamp: Timestamp specifying when the latest transmission of a + * currently pending packet has been started. May be %KTIME_MAX + * before or in-between transmission attempts. Used for the packet -+ * timeout implementation. ++ * timeout implementation. Must only be accessed while holding the ++ * pending lock after first submission. + * @queue_node: The list node for the packet queue. + * @pending_node: The list node for the set of pending packets. + * @ops: Packet operations. @@ -19223,7 +19346,8 @@ index 000000000000..376313f402b2 + * + * In case of failure, the reason for the failure is indicated by + * the value of the provided status code argument (``status``). This -+ * value will be zero in case of success. ++ * value will be zero in case of success and a regular errno ++ * otherwise. + * + * Note that a call to this callback does not guarantee that the + * request is not in use by the transport systems any more. @@ -19242,10 +19366,11 @@ index 000000000000..376313f402b2 + * @state: State and type flags describing current request state (dynamic) + * and type (static). See &enum ssh_request_flags for possible + * options. -+ * @timestamp: Timestamp specifying when we start waiting on the respnse of the -+ * request. This is set once the underlying packet has been completed -+ * and may be %KTIME_MAX before that, or when the request does not -+ * expect a response. Used for the request timeout implementation. ++ * @timestamp: Timestamp specifying when we start waiting on the response of ++ * the request. This is set once the underlying packet has been ++ * completed and may be %KTIME_MAX before that, or when the request ++ * does not expect a response. Used for the request timeout ++ * implementation. + * @ops: Request Operations. + */ +struct ssh_request { diff --git a/patches/5.9/0007-surface-typecover.patch b/patches/5.9/0007-surface-typecover.patch index 2121b6f73..668c278da 100644 --- a/patches/5.9/0007-surface-typecover.patch +++ b/patches/5.9/0007-surface-typecover.patch @@ -1,4 +1,4 @@ -From 8e9d159daab6be4c65b79cde4824677d4510c85d Mon Sep 17 00:00:00 2001 +From a210b2578d679f682b28223666f559a429484763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Thu, 5 Nov 2020 13:09:45 +0100 Subject: [PATCH] hid/multitouch: Turn off Type Cover keyboard backlight when diff --git a/pkg/arch/kernel/PKGBUILD b/pkg/arch/kernel/PKGBUILD index f05365441..ee54b239a 100644 --- a/pkg/arch/kernel/PKGBUILD +++ b/pkg/arch/kernel/PKGBUILD @@ -43,13 +43,13 @@ sha256sums=('5d7560465abd0b5fccee96084eb374afd1b66e8fb9e0b6b6088a737ba5c48ee0' '36439a90c9d2f860298d90e141f3bf9d897dd8ece9e21cd46508f4ed7b2151bb' 'cad2f23b058938c27ccdeb1944dcc492cf8696651b1ca9c74a86eb73a039f8c1' '8cd2b019aac6d3807a5cdcbbbe0aad81e63193ff3e8dffd7a79d4a1421b858f6' - '5cf4e8194c70ccbe7ab90b5c2885070e58961bba8d26d5c5ac70bd05bc60a3f6' - '845f5184d557d5d2e31d48a81a55927a051aba901e28c791cc39d21cf1bbbfd4' - 'a3289844a8c9131448c6b1fd84612d711334d6e1b048843393102d136df6c092' - 'b76affed4ab2b4cb343a5e78985eb436aecf49e23fcfcd8f1f3b73460e84e43a' - '85d1c0708cab487ebe413800c5a888aad98cb91ec2b4c486d51b38f87852258d' - '706fb5cf4e5aa5f96740e1a40098ba369d0db290473778e2e6118d3be0aef923' - '09c7a36c7f98aa373adbdef8d1883d98158a5d3864f6ac934dee14a55a64a96a') + '9a95e097e220f67f42d81c6929a6069690dd09810b70c264e9d5a3fd4b608bc3' + '8776e6a97ac866ba2b33d32e3b85805c0689a715dfb39f6af3f2603324faed39' + 'a782eea056c00efc4d3a970be37e1534143b5acdcf673619ec744d4b47870a20' + 'da92c82cd32b1fa8f7ee85975d52ea9447444a75b631e861a060772e8a2ece8d' + '9d682de8a2351aeab4a237a34b4c319d31c1b241bc1c18f89f090cd477e48ddc' + 'ceb5726ed1fd9ef224e71d011b2410aeb6894daeeaa5bb176f58c650f9e39a47' + '03d55c690b6ecddea74935f9f728bc1ef00ae97b5a443434361ba9ca4e7d160c') export KBUILD_BUILD_HOST=archlinux