From 3d9db379b4d915ba970942652ed5d61b38d6896a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 22 Oct 2020 18:20:27 +0200 Subject: [PATCH] Update v4.19 patches Changes: - SAM: - Update DTX driver state after resume. - Add DTX Documentation, misc. fixes, and cleanup. Links: - SAM: https://github.com/linux-surface/surface-aggregator-module/commit/af4bb01042d8ab707d8a73d4ee7ff770223a1c2f - kernel: https://github.com/linux-surface/kernel/commit/8bb4052b6bfb2fc8abe989df45cc17b06f13af46 --- patches/4.19/0001-surface3-power.patch | 6 +- .../0002-surface3-touchscreen-dma-fix.patch | 30 +- patches/4.19/0003-surface3-oemb.patch | 38 +- patches/4.19/0004-surface-buttons.patch | 362 ++- patches/4.19/0005-suspend.patch | 22 +- patches/4.19/0006-ipts.patch | 5 +- patches/4.19/0007-wifi.patch | 1443 ++++++++--- ...rface-gpe.patch => 0008-surface-gpe.patch} | 45 +- patches/4.19/0009-surface-sam-over-hid.patch | 97 +- ...rface-sam.patch => 0010-surface-sam.patch} | 2125 +++++++++++++---- ...-acpi_walk_dep_device_list-getting-c.patch | 6 +- pkg/arch/kernel-lts/0008-surface-gpe.patch | 1 + pkg/arch/kernel-lts/0008-surface-sam.patch | 1 - pkg/arch/kernel-lts/0010-surface-gpe.patch | 1 - pkg/arch/kernel-lts/0010-surface-sam.patch | 1 + pkg/arch/kernel-lts/PKGBUILD | 26 +- 16 files changed, 3248 insertions(+), 961 deletions(-) rename patches/4.19/{0010-surface-gpe.patch => 0008-surface-gpe.patch} (84%) rename patches/4.19/{0008-surface-sam.patch => 0010-surface-sam.patch} (93%) create mode 120000 pkg/arch/kernel-lts/0008-surface-gpe.patch delete mode 120000 pkg/arch/kernel-lts/0008-surface-sam.patch delete mode 120000 pkg/arch/kernel-lts/0010-surface-gpe.patch create mode 120000 pkg/arch/kernel-lts/0010-surface-sam.patch diff --git a/patches/4.19/0001-surface3-power.patch b/patches/4.19/0001-surface3-power.patch index dc7b8c3fb..4dfc108fc 100644 --- a/patches/4.19/0001-surface3-power.patch +++ b/patches/4.19/0001-surface3-power.patch @@ -1,8 +1,10 @@ -From 68915ae484c9d8881ed344ee3c639b1d11d8f29c Mon Sep 17 00:00:00 2001 +From 7712e7c7b39ac4af2c8d4d5a9a22ecc0d5a25077 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Sep 2019 18:00:43 +0200 -Subject: [PATCH 01/11] surface3-power +Subject: [PATCH] platform/x86: Surface 3 battery platform operation region + support +Patchset: surface3-power --- drivers/platform/x86/Kconfig | 7 + drivers/platform/x86/Makefile | 1 + diff --git a/patches/4.19/0002-surface3-touchscreen-dma-fix.patch b/patches/4.19/0002-surface3-touchscreen-dma-fix.patch index d701cd5f5..97ea2bd21 100644 --- a/patches/4.19/0002-surface3-touchscreen-dma-fix.patch +++ b/patches/4.19/0002-surface3-touchscreen-dma-fix.patch @@ -1,8 +1,34 @@ -From 26e5e3d5780b48ef1f2a7115ef7a1ef1f4bf1e67 Mon Sep 17 00:00:00 2001 +From 6893037808c47ada1b0bf8705ebe7f60dfd600b0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 5 Jul 2020 14:56:20 +0300 -Subject: [PATCH 02/11] surface3-touchscreen-dma-fix +Subject: [PATCH] dmaengine: dw: Initialize channel before each transfer +In some cases DMA can be used only with a consumer which does runtime power +management and on the platforms, that have DMA auto power gating logic +(see comments in the drivers/acpi/acpi_lpss.c), may result in DMA losing +its context. Simple mitigation of this issue is to initialize channel +each time the consumer initiates a transfer. + +Fixes: cfdf5b6cc598 ("dw_dmac: add support for Lynxpoint DMA controllers") +Reported-by: Tsuchiya Yuto +Signed-off-by: Andy Shevchenko +Acked-by: Viresh Kumar +BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206403 +Link: https://lore.kernel.org/r/20200705115620.51929-1-andriy.shevchenko@linux.intel.com +Signed-off-by: Vinod Koul + +(cherry picked from commit 99ba8b9b0d9780e9937eb1d488d120e9e5c2533d) +[Reason for cherry-picking this commit: + This commit fixes touch input when using DMA mode on Surface 3's + touchscreen. + Note: this commit was not backported to v4.19 by upstream. For now, + backport this patch ourselves.] +[ Conflicts: + drivers/dma/dw/core.c + Resolved conflict by accepting current change then removed + DW_DMA_IS_INITIALIZED lines] +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-touchscreen-dma-fix --- drivers/dma/dw/core.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/patches/4.19/0003-surface3-oemb.patch b/patches/4.19/0003-surface3-oemb.patch index 3038639c1..ef6fa9ff5 100644 --- a/patches/4.19/0003-surface3-oemb.patch +++ b/patches/4.19/0003-surface3-oemb.patch @@ -1,8 +1,38 @@ -From 118ae75f050cf4934c6b97d11f088492c2a628aa Mon Sep 17 00:00:00 2001 -From: Chih-Wei Huang -Date: Tue, 18 Sep 2018 11:01:37 +0800 -Subject: [PATCH 03/11] surface3-oemb +From bbc85da670e31aa65b92bead468c33f5d50ff55b 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 + table +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI data into dmi_system_id tables used +for quirks so that each driver can enable quirks even on the affected +systems. + +On affected systems, DMI data will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: surface3-oemb --- drivers/platform/x86/surface3-wmi.c | 7 +++++++ sound/soc/codecs/rt5645.c | 9 +++++++++ diff --git a/patches/4.19/0004-surface-buttons.patch b/patches/4.19/0004-surface-buttons.patch index ad967b6fa..aea0a8722 100644 --- a/patches/4.19/0004-surface-buttons.patch +++ b/patches/4.19/0004-surface-buttons.patch @@ -1,13 +1,117 @@ -From b9404424ac5fb0521a36308323493abd8a1d0df7 Mon Sep 17 00:00:00 2001 +From f6d0899d982873dad26c280ebc52be5470556b30 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 27 Jul 2019 17:51:37 +0200 -Subject: [PATCH 04/11] surface-buttons +Subject: [PATCH] platform/x86: surfacepro3_button: Fix device check +Do not use the surfacepro3_button driver on newer Microsoft Surface +models, only use it on the Surface Pro 3 and 4. Newer models (5th, 6th +and possibly future generations) use the same device as the Surface Pro +4 to represent their volume and power buttons (MSHW0040), but their +actual implementation is significantly different. This patch ensures +that the surfacepro3_button driver is only used on the Pro 3 and 4 +models, allowing a different driver to bind on other models. + +Signed-off-by: Maximilian Luz +Patchset: surface-buttons --- - drivers/input/misc/Kconfig | 6 +- - drivers/input/misc/soc_button_array.c | 114 +++++++++++++++++++--- - drivers/platform/x86/surfacepro3_button.c | 47 +++++++++ - 3 files changed, 151 insertions(+), 16 deletions(-) + drivers/platform/x86/surfacepro3_button.c | 47 +++++++++++++++++++++++ + 1 file changed, 47 insertions(+) + +diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c +index 1b491690ce07..96627627060e 100644 +--- a/drivers/platform/x86/surfacepro3_button.c ++++ b/drivers/platform/x86/surfacepro3_button.c +@@ -24,6 +24,12 @@ + #define SURFACE_BUTTON_OBJ_NAME "VGBI" + #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons" + ++#define MSHW0040_DSM_REVISION 0x01 ++#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision ++static const guid_t MSHW0040_DSM_UUID = ++ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65, ++ 0x49, 0x80, 0x35); ++ + #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8 + + #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6 +@@ -146,6 +152,44 @@ static int surface_button_resume(struct device *dev) + } + #endif + ++/* ++ * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device ++ * ID (MSHW0040) for the power/volume buttons. Make sure this is the right ++ * device by checking for the _DSM method and OEM Platform Revision. ++ * ++ * Returns true if the driver should bind to this device, i.e. the device is ++ * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. ++ */ ++static bool surface_button_check_MSHW0040(struct acpi_device *dev) ++{ ++ acpi_handle handle = dev->handle; ++ union acpi_object *result; ++ u64 oem_platform_rev = 0; // valid revisions are nonzero ++ ++ // get OEM platform revision ++ result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, ++ MSHW0040_DSM_REVISION, ++ MSHW0040_DSM_GET_OMPR, ++ NULL, ACPI_TYPE_INTEGER); ++ ++ /* ++ * If evaluating the _DSM fails, the method is not present. This means ++ * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we ++ * should use this driver. We use revision 0 indicating it is ++ * unavailable. ++ */ ++ ++ if (result) { ++ oem_platform_rev = result->integer.value; ++ ACPI_FREE(result); ++ } ++ ++ dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); ++ ++ return oem_platform_rev == 0; ++} ++ ++ + static int surface_button_add(struct acpi_device *device) + { + struct surface_button *button; +@@ -158,6 +202,9 @@ static int surface_button_add(struct acpi_device *device) + strlen(SURFACE_BUTTON_OBJ_NAME))) + return -ENODEV; + ++ if (!surface_button_check_MSHW0040(device)) ++ return -ENODEV; ++ + button = kzalloc(sizeof(struct surface_button), GFP_KERNEL); + if (!button) + return -ENOMEM; +-- +2.28.0 + +From a8202a8b7e876c56055d62ab2dea519af0071297 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Sat, 27 Jul 2019 17:52:01 +0200 +Subject: [PATCH] Input: soc_button_array - Add support for newer surface + devices + +Power and volume button support for 5th and 6th generation Microsoft +Surface devices via soc_button_array. + +Note that these devices use the same MSHW0040 device as on the Surface +Pro 4, however the implementation is different (GPIOs vs. ACPI +notifications). Thus some checking is required to ensure we only load +this driver on the correct devices. + +Signed-off-by: Maximilian Luz +Patchset: surface-buttons +--- + drivers/input/misc/Kconfig | 6 +- + drivers/input/misc/soc_button_array.c | 105 +++++++++++++++++++++++--- + 2 files changed, 96 insertions(+), 15 deletions(-) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ca59a2be9bc5..ea69610370e8 100644 @@ -28,7 +132,7 @@ index ca59a2be9bc5..ea69610370e8 100644 To compile this driver as a module, choose M here: the module will be called soc_button_array. diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c -index 55cd6e0b409c..c564ea99f47d 100644 +index 55cd6e0b409c..8f21c062c85d 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -29,6 +29,11 @@ struct soc_button_info { @@ -43,29 +147,22 @@ index 55cd6e0b409c..c564ea99f47d 100644 /* * Some of the buttons like volume up/down are auto repeat, while others * are not. To support both, we register two platform devices, and put -@@ -91,8 +96,20 @@ soc_button_device_create(struct platform_device *pdev, +@@ -91,8 +96,13 @@ soc_button_device_create(struct platform_device *pdev, continue; gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); - if (!gpio_is_valid(gpio)) -+ if (!gpio_is_valid(gpio)) { -+ /* -+ * Skip GPIO if not present. Note we deliberately -+ * ignore -EPROBE_DEFER errors here. On some devices -+ * Intel is using so called virtual GPIOs which are not -+ * GPIOs at all but some way for AML code to check some -+ * random status bits without need a custom opregion. -+ * In some cases the resources table we parse points to -+ * such a virtual GPIO, since these are not real GPIOs -+ * we do not have a driver for these so they will never -+ * show up, therefor we ignore -EPROBE_DEFER. -+ */ ++ if (gpio < 0 && gpio != -ENOENT) { ++ error = gpio; ++ goto err_free_mem; ++ } else if (!gpio_is_valid(gpio)) { ++ /* Skip GPIO if not present */ continue; + } gpio_keys[n_buttons].type = info->event_type; gpio_keys[n_buttons].code = info->event_code; -@@ -309,23 +326,26 @@ static int soc_button_remove(struct platform_device *pdev) +@@ -309,23 +319,26 @@ static int soc_button_remove(struct platform_device *pdev) static int soc_button_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -100,18 +197,16 @@ index 55cd6e0b409c..c564ea99f47d 100644 } error = gpiod_count(dev, NULL); -@@ -357,8 +377,8 @@ static int soc_button_probe(struct platform_device *pdev) +@@ -357,7 +370,7 @@ static int soc_button_probe(struct platform_device *pdev) if (!priv->children[0] && !priv->children[1]) return -ENODEV; - if (!id->driver_data) -- devm_kfree(dev, button_info); + if (!device_data || !device_data->button_info) -+ devm_kfree(dev, (void *)button_info); + devm_kfree(dev, button_info); return 0; - } -@@ -368,7 +388,7 @@ static int soc_button_probe(struct platform_device *pdev) +@@ -368,7 +381,7 @@ static int soc_button_probe(struct platform_device *pdev) * is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC * Platforms" */ @@ -120,7 +215,7 @@ index 55cd6e0b409c..c564ea99f47d 100644 { "power", 0, EV_KEY, KEY_POWER, false, true }, { "home", 1, EV_KEY, KEY_LEFTMETA, false, true }, { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, -@@ -377,9 +397,77 @@ static struct soc_button_info soc_button_PNP0C40[] = { +@@ -377,9 +390,77 @@ static struct soc_button_info soc_button_PNP0C40[] = { { } }; @@ -199,78 +294,147 @@ index 55cd6e0b409c..c564ea99f47d 100644 { } }; -diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c -index 1b491690ce07..96627627060e 100644 ---- a/drivers/platform/x86/surfacepro3_button.c -+++ b/drivers/platform/x86/surfacepro3_button.c -@@ -24,6 +24,12 @@ - #define SURFACE_BUTTON_OBJ_NAME "VGBI" - #define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons" - -+#define MSHW0040_DSM_REVISION 0x01 -+#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision -+static const guid_t MSHW0040_DSM_UUID = -+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65, -+ 0x49, 0x80, 0x35); -+ - #define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8 - - #define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6 -@@ -146,6 +152,44 @@ static int surface_button_resume(struct device *dev) - } - #endif - -+/* -+ * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device -+ * ID (MSHW0040) for the power/volume buttons. Make sure this is the right -+ * device by checking for the _DSM method and OEM Platform Revision. -+ * -+ * Returns true if the driver should bind to this device, i.e. the device is -+ * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1. -+ */ -+static bool surface_button_check_MSHW0040(struct acpi_device *dev) -+{ -+ acpi_handle handle = dev->handle; -+ union acpi_object *result; -+ u64 oem_platform_rev = 0; // valid revisions are nonzero -+ -+ // get OEM platform revision -+ result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID, -+ MSHW0040_DSM_REVISION, -+ MSHW0040_DSM_GET_OMPR, -+ NULL, ACPI_TYPE_INTEGER); -+ -+ /* -+ * If evaluating the _DSM fails, the method is not present. This means -+ * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we -+ * should use this driver. We use revision 0 indicating it is -+ * unavailable. -+ */ -+ -+ if (result) { -+ oem_platform_rev = result->integer.value; -+ ACPI_FREE(result); -+ } -+ -+ dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev); -+ -+ return oem_platform_rev == 0; -+} -+ -+ - static int surface_button_add(struct acpi_device *device) - { - struct surface_button *button; -@@ -158,6 +202,9 @@ static int surface_button_add(struct acpi_device *device) - strlen(SURFACE_BUTTON_OBJ_NAME))) - return -ENODEV; - -+ if (!surface_button_check_MSHW0040(device)) -+ return -ENODEV; -+ - button = kzalloc(sizeof(struct surface_button), GFP_KERNEL); - if (!button) - return -ENOMEM; +-- +2.28.0 + +From 0f703888a68cbdbd9bafae8b601a7180c8126eb8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 5 Oct 2019 14:11:58 +0200 +Subject: [PATCH] Input: soc_button_array - partial revert of support for newer + surface devices + +Commit c394159310d0 ("Input: soc_button_array - add support for newer +surface devices") not only added support for the MSHW0040 ACPI HID, +but for some reason it also makes changes to the error handling of the +soc_button_lookup_gpio() call in soc_button_device_create(). Note ideally +this seamingly unrelated change would have been made in a separate commit, +with a message explaining the what and why of this change. + +I guess this change may have been added to deal with -EPROBE_DEFER errors, +but in case of the existing support for PNP0C40 devices, treating +-EPROBE_DEFER as any other error is deliberate, see the comment this +commit adds for why. + +The actual returning of -EPROBE_DEFER to the caller of soc_button_probe() +introduced by the new error checking causes a serious regression: + +On devices with so called virtual GPIOs soc_button_lookup_gpio() will +always return -EPROBE_DEFER for these fake GPIOs, when this happens +during the second call of soc_button_device_create() we already have +successfully registered our first child. This causes the kernel to think +we are making progress with probing things even though we unregister the +child before again before we return the -EPROBE_DEFER. Since we are making +progress the kernel will retry deferred-probes again immediately ending +up stuck in a loop with the following showing in dmesg: + +[ 124.022697] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6537 +[ 124.040764] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6538 +[ 124.056967] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6539 +[ 124.072143] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6540 +[ 124.092373] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6541 +[ 124.108065] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6542 +[ 124.128483] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6543 +[ 124.147141] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6544 +[ 124.165070] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6545 +[ 124.179775] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6546 +[ 124.202726] input: gpio-keys as /devices/platform/INTCFD9:00/gpio-keys.0.auto/input/input6547 + + +And 1 CPU core being stuck at 100% and udev hanging since it is waiting +for the modprobe of soc_button_array to return. + +This patch reverts the soc_button_lookup_gpio() error handling changes, +fixing this regression. + +Fixes: c394159310d0 ("Input: soc_button_array - add support for newer surface devices") +BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=205031 +Cc: Maximilian Luz +Signed-off-by: Hans de Goede +Patchset: surface-buttons +--- + drivers/input/misc/soc_button_array.c | 17 ++++++++++++----- + 1 file changed, 12 insertions(+), 5 deletions(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 8f21c062c85d..5983733d78dd 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -96,11 +96,18 @@ soc_button_device_create(struct platform_device *pdev, + continue; + + gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); +- if (gpio < 0 && gpio != -ENOENT) { +- error = gpio; +- goto err_free_mem; +- } else if (!gpio_is_valid(gpio)) { +- /* Skip GPIO if not present */ ++ if (!gpio_is_valid(gpio)) { ++ /* ++ * Skip GPIO if not present. Note we deliberately ++ * ignore -EPROBE_DEFER errors here. On some devices ++ * Intel is using so called virtual GPIOs which are not ++ * GPIOs at all but some way for AML code to check some ++ * random status bits without need a custom opregion. ++ * In some cases the resources table we parse points to ++ * such a virtual GPIO, since these are not real GPIOs ++ * we do not have a driver for these so they will never ++ * show up, therefor we ignore -EPROBE_DEFER. ++ */ + continue; + } + +-- +2.28.0 + +From 38ad6b1492e4126a664f6247bd7dc8ee87a10c76 Mon Sep 17 00:00:00 2001 +From: "Tsuchiya Yuto (kitakar5525)" +Date: Mon, 11 May 2020 17:40:21 +0900 +Subject: [PATCH] Input: soc_button_array - fix Wdiscarded-qualifiers for + kernels below 4.20 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +There is a warning from compiler when building v4.19-surface kernel that +backported button patches from newer kernels. + + drivers/input/misc/soc_button_array.c: In function ‘soc_button_probe’: + drivers/input/misc/soc_button_array.c:381:19: warning: passing argument 2 of ‘devm_kfree’ discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers] + 381 | devm_kfree(dev, button_info); + | ^~~~~~~~~~~ + In file included from ./include/linux/input.h:22, + from drivers/input/misc/soc_button_array.c:14: + ./include/linux/device.h:695:50: note: expected ‘void *’ but argument is of type ‘const struct soc_button_info *’ + 695 | extern void devm_kfree(struct device *dev, void *p); + | ~~~~~~^ + +This warning happens bacause commit 0571967dfb5d25 ("devres: constify p +in devm_kfree()") has not been applied to v4.19 series (available after +v4.20-rc1). + +This commit casts button_info to (void *) when calling devm_kfree() to +avoid compiler warning. + +Fixes: b892fc124285ba ("Input: soc_button_array - Add support for newer surface devices") +Signed-off-by: Tsuchiya Yuto (kitakar5525) +Patchset: surface-buttons +--- + drivers/input/misc/soc_button_array.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c +index 5983733d78dd..c564ea99f47d 100644 +--- a/drivers/input/misc/soc_button_array.c ++++ b/drivers/input/misc/soc_button_array.c +@@ -378,7 +378,7 @@ static int soc_button_probe(struct platform_device *pdev) + return -ENODEV; + + if (!device_data || !device_data->button_info) +- devm_kfree(dev, button_info); ++ devm_kfree(dev, (void *)button_info); + + return 0; + } -- 2.28.0 diff --git a/patches/4.19/0005-suspend.patch b/patches/4.19/0005-suspend.patch index 710875f1d..fc40fef64 100644 --- a/patches/4.19/0005-suspend.patch +++ b/patches/4.19/0005-suspend.patch @@ -1,8 +1,26 @@ -From fb6b7e1a29e622cf19c57c17f397661ec9dae1da Mon Sep 17 00:00:00 2001 +From 8273cec8ad42f5a6d2349347878331069c296f07 Mon Sep 17 00:00:00 2001 From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> Date: Sat, 28 Sep 2019 17:48:21 +0200 -Subject: [PATCH 05/11] suspend +Subject: [PATCH] nvme: Backport changes for suspend +Backported commits are: + +- torvalds/linux@4eaefe8c621c6195c91044396ed8060c179f7aae + (nvme-pci: Allow PCI bus-level PM to be used if ASPM is disabled) + +- torvalds/linux@accd2dd72c8f087441d725dd916688171519e4e6 + (PCI/ASPM: Add pcie_aspm_enabled()) + +- torvalds/linux@d916b1be94b6dc8d293abed2451f3062f6af7551 + (nvme-pci: use host managed power state for suspend) + +- torvalds/linux@1a87ee657c530bb2f3e39e4ac184d48f5f959cda + (nvme: export get and set features) + +- torvalds/linux@d6135c3a1ec0cddda7b8b8e1b5b4abeeafd98289 + (nvme-pci: Sync queues on reset) + +Patchset: suspend --- drivers/nvme/host/core.c | 36 ++++++++++++-- drivers/nvme/host/nvme.h | 7 +++ diff --git a/patches/4.19/0006-ipts.patch b/patches/4.19/0006-ipts.patch index b15d4a172..2c98f62e0 100644 --- a/patches/4.19/0006-ipts.patch +++ b/patches/4.19/0006-ipts.patch @@ -1,8 +1,9 @@ -From f4a9111f3d630f2ad9a1746caa0d5c0bc319cb13 Mon Sep 17 00:00:00 2001 +From 067c4fbb383132758816350e07d5003b48d14fda Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 28 Sep 2019 17:58:17 +0200 -Subject: [PATCH 06/11] ipts +Subject: [PATCH] Add support for Intel IPTS touch devices +Patchset: ipts --- drivers/gpu/drm/i915/Makefile | 3 + drivers/gpu/drm/i915/i915_debugfs.c | 63 +- diff --git a/patches/4.19/0007-wifi.patch b/patches/4.19/0007-wifi.patch index 440f0d204..3db3a180e 100644 --- a/patches/4.19/0007-wifi.patch +++ b/patches/4.19/0007-wifi.patch @@ -1,139 +1,28 @@ -From d172c88f96b9e9187ea7d00231b7c124040526ae Mon Sep 17 00:00:00 2001 -From: kitakar5525 <34676735+kitakar5525@users.noreply.github.com> -Date: Thu, 20 Feb 2020 16:51:11 +0900 -Subject: [PATCH 07/11] wifi +From 80f7516fb978e63b6a7e04db4e774d5496071509 Mon Sep 17 00:00:00 2001 +From: Chuhong Yuan +Date: Wed, 24 Jul 2019 19:27:45 +0800 +Subject: [PATCH] mwifiex: pcie: Use dev_get_drvdata +Instead of using to_pci_dev + pci_get_drvdata, +use dev_get_drvdata to make code simpler. + +Signed-off-by: Chuhong Yuan +Signed-off-by: Kalle Valo + +(cherry picked from commit ffa4d78cbc2644b4867b8129b3fbb5ddcdfcdba2) +Reason for cherry-picking this commit: + to avoid conflicts when backporting incoming commits +Signed-off-by: Tsuchiya Yuto (kitakar5525) +Patchset: wifi --- - drivers/net/wireless/marvell/mwifiex/Makefile | 1 + - .../net/wireless/marvell/mwifiex/cfg80211.c | 26 ++ - drivers/net/wireless/marvell/mwifiex/main.c | 6 +- - drivers/net/wireless/marvell/mwifiex/pcie.c | 92 +++++-- - drivers/net/wireless/marvell/mwifiex/pcie.h | 3 + - .../wireless/marvell/mwifiex/pcie_quirks.c | 255 ++++++++++++++++++ - .../wireless/marvell/mwifiex/pcie_quirks.h | 17 ++ - .../net/wireless/marvell/mwifiex/sta_cmd.c | 14 +- - 8 files changed, 376 insertions(+), 38 deletions(-) - create mode 100644 drivers/net/wireless/marvell/mwifiex/pcie_quirks.c - create mode 100644 drivers/net/wireless/marvell/mwifiex/pcie_quirks.h + drivers/net/wireless/marvell/mwifiex/pcie.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) -diff --git a/drivers/net/wireless/marvell/mwifiex/Makefile b/drivers/net/wireless/marvell/mwifiex/Makefile -index fdfd9bf15ed4..8a1e7c5b9c6e 100644 ---- a/drivers/net/wireless/marvell/mwifiex/Makefile -+++ b/drivers/net/wireless/marvell/mwifiex/Makefile -@@ -49,6 +49,7 @@ mwifiex_sdio-y += sdio.o - obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o - - mwifiex_pcie-y += pcie.o -+mwifiex_pcie-y += pcie_quirks.o - obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o - - mwifiex_usb-y += usb.o -diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c -index 650191db25cb..dd487fc9c1a1 100644 ---- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c -+++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c -@@ -25,6 +25,11 @@ - static char *reg_alpha2; - module_param(reg_alpha2, charp, 0); - -+static bool allow_ps_mode; -+module_param(allow_ps_mode, bool, 0444); -+MODULE_PARM_DESC(allow_ps_mode, -+ "allow WiFi power management to be enabled. (default: disallowed)"); -+ - static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { - { - .max = 3, .types = BIT(NL80211_IFTYPE_STATION) | -@@ -439,6 +444,27 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, - - ps_mode = enabled; - -+ /* Allow ps_mode to be enabled only when allow_ps_mode is set -+ * (but always allow ps_mode to be disabled in case it gets enabled -+ * for unknown reason and you want to disable it) */ -+ if (ps_mode && !allow_ps_mode) { -+ dev_info(priv->adapter->dev, -+ "Request to enable ps_mode received but it's disallowed " -+ "by module parameter. Rejecting the request.\n"); -+ -+ /* Return negative value to inform userspace tools that setting -+ * power_save to be enabled is not permitted. */ -+ return -1; -+ } -+ -+ if (ps_mode) -+ dev_warn(priv->adapter->dev, -+ "WARN: Request to enable ps_mode received. Enabling it. " -+ "Disable it if you encounter connection instability.\n"); -+ else -+ dev_info(priv->adapter->dev, -+ "Request to disable ps_mode received. Disabling it.\n"); -+ - return mwifiex_drv_set_power(priv, &ps_mode); - } - -diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c -index e48b47f42554..55b71e3d0127 100644 ---- a/drivers/net/wireless/marvell/mwifiex/main.c -+++ b/drivers/net/wireless/marvell/mwifiex/main.c -@@ -1458,7 +1458,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) - } - - /* -- * This function gets called during PCIe function level reset. -+ * This function can be used for shutting down the adapter SW. - */ - int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) - { -@@ -1474,6 +1474,8 @@ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) - priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); - mwifiex_deauthenticate(priv, NULL); - -+ mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); -+ - mwifiex_uninit_sw(adapter); - - if (adapter->if_ops.down_dev) -@@ -1483,7 +1485,7 @@ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) - } - EXPORT_SYMBOL_GPL(mwifiex_shutdown_sw); - --/* This function gets called during PCIe function level reset. Required -+/* This function can be used for reinitting the adapter SW. Required - * code is extracted from mwifiex_add_card() - */ - int diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c -index 991b9cc18000..30cd52c2485f 100644 +index 991b9cc18000..2aa0436d3548 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c -@@ -27,12 +27,18 @@ - #include "wmm.h" - #include "11n.h" - #include "pcie.h" -+#include "pcie_quirks.h" - - #define PCIE_VERSION "1.0" - #define DRV_NAME "Marvell mwifiex PCIe" - - static struct mwifiex_if_ops pcie_ops; - -+static bool enable_device_dump; -+module_param(enable_device_dump, bool, 0644); -+MODULE_PARM_DESC(enable_device_dump, -+ "enable device_dump (default: disabled)"); -+ - static const struct of_device_id mwifiex_pcie_of_match_table[] = { - { .compatible = "pci11ab,2b42" }, - { .compatible = "pci1b4b,2b42" }, -@@ -144,19 +150,13 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) - * registered functions must have drivers with suspend and resume - * methods. Failing that the kernel simply removes the whole card. - * -- * If already not suspended, this function allocates and sends a host -- * sleep activate request to the firmware and turns off the traffic. -+ * This function shuts down the adapter. - */ +@@ -150,10 +150,8 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) static int mwifiex_pcie_suspend(struct device *dev) { struct mwifiex_adapter *adapter; @@ -142,114 +31,136 @@ index 991b9cc18000..30cd52c2485f 100644 + struct pcie_service_card *card = dev_get_drvdata(dev); - card = pci_get_drvdata(pdev); -- -- /* Might still be loading firmware */ -- wait_for_completion(&card->fw_done); - adapter = card->adapter; - if (!adapter) { -@@ -164,22 +164,15 @@ static int mwifiex_pcie_suspend(struct device *dev) - return 0; - } - -- mwifiex_enable_wake(adapter); -- -- /* Enable the Host Sleep */ -- if (!mwifiex_enable_hs(adapter)) { -+ /* Shut down SW */ -+ if (mwifiex_shutdown_sw(adapter)) { - mwifiex_dbg(adapter, ERROR, - "cmd: failed to suspend\n"); -- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); -- mwifiex_disable_wake(adapter); - return -EFAULT; - } - -- flush_workqueue(adapter->workqueue); -- - /* Indicate device suspended */ - set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); -- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); - - return 0; - } -@@ -189,16 +182,14 @@ static int mwifiex_pcie_suspend(struct device *dev) - * registered functions must have drivers with suspend and resume - * methods. Failing that the kernel simply removes the whole card. - * -- * If already not resumed, this function turns on the traffic and -- * sends a host sleep cancel request to the firmware. -+ * If already not resumed, this function reinits the adapter. - */ + /* Might still be loading firmware */ + wait_for_completion(&card->fw_done); +@@ -195,10 +193,8 @@ static int mwifiex_pcie_suspend(struct device *dev) static int mwifiex_pcie_resume(struct device *dev) { struct mwifiex_adapter *adapter; - struct pcie_service_card *card; - struct pci_dev *pdev = to_pci_dev(dev); + struct pcie_service_card *card = dev_get_drvdata(dev); -+ int ret; - card = pci_get_drvdata(pdev); if (!card->adapter) { dev_err(dev, "adapter structure is not valid\n"); -@@ -215,9 +206,11 @@ static int mwifiex_pcie_resume(struct device *dev) - - clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); - -- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), -- MWIFIEX_ASYNC_CMD); -- mwifiex_disable_wake(adapter); -+ ret = mwifiex_reinit_sw(adapter); -+ if (ret) -+ dev_err(dev, "reinit failed: %d\n", ret); -+ else -+ mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); - - return 0; - } -@@ -233,8 +226,13 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) - { - struct pcie_service_card *card; -+ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); - int ret; - -+ /* disable bridge_d3 to fix driver crashing after suspend on gen4+ -+ * Surface devices */ -+ parent_pdev->bridge_d3 = false; -+ - pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", - pdev->vendor, pdev->device, pdev->revision); - -@@ -265,6 +263,9 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, - return ret; - } - -+ /* check quirks */ -+ mwifiex_initialize_quirks(card); -+ - if (mwifiex_add_card(card, &card->fw_done, &pcie_ops, - MWIFIEX_PCIE, &pdev->dev)) { - pr_err("%s failed\n", __func__); -@@ -380,7 +381,16 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev) - mwifiex_shutdown_sw(adapter); +-- +2.28.0 + +From ed5d12e11559f0340ea3e73283a33ddb0b410e4c 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 + +If a reset is performed, but even the reset fails for some reasons (e.g., +on Surface devices, the fw reset requires another quirks), +cancel_work_sync() hangs in mwifiex_cleanup_pcie(). + + # reset performed after firmware went into bad state + kernel: mwifiex_pcie 0000:01:00.0: WLAN FW already running! Skip FW dnld + kernel: mwifiex_pcie 0000:01:00.0: WLAN FW is active + # but even the reset failed + kernel: mwifiex_pcie 0000:01:00.0: mwifiex_cmd_timeout_func: Timeout cmd id = 0xfa, act = 0xa000 + kernel: mwifiex_pcie 0000:01:00.0: num_data_h2c_failure = 0 + kernel: mwifiex_pcie 0000:01:00.0: num_cmd_h2c_failure = 0 + kernel: mwifiex_pcie 0000:01:00.0: is_cmd_timedout = 1 + kernel: mwifiex_pcie 0000:01:00.0: num_tx_timeout = 0 + kernel: mwifiex_pcie 0000:01:00.0: last_cmd_index = 2 + kernel: mwifiex_pcie 0000:01:00.0: last_cmd_id: 16 00 a4 00 fa 00 a4 00 7f 00 + kernel: mwifiex_pcie 0000:01:00.0: last_cmd_act: 00 00 00 00 00 a0 00 00 00 00 + kernel: mwifiex_pcie 0000:01:00.0: last_cmd_resp_index = 0 + kernel: mwifiex_pcie 0000:01:00.0: last_cmd_resp_id: 16 80 7f 80 16 80 a4 80 7f 80 + kernel: mwifiex_pcie 0000:01:00.0: last_event_index = 1 kernel: mwifiex_pcie 0000:01:00.0: last_event: 58 00 58 00 58 00 58 00 58 00 + kernel: mwifiex_pcie 0000:01:00.0: data_sent=0 cmd_sent=1 + kernel: mwifiex_pcie 0000:01:00.0: ps_mode=0 ps_state=0 + kernel: mwifiex_pcie 0000:01:00.0: info: _mwifiex_fw_dpc: unregister device + # mwifiex_pcie_work hanged + kernel: INFO: task kworker/0:0:24857 blocked for more than 122 seconds. + kernel: Tainted: G W OE 5.3.11-arch1-1 #1 + kernel: "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. + kernel: kworker/0:0 D 0 24857 2 0x80004000 + kernel: Workqueue: events mwifiex_pcie_work [mwifiex_pcie] + kernel: Call Trace: + kernel: ? __schedule+0x27f/0x6d0 + kernel: schedule+0x43/0xd0 + kernel: schedule_timeout+0x299/0x3d0 + kernel: ? __switch_to_asm+0x40/0x70 + kernel: wait_for_common+0xeb/0x190 + kernel: ? wake_up_q+0x60/0x60 + kernel: __flush_work+0x130/0x1e0 + kernel: ? flush_workqueue_prep_pwqs+0x130/0x130 + kernel: __cancel_work_timer+0x123/0x1b0 + kernel: mwifiex_cleanup_pcie+0x28/0xd0 [mwifiex_pcie] + kernel: mwifiex_free_adapter+0x24/0xe0 [mwifiex] + kernel: _mwifiex_fw_dpc+0x28d/0x520 [mwifiex] + kernel: mwifiex_reinit_sw+0x15d/0x2c0 [mwifiex] + kernel: mwifiex_pcie_reset_done+0x50/0x80 [mwifiex_pcie] + kernel: pci_try_reset_function+0x38/0x70 + kernel: process_one_work+0x1d1/0x3a0 + kernel: worker_thread+0x4a/0x3d0 + kernel: kthread+0xfb/0x130 + kernel: ? process_one_work+0x3a0/0x3a0 + kernel: ? kthread_park+0x80/0x80 + kernel: ret_from_fork+0x35/0x40 + +This is a deadlock caused by calling cancel_work_sync() in +mwifiex_cleanup_pcie(): + +- Device resets are done via mwifiex_pcie_card_reset() +- which schedules card->work to call mwifiex_pcie_card_reset_work() +- which calls pci_try_reset_function(). +- This leads to mwifiex_pcie_reset_done() be called on the same workqueue, + which in turn calls +- mwifiex_reinit_sw() and that calls +- _mwifiex_fw_dpc(). + +The problem is now that _mwifiex_fw_dpc() calls mwifiex_free_adapter() +in case firmware initialization fails. That ends up calling +mwifiex_cleanup_pcie(). + +Note that all those calls are still running on the workqueue. So when +mwifiex_cleanup_pcie() now calls cancel_work_sync(), it's really waiting +on itself to complete, causing a deadlock. + +This commit fixes the deadlock by skipping cancel_work_sync() on a reset +failure path. + +After this commit, when reset fails, the following output is +expected to be shown: + + kernel: mwifiex_pcie 0000:03:00.0: info: _mwifiex_fw_dpc: unregister device + kernel: mwifiex: Failed to bring up adapter: -5 + kernel: mwifiex_pcie 0000:03:00.0: reinit failed: -5 + +To reproduce this issue, for example, try putting the root port of wifi +into D3 (replace "00:1d.3" with your setup). + + # put into D3 (root port) + sudo setpci -v -s 00:1d.3 CAP_PM+4.b=0b + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 18 +++++++++++++++++- + drivers/net/wireless/marvell/mwifiex/pcie.h | 2 ++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 2aa0436d3548..4e655038e3f3 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -377,6 +377,8 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev) clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); -+ -+ /* For Surface gen4+ devices, we need to put wifi into D3cold right -+ * before performing FLR -+ */ -+ if (card->quirks & QUIRK_FW_RST_D3COLD) -+ mwifiex_pcie_reset_d3cold_quirk(pdev); -+ mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); + + card->pci_reset_ongoing = true; } /* -@@ -409,6 +419,8 @@ static void mwifiex_pcie_reset_done(struct pci_dev *pdev) +@@ -405,6 +407,8 @@ static void mwifiex_pcie_reset_done(struct pci_dev *pdev) dev_err(&pdev->dev, "reinit failed: %d\n", ret); else mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); @@ -258,37 +169,7 @@ index 991b9cc18000..30cd52c2485f 100644 } static const struct pci_error_handlers mwifiex_pcie_err_handler = { -@@ -2789,6 +2801,12 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) - - static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter) - { -+ if (!enable_device_dump) { -+ mwifiex_dbg(adapter, MSG, -+ "device_dump is disabled by module parameter\n"); -+ return; -+ } -+ - adapter->devdump_data = vzalloc(MWIFIEX_FW_DUMP_SIZE); - if (!adapter->devdump_data) { - mwifiex_dbg(adapter, ERROR, -@@ -2806,6 +2824,16 @@ static void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter) - { - struct pcie_service_card *card = adapter->card; - -+ /* On Surface 3, reset_wsid method removes then re-probes card by -+ * itself. So, need to place it here and skip performing any other -+ * reset-related works. -+ */ -+ if (card->quirks & QUIRK_FW_RST_WSID_S3) { -+ mwifiex_pcie_reset_wsid_quirk(card->dev); -+ /* skip performing any other reset-related works */ -+ return; -+ } -+ - /* We can't afford to wait here; remove() might be waiting on us. If we - * can't grab the device lock, maybe we'll get another chance later. - */ -@@ -3000,7 +3028,19 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter) +@@ -2996,7 +3000,19 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter) int ret; u32 fw_status; @@ -310,25 +191,95 @@ index 991b9cc18000..30cd52c2485f 100644 ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status); if (fw_status == FIRMWARE_READY_PCIE) { diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h -index f7ce9b6db6b4..f7e968306a0c 100644 +index f7ce9b6db6b4..72d0c01ff359 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie.h -@@ -391,6 +391,9 @@ struct pcie_service_card { +@@ -391,6 +391,8 @@ struct pcie_service_card { struct mwifiex_msix_context share_irq_ctx; struct work_struct work; unsigned long work_flags; + + bool pci_reset_ongoing; + }; + + static inline int +-- +2.28.0 + +From 45ddc398a7d6afa875840ab9f4fb920da3b3eb0f 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 + +This commit adds quirk implementation based on DMI matching with DMI +table for Surface devices. + +This implementation can be used for quirks later. + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/Makefile | 1 + + drivers/net/wireless/marvell/mwifiex/pcie.c | 4 + + drivers/net/wireless/marvell/mwifiex/pcie.h | 1 + + .../wireless/marvell/mwifiex/pcie_quirks.c | 114 ++++++++++++++++++ + .../wireless/marvell/mwifiex/pcie_quirks.h | 11 ++ + 5 files changed, 131 insertions(+) + create mode 100644 drivers/net/wireless/marvell/mwifiex/pcie_quirks.c + create mode 100644 drivers/net/wireless/marvell/mwifiex/pcie_quirks.h + +diff --git a/drivers/net/wireless/marvell/mwifiex/Makefile b/drivers/net/wireless/marvell/mwifiex/Makefile +index fdfd9bf15ed4..8a1e7c5b9c6e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/Makefile ++++ b/drivers/net/wireless/marvell/mwifiex/Makefile +@@ -49,6 +49,7 @@ mwifiex_sdio-y += sdio.o + obj-$(CONFIG_MWIFIEX_SDIO) += mwifiex_sdio.o + + mwifiex_pcie-y += pcie.o ++mwifiex_pcie-y += pcie_quirks.o + obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o + + mwifiex_usb-y += usb.o +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 4e655038e3f3..d56c9d7f36bd 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -27,6 +27,7 @@ + #include "wmm.h" + #include "11n.h" + #include "pcie.h" ++#include "pcie_quirks.h" + + #define PCIE_VERSION "1.0" + #define DRV_NAME "Marvell mwifiex PCIe" +@@ -261,6 +262,9 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return ret; + } + ++ /* check quirks */ ++ mwifiex_initialize_quirks(card); ++ + if (mwifiex_add_card(card, &card->fw_done, &pcie_ops, + MWIFIEX_PCIE, &pdev->dev)) { + pr_err("%s failed\n", __func__); +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.h b/drivers/net/wireless/marvell/mwifiex/pcie.h +index 72d0c01ff359..f7e968306a0c 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.h +@@ -393,6 +393,7 @@ struct pcie_service_card { + unsigned long work_flags; + + bool pci_reset_ongoing; + unsigned long quirks; }; static inline int diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c new file mode 100644 -index 000000000000..34dcd84f02a6 +index 000000000000..929aee2b0a60 --- /dev/null +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c -@@ -0,0 +1,255 @@ +@@ -0,0 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * File for PCIe quirks. @@ -340,21 +291,10 @@ index 000000000000..34dcd84f02a6 + * down, or causes NULL ptr deref). + */ + -+#include +#include + +#include "pcie_quirks.h" + -+/* For reset_wsid quirk */ -+#define ACPI_WSID_PATH "\\_SB.WSID" -+#define WSID_REV 0x0 -+#define WSID_FUNC_WIFI_PWR_OFF 0x1 -+#define WSID_FUNC_WIFI_PWR_ON 0x2 -+/* WSID _DSM UUID: "534ea3bf-fcc2-4e7a-908f-a13978f0c7ef" */ -+static const guid_t wsid_dsm_guid = -+ GUID_INIT(0x534ea3bf, 0xfcc2, 0x4e7a, -+ 0x90, 0x8f, 0xa1, 0x39, 0x78, 0xf0, 0xc7, 0xef); -+ +/* quirk table based on DMI matching */ +static const struct dmi_system_id mwifiex_quirk_table[] = { + { @@ -363,7 +303,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Pro 5", @@ -372,7 +312,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Pro 5 (LTE)", @@ -381,7 +321,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Pro 6", @@ -389,7 +329,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Book 1", @@ -397,7 +337,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Book 2", @@ -405,7 +345,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Laptop 1", @@ -413,7 +353,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface Laptop 2", @@ -421,7 +361,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = 0, + }, + { + .ident = "Surface 3", @@ -429,16 +369,7 @@ index 000000000000..34dcd84f02a6 + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, -+ .driver_data = (void *)QUIRK_FW_RST_WSID_S3, -+ }, -+ { -+ .ident = "Surface 3", -+ .matches = { -+ DMI_EXACT_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), -+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OEMB"), -+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "OEMB"), -+ }, -+ .driver_data = (void *)QUIRK_FW_RST_WSID_S3, ++ .driver_data = 0, + }, + { + .ident = "Surface Pro 3", @@ -462,11 +393,156 @@ index 000000000000..34dcd84f02a6 + + if (!card->quirks) + dev_info(&pdev->dev, "no quirks enabled\n"); ++} +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +new file mode 100644 +index 000000000000..5326ae7e5671 +--- /dev/null ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -0,0 +1,11 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Header file for PCIe quirks. ++ */ ++ ++#include "pcie.h" ++ ++/* quirks */ ++// quirk flags can be added here ++ ++void mwifiex_initialize_quirks(struct pcie_service_card *card); +-- +2.28.0 + +From 73c434f78849f6483b76719748abef519a20faa7 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+ + devices + +To reset mwifiex on Surface gen4+ (Pro 4 or later gen) devices, it +seems that putting the wifi device into D3cold is required according +to errata.inf file on Windows installation (Windows/INF/errata.inf). + +This patch adds a function that performs power-cycle (put into D3cold +then D0) and call the function at the end of reset_prepare(). + +Note: Need to also reset the parent device (bridge) of wifi on SB1; +it might be because the bridge of wifi always reports it's in D3hot. +When I tried to reset only the wifi device (not touching parent), it gave +the following error and the reset failed: + + acpi device:4b: Cannot transition to power state D0 for parent in D3hot + mwifiex_pcie 0000:03:00.0: can't change power state from D3cold to D0 (config space inaccessible) + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 ++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 73 +++++++++++++++++-- + .../wireless/marvell/mwifiex/pcie_quirks.h | 3 +- + 3 files changed, 74 insertions(+), 9 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index d56c9d7f36bd..408fe05b9384 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -380,6 +380,13 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev) + mwifiex_shutdown_sw(adapter); + clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags); + clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags); ++ ++ /* For Surface gen4+ devices, we need to put wifi into D3cold right ++ * before performing FLR ++ */ ++ if (card->quirks & QUIRK_FW_RST_D3COLD) ++ mwifiex_pcie_reset_d3cold_quirk(pdev); ++ + mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); + + card->pci_reset_ongoing = true; +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index 929aee2b0a60..edc739c542fe 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -21,7 +21,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 5", +@@ -30,7 +30,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -39,7 +39,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Pro 6", +@@ -47,7 +47,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Book 1", +@@ -55,7 +55,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Book 2", +@@ -63,7 +63,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Laptop 1", +@@ -71,7 +71,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface Laptop 2", +@@ -79,7 +79,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_D3COLD, + }, + { + .ident = "Surface 3", +@@ -111,4 +111,61 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + + if (!card->quirks) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); -+ if (card->quirks & QUIRK_FW_RST_WSID_S3) -+ dev_info(&pdev->dev, -+ "quirk reset_wsid for Surface 3 enabled\n"); +} + +static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) @@ -522,7 +598,122 @@ index 000000000000..34dcd84f02a6 + return ret; + + return 0; -+} + } +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 5326ae7e5671..8b9dcb5070d8 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -6,6 +6,7 @@ + #include "pcie.h" + + /* quirks */ +-// quirk flags can be added here ++#define QUIRK_FW_RST_D3COLD BIT(0) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); ++int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.28.0 + +From 68d4b66ab18907af945a39efb8bd02666edf073b 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 + +This commit adds reset_wsid quirk and uses this quirk for Surface 3 on +card reset. + +To reset mwifiex on Surface 3, it seems that calling the _DSM method +exists in \_SB.WSID [1] device is required. + +On Surface 3, calling the _DSM method removes/re-probes the card by +itself. So, need to place the reset function before performing FLR and +skip performing any other reset-related works. + +Note that Surface Pro 3 also has the WSID device [2], but it seems to need +more work. This commit only supports Surface 3 yet. + +[1] https://github.com/linux-surface/acpidumps/blob/05cba925f3a515f222acb5b3551a032ddde958fe/surface_3/dsdt.dsl#L11947-L12011 +[2] https://github.com/linux-surface/acpidumps/blob/05cba925f3a515f222acb5b3551a032ddde958fe/surface_pro_3/dsdt.dsl#L12164-L12216 + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 10 +++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 77 ++++++++++++++++++- + .../wireless/marvell/mwifiex/pcie_quirks.h | 5 ++ + 3 files changed, 91 insertions(+), 1 deletion(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 408fe05b9384..290427c98630 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -2817,6 +2817,16 @@ static void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter) + { + struct pcie_service_card *card = adapter->card; + ++ /* On Surface 3, reset_wsid method removes then re-probes card by ++ * itself. So, need to place it here and skip performing any other ++ * reset-related works. ++ */ ++ if (card->quirks & QUIRK_FW_RST_WSID_S3) { ++ mwifiex_pcie_reset_wsid_quirk(card->dev); ++ /* skip performing any other reset-related works */ ++ return; ++ } ++ + /* We can't afford to wait here; remove() might be waiting on us. If we + * can't grab the device lock, maybe we'll get another chance later. + */ +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index edc739c542fe..f0a6fa0a7ae5 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -9,10 +9,21 @@ + * down, or causes NULL ptr deref). + */ + ++#include + #include + + #include "pcie_quirks.h" + ++/* For reset_wsid quirk */ ++#define ACPI_WSID_PATH "\\_SB.WSID" ++#define WSID_REV 0x0 ++#define WSID_FUNC_WIFI_PWR_OFF 0x1 ++#define WSID_FUNC_WIFI_PWR_ON 0x2 ++/* WSID _DSM UUID: "534ea3bf-fcc2-4e7a-908f-a13978f0c7ef" */ ++static const guid_t wsid_dsm_guid = ++ GUID_INIT(0x534ea3bf, 0xfcc2, 0x4e7a, ++ 0x90, 0x8f, 0xa1, 0x39, 0x78, 0xf0, 0xc7, 0xef); ++ + /* quirk table based on DMI matching */ + static const struct dmi_system_id mwifiex_quirk_table[] = { + { +@@ -87,7 +98,7 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, +- .driver_data = 0, ++ .driver_data = (void *)QUIRK_FW_RST_WSID_S3, + }, + { + .ident = "Surface Pro 3", +@@ -113,6 +124,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + dev_info(&pdev->dev, "no quirks enabled\n"); + if (card->quirks & QUIRK_FW_RST_D3COLD) + dev_info(&pdev->dev, "quirk reset_d3cold enabled\n"); ++ if (card->quirks & QUIRK_FW_RST_WSID_S3) ++ dev_info(&pdev->dev, ++ "quirk reset_wsid for Surface 3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +@@ -169,3 +183,64 @@ int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev) + + return 0; + } + +int mwifiex_pcie_reset_wsid_quirk(struct pci_dev *pdev) +{ @@ -585,53 +776,651 @@ index 000000000000..34dcd84f02a6 + return 0; +} diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -new file mode 100644 -index 000000000000..3ef7440418e3 ---- /dev/null +index 8b9dcb5070d8..3ef7440418e3 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h -@@ -0,0 +1,17 @@ -+/* SPDX-License-Identifier: GPL-2.0 */ -+/* -+ * Header file for PCIe quirks. -+ */ -+ -+#include "pcie.h" -+ -+/* quirks */ -+#define QUIRK_FW_RST_D3COLD BIT(0) +@@ -7,6 +7,11 @@ + + /* quirks */ + #define QUIRK_FW_RST_D3COLD BIT(0) +/* Surface 3 and Surface Pro 3 have the same _DSM method but need to + * be handled differently. Currently, only S3 is supported. + */ +#define QUIRK_FW_RST_WSID_S3 BIT(1) -+ -+void mwifiex_initialize_quirks(struct pcie_service_card *card); -+int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +int mwifiex_pcie_reset_wsid_quirk(struct pci_dev *pdev); -diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c -index 4ed10cf82f9a..bd735eb04981 100644 ---- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c -+++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c -@@ -2339,16 +2339,10 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) - if (ret) - return -1; - -- if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { -- /* Enable IEEE PS by default */ -- priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; -- ret = mwifiex_send_cmd(priv, -- HostCmd_CMD_802_11_PS_MODE_ENH, -- EN_AUTO_PS, BITMAP_STA_PS, NULL, -- true); -- if (ret) -- return -1; -- } -+ /* Not enabling ps_mode (IEEE power_save) by default. Enabling -+ * this causes connection instability, especially on 5GHz APs -+ * and eventually causes "firmware wakeup failed". Therefore, -+ * the relevant code was removed from here. */ - - if (drcs) { - adapter->drcs_enabled = true; +-- +2.28.0 + +From 570dab9301a4f95fc96f635b3d58d55a39ba2fcf 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 + table + +(made referring to http://git.osdn.net/view?p=android-x86/kernel.git;a=commitdiff;h=18e2e857c57633b25b3b4120f212224a108cd883) + +On some Surface 3, the DMI table gets corrupted for unknown reasons +and breaks existing DMI matching used for device-specific quirks. + +This commit adds the (broken) DMI info for the affected Surface 3. + +On affected systems, DMI info will look like this: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:OEMB + /sys/devices/virtual/dmi/id/board_vendor:OEMB + /sys/devices/virtual/dmi/id/chassis_vendor:OEMB + /sys/devices/virtual/dmi/id/product_name:OEMB + /sys/devices/virtual/dmi/id/sys_vendor:OEMB + +Expected: + $ grep . /sys/devices/virtual/dmi/id/{bios_vendor,board_name,board_vendor,\ + chassis_vendor,product_name,sys_vendor} + /sys/devices/virtual/dmi/id/bios_vendor:American Megatrends Inc. + /sys/devices/virtual/dmi/id/board_name:Surface 3 + /sys/devices/virtual/dmi/id/board_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/chassis_vendor:Microsoft Corporation + /sys/devices/virtual/dmi/id/product_name:Surface 3 + /sys/devices/virtual/dmi/id/sys_vendor:Microsoft Corporation + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/pcie_quirks.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index f0a6fa0a7ae5..34dcd84f02a6 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -100,6 +100,15 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + }, + .driver_data = (void *)QUIRK_FW_RST_WSID_S3, + }, ++ { ++ .ident = "Surface 3", ++ .matches = { ++ DMI_EXACT_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."), ++ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "OEMB"), ++ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "OEMB"), ++ }, ++ .driver_data = (void *)QUIRK_FW_RST_WSID_S3, ++ }, + { + .ident = "Surface Pro 3", + .matches = { +-- +2.28.0 + +From 34c2ccb41cddec7c3346d11808008d2c00897c8d 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 + +When FLR is performed but without fw reset for some reasons (e.g. on +Surface devices, fw reset requires another quirk), it fails to reset +properly. You can trigger the issue on such devices via debugfs entry +for reset: + + $ echo 1 | sudo tee /sys/kernel/debug/mwifiex/mlan0/reset + +and the resulting dmesg log: + + mwifiex_pcie 0000:03:00.0: Resetting per request + mwifiex_pcie 0000:03:00.0: info: successfully disconnected from [BSSID]: reason code 3 + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: info: shutdown mwifiex... + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: PREP_CMD: card is removed + mwifiex_pcie 0000:03:00.0: WLAN FW already running! Skip FW dnld + mwifiex_pcie 0000:03:00.0: WLAN FW is active + mwifiex_pcie 0000:03:00.0: Unknown api_id: 4 + mwifiex_pcie 0000:03:00.0: info: MWIFIEX VERSION: mwifiex 1.0 (15.68.19.p21) + mwifiex_pcie 0000:03:00.0: driver_version = mwifiex 1.0 (15.68.19.p21) + mwifiex_pcie 0000:03:00.0: info: trying to associate to '[SSID]' bssid [BSSID] + mwifiex_pcie 0000:03:00.0: info: associated to bssid [BSSID] successfully + mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110 + mwifiex_pcie 0000:03:00.0: info: successfully disconnected from [BSSID]: reason code 15 + mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110 + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110 + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + mwifiex_pcie 0000:03:00.0: cmd_wait_q terminated: -110 + mwifiex_pcie 0000:03:00.0: deleting the crypto keys + [...] + +When comparing mwifiex_shutdown_sw() with mwifiex_pcie_remove(), it +lacks mwifiex_init_shutdown_fw(). + +This commit fixes mwifiex_shutdown_sw() by adding the missing +mwifiex_init_shutdown_fw(). + +Fixes: 4c5dae59d2e9 ("mwifiex: add PCIe function level reset support") +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c +index e48b47f42554..ceac611ef086 100644 +--- a/drivers/net/wireless/marvell/mwifiex/main.c ++++ b/drivers/net/wireless/marvell/mwifiex/main.c +@@ -1474,6 +1474,8 @@ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + mwifiex_deauthenticate(priv, NULL); + ++ mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN); ++ + mwifiex_uninit_sw(adapter); + + if (adapter->if_ops.down_dev) +-- +2.28.0 + +From 2c363d783f3605142464fa5049101a76b01df40d 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 + suspend()/resume() + +There are issues with S0ix achievement and AP scanning after suspend +with the current Host Sleep method. + +When using the Host Sleep method, it prevents the platform to reach S0ix +during suspend. Also, after suspend, sometimes AP scanning won't work, +resulting in non-working wifi. + +To fix such issues, perform shutdown_sw()/reinit_sw() instead of Host +Sleep. + +As a side effect, this patch disables wakeups (means that Wake-On-WLAN +can't be used anymore, if it was working before), and might also reset +some internal states. + +Note that suspend() no longer checks if it's already suspended. + +With the previous Host Sleep method, the check was done by looking at +adapter->hs_activated in mwifiex_enable_hs() [sta_ioctl.c], but not +MWIFIEX_IS_SUSPENDED. So, what the previous method checked was instead +Host Sleep state, not suspend itself. Therefore, there is no need to check +the suspend state now. + +Also removed comment for suspend state check at top of suspend() +accordingly. + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/main.c | 4 +-- + drivers/net/wireless/marvell/mwifiex/pcie.c | 29 +++++++-------------- + 2 files changed, 12 insertions(+), 21 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c +index ceac611ef086..55b71e3d0127 100644 +--- a/drivers/net/wireless/marvell/mwifiex/main.c ++++ b/drivers/net/wireless/marvell/mwifiex/main.c +@@ -1458,7 +1458,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) + } + + /* +- * This function gets called during PCIe function level reset. ++ * This function can be used for shutting down the adapter SW. + */ + int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) + { +@@ -1485,7 +1485,7 @@ int mwifiex_shutdown_sw(struct mwifiex_adapter *adapter) + } + EXPORT_SYMBOL_GPL(mwifiex_shutdown_sw); + +-/* This function gets called during PCIe function level reset. Required ++/* This function can be used for reinitting the adapter SW. Required + * code is extracted from mwifiex_add_card() + */ + int +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index 290427c98630..d80eb18fb0d1 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -145,8 +145,7 @@ static bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter) + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * +- * If already not suspended, this function allocates and sends a host +- * sleep activate request to the firmware and turns off the traffic. ++ * This function shuts down the adapter. + */ + static int mwifiex_pcie_suspend(struct device *dev) + { +@@ -154,31 +153,21 @@ static int mwifiex_pcie_suspend(struct device *dev) + struct pcie_service_card *card = dev_get_drvdata(dev); + + +- /* Might still be loading firmware */ +- wait_for_completion(&card->fw_done); +- + adapter = card->adapter; + if (!adapter) { + dev_err(dev, "adapter is not valid\n"); + return 0; + } + +- mwifiex_enable_wake(adapter); +- +- /* Enable the Host Sleep */ +- if (!mwifiex_enable_hs(adapter)) { ++ /* Shut down SW */ ++ if (mwifiex_shutdown_sw(adapter)) { + mwifiex_dbg(adapter, ERROR, + "cmd: failed to suspend\n"); +- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); +- mwifiex_disable_wake(adapter); + return -EFAULT; + } + +- flush_workqueue(adapter->workqueue); +- + /* Indicate device suspended */ + set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); +- clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags); + + return 0; + } +@@ -188,13 +177,13 @@ static int mwifiex_pcie_suspend(struct device *dev) + * registered functions must have drivers with suspend and resume + * methods. Failing that the kernel simply removes the whole card. + * +- * If already not resumed, this function turns on the traffic and +- * sends a host sleep cancel request to the firmware. ++ * If already not resumed, this function reinits the adapter. + */ + static int mwifiex_pcie_resume(struct device *dev) + { + struct mwifiex_adapter *adapter; + struct pcie_service_card *card = dev_get_drvdata(dev); ++ int ret; + + + if (!card->adapter) { +@@ -212,9 +201,11 @@ static int mwifiex_pcie_resume(struct device *dev) + + clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags); + +- mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), +- MWIFIEX_ASYNC_CMD); +- mwifiex_disable_wake(adapter); ++ ret = mwifiex_reinit_sw(adapter); ++ if (ret) ++ dev_err(dev, "reinit failed: %d\n", ret); ++ else ++ mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__); + + return 0; + } +-- +2.28.0 + +From e29ab6dce0e19ec82c04421da520d6a8cd4a7f17 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 + +The devicve_dump may take a little bit long time and users may want to +disable the dump for daily usage. + +This commit adds a new module parameter and disables device_dump by +default. + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index d80eb18fb0d1..ea766584d3b7 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -34,6 +34,11 @@ + + static struct mwifiex_if_ops pcie_ops; + ++static bool enable_device_dump; ++module_param(enable_device_dump, bool, 0644); ++MODULE_PARM_DESC(enable_device_dump, ++ "enable device_dump (default: disabled)"); ++ + static const struct of_device_id mwifiex_pcie_of_match_table[] = { + { .compatible = "pci11ab,2b42" }, + { .compatible = "pci1b4b,2b42" }, +@@ -2791,6 +2796,12 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter) + + static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter) + { ++ if (!enable_device_dump) { ++ mwifiex_dbg(adapter, MSG, ++ "device_dump is disabled by module parameter\n"); ++ return; ++ } ++ + adapter->devdump_data = vzalloc(MWIFIEX_FW_DUMP_SIZE); + if (!adapter->devdump_data) { + mwifiex_dbg(adapter, ERROR, +-- +2.28.0 + +From 3cf8c0e5130ca4accf9548c6851d08ebf73b2fc6 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+ + +Currently, mwifiex fw will crash after suspend on recent kernel series. +On Windows, it seems that the root port of wifi will never enter D3 state +(stay on D0 state). And on Linux, disabling the D3 state for the +bridge fixes fw crashing after suspend. + +This commit disables the D3 state of root port on driver initialization +and fixes fw crashing after suspend. + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/pcie.c | 7 +++++ + .../wireless/marvell/mwifiex/pcie_quirks.c | 27 +++++++++++++------ + .../wireless/marvell/mwifiex/pcie_quirks.h | 1 + + 3 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c +index ea766584d3b7..f8c7e6ce0c3c 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie.c +@@ -226,6 +226,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) + { + struct pcie_service_card *card; ++ struct pci_dev *parent_pdev = pci_upstream_bridge(pdev); + int ret; + + pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n", +@@ -267,6 +268,12 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev, + return -1; + } + ++ /* disable bridge_d3 for Surface gen4+ devices to fix fw crashing ++ * after suspend ++ */ ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ parent_pdev->bridge_d3 = false; ++ + return 0; + } + +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +index 34dcd84f02a6..a2aeb2af907e 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.c +@@ -32,7 +32,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 4"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5", +@@ -41,7 +42,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1796"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 5 (LTE)", +@@ -50,7 +52,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "Surface_Pro_1807"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Pro 6", +@@ -58,7 +61,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Pro 6"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 1", +@@ -66,7 +70,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Book 2", +@@ -74,7 +79,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Book 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 1", +@@ -82,7 +88,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface Laptop 2", +@@ -90,7 +97,8 @@ static const struct dmi_system_id mwifiex_quirk_table[] = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Surface Laptop 2"), + }, +- .driver_data = (void *)QUIRK_FW_RST_D3COLD, ++ .driver_data = (void *)(QUIRK_FW_RST_D3COLD | ++ QUIRK_NO_BRIDGE_D3), + }, + { + .ident = "Surface 3", +@@ -136,6 +144,9 @@ void mwifiex_initialize_quirks(struct pcie_service_card *card) + if (card->quirks & QUIRK_FW_RST_WSID_S3) + dev_info(&pdev->dev, + "quirk reset_wsid for Surface 3 enabled\n"); ++ if (card->quirks & QUIRK_NO_BRIDGE_D3) ++ dev_info(&pdev->dev, ++ "quirk no_brigde_d3 enabled\n"); + } + + static void mwifiex_pcie_set_power_d3cold(struct pci_dev *pdev) +diff --git a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +index 3ef7440418e3..a95ebac06e13 100644 +--- a/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h ++++ b/drivers/net/wireless/marvell/mwifiex/pcie_quirks.h +@@ -11,6 +11,7 @@ + * be handled differently. Currently, only S3 is supported. + */ + #define QUIRK_FW_RST_WSID_S3 BIT(1) ++#define QUIRK_NO_BRIDGE_D3 BIT(2) + + void mwifiex_initialize_quirks(struct pcie_service_card *card); + int mwifiex_pcie_reset_d3cold_quirk(struct pci_dev *pdev); +-- +2.28.0 + +From 52e3edee84ced375bb626773318578f3fd020194 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 + +This commit adds the allow_ps_mode module parameter and set it false +(disallowed) by default, to make ps_mode (power_save) control easier. + +On some setups (e.g., with 5GHz AP), power_save causes connection +completely unstable. So, we need to disable it. However, userspace tools +may try to enable it. For this reason, we need to tell userspace that +power_save is disallowed by default. + +When this parameter is set to false, changing the power_save mode will +be disallowed like the following: + + $ sudo iw dev mlan0 set power_save on + command failed: Operation not permitted (-1) + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/cfg80211.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +index 650191db25cb..dd1f08a2325f 100644 +--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +@@ -25,6 +25,11 @@ + static char *reg_alpha2; + module_param(reg_alpha2, charp, 0); + ++static bool allow_ps_mode; ++module_param(allow_ps_mode, bool, 0644); ++MODULE_PARM_DESC(allow_ps_mode, ++ "allow WiFi power management to be enabled. (default: disallowed)"); ++ + static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { + { + .max = 3, .types = BIT(NL80211_IFTYPE_STATION) | +@@ -439,6 +444,17 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + + ps_mode = enabled; + ++ /* Allow ps_mode to be enabled only when allow_ps_mode is true */ ++ if (ps_mode && !allow_ps_mode) { ++ mwifiex_dbg(priv->adapter, MSG, ++ "Enabling ps_mode disallowed by modparam\n"); ++ ++ /* Return -EPERM to inform userspace tools that setting ++ * power_save to be enabled is not permitted. ++ */ ++ return -EPERM; ++ } ++ + return mwifiex_drv_set_power(priv, &ps_mode); + } + +-- +2.28.0 + +From 2a4cdeb78a41d90ee8062d4ed03ad0acd7b83c71 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 + +Users may want to know the ps_mode state change (e.g., diagnosing +connection issues). This commit adds the print when changing ps_mode. + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/cfg80211.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +index dd1f08a2325f..ee88da92b97c 100644 +--- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c ++++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c +@@ -455,6 +455,13 @@ mwifiex_cfg80211_set_power_mgmt(struct wiphy *wiphy, + return -EPERM; + } + ++ if (ps_mode) ++ mwifiex_dbg(priv->adapter, MSG, ++ "Enabling ps_mode, disable if unstable.\n"); ++ else ++ mwifiex_dbg(priv->adapter, MSG, ++ "Disabling ps_mode.\n"); ++ + return mwifiex_drv_set_power(priv, &ps_mode); + } + +-- +2.28.0 + +From 13febaae5f0d645765c83a0c4141514434458b39 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 + +At least on Surface devices, the ps_mode causes connection unstable, +especially with 5GHz APs. Then, it eventually causes fw crashing. + +This commit disables ps_mode by default instead of enabling it. + +Required code is extracted from mwifiex_drv_set_power(). + +Signed-off-by: Tsuchiya Yuto +Patchset: wifi +--- + drivers/net/wireless/marvell/mwifiex/sta_cmd.c | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +index 4ed10cf82f9a..ed0fffb9eba6 100644 +--- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c ++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +@@ -2340,14 +2340,19 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) + return -1; + + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { +- /* Enable IEEE PS by default */ +- priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; ++ /* Disable IEEE PS by default */ ++ priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_CAM; + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_802_11_PS_MODE_ENH, +- EN_AUTO_PS, BITMAP_STA_PS, NULL, ++ DIS_AUTO_PS, BITMAP_STA_PS, NULL, + true); + if (ret) + return -1; ++ ret = mwifiex_send_cmd(priv, ++ HostCmd_CMD_802_11_PS_MODE_ENH, ++ GET_PS, 0, NULL, false); ++ if (ret) ++ return -1; + } + + if (drcs) { -- 2.28.0 diff --git a/patches/4.19/0010-surface-gpe.patch b/patches/4.19/0008-surface-gpe.patch similarity index 84% rename from patches/4.19/0010-surface-gpe.patch rename to patches/4.19/0008-surface-gpe.patch index b86c82a57..49b3d7181 100644 --- a/patches/4.19/0010-surface-gpe.patch +++ b/patches/4.19/0008-surface-gpe.patch @@ -1,8 +1,35 @@ -From 5796288595a85c616fb0b3eabd9e7a240d519287 Mon Sep 17 00:00:00 2001 +From a80e327970c6f03b0516fd354f2df0563b1497f2 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 16 Aug 2020 23:39:56 +0200 -Subject: [PATCH 10/11] surface-gpe +Subject: [PATCH] platform/x86: Add Driver to set up lid GPEs on MS Surface + device +Conventionally, wake-up events for a specific device, in our case the +lid device, are managed via the ACPI _PRW field. While this does not +seem strictly necessary based on ACPI spec, the kernel disables GPE +wakeups to avoid non-wakeup interrupts preventing suspend by default and +only enables GPEs associated via the _PRW field with a wake-up capable +device. This behavior has been introduced in commit + + f941d3e41da7f86bdb9dcc1977c2bcc6b89bfe47 + ACPI: EC / PM: Disable non-wakeup GPEs for suspend-to-idle + +and is described in more detail in its commit message. + +Unfortunately, on MS Surface devices, there is no _PRW field present on +the lid device, thus no GPE is associated with it, and therefore the GPE +responsible for sending the status-change notification to the lid gets +disabled during suspend, making it impossible to wake the device via the +lid. + +This patch introduces a pseudo-device and respective driver which, based +on some DMI matching, mark the corresponding GPE of the lid device for +wake and enable it during suspend. The behavior of this driver models +the behavior of the ACPI/PM core for normal wakeup GPEs, properly +declared via the _PRW field. + +Signed-off-by: Maximilian Luz +Patchset: surface-gpe --- drivers/platform/x86/Kconfig | 9 + drivers/platform/x86/Makefile | 1 + @@ -11,12 +38,12 @@ Subject: [PATCH 10/11] surface-gpe create mode 100644 drivers/platform/x86/surface_gpe.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index 1e1ec7e562e8..0b50f1e4c437 100644 +index 0d20ffdb5a67..cd2442056cec 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig -@@ -1175,6 +1175,15 @@ config SURFACE_BOOK1_DGPU_SWITCH - This driver provides a sysfs switch to set the power-state of the - discrete GPU found on the Microsoft Surface Book 1. +@@ -1168,6 +1168,15 @@ config SURFACE_3_POWER_OPREGION + Select this option to enable support for ACPI operation + region of the Surface 3 battery platform driver. +config SURFACE_GPE + tristate "Surface GPE/Lid Driver" @@ -31,13 +58,13 @@ index 1e1ec7e562e8..0b50f1e4c437 100644 tristate "Intel P-Unit IPC Driver" ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 3911b95487c7..0dfc55b07a48 100644 +index 2ea90039a3e4..49238e9d4abf 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile -@@ -83,6 +83,7 @@ obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o +@@ -82,6 +82,7 @@ obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o + obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o - obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += sb1_dgpu_sw.o +obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o diff --git a/patches/4.19/0009-surface-sam-over-hid.patch b/patches/4.19/0009-surface-sam-over-hid.patch index fe6254d60..82a867dc9 100644 --- a/patches/4.19/0009-surface-sam-over-hid.patch +++ b/patches/4.19/0009-surface-sam-over-hid.patch @@ -1,15 +1,57 @@ -From b91f59f3002ceab95cae05a5bc6c9428063b1485 Mon Sep 17 00:00:00 2001 +From bcb8584fbaa4854a8bcfc35c167712df1230cd5a Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH 09/11] surface-sam-over-hid +Subject: [PATCH] i2c: acpi: Implement RawBytes read access +Microsoft Surface Pro 4 and Book 1 devices access the MSHW0030 I2C +device via a generic serial bus operation region and RawBytes read +access. On the Surface Book 1, this access is required to turn on (and +off) the discrete GPU. + +Multiple things are to note here: + +a) The RawBytes access is device/driver dependent. The ACPI + specification states: + + > Raw accesses assume that the writer has knowledge of the bus that + > the access is made over and the device that is being accessed. The + > protocol may only ensure that the buffer is transmitted to the + > appropriate driver, but the driver must be able to interpret the + > buffer to communicate to a register. + + Thus this implementation may likely not work on other devices + accessing I2C via the RawBytes accessor type. + +b) The MSHW0030 I2C device is an HID-over-I2C device which seems to + serve multiple functions: + + 1. It is the main access point for the legacy-type Surface Aggregator + Module (also referred to as SAM-over-HID, as opposed to the newer + SAM-over-SSH/UART). It has currently not been determined on how + support for the legacy SAM should be implemented. Likely via a + custom HID driver. + + 2. It seems to serve as the HID device for the Integrated Sensor Hub. + This might complicate matters with regards to implementing a + SAM-over-HID driver required by legacy SAM. + +In light of this, the simplest approach has been chosen for now. +However, it may make more sense regarding breakage and compatibility to +either provide functionality for replacing or enhancing the default +operation region handler via some additional API functions, or even to +completely blacklist MSHW0030 from the I2C core and provide a custom +driver for it. + +Replacing/enhancing the default operation region handler would, however, +either require some sort of secondary driver and access point for it, +from which the new API functions would be called and the new handler +(part) would be installed, or hard-coding them via some sort of +quirk-like interface into the I2C core. + +Patchset: surface-sam-over-hid --- - drivers/i2c/i2c-core-acpi.c | 35 +++++++ - drivers/platform/x86/Kconfig | 7 ++ - drivers/platform/x86/Makefile | 1 + - drivers/platform/x86/sb1_dgpu_sw.c | 162 +++++++++++++++++++++++++++++ - 4 files changed, 205 insertions(+) - create mode 100644 drivers/platform/x86/sb1_dgpu_sw.c + drivers/i2c/i2c-core-acpi.c | 35 +++++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index eb0569359387..c2b5a2aca731 100644 @@ -64,13 +106,38 @@ index eb0569359387..c2b5a2aca731 100644 default: dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); +-- +2.28.0 + +From 53e895a0bfdf74dddb2f295f4d4e1ab93229fc40 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 + +Add driver exposing the discrete GPU power-switch of the Microsoft +Surface Book 1 to user-space. + +On the Surface Book 1, the dGPU power is controlled via the Surface +System Aggregator Module (SAM). The specific SAM-over-HID command for +this is exposed via ACPI. This module provides a simple driver exposing +the ACPI call via a sysfs parameter to user-space, so that users can +easily power-on/-off the dGPU. + +Patchset: surface-sam-over-hid +--- + drivers/platform/x86/Kconfig | 7 ++ + drivers/platform/x86/Makefile | 1 + + drivers/platform/x86/sb1_dgpu_sw.c | 162 +++++++++++++++++++++++++++++ + 3 files changed, 170 insertions(+) + create mode 100644 drivers/platform/x86/sb1_dgpu_sw.c + diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index 0d20ffdb5a67..1e1ec7e562e8 100644 +index cd2442056cec..52fdf87b21f2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig -@@ -1168,6 +1168,13 @@ config SURFACE_3_POWER_OPREGION - Select this option to enable support for ACPI operation - region of the Surface 3 battery platform driver. +@@ -1177,6 +1177,13 @@ config SURFACE_GPE + accordingly. It is required on those devices to allow wake-ups from + suspend by opening the lid. +config SURFACE_BOOK1_DGPU_SWITCH + tristate "Surface Book 1 dGPU Switch Driver" @@ -83,13 +150,13 @@ index 0d20ffdb5a67..1e1ec7e562e8 100644 tristate "Intel P-Unit IPC Driver" ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 2ea90039a3e4..3911b95487c7 100644 +index 49238e9d4abf..6b028d1ee802 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile -@@ -82,6 +82,7 @@ obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o - obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o +@@ -83,6 +83,7 @@ obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_SURFACE_3_POWER_OPREGION) += surface3_power.o + obj-$(CONFIG_SURFACE_GPE) += surface_gpe.o +obj-$(CONFIG_SURFACE_BOOK1_DGPU_SWITCH) += sb1_dgpu_sw.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o diff --git a/patches/4.19/0008-surface-sam.patch b/patches/4.19/0010-surface-sam.patch similarity index 93% rename from patches/4.19/0008-surface-sam.patch rename to patches/4.19/0010-surface-sam.patch index 9922bb86a..f35c51ecd 100644 --- a/patches/4.19/0008-surface-sam.patch +++ b/patches/4.19/0010-surface-sam.patch @@ -1,22 +1,405 @@ -From 69777ceca6c4036a9f071a37c582dbc2359f0c3f Mon Sep 17 00:00:00 2001 +From 5d78acea2443324844d4535f30e1026fb14799fc Mon Sep 17 00:00:00 2001 From: qzed Date: Mon, 26 Aug 2019 01:15:40 +0200 -Subject: [PATCH 08/11] surface-sam +Subject: [PATCH] ACPI: Fix buffer/integer type mismatch +This is actually not a bug in the kernel, but rather Microsoft not +conforming with the ACPI specification. + +Patchset: surface-sam +--- + drivers/acpi/acpica/dsopcode.c | 2 +- + drivers/acpi/acpica/exfield.c | 26 ++++++++++---------------- + 2 files changed, 11 insertions(+), 17 deletions(-) + +diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c +index 2f4641e5ecde..beb22d7e245e 100644 +--- a/drivers/acpi/acpica/dsopcode.c ++++ b/drivers/acpi/acpica/dsopcode.c +@@ -123,7 +123,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode, + + /* Offset is in bits, count is in bits */ + +- field_flags = AML_FIELD_ACCESS_BYTE; ++ field_flags = AML_FIELD_ACCESS_BUFFER; + bit_offset = offset; + bit_count = (u32) length_desc->integer.value; + +diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c +index b272c329d45d..cf547883a993 100644 +--- a/drivers/acpi/acpica/exfield.c ++++ b/drivers/acpi/acpica/exfield.c +@@ -102,6 +102,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + void *buffer; + u32 function; + u16 accessor_type; ++ u8 field_flags; + + ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); + +@@ -199,11 +200,16 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + * Note: Field.length is in bits. + */ + length = +- (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); ++ (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); ++ field_flags = obj_desc->common_field.field_flags; + +- if (length > acpi_gbl_integer_byte_width) { ++ if (length > acpi_gbl_integer_byte_width || ++ (field_flags & AML_FIELD_ACCESS_TYPE_MASK) == AML_FIELD_ACCESS_BUFFER) { + +- /* Field is too large for an Integer, create a Buffer instead */ ++ /* ++ * Field is either too large for an Integer, or a actually of type ++ * buffer, so create a Buffer. ++ */ + + buffer_desc = acpi_ut_create_buffer_object(length); + if (!buffer_desc) { +@@ -366,19 +372,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, + } else if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS) { + accessor_type = obj_desc->field.attribute; +- length = +- acpi_ex_get_serial_access_length(accessor_type, +- obj_desc->field. +- access_length); +- +- /* +- * Add additional 2 bytes for the generic_serial_bus data buffer: +- * +- * Status; (Byte 0 of the data buffer) +- * Length; (Byte 1 of the data buffer) +- * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) +- */ +- length += 2; ++ length = source_desc->buffer.length; + function = ACPI_WRITE | (accessor_type << 16); + } else { /* IPMI */ + +-- +2.28.0 + +From 5a933ea960eb31d07159b624e74c243f1bfbef76 Mon Sep 17 00:00:00 2001 +From: Maximilian Luz +Date: Tue, 24 Sep 2019 17:38:12 +0200 +Subject: [PATCH] serdev: Add ACPI devices by ResourceSource field + +When registering a serdev controller, ACPI needs to be checked for +devices attached to it. Currently, all immediate children of the ACPI +node of the controller are assumed to be UART client devices for this +controller. Furthermore, these devices are not searched elsewhere. + +This is incorrect: Similar to SPI and I2C devices, the UART client +device definition (via UARTSerialBusV2) can reside anywhere in the ACPI +namespace as resource definition inside the _CRS method and points to +the controller via its ResourceSource field. This field may either +contain a fully qualified or relative path, indicating the controller +device. To address this, we need to walk over the whole ACPI namespace, +looking at each resource definition, and match the client device to the +controller via this field. + +This patch is based on the existing acpi serial bus implementations in +drivers/i2c/i2c-core-acpi.c and drivers/spi/spi.c, specifically commit +4c3c59544f33e97cf8557f27e05a9904ead16363 ("spi/acpi: enumerate all SPI +slaves in the namespace"). + +Signed-off-by: Maximilian Luz +Patchset: surface-sam +--- + drivers/tty/serdev/core.c | 111 +++++++++++++++++++++++++++++++++----- + 1 file changed, 99 insertions(+), 12 deletions(-) + +diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c +index c66a04d24f1d..1b18d12d217f 100644 +--- a/drivers/tty/serdev/core.c ++++ b/drivers/tty/serdev/core.c +@@ -496,16 +496,97 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl) + } + + #ifdef CONFIG_ACPI ++ ++#define SERDEV_ACPI_MAX_SCAN_DEPTH 32 ++ ++struct acpi_serdev_lookup { ++ acpi_handle device_handle; ++ acpi_handle controller_handle; ++ int n; ++ int index; ++}; ++ ++static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data) ++{ ++ struct acpi_serdev_lookup *lookup = data; ++ struct acpi_resource_uart_serialbus *sb; ++ acpi_status status; ++ ++ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) ++ return 1; ++ ++ if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART) ++ return 1; ++ ++ if (lookup->index != -1 && lookup->n++ != lookup->index) ++ return 1; ++ ++ sb = &ares->data.uart_serial_bus; ++ ++ status = acpi_get_handle(lookup->device_handle, ++ sb->resource_source.string_ptr, ++ &lookup->controller_handle); ++ if (ACPI_FAILURE(status)) ++ return 1; ++ ++ /* ++ * NOTE: Ideally, we would also want to retreive other properties here, ++ * once setting them before opening the device is supported by serdev. ++ */ ++ ++ return 1; ++} ++ ++static int acpi_serdev_do_lookup(struct acpi_device *adev, ++ struct acpi_serdev_lookup *lookup) ++{ ++ struct list_head resource_list; ++ int ret; ++ ++ lookup->device_handle = acpi_device_handle(adev); ++ lookup->controller_handle = NULL; ++ lookup->n = 0; ++ ++ INIT_LIST_HEAD(&resource_list); ++ ret = acpi_dev_get_resources(adev, &resource_list, ++ acpi_serdev_parse_resource, lookup); ++ acpi_dev_free_resource_list(&resource_list); ++ ++ if (ret < 0) ++ return -EINVAL; ++ ++ return 0; ++} ++ ++static int acpi_serdev_check_resources(struct serdev_controller *ctrl, ++ struct acpi_device *adev) ++{ ++ struct acpi_serdev_lookup lookup; ++ int ret; ++ ++ if (acpi_bus_get_status(adev) || !adev->status.present) ++ return -EINVAL; ++ ++ /* Look for UARTSerialBusV2 resource */ ++ lookup.index = -1; // we only care for the last device ++ ++ ret = acpi_serdev_do_lookup(adev, &lookup); ++ if (ret) ++ return ret; ++ ++ /* Make sure controller and ResourceSource handle match */ ++ if (ACPI_HANDLE(ctrl->dev.parent) != lookup.controller_handle) ++ return -ENODEV; ++ ++ return 0; ++} ++ + static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, +- struct acpi_device *adev) ++ struct acpi_device *adev) + { +- struct serdev_device *serdev = NULL; ++ struct serdev_device *serdev; + int err; + +- if (acpi_bus_get_status(adev) || !adev->status.present || +- acpi_device_enumerated(adev)) +- return AE_OK; +- + serdev = serdev_device_alloc(ctrl); + if (!serdev) { + dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n", +@@ -533,7 +614,7 @@ static const struct acpi_device_id serdev_acpi_devices_blacklist[] = { + }; + + static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, +- void *data, void **return_value) ++ void *data, void **return_value) + { + struct serdev_controller *ctrl = data; + struct acpi_device *adev; +@@ -541,26 +622,32 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + ++ if (acpi_device_enumerated(adev)) ++ return AE_OK; ++ + /* Skip if black listed */ + if (!acpi_match_device_ids(adev, serdev_acpi_devices_blacklist)) + return AE_OK; + ++ if (acpi_serdev_check_resources(ctrl, adev)) ++ return AE_OK; ++ + return acpi_serdev_register_device(ctrl, adev); + } + ++ + static int acpi_serdev_register_devices(struct serdev_controller *ctrl) + { + acpi_status status; +- acpi_handle handle; + +- handle = ACPI_HANDLE(ctrl->dev.parent); +- if (!handle) ++ if (!has_acpi_companion(ctrl->dev.parent)) + return -ENODEV; + +- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, ++ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ++ SERDEV_ACPI_MAX_SCAN_DEPTH, + acpi_serdev_add_device, NULL, ctrl, NULL); + if (ACPI_FAILURE(status)) +- dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n"); ++ dev_warn(&ctrl->dev, "failed to enumerate serdev slaves\n"); + + if (!ctrl->serdev) + return -ENODEV; +-- +2.28.0 + +From 632b5dc29badc5b21510aa8d6f3a436d9f452dc9 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 + devices + +Implement file2alias support for Surface System Aggregator Module (SSAM) +devices. This allows modules to be auto-loaded for specific devices via +their respective module alias. + +Patchset: surface-sam +--- + include/linux/mod_devicetable.h | 17 +++++++++++++++++ + scripts/mod/devicetable-offsets.c | 7 +++++++ + scripts/mod/file2alias.c | 21 +++++++++++++++++++++ + 3 files changed, 45 insertions(+) + +diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h +index 610cdf8082f2..69f4527315e7 100644 +--- a/include/linux/mod_devicetable.h ++++ b/include/linux/mod_devicetable.h +@@ -768,4 +768,21 @@ struct typec_device_id { + kernel_ulong_t driver_data; + }; + ++/* Surface System Aggregator Module */ ++ ++#define SSAM_MATCH_CHANNEL 0x1 ++#define SSAM_MATCH_INSTANCE 0x2 ++#define SSAM_MATCH_FUNCTION 0x4 ++ ++struct ssam_device_id { ++ __u8 match_flags; ++ ++ __u8 category; ++ __u8 channel; ++ __u8 instance; ++ __u8 function; ++ ++ kernel_ulong_t driver_data; ++}; ++ + #endif /* LINUX_MOD_DEVICETABLE_H */ +diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c +index 293004499b4d..13acbf55c6fd 100644 +--- a/scripts/mod/devicetable-offsets.c ++++ b/scripts/mod/devicetable-offsets.c +@@ -225,5 +225,12 @@ int main(void) + DEVID_FIELD(typec_device_id, svid); + DEVID_FIELD(typec_device_id, mode); + ++ DEVID(ssam_device_id); ++ DEVID_FIELD(ssam_device_id, match_flags); ++ DEVID_FIELD(ssam_device_id, category); ++ DEVID_FIELD(ssam_device_id, channel); ++ DEVID_FIELD(ssam_device_id, instance); ++ DEVID_FIELD(ssam_device_id, function); ++ + return 0; + } +diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c +index 7f40b6aab689..76e3b1d7db45 100644 +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -1276,6 +1276,26 @@ static int do_typec_entry(const char *filename, void *symval, char *alias) + return 1; + } + ++/* Looks like: ssam:cNtNiNfN ++ * ++ * N is exactly 2 digits, where each is an upper-case hex digit. ++ */ ++static int do_ssam_entry(const char *filename, void *symval, char *alias) ++{ ++ DEF_FIELD(symval, ssam_device_id, match_flags); ++ DEF_FIELD(symval, ssam_device_id, category); ++ DEF_FIELD(symval, ssam_device_id, channel); ++ DEF_FIELD(symval, ssam_device_id, instance); ++ DEF_FIELD(symval, ssam_device_id, function); ++ ++ sprintf(alias, "ssam:c%02X", category); ++ ADD(alias, "t", match_flags & SSAM_MATCH_CHANNEL, channel); ++ ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); ++ ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); ++ ++ return 1; ++} ++ + /* Does namelen bytes of name exactly match the symbol? */ + static bool sym_is(const char *name, unsigned namelen, const char *symbol) + { +@@ -1346,6 +1366,7 @@ static const struct devtable devtable[] = { + {"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry}, + {"tbsvc", SIZE_tb_service_id, do_tbsvc_entry}, + {"typec", SIZE_typec_device_id, do_typec_entry}, ++ {"ssam", SIZE_ssam_device_id, do_ssam_entry}, + }; + + /* Create MODULE_ALIAS() statements. +-- +2.28.0 + +From a14fa36daaee6d27744986e0cfdd336127146662 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 + +Add support for the Surface System Aggregator Module (SSAM), an embedded +controller that can be found on 5th and later generation Microsoft +Surface devices. The responsibilities of this EC vary from device to +device. It provides battery information on all 5th and later generation +devices, temperature sensor and cooling capability access, functionality +for clipboard detaching on the Surface Books (2 and 3), as well as +HID-over-SSAM input devices, including keyboard on the Surface Laptop 1 +and 2, and keyboard as well as touchpad input on the Surface Laptop 3 +and Surface Book 3. + +Patchset: surface-sam --- Documentation/driver-api/index.rst | 1 + .../surface_aggregator/client-api.rst | 38 + .../driver-api/surface_aggregator/client.rst | 394 +++ .../surface_aggregator/clients/cdev.rst | 85 + - .../surface_aggregator/clients/index.rst | 21 + + .../surface_aggregator/clients/dtx.rst | 712 +++++ + .../surface_aggregator/clients/index.rst | 22 + .../surface_aggregator/clients/san.rst | 44 + .../driver-api/surface_aggregator/index.rst | 21 + .../surface_aggregator/internal-api.rst | 67 + .../surface_aggregator/internal.rst | 50 + .../surface_aggregator/overview.rst | 76 + .../driver-api/surface_aggregator/ssh.rst | 343 +++ - drivers/acpi/acpica/dsopcode.c | 2 +- - drivers/acpi/acpica/exfield.c | 26 +- drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/surface_aggregator/Kconfig | 67 + @@ -29,7 +412,7 @@ Subject: [PATCH 08/11] surface-sam .../clients/surface_aggregator_cdev.c | 299 ++ .../clients/surface_aggregator_registry.c | 605 ++++ .../clients/surface_battery.c | 1192 ++++++++ - .../surface_aggregator/clients/surface_dtx.c | 1127 ++++++++ + .../surface_aggregator/clients/surface_dtx.c | 1268 ++++++++ .../surface_aggregator/clients/surface_hid.c | 919 ++++++ .../clients/surface_hotplug.c | 1285 +++++++++ .../clients/surface_perfmode.c | 122 + @@ -44,19 +427,20 @@ Subject: [PATCH 08/11] surface-sam .../surface_aggregator/ssh_request_layer.c | 1254 ++++++++ .../surface_aggregator/ssh_request_layer.h | 142 + drivers/misc/surface_aggregator/trace.h | 625 ++++ - drivers/tty/serdev/core.c | 111 +- - include/linux/mod_devicetable.h | 18 + + include/linux/mod_devicetable.h | 5 +- include/linux/surface_acpi_notify.h | 39 + include/linux/surface_aggregator/controller.h | 815 ++++++ include/linux/surface_aggregator/device.h | 430 +++ include/linux/surface_aggregator/serial_hub.h | 655 +++++ include/uapi/linux/surface_aggregator/cdev.h | 58 + - scripts/mod/devicetable-offsets.c | 8 + - scripts/mod/file2alias.c | 23 + - 49 files changed, 18904 insertions(+), 29 deletions(-) + include/uapi/linux/surface_aggregator/dtx.h | 150 + + scripts/mod/devicetable-offsets.c | 3 +- + scripts/mod/file2alias.c | 10 +- + 48 files changed, 19760 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 + create mode 100644 Documentation/driver-api/surface_aggregator/clients/dtx.rst create mode 100644 Documentation/driver-api/surface_aggregator/clients/index.rst create mode 100644 Documentation/driver-api/surface_aggregator/clients/san.rst create mode 100644 Documentation/driver-api/surface_aggregator/index.rst @@ -94,6 +478,7 @@ Subject: [PATCH 08/11] surface-sam create mode 100644 include/linux/surface_aggregator/device.h create mode 100644 include/linux/surface_aggregator/serial_hub.h create mode 100644 include/uapi/linux/surface_aggregator/cdev.h + create mode 100644 include/uapi/linux/surface_aggregator/dtx.h diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index 6d9f2f9fe20e..e36fbb60c676 100644 @@ -642,12 +1027,730 @@ index 000000000000..63b5afcb89b5 + +.. kernel-doc:: include/uapi/linux/surface_aggregator/cdev.h + :functions: ssam_cdev_request +diff --git a/Documentation/driver-api/surface_aggregator/clients/dtx.rst b/Documentation/driver-api/surface_aggregator/clients/dtx.rst +new file mode 100644 +index 000000000000..e974c2b04e9f +--- /dev/null ++++ b/Documentation/driver-api/surface_aggregator/clients/dtx.rst +@@ -0,0 +1,712 @@ ++.. SPDX-License-Identifier: GPL-2.0+ ++ ++.. |__u16| replace:: :c:type:`__u16 <__u16>` ++.. |sdtx_event| replace:: :c:type:`struct sdtx_event ` ++.. |sdtx_event_code| replace:: :c:type:`enum sdtx_event_code ` ++.. |sdtx_base_info| replace:: :c:type:`struct sdtx_base_info ` ++.. |sdtx_device_mode| replace:: :c:type:`struct sdtx_device_mode ` ++ ++====================================================== ++User-Space DTX (Clipboard Detachment System) Interface ++====================================================== ++ ++The ``surface_dtx`` driver is responsible for proper clipboard detachment ++and re-attachment handling. To this end, it provides the ``/dev/surface/dtx`` ++device file, through which it can interface with a user-space daemon. This ++daemon is then ultimately responsible for determining and taking necessary ++actions, such as unmounting devices attached to the base, ++unloading/reloading the graphics-driver, user-notifications, etc. ++ ++There are two basic communication principles used in this driver: Commands ++(in other parts of the documentation also referred to as requests) and ++events. Commands are sent to the EC and may have a different implications in ++different contexts. Events are sent by the EC upon some internal state ++change. Commands are always driver-initiated, whereas events are always ++initiated by the EC. ++ ++.. contents:: ++ ++Nomenclature ++============ ++ ++* **Clipboard:** ++ The detachable upper part of the Surface Book, housing the screen and CPU. ++ ++* **Base:** ++ The lower part of the Surface Book from which the clipboard can be ++ detached, optionally (model dependent) housing the discrete GPU (dGPU). ++ ++* **Latch:** ++ The mechanism keeping the clipboard attached to the base in normal ++ operation and allowing it to be detached when requested. ++ ++* **Silently ignored commands:** ++ The command is accepted by the EC as a valid command and acknowledged ++ (following the standard communication protocol), but the EC does not act ++ upon it, i.e. ignores it.e upper part of the ++ ++ ++Detachment Process ++================== ++ ++Warning: This part of the documentation is based on reverse engineering and ++testing and thus may contain errors or be incomplete. ++ ++Latch States ++------------ ++ ++The latch mechanism has two major states: *open* and *closed*. In the ++*closed* state (default), the clipboard is secured to the base, whereas in ++the *open* state, the clipboard can be removed by a user. ++ ++The latch can additionally be locked and, correspondingly, unlocked, which ++can influence the detachment procedure. Specifically, this locking mechanism ++is intended to prevent the the dGPU, positioned in the base of the device, ++from being hot-unplugged while in use. More details can be found in the ++documentation for the detachment procedure below. By default, the latch is ++unlocked. ++ ++Detachment Procedure ++-------------------- ++ ++Note that the detachment process is governed fully by the EC. The ++``surface_dtx`` driver only relays events from the EC to user-space and ++commands from user-space to the EC, i.e. it does not influence this process. ++ ++The detachment process is started with the user pressing the *detach* button ++on the base of the device or executing the ``SDTX_IOCTL_LATCH_REQUEST`` IOCTL. ++Following that: ++ ++1. The EC turns on the indicator led on the detach-button, sends a ++ *detach-request* event (``SDTX_EVENT_REQUEST``), and awaits further ++ instructions/commands. In case the latch is unlocked, the led will flash ++ green. If the latch has been locked, the led will be solid red ++ ++2. The event is, via the ``surface_dtx`` driver, relayed to user-space, where ++ an appropriate user-space daemon can handle it and send instructions back ++ to the EC via IOCTLs provided by this driver. ++ ++3. The EC waits for instructions from user-space and acts according to them. ++ If the EC does not receive any instructions in a given period, it will ++ time out and continue as follows: ++ ++ - If the latch is unlocked, the EC will open the latch and the clipboard ++ can be detached from the base. This is the exact behavior as without ++ this driver or any user-space daemon. See the ``SDTX_IOCTL_LATCH_CONFIRM`` ++ description below for more details on the follow-up behavior of the EC. ++ ++ - If the latch is locked, the EC will *not* open the latch, meaning the ++ clipboard cannot be detached from the base. Furthermore, the EC sends ++ an cancel event (``SDTX_EVENT_CANCEL``) detailing this with the cancel ++ reason ``SDTX_DETACH_TIMEDOUT`` (see :ref:`events` for details). ++ ++Valid responses by a user-space daemon to a detachment request event are: ++ ++- Execute ``SDTX_IOCTL_LATCH_REQUEST``. This will immediately abort the ++ detachment process. Furthermore, the EC will send a detach-request event, ++ similar to the user pressing the detach-button to cancel said process (see ++ below). ++ ++- Execute ``SDTX_IOCTL_LATCH_CONFIRM``. This will cause the EC to open the ++ latch, after which the user can separate clipboard and base. ++ ++ As this changes the latch state, a *latch-status* event ++ (``SDTX_EVENT_LATCH_STATUS``) will be sent once the latch has been opened ++ successfully. If the EC fails to open the latch, e.g. due to hardware ++ error or low battery, a latch-cancel event (``SDTX_EVENT_CANCEL``) will be ++ sent with the cancel reason indicating the specific failure. ++ ++ If the latch is currently locked, the latch will automatically be ++ unlocked before it is opened. ++ ++- Execute ``SDTX_IOCTL_LATCH_HEARTBEAT``. This will reset the internal timeout. ++ No other actions will be performed, i.e. the detachment process will neither ++ be completed nor canceled, and the EC will still be waiting for further ++ responses. ++ ++- Execute ``SDTX_IOCTL_LATCH_CANCEL``. This will abort the detachment process, ++ similar to ``SDTX_IOCTL_LATCH_REQUEST``, described above, or the button ++ press, described below. A *generic request* event (``SDTX_EVENT_REQUEST``) ++ is send in response to this. In contrast to those, however, this command ++ does not trigger a new detachment process if none is currently in ++ progress. ++ ++- Do nothing. The detachment process eventually times out as described in ++ point 3. ++ ++See :ref:`ioctls` for more details on these responses. ++ ++It is important to note that, if the user presses the detach button at any ++point when a detachment operation is in progress (i.e. after the the EC has ++sent the initial *detach-request* event (``SDTX_EVENT_REQUEST``) and before ++it received the corresponding response concluding the process), the ++detachment process is canceled on the EC-level and an identical event is ++being sent. Thus a *detach-request* event, by itself, does not signal the ++start of the detachment process. ++ ++The detachment process may further be canceled by the EC due to hardware ++failures or a low clipboard battery. This is done via a cancel event ++(``SDTX_EVENT_CANCEL``) with the corresponding cancel reason. ++ ++ ++User-Space Interface Documentation ++================================== ++ ++Error Codes and Status Values ++----------------------------- ++ ++Error and status codes are divided into different categories, which can be ++used to determine if the status code is an error, and, if it is, the ++severity and type of that error. The current categories are: ++ ++.. flat-table:: Overview of Status/Error Categories. ++ :widths: 2 1 3 ++ :header-rows: 1 ++ ++ * - Name ++ - Value ++ - Short Description ++ ++ * - ``STATUS`` ++ - ``0x0000`` ++ - Non-error status codes. ++ ++ * - ``RUNTIME_ERROR`` ++ - ``0x1000`` ++ - Non-critical runtime errors. ++ ++ * - ``HARDWARE_ERROR`` ++ - ``0x2000`` ++ - Critical hardware failures. ++ ++ * - ``UNKNOWN`` ++ - ``0xF000`` ++ - Unknown error codes. ++ ++Other categories are reserved for future use. The ``SDTX_CATEGORY()`` macro ++can be used to determine the category of any status value. The ++``SDTX_SUCCESS()`` macro can be used to check if the status value is a ++success value (``SDTX_CATEGORY_STATUS``) or if it indicates a failure. ++ ++Unknown status or error codes sent by the EC are assigned to the ``UNKNOWN`` ++category by the driver and may be implemented via their own code in the ++future. ++ ++Currently used error codes are: ++ ++.. flat-table:: Overview of Error Codes. ++ :widths: 2 1 1 3 ++ :header-rows: 1 ++ ++ * - Name ++ - Category ++ - Value ++ - Short Description ++ ++ * - ``SDTX_DETACH_NOT_FEASIBLE`` ++ - ``RUNTIME`` ++ - ``0x1001`` ++ - Detachment not feasible due to low clipboard battery. ++ ++ * - ``SDTX_DETACH_TIMEDOUT`` ++ - ``RUNTIME`` ++ - ``0x1002`` ++ - Detachment process timed out while the latch was locked. ++ ++ * - ``SDTX_ERR_FAILED_TO_OPEN`` ++ - ``HARDWARE`` ++ - ``0x2001`` ++ - Failed to open latch. ++ ++ * - ``SDTX_ERR_FAILED_TO_REMAIN_OPEN`` ++ - ``HARDWARE`` ++ - ``0x2002`` ++ - Failed to keep latch open. ++ ++ * - ``SDTX_ERR_FAILED_TO_CLOSE`` ++ - ``HARDWARE`` ++ - ``0x2003`` ++ - Failed to close latch. ++ ++Other error codes are reserved for future use. Non-error status codes may ++overlap and are generally only unique within their use-case: ++ ++.. flat-table:: Latch Status Codes. ++ :widths: 2 1 1 3 ++ :header-rows: 1 ++ ++ * - Name ++ - Category ++ - Value ++ - Short Description ++ ++ * - ``SDTX_LATCH_CLOSED`` ++ - ``STATUS`` ++ - ``0x0000`` ++ - Latch is closed/has been closed. ++ ++ * - ``SDTX_LATCH_OPENED`` ++ - ``STATUS`` ++ - ``0x0001`` ++ - Latch is open/has been opened. ++ ++.. flat-table:: Base State Codes. ++ :widths: 2 1 1 3 ++ :header-rows: 1 ++ ++ * - Name ++ - Category ++ - Value ++ - Short Description ++ ++ * - ``SDTX_BASE_DETACHED`` ++ - ``STATUS`` ++ - ``0x0000`` ++ - Base has been detached/is not present. ++ ++ * - ``SDTX_BASE_ATTACHED`` ++ - ``STATUS`` ++ - ``0x0001`` ++ - Base has been attached/is present. ++ ++Again, other codes are reserved for future use. ++ ++.. _events: ++ ++Events ++------ ++ ++Events can be received by reading from the device file. They are disabled by ++default and have to be enabled by executing ``SDTX_IOCTL_EVENTS_ENABLE`` ++first. All events follow the layout prescribed by |sdtx_event|. Specific ++event types can be identified by their event code, described in ++|sdtx_event_code|. Note that other event codes are reserved for future use, ++thus an event parser must be able to handle any unknown/unsupported event ++types gracefully, by relying on the payload length given in the event header. ++ ++Currently provided event types are: ++ ++.. flat-table:: Overview of DTX events. ++ :widths: 2 1 1 3 ++ :header-rows: 1 ++ ++ * - Name ++ - Code ++ - Payload ++ - Short Description ++ ++ * - ``SDTX_EVENT_REQUEST`` ++ - ``1`` ++ - ``0`` bytes ++ - Detachment process initiated/aborted. ++ ++ * - ``SDTX_EVENT_CANCEL`` ++ - ``2`` ++ - ``2`` bytes ++ - EC canceled detachment process. ++ ++ * - ``SDTX_EVENT_BASE_CONNECTION`` ++ - ``3`` ++ - ``4`` bytes ++ - Base connection state changed. ++ ++ * - ``SDTX_EVENT_LATCH_STATUS`` ++ - ``4`` ++ - ``2`` bytes ++ - Latch status changed. ++ ++ * - ``SDTX_EVENT_DEVICE_MODE`` ++ - ``5`` ++ - ``2`` bytes ++ - Device mode changed. ++ ++Individual events in more detail: ++ ++``SDTX_EVENT_REQUEST`` ++^^^^^^^^^^^^^^^^^^^^^^ ++ ++Sent when a detachment process is started or, if in progress, aborted by the ++user, either via a detach button press or a detach request ++(``SDTX_IOCTL_LATCH_REQUEST``) being sent from user-space. ++ ++Does not have any payload. ++ ++``SDTX_EVENT_CANCEL`` ++^^^^^^^^^^^^^^^^^^^^^ ++ ++Sent when a detachment process is canceled by the EC due to unfulfilled ++preconditions (e.g. clipboard battery too low to detach) or hardware ++failure. The reason for cancellation is given in the event payload detailed ++below and can be one of ++ ++* ``SDTX_DETACH_TIMEDOUT``: Detachment timed out while the latch was locked. ++ The latch has neither been opened nor unlocked. ++ ++* ``SDTX_DETACH_NOT_FEASIBLE``: Detachment not feasible due to low clipboard ++ battery. ++ ++* ``SDTX_ERR_FAILED_TO_OPEN``: Could not open the latch (hardware failure). ++ ++* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``: Could not keep the latch open (hardware ++ failure). ++ ++* ``SDTX_ERR_FAILED_TO_CLOSE``: Could not close the latch (hardware failure). ++ ++Other error codes in this context are reserved for future use. ++ ++These codes can be classified via the ``SDTX_CATEGORY()`` macro to discern ++between critical hardware errors (``SDTX_CATEGORY_HARDWARE_ERROR``) or ++runtime errors (``SDTX_CATEGORY_RUNTIME_ERROR``), the latter of which may ++happen during normal operation if certain preconditions for detachment are ++not given. ++ ++.. flat-table:: Detachment Cancel Event Payload ++ :widths: 1 1 4 ++ :header-rows: 1 ++ ++ * - Field ++ - Type ++ - Description ++ ++ * - ``reason`` ++ - |__u16| ++ - Reason for cancellation. ++ ++``SDTX_EVENT_BASE_CONNECTION`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Sent when the base connection state has changed, i.e. when the base has been ++attached, detached, or detachment has become infeasible due to low clipboard ++battery. The new state and, if a base is connected, ID of the base is ++provided as payload of type |sdtx_base_info| with its layout presented ++below: ++ ++.. flat-table:: Base-Connection-Change Event Payload ++ :widths: 1 1 4 ++ :header-rows: 1 ++ ++ * - Field ++ - Type ++ - Description ++ ++ * - ``state`` ++ - |__u16| ++ - Base connection state. ++ ++ * - ``base_id`` ++ - |__u16| ++ - Type of base connected (zero if none). ++ ++Possible values for ``state`` are: ++ ++* ``SDTX_BASE_DETACHED``, ++* ``SDTX_BASE_ATTACHED``, and ++* ``SDTX_DETACH_NOT_FEASIBLE``. ++ ++Other values are reserved for future use. ++ ++``SDTX_EVENT_LATCH_STATUS`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Sent when the latch status has changed, i.e. when the latch has been opened, ++closed, or an error occurred. The current status is provided as payload: ++ ++.. flat-table:: Latch-Status-Change Event Payload ++ :widths: 1 1 4 ++ :header-rows: 1 ++ ++ * - Field ++ - Type ++ - Description ++ ++ * - ``status`` ++ - |__u16| ++ - Latch status. ++ ++Possible values for ``status`` are: ++ ++* ``SDTX_LATCH_CLOSED``, ++* ``SDTX_LATCH_OPENED``, ++* ``SDTX_ERR_FAILED_TO_OPEN``, ++* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``, and ++* ``SDTX_ERR_FAILED_TO_CLOSE``. ++ ++Other values are reserved for future use. ++ ++``SDTX_EVENT_DEVICE_MODE`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Sent when the device mode has changed. The new device mode is provided as ++payload: ++ ++.. flat-table:: Device-Mode-Change Event Payload ++ :widths: 1 1 4 ++ :header-rows: 1 ++ ++ * - Field ++ - Type ++ - Description ++ ++ * - ``mode`` ++ - |__u16| ++ - Device operation mode. ++ ++Possible values for ``mode`` are: ++ ++* ``SDTX_DEVICE_MODE_TABLET``, ++* ``SDTX_DEVICE_MODE_LAPTOP``, and ++* ``SDTX_DEVICE_MODE_STUDIO``. ++ ++Other values are reserved for future use. ++ ++.. _ioctls: ++ ++IOCTLs ++------ ++ ++The following IOCTLs are provided: ++ ++.. flat-table:: Overview of DTX IOCTLs ++ :widths: 1 1 1 1 4 ++ :header-rows: 1 ++ ++ * - Type ++ - Number ++ - Direction ++ - Name ++ - Description ++ ++ * - ``0xA5`` ++ - ``0x21`` ++ - ``-`` ++ - ``EVENTS_ENABLE`` ++ - Enable events for the current file descriptor. ++ ++ * - ``0xA5`` ++ - ``0x22`` ++ - ``-`` ++ - ``EVENTS_DISABLE`` ++ - Disable events for the current file descriptor. ++ ++ * - ``0xA5`` ++ - ``0x23`` ++ - ``-`` ++ - ``LATCH_LOCK`` ++ - Lock the latch. ++ ++ * - ``0xA5`` ++ - ``0x24`` ++ - ``-`` ++ - ``LATCH_UNLOCK`` ++ - Unlock the latch. ++ ++ * - ``0xA5`` ++ - ``0x25`` ++ - ``-`` ++ - ``LATCH_REQUEST`` ++ - Request clipboard detachment. ++ ++ * - ``0xA5`` ++ - ``0x26`` ++ - ``-`` ++ - ``LATCH_CONFIRM`` ++ - Confirm clipboard detachment request. ++ ++ * - ``0xA5`` ++ - ``0x27`` ++ - ``-`` ++ - ``LATCH_HEARTBEAT`` ++ - Send heartbeat signal to EC. ++ ++ * - ``0xA5`` ++ - ``0x28`` ++ - ``-`` ++ - ``LATCH_CANCEL`` ++ - Cancel detachment process. ++ ++ * - ``0xA5`` ++ - ``0x29`` ++ - ``R`` ++ - ``GET_BASE_INFO`` ++ - Get current base/connection information. ++ ++ * - ``0xA5`` ++ - ``0x2A`` ++ - ``R`` ++ - ``GET_DEVICE_MODE`` ++ - Get current device operation mode. ++ ++ * - ``0xA5`` ++ - ``0x2B`` ++ - ``R`` ++ - ``GET_LATCH_STATUS`` ++ - Get current device latch status. ++ ++``SDTX_IOCTL_EVENTS_ENABLE`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x22)``. ++ ++Enable events for the current file descriptor. Events can be obtained by ++reading from the device, if enabled. Events are disabled by default. ++ ++``SDTX_IOCTL_EVENTS_DISABLE`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x22)``. ++ ++Disable events for the current file descriptor. Events can be obtained by ++reading from the device, if enabled. Events are disabled by default. ++ ++``SDTX_IOCTL_LATCH_LOCK`` ++^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x23)``. ++ ++Locks the latch, causing the detachment procedure to abort without opening ++the latch on timeout. The latch is unlocked by default. This command will be ++silently ignored if the latch is already locked. ++ ++``SDTX_IOCTL_LATCH_UNLOCK`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x24)``. ++ ++Unlocks the latch, causing the detachment procedure to open the latch on ++timeout. The latch is unlocked by default. This command will not open the ++latch when sent during an ongoing detachment process. It will be silently ++ignored if the latch is already unlocked. ++ ++``SDTX_IOCTL_LATCH_REQUEST`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x25)``. ++ ++Generic latch request. Behavior depends on the context: If no ++detachment-process is active, detachment is requested. Otherwise the ++currently active detachment-process will be aborted. ++ ++If a detachment process is canceled by this operation, a generic detachment ++request event (``SDTX_EVENT_REQUEST``) will be sent. ++ ++This essentially behaves the same as a detachment button press. ++ ++``SDTX_IOCTL_LATCH_CONFIRM`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x26)``. ++ ++Acknowledges and confirms a latch request. If sent during an ongoing ++detachment process, this command causes the latch to be opened immediately. ++The latch will also be opened if it has been locked. In this case, the latch ++lock is reset to the unlocked state. ++ ++This command will be silently ignored if there is currently no detachment ++procedure in progress. ++ ++``SDTX_IOCTL_LATCH_HEARTBEAT`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x27)``. ++ ++Sends a heartbeat, essentially resetting the detachment timeout. This ++command can be used to keep the detachment process alive while work required ++for the detachment to succeed is still in progress. ++ ++This command will be silently ignored if there is currently no detachment ++procedure in progress. ++ ++``SDTX_IOCTL_LATCH_CANCEL`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IO(0xA5, 0x28)``. ++ ++Cancels detachment in progress (if any). If a detachment process is canceled ++by this operation, a generic detachment request event ++(``SDTX_EVENT_REQUEST``) will be sent. ++ ++This command will be silently ignored if there is currently no detachment ++procedure in progress. ++ ++``SDTX_IOCTL_GET_BASE_INFO`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IOR(0xA5, 0x29, struct sdtx_base_info)``. ++ ++Get the current base connection state (i.e. attached/detached) and the type ++of the base connected to the clipboard. This is command essentially provides ++a way to query the information provided by the base connection change event ++(``SDTX_EVENT_BASE_CONNECTION``). ++ ++Possible values for ``struct sdtx_base_info.state`` are: ++ ++* ``SDTX_BASE_DETACHED``, ++* ``SDTX_BASE_ATTACHED``, and ++* ``SDTX_DETACH_NOT_FEASIBLE``. ++ ++Other values are reserved for future use. ++ ++``SDTX_IOCTL_GET_DEVICE_MODE`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IOR(0xA5, 0x2A, __u16)``. ++ ++Returns the device operation mode, indicating if and how the base is ++attached to the clipboard. This is command essentially provides a way to ++query the information provided by the device mode change event ++(``SDTX_EVENT_DEVICE_MODE``). ++ ++Returned values are: ++ ++* ``SDTX_DEVICE_MODE_LAPTOP`` ++* ``SDTX_DEVICE_MODE_TABLET`` ++* ``SDTX_DEVICE_MODE_STUDIO`` ++ ++See |sdtx_device_mode| for details. Other values are reserved for future ++use. ++ ++ ++``SDTX_IOCTL_GET_LATCH_STATUS`` ++^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ++ ++Defined as ``_IOR(0xA5, 0x2B, __u16)``. ++ ++Get the current latch status or (presumably) the last error encountered when ++trying to open/close the latch. This is command essentially provides a way ++to query the information provided by the latch status change event ++(``SDTX_EVENT_LATCH_STATUS``). ++ ++Returned values are: ++ ++* ``SDTX_LATCH_CLOSED``, ++* ``SDTX_LATCH_OPENED``, ++* ``SDTX_ERR_FAILED_TO_OPEN``, ++* ``SDTX_ERR_FAILED_TO_REMAIN_OPEN``, and ++* ``SDTX_ERR_FAILED_TO_CLOSE``. ++ ++Other values are reserved for future use. ++ ++A Note on Base IDs ++------------------ ++ ++Base types/IDs provided via ``SDTX_EVENT_BASE_CONNECTION`` or ++``SDTX_IOCTL_GET_BASE_INFO`` are directly forwarded from from the EC in the ++lower byte of the combined |__u16| value, with the driver storing the EC ++type from which this ID comes in the high byte (without this, base IDs over ++different types of ECs may be overlapping). ++ ++The ``SDTX_DEVICE_TYPE()`` macro can be used to determine the EC device ++type. This can be one of ++ ++* ``SDTX_DEVICE_TYPE_HID``, for Surface Aggregator Module over HID, and ++ ++* ``SDTX_DEVICE_TYPE_SSH``, for Surface Aggregator Module over Surface Serial ++ Hub. ++ ++Note that currently only the ``SSH`` type EC is supported, however ``HID`` ++type is reserved for future use. ++ ++Structures and Enums ++-------------------- ++ ++.. kernel-doc:: include/uapi/linux/surface_aggregator/dtx.h diff --git a/Documentation/driver-api/surface_aggregator/clients/index.rst b/Documentation/driver-api/surface_aggregator/clients/index.rst new file mode 100644 -index 000000000000..3ccabce23271 +index 000000000000..98ea9946b8a2 --- /dev/null +++ b/Documentation/driver-api/surface_aggregator/clients/index.rst -@@ -0,0 +1,21 @@ +@@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +=========================== @@ -661,6 +1764,7 @@ index 000000000000..3ccabce23271 + :maxdepth: 1 + + cdev ++ dtx + san + +.. only:: subproject and html @@ -1306,72 +2410,6 @@ index 000000000000..0b68228010e9 +(per party, effectively leading to synchronous communication regarding +frames) and at most three pending commands. The limit to synchronous frame +transfers seems to be consistent with behavior observed on Windows. -diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c -index 2f4641e5ecde..beb22d7e245e 100644 ---- a/drivers/acpi/acpica/dsopcode.c -+++ b/drivers/acpi/acpica/dsopcode.c -@@ -123,7 +123,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode, - - /* Offset is in bits, count is in bits */ - -- field_flags = AML_FIELD_ACCESS_BYTE; -+ field_flags = AML_FIELD_ACCESS_BUFFER; - bit_offset = offset; - bit_count = (u32) length_desc->integer.value; - -diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c -index b272c329d45d..cf547883a993 100644 ---- a/drivers/acpi/acpica/exfield.c -+++ b/drivers/acpi/acpica/exfield.c -@@ -102,6 +102,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, - void *buffer; - u32 function; - u16 accessor_type; -+ u8 field_flags; - - ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); - -@@ -199,11 +200,16 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, - * Note: Field.length is in bits. - */ - length = -- (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->field.bit_length); -+ (acpi_size)ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length); -+ field_flags = obj_desc->common_field.field_flags; - -- if (length > acpi_gbl_integer_byte_width) { -+ if (length > acpi_gbl_integer_byte_width || -+ (field_flags & AML_FIELD_ACCESS_TYPE_MASK) == AML_FIELD_ACCESS_BUFFER) { - -- /* Field is too large for an Integer, create a Buffer instead */ -+ /* -+ * Field is either too large for an Integer, or a actually of type -+ * buffer, so create a Buffer. -+ */ - - buffer_desc = acpi_ut_create_buffer_object(length); - if (!buffer_desc) { -@@ -366,19 +372,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, - } else if (obj_desc->field.region_obj->region.space_id == - ACPI_ADR_SPACE_GSBUS) { - accessor_type = obj_desc->field.attribute; -- length = -- acpi_ex_get_serial_access_length(accessor_type, -- obj_desc->field. -- access_length); -- -- /* -- * Add additional 2 bytes for the generic_serial_bus data buffer: -- * -- * Status; (Byte 0 of the data buffer) -- * Length; (Byte 1 of the data buffer) -- * Data[x-1]: (Bytes 2-x of the arbitrary length data buffer) -- */ -- length += 2; -+ length = source_desc->buffer.length; - function = ACPI_WRITE | (accessor_type << 16); - } else { /* IPMI */ - diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 77263b5f5915..75253cf45905 100644 --- a/drivers/misc/Kconfig @@ -5131,10 +6169,10 @@ index 000000000000..d43797590cd9 +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..e177e9873a0c +index 000000000000..114cf4c21172 --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_dtx.c -@@ -0,0 +1,1127 @@ +@@ -0,0 +1,1268 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface Book (gen. 2 and later) detachment system (DTX) driver. @@ -5166,98 +6204,7 @@ index 000000000000..e177e9873a0c + +#include +#include -+ -+ -+/* -- Public interface. ----------------------------------------------------- */ -+ -+/* Status/error categories */ -+#define SDTX_CATEGORY_STATUS 0x0000 -+#define SDTX_CATEGORY_RUNTIME_ERROR 0x1000 -+#define SDTX_CATEGORY_HARDWARE_ERROR 0x2000 -+#define SDTX_CATEGORY_UNKNOWN 0xf000 -+ -+#define SDTX_CATEGORY_MASK 0xf000 -+#define SDTX_CATEGORY(value) ((value) & SDTX_CATEGORY_MASK) -+ -+#define SDTX_STATUS(code) ((code) | SDTX_CATEGORY_STATUS) -+#define SDTX_ERR_RT(code) ((code) | SDTX_CATEGORY_RUNTIME_ERROR) -+#define SDTX_ERR_HW(code) ((code) | SDTX_CATEGORY_HARDWARE_ERROR) -+#define SDTX_UNKNOWN(code) ((code) | SDTX_CATEGORY_UNKNOWN) -+ -+#define SDTX_SUCCESS(value) (SDTX_CATEGORY(value) == SDTX_CATEGORY_STATUS) -+ -+/* Latch status values */ -+#define SDTX_LATCH_CLOSED SDTX_STATUS(0x00) -+#define SDTX_LATCH_OPENED SDTX_STATUS(0x01) -+ -+/* Base state values */ -+#define SDTX_BASE_DETACHED SDTX_STATUS(0x00) -+#define SDTX_BASE_ATTACHED SDTX_STATUS(0x01) -+ -+/* Runtime errors (non-critical) */ -+#define SDTX_DETACH_NOT_FEASIBLE SDTX_ERR_RT(0x01) -+#define SDTX_DETACH_TIMEDOUT SDTX_ERR_RT(0x02) -+ -+/* Hardware errors (critical) */ -+#define SDTX_ERR_FAILED_TO_OPEN SDTX_ERR_HW(0x01) -+#define SDTX_ERR_FAILED_TO_REMAIN_OPEN SDTX_ERR_HW(0x02) -+#define SDTX_ERR_FAILED_TO_CLOSE SDTX_ERR_HW(0x03) -+ -+ -+/* Base types */ -+#define SDTX_DEVICE_TYPE_HID 0x0100 -+#define SDTX_DEVICE_TYPE_SSH 0x0200 -+ -+#define SDTX_DEVICE_TYPE_MASK 0x0f00 -+#define SDTX_DEVICE_TYPE(value) ((value) & SDTX_DEVICE_TYPE_MASK) -+ -+#define SDTX_BASE_TYPE_HID(id) ((id) | SDTX_DEVICE_TYPE_HID) -+#define SDTX_BASE_TYPE_SSH(id) ((id) | SDTX_DEVICE_TYPE_SSH) -+ -+ -+/* Device mode */ -+enum sdtx_device_mode { -+ SDTX_DEVICE_MODE_TABLET = 0x00, -+ SDTX_DEVICE_MODE_LAPTOP = 0x01, -+ SDTX_DEVICE_MODE_STUDIO = 0x02, -+}; -+ -+ -+/* Event provided by reading from the device */ -+struct sdtx_event { -+ __u16 length; -+ __u16 code; -+ __u8 data[]; -+} __packed; -+ -+enum sdtx_event_code { -+ SDTX_EVENT_REQUEST = 1, -+ SDTX_EVENT_CANCEL = 2, -+ SDTX_EVENT_BASE_CONNECTION = 3, -+ SDTX_EVENT_LATCH_STATUS = 4, -+ SDTX_EVENT_DEVICE_MODE = 5, -+}; -+ -+ -+/* IOCTL interface */ -+struct sdtx_base_info { -+ __u16 state; -+ __u16 base_id; -+} __packed; -+ -+#define SDTX_IOCTL_EVENTS_ENABLE _IO(0xa5, 0x21) -+#define SDTX_IOCTL_EVENTS_DISABLE _IO(0xa5, 0x22) -+ -+#define SDTX_IOCTL_LATCH_LOCK _IO(0xa5, 0x23) -+#define SDTX_IOCTL_LATCH_UNLOCK _IO(0xa5, 0x24) -+#define SDTX_IOCTL_LATCH_REQUEST _IO(0xa5, 0x25) -+#define SDTX_IOCTL_LATCH_CONFIRM _IO(0xa5, 0x26) -+#define SDTX_IOCTL_LATCH_HEARTBEAT _IO(0xa5, 0x27) -+#define SDTX_IOCTL_LATCH_CANCEL _IO(0xa5, 0x28) -+ -+#define SDTX_IOCTL_GET_BASE_INFO _IOR(0xa5, 0x29, struct sdtx_base_info) -+#define SDTX_IOCTL_GET_DEVICE_MODE _IOR(0xa5, 0x2a, u16) -+#define SDTX_IOCTL_GET_LATCH_STATUS _IOR(0xa5, 0x2b, u16) ++#include + + +/* -- SSAM interface. ------------------------------------------------------- */ @@ -5269,30 +6216,29 @@ index 000000000000..e177e9873a0c + SAM_EVENT_CID_DTX_LATCH_STATUS = 0x11, +}; + -+enum dtx_base_state { -+ SDTX_BASE_STATE_DETACH_SUCCESS = 0x00, -+ SDTX_BASE_STATE_ATTACHED = 0x01, -+ SDTX_BASE_STATE_NOT_FEASIBLE = 0x02, ++enum ssam_bas_base_state { ++ SSAM_BAS_BASE_STATE_DETACH_SUCCESS = 0x00, ++ SSAM_BAS_BASE_STATE_ATTACHED = 0x01, ++ SSAM_BAS_BASE_STATE_NOT_FEASIBLE = 0x02, +}; + -+enum dtx_latch_status { -+ SDTX_LATCH_STATUS_CLOSED = 0x00, -+ SDTX_LATCH_STATUS_OPENED = 0x01, -+ SDTX_LATCH_STATUS_FAILED_TO_OPEN = 0x02, -+ SDTX_LATCH_STATUS_FAILED_TO_REMAIN_OPEN = 0x03, -+ SDTX_LATCH_STATUS_FAILED_TO_CLOSE = 0x04, ++enum ssam_bas_latch_status { ++ SSAM_BAS_LATCH_STATUS_CLOSED = 0x00, ++ SSAM_BAS_LATCH_STATUS_OPENED = 0x01, ++ SSAM_BAS_LATCH_STATUS_FAILED_TO_OPEN = 0x02, ++ SSAM_BAS_LATCH_STATUS_FAILED_TO_REMAIN_OPEN = 0x03, ++ SSAM_BAS_LATCH_STATUS_FAILED_TO_CLOSE = 0x04, +}; + -+enum dtx_cancel_reason { -+ SDTX_CANCEL_REASON_NOT_FEASIBLE = 0x00, // low battery -+ SDTX_CANCEL_REASON_TIMEOUT = 0x02, -+ SDTX_CANCEL_REASON_FAILED_TO_OPEN = 0x03, -+ SDTX_CANCEL_REASON_FAILED_TO_REMAIN_OPEN = 0x04, -+ SDTX_CANCEL_REASON_FAILED_TO_CLOSE = 0x05, ++enum ssam_bas_cancel_reason { ++ SSAM_BAS_CANCEL_REASON_NOT_FEASIBLE = 0x00, // low battery ++ SSAM_BAS_CANCEL_REASON_TIMEOUT = 0x02, ++ SSAM_BAS_CANCEL_REASON_FAILED_TO_OPEN = 0x03, ++ SSAM_BAS_CANCEL_REASON_FAILED_TO_REMAIN_OPEN = 0x04, ++ SSAM_BAS_CANCEL_REASON_FAILED_TO_CLOSE = 0x05, +}; + -+ -+struct ssam_dtx_base_info { ++struct ssam_bas_base_info { + u8 state; + u8 base_id; +} __packed; @@ -5339,7 +6285,7 @@ index 000000000000..e177e9873a0c + .instance_id = 0x00, +}); + -+static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_dtx_base_info, { ++static SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, { + .target_category = SSAM_SSH_TC_BAS, + .target_id = 0x01, + .command_id = 0x0c, @@ -5364,7 +6310,10 @@ index 000000000000..e177e9873a0c +/* -- Main structures. ------------------------------------------------------ */ + +enum sdtx_device_state { -+ SDTX_DEVICE_SHUTDOWN = BIT(0), ++ SDTX_DEVICE_SHUTDOWN_BIT = BIT(0), ++ SDTX_DEVICE_DIRTY_BASE_BIT = BIT(1), ++ SDTX_DEVICE_DIRTY_MODE_BIT = BIT(2), ++ SDTX_DEVICE_DIRTY_LATCH_BIT = BIT(3), +}; + +struct sdtx_device { @@ -5373,35 +6322,39 @@ index 000000000000..e177e9873a0c + + struct device *dev; + struct ssam_controller *ctrl; -+ unsigned long state; ++ unsigned long flags; + + struct miscdevice mdev; + wait_queue_head_t waitq; ++ struct mutex write_lock; + struct rw_semaphore client_lock; + struct list_head client_list; + ++ struct delayed_work state_work; ++ struct { ++ struct ssam_bas_base_info base; ++ u8 device_mode; ++ u8 latch_status; ++ } state; ++ + struct delayed_work mode_work; + struct input_dev *mode_switch; + + struct ssam_event_notifier notif; -+ -+ struct mutex mutex; -+ bool active; +}; + +enum sdtx_client_state { -+ SDTX_CLIENT_EVENTS_ENABLED = BIT(0), ++ SDTX_CLIENT_EVENTS_ENABLED_BIT = BIT(0), +}; + +struct sdtx_client { + struct sdtx_device *ddev; + struct list_head node; -+ unsigned long state; ++ unsigned long flags; + + struct fasync_struct *fasync; + + struct mutex read_lock; -+ spinlock_t write_lock; + DECLARE_KFIFO(buffer, u8, 512); +}; + @@ -5430,13 +6383,13 @@ index 000000000000..e177e9873a0c +static u16 sdtx_translate_base_state(struct sdtx_device *ddev, u8 state) +{ + switch (state) { -+ case SDTX_BASE_STATE_ATTACHED: ++ case SSAM_BAS_BASE_STATE_ATTACHED: + return SDTX_BASE_ATTACHED; + -+ case SDTX_BASE_STATE_DETACH_SUCCESS: ++ case SSAM_BAS_BASE_STATE_DETACH_SUCCESS: + return SDTX_BASE_DETACHED; + -+ case SDTX_BASE_STATE_NOT_FEASIBLE: ++ case SSAM_BAS_BASE_STATE_NOT_FEASIBLE: + return SDTX_DETACH_NOT_FEASIBLE; + + default: @@ -5448,19 +6401,19 @@ index 000000000000..e177e9873a0c +static u16 sdtx_translate_latch_status(struct sdtx_device *ddev, u8 status) +{ + switch (status) { -+ case SDTX_LATCH_STATUS_CLOSED: ++ case SSAM_BAS_LATCH_STATUS_CLOSED: + return SDTX_LATCH_CLOSED; + -+ case SDTX_LATCH_STATUS_OPENED: ++ case SSAM_BAS_LATCH_STATUS_OPENED: + return SDTX_LATCH_OPENED; + -+ case SDTX_LATCH_STATUS_FAILED_TO_OPEN: ++ case SSAM_BAS_LATCH_STATUS_FAILED_TO_OPEN: + return SDTX_ERR_FAILED_TO_OPEN; + -+ case SDTX_LATCH_STATUS_FAILED_TO_REMAIN_OPEN: ++ case SSAM_BAS_LATCH_STATUS_FAILED_TO_REMAIN_OPEN: + return SDTX_ERR_FAILED_TO_REMAIN_OPEN; + -+ case SDTX_LATCH_STATUS_FAILED_TO_CLOSE: ++ case SSAM_BAS_LATCH_STATUS_FAILED_TO_CLOSE: + return SDTX_ERR_FAILED_TO_CLOSE; + + default: @@ -5472,19 +6425,19 @@ index 000000000000..e177e9873a0c +static u16 sdtx_translate_cancel_reason(struct sdtx_device *ddev, u8 reason) +{ + switch (reason) { -+ case SDTX_CANCEL_REASON_NOT_FEASIBLE: ++ case SSAM_BAS_CANCEL_REASON_NOT_FEASIBLE: + return SDTX_DETACH_NOT_FEASIBLE; + -+ case SDTX_CANCEL_REASON_TIMEOUT: ++ case SSAM_BAS_CANCEL_REASON_TIMEOUT: + return SDTX_DETACH_TIMEDOUT; + -+ case SDTX_CANCEL_REASON_FAILED_TO_OPEN: ++ case SSAM_BAS_CANCEL_REASON_FAILED_TO_OPEN: + return SDTX_ERR_FAILED_TO_OPEN; + -+ case SDTX_CANCEL_REASON_FAILED_TO_REMAIN_OPEN: ++ case SSAM_BAS_CANCEL_REASON_FAILED_TO_REMAIN_OPEN: + return SDTX_ERR_FAILED_TO_REMAIN_OPEN; + -+ case SDTX_CANCEL_REASON_FAILED_TO_CLOSE: ++ case SSAM_BAS_CANCEL_REASON_FAILED_TO_CLOSE: + return SDTX_ERR_FAILED_TO_CLOSE; + + default: @@ -5499,7 +6452,7 @@ index 000000000000..e177e9873a0c +static int sdtx_ioctl_get_base_info(struct sdtx_device *ddev, + struct sdtx_base_info __user *buf) +{ -+ struct ssam_dtx_base_info raw; ++ struct ssam_bas_base_info raw; + struct sdtx_base_info info; + int status; + @@ -5547,11 +6500,11 @@ index 000000000000..e177e9873a0c + + switch (cmd) { + case SDTX_IOCTL_EVENTS_ENABLE: -+ set_bit(SDTX_CLIENT_EVENTS_ENABLED, &client->state); ++ set_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags); + return 0; + + case SDTX_IOCTL_EVENTS_DISABLE: -+ clear_bit(SDTX_CLIENT_EVENTS_ENABLED, &client->state); ++ clear_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags); + return 0; + + case SDTX_IOCTL_LATCH_LOCK: @@ -5596,7 +6549,7 @@ index 000000000000..e177e9873a0c + if (down_read_killable(&client->ddev->lock)) + return -ERESTARTSYS; + -+ if (test_bit(SDTX_DEVICE_SHUTDOWN, &client->ddev->state)) { ++ if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) { + up_read(&client->ddev->lock); + return -ENODEV; + } @@ -5627,7 +6580,6 @@ index 000000000000..e177e9873a0c + INIT_LIST_HEAD(&client->node); + + mutex_init(&client->read_lock); -+ spin_lock_init(&client->write_lock); + INIT_KFIFO(client->buffer); + + file->private_data = client; @@ -5636,7 +6588,7 @@ index 000000000000..e177e9873a0c + down_write(&ddev->client_lock); + + // do not add a new client if the device has been shut down -+ if (test_bit(SDTX_DEVICE_SHUTDOWN, &ddev->state)) { ++ if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { + up_write(&ddev->client_lock); + sdtx_device_put(client->ddev); + kfree(client); @@ -5677,7 +6629,7 @@ index 000000000000..e177e9873a0c + return -ERESTARTSYS; + + // make sure we're not shut down -+ if (test_bit(SDTX_DEVICE_SHUTDOWN, &ddev->state)) { ++ if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { + up_read(&ddev->lock); + return -ENODEV; + } @@ -5692,8 +6644,8 @@ index 000000000000..e177e9873a0c + + status = wait_event_interruptible(ddev->waitq, + !kfifo_is_empty(&client->buffer) -+ || test_bit(SDTX_DEVICE_SHUTDOWN, -+ &ddev->state)); ++ || test_bit(SDTX_DEVICE_SHUTDOWN_BIT, ++ &ddev->flags)); + if (status < 0) + return status; + @@ -5701,7 +6653,7 @@ index 000000000000..e177e9873a0c + return -ERESTARTSYS; + + // need to check that we're not shut down again -+ if (test_bit(SDTX_DEVICE_SHUTDOWN, &ddev->state)) { ++ if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags)) { + up_read(&ddev->lock); + return -ENODEV; + } @@ -5740,7 +6692,7 @@ index 000000000000..e177e9873a0c + if (down_read_killable(&client->ddev->lock)) + return -ERESTARTSYS; + -+ if (test_bit(SDTX_DEVICE_SHUTDOWN, &client->ddev->state)) { ++ if (test_bit(SDTX_DEVICE_SHUTDOWN_BIT, &client->ddev->flags)) { + up_read(&client->ddev->lock); + return EPOLLHUP | EPOLLERR; + } @@ -5790,12 +6742,12 @@ index 000000000000..e177e9873a0c +#define SDTX_DEVICE_MODE_DELAY_CONNECT msecs_to_jiffies(100) +#define SDTX_DEVICE_MODE_DELAY_RECHECK msecs_to_jiffies(100) + -+static void sdtx_device_mode_update(struct sdtx_device *ddev, unsigned long delay); ++static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay); + + +struct sdtx_status_event { + struct sdtx_event e; -+ u16 v; ++ __u16 v; +} __packed; + +struct sdtx_base_info_event { @@ -5809,6 +6761,7 @@ index 000000000000..e177e9873a0c + struct sdtx_base_info_event base; +}; + ++/* Must be executed with ddev->write_lock held. */ +static void sdtx_push_event(struct sdtx_device *ddev, struct sdtx_event *evt) +{ + const size_t len = sizeof(struct sdtx_event) + evt->length; @@ -5816,18 +6769,13 @@ index 000000000000..e177e9873a0c + + down_read(&ddev->client_lock); + list_for_each_entry(client, &ddev->client_list, node) { -+ if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED, &client->state)) ++ if (!test_bit(SDTX_CLIENT_EVENTS_ENABLED_BIT, &client->flags)) + continue; + -+ spin_lock(&client->write_lock); -+ -+ if (likely(kfifo_avail(&client->buffer) >= len)) { ++ if (likely(kfifo_avail(&client->buffer) >= len)) + kfifo_in(&client->buffer, (const u8 *)evt, len); -+ spin_unlock(&client->write_lock); -+ } else { -+ spin_unlock(&client->write_lock); ++ else + dev_warn(ddev->dev, "event buffer overrun\n"); -+ } + + kill_fasync(&client->fasync, SIGIO, POLL_IN); + } @@ -5871,11 +6819,23 @@ index 000000000000..e177e9873a0c + return 0; + } + ++ mutex_lock(&ddev->write_lock); ++ + // translate event + switch (in->command_id) { + case SAM_EVENT_CID_DTX_CONNECTION: -+ event.base.e.code = SDTX_EVENT_BASE_CONNECTION; ++ clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); ++ ++ // if state has not changed: do not send new event ++ if (ddev->state.base.state == in->data[0] ++ && ddev->state.base.base_id == in->data[1]) ++ goto out; ++ ++ ddev->state.base.state = in->data[0]; ++ ddev->state.base.base_id = in->data[1]; ++ + event.base.e.length = sizeof(struct sdtx_base_info); ++ event.base.e.code = SDTX_EVENT_BASE_CONNECTION; + event.base.v.state = sdtx_translate_base_state(ddev, in->data[0]); + event.base.v.base_id = SDTX_BASE_TYPE_SSH(in->data[1]); + break; @@ -5886,14 +6846,22 @@ index 000000000000..e177e9873a0c + break; + + case SAM_EVENT_CID_DTX_CANCEL: -+ event.status.e.code = SDTX_EVENT_CANCEL; + event.status.e.length = sizeof(u16); ++ event.status.e.code = SDTX_EVENT_CANCEL; + event.status.v = sdtx_translate_cancel_reason(ddev, in->data[0]); + break; + + case SAM_EVENT_CID_DTX_LATCH_STATUS: -+ event.status.e.code = SDTX_EVENT_LATCH_STATUS; ++ clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); ++ ++ // if state has not changed: do not send new event ++ if (ddev->state.latch_status == in->data[0]) ++ goto out; ++ ++ ddev->state.latch_status = in->data[0]; ++ + event.status.e.length = sizeof(u16); ++ event.status.e.code = SDTX_EVENT_LATCH_STATUS; + event.status.v = sdtx_translate_latch_status(ddev, in->data[0]); + break; + } @@ -5905,27 +6873,31 @@ index 000000000000..e177e9873a0c + unsigned long delay; + + delay = in->data[0] ? SDTX_DEVICE_MODE_DELAY_CONNECT : 0; -+ sdtx_device_mode_update(ddev, delay); ++ sdtx_update_device_mode(ddev, delay); + } + ++out: ++ mutex_unlock(&ddev->write_lock); + return SSAM_NOTIF_HANDLED; +} + + -+/* -- Tablet-mode switch. --------------------------------------------------- */ ++/* -- State update functions. ----------------------------------------------- */ + -+static void sdtx_device_mode_update(struct sdtx_device *ddev, unsigned long delay) ++static bool sdtx_device_mode_invalid(u8 mode, u8 base_state) +{ -+ schedule_delayed_work(&ddev->mode_work, delay); ++ return ((base_state == SSAM_BAS_BASE_STATE_ATTACHED) ++ && (mode == SDTX_DEVICE_MODE_TABLET)) ++ || ((base_state == SSAM_BAS_BASE_STATE_DETACH_SUCCESS) ++ && (mode != SDTX_DEVICE_MODE_TABLET)); +} + +static void sdtx_device_mode_workfn(struct work_struct *work) +{ + struct sdtx_device *ddev; + struct sdtx_status_event event; -+ struct ssam_dtx_base_info base; ++ struct ssam_bas_base_info base; + int status, tablet; -+ bool invalid; + u8 mode; + + ddev = container_of(work, struct sdtx_device, mode_work.work); @@ -5950,19 +6922,89 @@ index 000000000000..e177e9873a0c + * makes sense for the given base state and try again later if it + * doesn't. + */ -+ invalid = ((base.state == SDTX_BASE_STATE_ATTACHED) -+ && (mode == SDTX_DEVICE_MODE_TABLET)) -+ || ((base.state == SDTX_BASE_STATE_DETACH_SUCCESS) -+ && (mode != SDTX_DEVICE_MODE_TABLET)); -+ -+ if (invalid) { ++ if (sdtx_device_mode_invalid(mode, base.state)) { + dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); -+ sdtx_device_mode_update(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK); ++ sdtx_update_device_mode(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK); + return; + } + -+ event.e.code = SDTX_EVENT_DEVICE_MODE; ++ mutex_lock(&ddev->write_lock); ++ clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); ++ ++ // avoid sending duplicate device-mode events ++ if (ddev->state.device_mode == mode) { ++ mutex_unlock(&ddev->write_lock); ++ return; ++ } ++ ++ ddev->state.device_mode = mode; ++ + event.e.length = sizeof(u16); ++ event.e.code = SDTX_EVENT_DEVICE_MODE; ++ event.v = mode; ++ ++ sdtx_push_event(ddev, &event.e); ++ ++ // send SW_TABLET_MODE event ++ tablet = mode != SDTX_DEVICE_MODE_LAPTOP; ++ input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet); ++ input_sync(ddev->mode_switch); ++ ++ mutex_unlock(&ddev->write_lock); ++} ++ ++static void sdtx_update_device_mode(struct sdtx_device *ddev, unsigned long delay) ++{ ++ schedule_delayed_work(&ddev->mode_work, delay); ++} ++ ++ ++static void __sdtx_device_state_update_base(struct sdtx_device *ddev, ++ struct ssam_bas_base_info info) ++{ ++ struct sdtx_base_info_event event; ++ ++ // prevent duplicate events ++ if (ddev->state.base.state == info.state ++ && ddev->state.base.base_id == info.base_id) ++ return; ++ ++ ddev->state.base = info; ++ ++ event.e.length = sizeof(struct sdtx_base_info); ++ event.e.code = SDTX_EVENT_BASE_CONNECTION; ++ event.v.state = sdtx_translate_base_state(ddev, info.state); ++ event.v.base_id = SDTX_BASE_TYPE_SSH(info.base_id); ++ ++ sdtx_push_event(ddev, &event.e); ++} ++ ++static void __sdtx_device_state_update_mode(struct sdtx_device *ddev, u8 mode) ++{ ++ struct sdtx_status_event event; ++ int tablet; ++ ++ /* ++ * Note: This function must be called after updating the base state ++ * via __sdtx_device_state_update_base(), as we rely on the updated ++ * base state value in the validity check below. ++ */ ++ ++ if (sdtx_device_mode_invalid(mode, ddev->state.base.state)) { ++ dev_dbg(ddev->dev, "device mode is invalid, trying again\n"); ++ sdtx_update_device_mode(ddev, SDTX_DEVICE_MODE_DELAY_RECHECK); ++ return; ++ } ++ ++ // prevent duplicate events ++ if (ddev->state.device_mode == mode) ++ return; ++ ++ ddev->state.device_mode = mode; ++ ++ // send event ++ event.e.length = sizeof(u16); ++ event.e.code = SDTX_EVENT_DEVICE_MODE; + event.v = mode; + + sdtx_push_event(ddev, &event.e); @@ -5973,14 +7015,97 @@ index 000000000000..e177e9873a0c + input_sync(ddev->mode_switch); +} + ++static void __sdtx_device_state_update_latch(struct sdtx_device *ddev, u8 status) ++{ ++ struct sdtx_status_event event; ++ ++ // prevent duplicate events ++ if (ddev->state.latch_status == status) ++ return; ++ ++ ddev->state.latch_status = status; ++ ++ event.e.length = sizeof(struct sdtx_base_info); ++ event.e.code = SDTX_EVENT_BASE_CONNECTION; ++ event.v = sdtx_translate_latch_status(ddev, status); ++ ++ sdtx_push_event(ddev, &event.e); ++} ++ ++static void sdtx_device_state_workfn(struct work_struct *work) ++{ ++ struct sdtx_device *ddev; ++ struct ssam_bas_base_info base; ++ u8 mode, latch; ++ int status; ++ ++ ddev = container_of(work, struct sdtx_device, state_work.work); ++ ++ // mark everyting as dirty ++ set_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags); ++ set_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags); ++ set_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags); ++ ++ /* ++ * Ensure that the state gets marked as dirty before continuing to ++ * query it. Necessary to ensure that clear_bit() calls in ++ * sdtx_notifier() and sdtx_device_mode_workfn() actually clear these ++ * bits if an event is received while updating the state here. ++ */ ++ smp_mb__after_atomic(); ++ ++ status = ssam_bas_get_base(ddev->ctrl, &base); ++ if (status) { ++ dev_err(ddev->dev, "failed to get base state: %d\n", status); ++ return; ++ } ++ ++ status = ssam_bas_get_device_mode(ddev->ctrl, &mode); ++ if (status) { ++ dev_err(ddev->dev, "failed to get device mode: %d\n", status); ++ return; ++ } ++ ++ status = ssam_bas_get_latch_status(ddev->ctrl, &latch); ++ if (status) { ++ dev_err(ddev->dev, "failed to get latch status: %d\n", status); ++ return; ++ } ++ ++ mutex_lock(&ddev->write_lock); ++ ++ /* ++ * If the respective dirty-bit has been cleared, an event has been ++ * received, updating this state. The queried state may thus be out of ++ * date. At this point, we can safely assume that the state provided ++ * by the event is either up to date, or we're about to receive ++ * another event updating it. ++ */ ++ ++ if (test_and_clear_bit(SDTX_DEVICE_DIRTY_BASE_BIT, &ddev->flags)) ++ __sdtx_device_state_update_base(ddev, base); ++ ++ if (test_and_clear_bit(SDTX_DEVICE_DIRTY_MODE_BIT, &ddev->flags)) ++ __sdtx_device_state_update_mode(ddev, mode); ++ ++ if (test_and_clear_bit(SDTX_DEVICE_DIRTY_LATCH_BIT, &ddev->flags)) ++ __sdtx_device_state_update_latch(ddev, latch); ++ ++ mutex_unlock(&ddev->write_lock); ++} ++ ++static void sdtx_update_device_state(struct sdtx_device *ddev, unsigned long delay) ++{ ++ schedule_delayed_work(&ddev->state_work, delay); ++} ++ + +/* -- Common device initialization. ----------------------------------------- */ + +static int sdtx_device_init(struct sdtx_device *ddev, struct device *dev, + struct ssam_controller *ctrl) +{ -+ int status; -+ u8 mode; ++ int status, tablet_mode; + + // basic initialization + kref_init(&ddev->kref); @@ -6001,17 +7126,35 @@ index 000000000000..e177e9873a0c + ddev->notif.event.flags = SSAM_EVENT_SEQUENCED; + + init_waitqueue_head(&ddev->waitq); ++ mutex_init(&ddev->write_lock); + init_rwsem(&ddev->client_lock); + INIT_LIST_HEAD(&ddev->client_list); + + INIT_DELAYED_WORK(&ddev->mode_work, sdtx_device_mode_workfn); ++ INIT_DELAYED_WORK(&ddev->state_work, sdtx_device_state_workfn); + -+ // get current device mode -+ status = ssam_bas_get_device_mode(ddev->ctrl, &mode); ++ /* ++ * Get current device state. We want to guarantee that events are only ++ * sent when state actually changes. Thus we cannot use special ++ * "uninitialized" values, as that would cause problems when manually ++ * querying the state in surface_dtx_pm_complete(). I.e. we would not ++ * be able to detect state changes there if no change event has been ++ * received between driver initialization and first device suspension. ++ * ++ * Note that we also need to do this before registring the event ++ * notifier, as that may access the state values. ++ */ ++ status = ssam_bas_get_base(ddev->ctrl, &ddev->state.base); + if (status) + return status; + -+ mode = (mode != SDTX_DEVICE_MODE_LAPTOP); ++ status = ssam_bas_get_device_mode(ddev->ctrl, &ddev->state.device_mode); ++ if (status) ++ return status; ++ ++ status = ssam_bas_get_latch_status(ddev->ctrl, &ddev->state.latch_status); ++ if (status) ++ return status; + + // set up tablet mode switch + ddev->mode_switch = input_allocate_device(); @@ -6023,8 +7166,9 @@ index 000000000000..e177e9873a0c + ddev->mode_switch->id.bustype = BUS_HOST; + ddev->mode_switch->dev.parent = ddev->dev; + ++ tablet_mode = (ddev->state.device_mode != SDTX_DEVICE_MODE_LAPTOP); + input_set_capability(ddev->mode_switch, EV_SW, SW_TABLET_MODE); -+ input_report_switch(ddev->mode_switch, SW_TABLET_MODE, mode); ++ input_report_switch(ddev->mode_switch, SW_TABLET_MODE, tablet_mode); + + status = input_register_device(ddev->mode_switch); + if (status) { @@ -6043,13 +7187,10 @@ index 000000000000..e177e9873a0c + goto err_mdev; + + /* -+ * Update device mode in case it has changed between getting the -+ * initial mode and registring the event notifier. Note that this is -+ * safe with regards to concurrent connection change events as the -+ * update work will actually check for consistency with base info. ++ * Update device state in case it has changed between getting the ++ * initial mode and registring the event notifier. + */ -+ sdtx_device_mode_update(ddev, 0); -+ ++ sdtx_update_device_state(ddev, 0); + return 0; + +err_notif: @@ -6096,7 +7237,7 @@ index 000000000000..e177e9873a0c + * Mark device as shut-down. Prevent new clients from being added and + * new operations from being executed. + */ -+ set_bit(SDTX_DEVICE_SHUTDOWN, &ddev->state); ++ set_bit(SDTX_DEVICE_SHUTDOWN_BIT, &ddev->flags); + + // wake up async clients + down_write(&ddev->client_lock); @@ -6129,6 +7270,43 @@ index 000000000000..e177e9873a0c +} + + ++/* -- PM ops. --------------------------------------------------------------- */ ++ ++#ifdef CONFIG_PM_SLEEP ++ ++static void surface_dtx_pm_complete(struct device *dev) ++{ ++ struct sdtx_device *ddev = dev_get_drvdata(dev); ++ ++ /* ++ * Normally, the EC will store events while suspended (i.e. in ++ * display-off state) and release them when resumed (i.e. transitioned ++ * to display-on state). During hibernation, however, the EC will be ++ * shut down and does not store events. Furthermore, events might be ++ * dropped during prolonged suspension (it is scurrently unknown how ++ * big this event buffer is and how it behaves on overruns). ++ * ++ * To prevent any problems, we update the device state here. We do ++ * this delayed to ensure that any events sent by the EC directly ++ * after resuming will be handled first. The delay below has been ++ * chosen (experimentally), so that there should be ample time for ++ * these events to be handled, before we check and, if necessary, ++ * update the state. ++ */ ++ sdtx_update_device_state(ddev, msecs_to_jiffies(1000)); ++} ++ ++static const struct dev_pm_ops surface_dtx_pm_ops = { ++ .complete = surface_dtx_pm_complete, ++}; ++ ++#else /* CONFIG_PM_SLEEP */ ++ ++static const struct dev_pm_ops surface_dtx_pm_ops = {}; ++ ++#endif /* CONFIG_PM_SLEEP */ ++ ++ +/* -- Platform driver. ------------------------------------------------------ */ + +static int surface_dtx_platform_probe(struct platform_device *pdev) @@ -6168,6 +7346,7 @@ index 000000000000..e177e9873a0c + .driver = { + .name = "surface_dtx_pltf", + .acpi_match_table = surface_dtx_acpi_match, ++ .pm = &surface_dtx_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; @@ -17147,188 +18326,29 @@ index 000000000000..232bf1142aae +#define TRACE_INCLUDE_FILE trace + +#include -diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c -index c66a04d24f1d..1b18d12d217f 100644 ---- a/drivers/tty/serdev/core.c -+++ b/drivers/tty/serdev/core.c -@@ -496,16 +496,97 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl) - } - - #ifdef CONFIG_ACPI -+ -+#define SERDEV_ACPI_MAX_SCAN_DEPTH 32 -+ -+struct acpi_serdev_lookup { -+ acpi_handle device_handle; -+ acpi_handle controller_handle; -+ int n; -+ int index; -+}; -+ -+static int acpi_serdev_parse_resource(struct acpi_resource *ares, void *data) -+{ -+ struct acpi_serdev_lookup *lookup = data; -+ struct acpi_resource_uart_serialbus *sb; -+ acpi_status status; -+ -+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) -+ return 1; -+ -+ if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART) -+ return 1; -+ -+ if (lookup->index != -1 && lookup->n++ != lookup->index) -+ return 1; -+ -+ sb = &ares->data.uart_serial_bus; -+ -+ status = acpi_get_handle(lookup->device_handle, -+ sb->resource_source.string_ptr, -+ &lookup->controller_handle); -+ if (ACPI_FAILURE(status)) -+ return 1; -+ -+ /* -+ * NOTE: Ideally, we would also want to retreive other properties here, -+ * once setting them before opening the device is supported by serdev. -+ */ -+ -+ return 1; -+} -+ -+static int acpi_serdev_do_lookup(struct acpi_device *adev, -+ struct acpi_serdev_lookup *lookup) -+{ -+ struct list_head resource_list; -+ int ret; -+ -+ lookup->device_handle = acpi_device_handle(adev); -+ lookup->controller_handle = NULL; -+ lookup->n = 0; -+ -+ INIT_LIST_HEAD(&resource_list); -+ ret = acpi_dev_get_resources(adev, &resource_list, -+ acpi_serdev_parse_resource, lookup); -+ acpi_dev_free_resource_list(&resource_list); -+ -+ if (ret < 0) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+static int acpi_serdev_check_resources(struct serdev_controller *ctrl, -+ struct acpi_device *adev) -+{ -+ struct acpi_serdev_lookup lookup; -+ int ret; -+ -+ if (acpi_bus_get_status(adev) || !adev->status.present) -+ return -EINVAL; -+ -+ /* Look for UARTSerialBusV2 resource */ -+ lookup.index = -1; // we only care for the last device -+ -+ ret = acpi_serdev_do_lookup(adev, &lookup); -+ if (ret) -+ return ret; -+ -+ /* Make sure controller and ResourceSource handle match */ -+ if (ACPI_HANDLE(ctrl->dev.parent) != lookup.controller_handle) -+ return -ENODEV; -+ -+ return 0; -+} -+ - static acpi_status acpi_serdev_register_device(struct serdev_controller *ctrl, -- struct acpi_device *adev) -+ struct acpi_device *adev) - { -- struct serdev_device *serdev = NULL; -+ struct serdev_device *serdev; - int err; - -- if (acpi_bus_get_status(adev) || !adev->status.present || -- acpi_device_enumerated(adev)) -- return AE_OK; -- - serdev = serdev_device_alloc(ctrl); - if (!serdev) { - dev_err(&ctrl->dev, "failed to allocate serdev device for %s\n", -@@ -533,7 +614,7 @@ static const struct acpi_device_id serdev_acpi_devices_blacklist[] = { - }; - - static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, -- void *data, void **return_value) -+ void *data, void **return_value) - { - struct serdev_controller *ctrl = data; - struct acpi_device *adev; -@@ -541,26 +622,32 @@ static acpi_status acpi_serdev_add_device(acpi_handle handle, u32 level, - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - -+ if (acpi_device_enumerated(adev)) -+ return AE_OK; -+ - /* Skip if black listed */ - if (!acpi_match_device_ids(adev, serdev_acpi_devices_blacklist)) - return AE_OK; - -+ if (acpi_serdev_check_resources(ctrl, adev)) -+ return AE_OK; -+ - return acpi_serdev_register_device(ctrl, adev); - } - -+ - static int acpi_serdev_register_devices(struct serdev_controller *ctrl) - { - acpi_status status; -- acpi_handle handle; - -- handle = ACPI_HANDLE(ctrl->dev.parent); -- if (!handle) -+ if (!has_acpi_companion(ctrl->dev.parent)) - return -ENODEV; - -- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, -+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, -+ SERDEV_ACPI_MAX_SCAN_DEPTH, - acpi_serdev_add_device, NULL, ctrl, NULL); - if (ACPI_FAILURE(status)) -- dev_dbg(&ctrl->dev, "failed to enumerate serdev slaves\n"); -+ dev_warn(&ctrl->dev, "failed to enumerate serdev slaves\n"); - - if (!ctrl->serdev) - return -ENODEV; diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h -index 610cdf8082f2..2c8dd2abbd04 100644 +index 69f4527315e7..2c8dd2abbd04 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h -@@ -768,4 +768,22 @@ struct typec_device_id { - kernel_ulong_t driver_data; - }; +@@ -770,15 +770,16 @@ struct typec_device_id { -+/* Surface System Aggregator Module */ -+ + /* Surface System Aggregator Module */ + +-#define SSAM_MATCH_CHANNEL 0x1 +#define SSAM_MATCH_TARGET 0x1 -+#define SSAM_MATCH_INSTANCE 0x2 -+#define SSAM_MATCH_FUNCTION 0x4 -+ -+struct ssam_device_id { -+ __u8 match_flags; -+ + #define SSAM_MATCH_INSTANCE 0x2 + #define SSAM_MATCH_FUNCTION 0x4 + + struct ssam_device_id { + __u8 match_flags; + + __u8 domain; -+ __u8 category; + __u8 category; +- __u8 channel; + __u8 target; -+ __u8 instance; -+ __u8 function; -+ -+ kernel_ulong_t driver_data; -+}; -+ - #endif /* LINUX_MOD_DEVICETABLE_H */ + __u8 instance; + __u8 function; + diff --git a/include/linux/surface_acpi_notify.h b/include/linux/surface_acpi_notify.h new file mode 100644 index 000000000000..8e3e86c7d78c @@ -19294,7 +20314,7 @@ index 000000000000..3974535796ca +#endif /* _LINUX_SURFACE_AGGREGATOR_SERIAL_HUB_H */ diff --git a/include/uapi/linux/surface_aggregator/cdev.h b/include/uapi/linux/surface_aggregator/cdev.h new file mode 100644 -index 000000000000..e85351141a2d +index 000000000000..1a8bc0249f8e --- /dev/null +++ b/include/uapi/linux/surface_aggregator/cdev.h @@ -0,0 +1,58 @@ @@ -19312,8 +20332,8 @@ index 000000000000..e85351141a2d +#ifndef _UAPI_LINUX_SURFACE_AGGREGATOR_CDEV_H +#define _UAPI_LINUX_SURFACE_AGGREGATOR_CDEV_H + -+#include +#include ++#include + +/** + * struct ssam_cdev_request - Controller request IOCTL argument. @@ -19356,65 +20376,208 @@ index 000000000000..e85351141a2d +#define SSAM_CDEV_REQUEST _IOWR(0xA5, 1, struct ssam_cdev_request) + +#endif /* _UAPI_LINUX_SURFACE_AGGREGATOR_CDEV_H */ +diff --git a/include/uapi/linux/surface_aggregator/dtx.h b/include/uapi/linux/surface_aggregator/dtx.h +new file mode 100644 +index 000000000000..d88cabfb8dd7 +--- /dev/null ++++ b/include/uapi/linux/surface_aggregator/dtx.h +@@ -0,0 +1,150 @@ ++/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ ++/* ++ * Surface DTX (clipboard detachment system driver) user-space interface. ++ * ++ * Definitions, structs, and IOCTLs for the /dev/surface/dtx misc device. This ++ * device allows user-space to control the clipboard detachment process on ++ * Surface Book series devices. ++ * ++ * Copyright (C) 2020 Maximilian Luz ++ */ ++ ++#ifndef _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H ++#define _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H ++ ++#include ++#include ++ ++ ++/* Status/error categories */ ++#define SDTX_CATEGORY_STATUS 0x0000 ++#define SDTX_CATEGORY_RUNTIME_ERROR 0x1000 ++#define SDTX_CATEGORY_HARDWARE_ERROR 0x2000 ++#define SDTX_CATEGORY_UNKNOWN 0xf000 ++ ++#define SDTX_CATEGORY_MASK 0xf000 ++#define SDTX_CATEGORY(value) ((value) & SDTX_CATEGORY_MASK) ++ ++#define SDTX_STATUS(code) ((code) | SDTX_CATEGORY_STATUS) ++#define SDTX_ERR_RT(code) ((code) | SDTX_CATEGORY_RUNTIME_ERROR) ++#define SDTX_ERR_HW(code) ((code) | SDTX_CATEGORY_HARDWARE_ERROR) ++#define SDTX_UNKNOWN(code) ((code) | SDTX_CATEGORY_UNKNOWN) ++ ++#define SDTX_SUCCESS(value) (SDTX_CATEGORY(value) == SDTX_CATEGORY_STATUS) ++ ++/* Latch status values */ ++#define SDTX_LATCH_CLOSED SDTX_STATUS(0x00) ++#define SDTX_LATCH_OPENED SDTX_STATUS(0x01) ++ ++/* Base state values */ ++#define SDTX_BASE_DETACHED SDTX_STATUS(0x00) ++#define SDTX_BASE_ATTACHED SDTX_STATUS(0x01) ++ ++/* Runtime errors (non-critical) */ ++#define SDTX_DETACH_NOT_FEASIBLE SDTX_ERR_RT(0x01) ++#define SDTX_DETACH_TIMEDOUT SDTX_ERR_RT(0x02) ++ ++/* Hardware errors (critical) */ ++#define SDTX_ERR_FAILED_TO_OPEN SDTX_ERR_HW(0x01) ++#define SDTX_ERR_FAILED_TO_REMAIN_OPEN SDTX_ERR_HW(0x02) ++#define SDTX_ERR_FAILED_TO_CLOSE SDTX_ERR_HW(0x03) ++ ++ ++/* Base types */ ++#define SDTX_DEVICE_TYPE_HID 0x0100 ++#define SDTX_DEVICE_TYPE_SSH 0x0200 ++ ++#define SDTX_DEVICE_TYPE_MASK 0x0f00 ++#define SDTX_DEVICE_TYPE(value) ((value) & SDTX_DEVICE_TYPE_MASK) ++ ++#define SDTX_BASE_TYPE_HID(id) ((id) | SDTX_DEVICE_TYPE_HID) ++#define SDTX_BASE_TYPE_SSH(id) ((id) | SDTX_DEVICE_TYPE_SSH) ++ ++ ++/** ++ * enum sdtx_device_mode - Mode describing how (and if) the clipboard is ++ * attached to the base of the device. ++ * @SDTX_DEVICE_MODE_TABLET: The clipboard is detached from the base and the ++ * device operates as tablet. ++ * @SDTX_DEVICE_MODE_LAPTOP: The clipboard is attached normally to the base ++ * and the device operates as laptop. ++ * @SDTX_DEVICE_MODE_STUDIO: The clipboard is attached to the base in reverse. ++ * The device operates as tablet with keyboard and ++ * touchpad deactivated, however, the base battery ++ * and, if present in the specific device model, dGPU ++ * are available to the system. ++ */ ++enum sdtx_device_mode { ++ SDTX_DEVICE_MODE_TABLET = 0x00, ++ SDTX_DEVICE_MODE_LAPTOP = 0x01, ++ SDTX_DEVICE_MODE_STUDIO = 0x02, ++}; ++ ++/** ++ * struct sdtx_event - Event provided by reading from the DTX device file. ++ * @length: Length of the event payload, in bytes. ++ * @code: Event code, detailing what type of event this is. ++ * @data: Payload of the event, containing @length bytes. ++ * ++ * See &enum sdtx_event_code for currently valid event codes. ++ */ ++struct sdtx_event { ++ __u16 length; ++ __u16 code; ++ __u8 data[]; ++} __packed; ++ ++/** ++ * enum sdtx_event_code - Code describing the type of an event. ++ * @SDTX_EVENT_REQUEST: Detachment request event type. ++ * @SDTX_EVENT_CANCEL: Cancel detachment process event type. ++ * @SDTX_EVENT_BASE_CONNECTION: Base/clipboard connection change event type. ++ * @SDTX_EVENT_LATCH_STATUS: Latch status change event type. ++ * @SDTX_EVENT_DEVICE_MODE: Device mode change event type. ++ * ++ * Used in @struct sdtx_event to describe the type of the event. Further event ++ * codes are reserved for future use. Any event parser should be able to ++ * gracefully handle unknown events, i.e. by simply skipping them. ++ * ++ * Consult the DTX user-space interface documentation for details regarding ++ * the individual event types. ++ */ ++enum sdtx_event_code { ++ SDTX_EVENT_REQUEST = 1, ++ SDTX_EVENT_CANCEL = 2, ++ SDTX_EVENT_BASE_CONNECTION = 3, ++ SDTX_EVENT_LATCH_STATUS = 4, ++ SDTX_EVENT_DEVICE_MODE = 5, ++}; ++ ++/** ++ * struct sdtx_base_info - Describes if and what type of base is connected. ++ * @state: The state of the connection. Valid values are %SDTX_BASE_DETACHED, ++ * %SDTX_BASE_ATTACHED, and %SDTX_DETACH_NOT_FEASIBLE (in case a base ++ * is attached but low clipboard battery prevents detachment). Other ++ * values are currently reserved. ++ * @base_id: The type of base connected. Zero if no base is connected. ++ */ ++struct sdtx_base_info { ++ __u16 state; ++ __u16 base_id; ++} __packed; ++ ++ ++/* IOCTLs */ ++#define SDTX_IOCTL_EVENTS_ENABLE _IO(0xa5, 0x21) ++#define SDTX_IOCTL_EVENTS_DISABLE _IO(0xa5, 0x22) ++ ++#define SDTX_IOCTL_LATCH_LOCK _IO(0xa5, 0x23) ++#define SDTX_IOCTL_LATCH_UNLOCK _IO(0xa5, 0x24) ++ ++#define SDTX_IOCTL_LATCH_REQUEST _IO(0xa5, 0x25) ++#define SDTX_IOCTL_LATCH_CONFIRM _IO(0xa5, 0x26) ++#define SDTX_IOCTL_LATCH_HEARTBEAT _IO(0xa5, 0x27) ++#define SDTX_IOCTL_LATCH_CANCEL _IO(0xa5, 0x28) ++ ++#define SDTX_IOCTL_GET_BASE_INFO _IOR(0xa5, 0x29, struct sdtx_base_info) ++#define SDTX_IOCTL_GET_DEVICE_MODE _IOR(0xa5, 0x2a, __u16) ++#define SDTX_IOCTL_GET_LATCH_STATUS _IOR(0xa5, 0x2b, __u16) ++ ++#endif /* _UAPI_LINUX_SURFACE_AGGREGATOR_DTX_H */ diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c -index 293004499b4d..6a319852083e 100644 +index 13acbf55c6fd..6a319852083e 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c -@@ -225,5 +225,13 @@ int main(void) - DEVID_FIELD(typec_device_id, svid); - DEVID_FIELD(typec_device_id, mode); +@@ -227,8 +227,9 @@ int main(void) -+ DEVID(ssam_device_id); -+ DEVID_FIELD(ssam_device_id, match_flags); + DEVID(ssam_device_id); + DEVID_FIELD(ssam_device_id, match_flags); + DEVID_FIELD(ssam_device_id, domain); -+ DEVID_FIELD(ssam_device_id, category); + DEVID_FIELD(ssam_device_id, category); +- DEVID_FIELD(ssam_device_id, channel); + DEVID_FIELD(ssam_device_id, target); -+ DEVID_FIELD(ssam_device_id, instance); -+ DEVID_FIELD(ssam_device_id, function); -+ - return 0; - } + DEVID_FIELD(ssam_device_id, instance); + DEVID_FIELD(ssam_device_id, function); + diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c -index 7f40b6aab689..f171616ab318 100644 +index 76e3b1d7db45..f171616ab318 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c -@@ -1276,6 +1276,28 @@ static int do_typec_entry(const char *filename, void *symval, char *alias) +@@ -1276,20 +1276,22 @@ static int do_typec_entry(const char *filename, void *symval, char *alias) return 1; } +-/* Looks like: ssam:cNtNiNfN +/* + * Looks like: ssam:dNcNtNiNfN -+ * -+ * N is exactly 2 digits, where each is an upper-case hex digit. -+ */ -+static int do_ssam_entry(const char *filename, void *symval, char *alias) -+{ -+ DEF_FIELD(symval, ssam_device_id, match_flags); + * + * N is exactly 2 digits, where each is an upper-case hex digit. + */ + static int do_ssam_entry(const char *filename, void *symval, char *alias) + { + DEF_FIELD(symval, ssam_device_id, match_flags); + DEF_FIELD(symval, ssam_device_id, domain); -+ DEF_FIELD(symval, ssam_device_id, category); + DEF_FIELD(symval, ssam_device_id, category); +- DEF_FIELD(symval, ssam_device_id, channel); + DEF_FIELD(symval, ssam_device_id, target); -+ DEF_FIELD(symval, ssam_device_id, instance); -+ DEF_FIELD(symval, ssam_device_id, function); -+ + DEF_FIELD(symval, ssam_device_id, instance); + DEF_FIELD(symval, ssam_device_id, function); + +- sprintf(alias, "ssam:c%02X", category); +- ADD(alias, "t", match_flags & SSAM_MATCH_CHANNEL, channel); + sprintf(alias, "ssam:d%02Xc%02X", domain, category); + ADD(alias, "t", match_flags & SSAM_MATCH_TARGET, target); -+ ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); -+ ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); -+ -+ return 1; -+} -+ - /* Does namelen bytes of name exactly match the symbol? */ - static bool sym_is(const char *name, unsigned namelen, const char *symbol) - { -@@ -1346,6 +1368,7 @@ static const struct devtable devtable[] = { - {"fslmc", SIZE_fsl_mc_device_id, do_fsl_mc_entry}, - {"tbsvc", SIZE_tb_service_id, do_tbsvc_entry}, - {"typec", SIZE_typec_device_id, do_typec_entry}, -+ {"ssam", SIZE_ssam_device_id, do_ssam_entry}, - }; + ADD(alias, "i", match_flags & SSAM_MATCH_INSTANCE, instance); + ADD(alias, "f", match_flags & SSAM_MATCH_FUNCTION, function); - /* Create MODULE_ALIAS() statements. -- 2.28.0 diff --git a/patches/4.19/0011-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch b/patches/4.19/0011-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch index c8a99c0d8..1ccc3d8b7 100644 --- a/patches/4.19/0011-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch +++ b/patches/4.19/0011-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch @@ -1,8 +1,8 @@ -From e134b2f1c836a5beef7d16d86393744387bb4830 Mon Sep 17 00:00:00 2001 +From c523e2ba98307da63f228ec499d9f011e4ebd916 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 14 Oct 2020 16:41:58 +0200 -Subject: [PATCH 11/11] i2c: core: Restore acpi_walk_dep_device_list() getting - called after registering the ACPI i2c devs +Subject: [PATCH] i2c: core: Restore acpi_walk_dep_device_list() getting called + after registering the ACPI i2c devs Commit 21653a4181ff ("i2c: core: Call i2c_acpi_install_space_handler() before i2c_acpi_register_devices()")'s intention was to only move the diff --git a/pkg/arch/kernel-lts/0008-surface-gpe.patch b/pkg/arch/kernel-lts/0008-surface-gpe.patch new file mode 120000 index 000000000..e684c85b0 --- /dev/null +++ b/pkg/arch/kernel-lts/0008-surface-gpe.patch @@ -0,0 +1 @@ +../../../patches/4.19/0008-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel-lts/0008-surface-sam.patch b/pkg/arch/kernel-lts/0008-surface-sam.patch deleted file mode 120000 index ecaca8ac4..000000000 --- a/pkg/arch/kernel-lts/0008-surface-sam.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/4.19/0008-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel-lts/0010-surface-gpe.patch b/pkg/arch/kernel-lts/0010-surface-gpe.patch deleted file mode 120000 index fcd545d35..000000000 --- a/pkg/arch/kernel-lts/0010-surface-gpe.patch +++ /dev/null @@ -1 +0,0 @@ -../../../patches/4.19/0010-surface-gpe.patch \ No newline at end of file diff --git a/pkg/arch/kernel-lts/0010-surface-sam.patch b/pkg/arch/kernel-lts/0010-surface-sam.patch new file mode 120000 index 000000000..64c8766fe --- /dev/null +++ b/pkg/arch/kernel-lts/0010-surface-sam.patch @@ -0,0 +1 @@ +../../../patches/4.19/0010-surface-sam.patch \ No newline at end of file diff --git a/pkg/arch/kernel-lts/PKGBUILD b/pkg/arch/kernel-lts/PKGBUILD index 5ce25fc29..935308ed7 100644 --- a/pkg/arch/kernel-lts/PKGBUILD +++ b/pkg/arch/kernel-lts/PKGBUILD @@ -27,9 +27,9 @@ source=( 0005-suspend.patch 0006-ipts.patch 0007-wifi.patch - 0008-surface-sam.patch + 0008-surface-gpe.patch 0009-surface-sam-over-hid.patch - 0010-surface-gpe.patch + 0010-surface-sam.patch 0011-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch ) validpgpkeys=( @@ -42,17 +42,17 @@ sha256sums=('c7b134c6d45f77df0909c225300e64379d7f9d69abd9ad73ff6a289aa2b6a36e' '4e68572e7cc4c5368f0236e0792660ae8498373988625dca46e509399a7eaea6' 'a13581d3c6dc595206e4fe7fcf6b542e7a1bdbe96101f0f010fc5be49f99baf2' '1c4963e4a911e74ed56f1fe0065c31201edca9a5e3f89eb30b7063f9981ebdd8' - '3892c3974f53e87e2efa059326359c3108bba1a411eecd5a2b614174384e8755' - 'e73d7567a23d10babda2124a65337c8f57ff61fbb1c65a629afdfcc7a3d542e2' - '33c4264b920e2e4466de8369e3f2fcf3383c2e0eb68dacff82e107ae9f8d2354' - '20c72eea089af4ca105bec93bd7c7e91c2e8fbe5d24c88188e4ca2c77699a7ab' - '776ce945b51e59c543e19cc9e006b5047b22ec06255c2cce1163152aa3c65894' - '6185565a16689190140e6fe19df4d51fac4eeb1ac4a927855ec555f2274d7d0c' - 'd205cf4756307c6c0909e26ca4b2ca45354a82df29255cd5809caf4b6aed41e1' - '0f5f2b61befacc735689604af5f6641b6b490d83745f4c78d13e9d2621e6f383' - '227182760913e58b9e42efd3315136379bd2c0a6cb5116ac7659baf98a40dcfe' - 'f50f44b4c132387923ee0fd1209ec860e4ab9d33ef03155ae36596d52f8e3ae4' - '2de700c366cf3273f49d02efc5dc0416a5ff12eccf3d7847f21f1923458f1883') + '111b4f7814d49c06f3f328feba30c8991e423acce36aa9c737a31489a64b9e5d' + 'b85aa40e2c3c04514aa14538c7486653cc987276acffae532e3b8516d3328bfc' + '602fb64b0b2073e0b016f39be34d86113fb0b3e63b4490cc26611d1313b3665e' + '99bc4ce339713433a06d936bb6c339d2797b6bec8e7af91be017bcf30bc658b3' + '0d0bd51185191cdc29405db26cfa8d79debb85aa090931672b8ac5c3ee4a7e10' + '0383649af9c5f63c47b515d03e9279a4090fec1fb32a9d47692a491c80f5a1b5' + 'e5fd01b8fdb8c53f46ac58fdffd4d7a75f009217e5f2a484ac00a6bb9968eab4' + '4a5c643ec9a3c3e15ceff45e024fce0462dc314b516fe0620de6858178d96fc8' + 'f28bc22540ad92769c4bd787140ab759f665f262f1c9cb8827010d8c8f6c5d4c' + '71deb9a7421a7ba3be46059e5246a2900b1d1cd206339716f1fb9f1c848731d7' + '12dd1c955d2b9123afaad2690d65905ea394f297ba27ab4fec32dd5655553c8c') export KBUILD_BUILD_HOST=archlinux export KBUILD_BUILD_USER=$pkgbase