From bc7af3a34da47cc62dfb8d288532efdffcaa6cae Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Thu, 22 Oct 2020 18:23:30 +0200 Subject: [PATCH] Update v5.4 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/857c9b5da9280e5d2aefc7752acbd1a9e4c56921 --- patches/5.4/0001-surface3-power.patch | 6 +- patches/5.4/0002-surface3-oemb.patch | 38 +- patches/5.4/0003-wifi.patch | 1426 ++++++++--- patches/5.4/0004-ipts.patch | 144 +- ...rface-gpe.patch => 0005-surface-gpe.patch} | 45 +- patches/5.4/0006-surface-sam-over-hid.patch | 97 +- ...rface-sam.patch => 0007-surface-sam.patch} | 2085 +++++++++++++---- ...-acpi_walk_dep_device_list-getting-c.patch | 6 +- 8 files changed, 2955 insertions(+), 892 deletions(-) rename patches/5.4/{0007-surface-gpe.patch => 0005-surface-gpe.patch} (84%) rename patches/5.4/{0005-surface-sam.patch => 0007-surface-sam.patch} (93%) diff --git a/patches/5.4/0001-surface3-power.patch b/patches/5.4/0001-surface3-power.patch index 840edd044..2c380fcbd 100644 --- a/patches/5.4/0001-surface3-power.patch +++ b/patches/5.4/0001-surface3-power.patch @@ -1,8 +1,10 @@ -From cea7d9a2a9272d208417165c2931bd18e7728b60 Mon Sep 17 00:00:00 2001 +From 34fd11b0f32b5c15987dabbb7fcf6590341bd62c Mon Sep 17 00:00:00 2001 From: qzed Date: Tue, 17 Sep 2019 17:17:56 +0200 -Subject: [PATCH 1/8] 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/5.4/0002-surface3-oemb.patch b/patches/5.4/0002-surface3-oemb.patch index 364ded10d..a3ec3cf8f 100644 --- a/patches/5.4/0002-surface3-oemb.patch +++ b/patches/5.4/0002-surface3-oemb.patch @@ -1,8 +1,38 @@ -From a0bb18b7b173214237fd0d459979ec6204e350d8 Mon Sep 17 00:00:00 2001 -From: Chih-Wei Huang -Date: Tue, 18 Sep 2018 11:01:37 +0800 -Subject: [PATCH 2/8] surface3-oemb +From afc394c0540ca91a9ee31c84c500a90d82cf34ac 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/5.4/0003-wifi.patch b/patches/5.4/0003-wifi.patch index 6d6a09616..2a1450bc4 100644 --- a/patches/5.4/0003-wifi.patch +++ b/patches/5.4/0003-wifi.patch @@ -1,248 +1,116 @@ -From 3c7c2507efd9b6598e440097e068354292cc5566 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 3/8] wifi +From d87415b12bf41348cb809096313ec152acf006a6 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/Makefile | 1 + - .../net/wireless/marvell/mwifiex/cfg80211.c | 26 ++ - drivers/net/wireless/marvell/mwifiex/main.c | 6 +- - drivers/net/wireless/marvell/mwifiex/pcie.c | 84 ++++-- - 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, 374 insertions(+), 32 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 | 18 +++++++++++++++++- + drivers/net/wireless/marvell/mwifiex/pcie.h | 2 ++ + 2 files changed, 19 insertions(+), 1 deletion(-) -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 9e6dc289ec3e..00b4bc446989 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 d14e55e3c9da..99cc391e4afb 100644 ---- a/drivers/net/wireless/marvell/mwifiex/main.c -+++ b/drivers/net/wireless/marvell/mwifiex/main.c -@@ -1453,7 +1453,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) - { -@@ -1469,6 +1469,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); - adapter->is_up = false; - -@@ -1479,7 +1481,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 fc1706d0647d..0b1fec807d28 100644 +index fc1706d0647d..58c9623c3a91 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,8 +150,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) - { -@@ -153,31 +158,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; - } -@@ -187,13 +182,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) { -@@ -211,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; - } -@@ -229,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); - -@@ -261,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__); -@@ -376,7 +381,16 @@ static void mwifiex_pcie_reset_prepare(struct pci_dev *pdev) - mwifiex_shutdown_sw(adapter); +@@ -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; } /* -@@ -405,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__); @@ -251,37 +119,7 @@ index fc1706d0647d..0b1fec807d28 100644 } static const struct pci_error_handlers mwifiex_pcie_err_handler = { -@@ -2785,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, -@@ -2802,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. - */ -@@ -2995,7 +3027,19 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter) +@@ -2995,7 +2999,19 @@ static void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter) int ret; u32 fw_status; @@ -303,25 +141,95 @@ index fc1706d0647d..0b1fec807d28 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 485e47491fdf3380380351eae257289cc3a45fe2 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 58c9623c3a91..faf0c82e0b2c 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. @@ -333,21 +241,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[] = { + { @@ -356,7 +253,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", @@ -365,7 +262,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)", @@ -374,7 +271,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", @@ -382,7 +279,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", @@ -390,7 +287,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", @@ -398,7 +295,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", @@ -406,7 +303,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", @@ -414,7 +311,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", @@ -422,16 +319,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", @@ -455,11 +343,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 9e9258cd222851f0a4926139fcc53233b4cf4707 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 faf0c82e0b2c..828957cd5449 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) @@ -515,7 +548,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 2b2bb6db9675605dc6812ae1aa0ad62b93dcb23d 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 828957cd5449..263d918767bd 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) +{ @@ -578,53 +726,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 d7a83ffb7faaed1215873f48c9cd541ff911f41d 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 9b8c3430c962d4bcf7066da6bfc9a5522330aceb 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 d14e55e3c9da..5894566ec480 100644 +--- a/drivers/net/wireless/marvell/mwifiex/main.c ++++ b/drivers/net/wireless/marvell/mwifiex/main.c +@@ -1469,6 +1469,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); + adapter->is_up = false; + +-- +2.28.0 + +From 74c1334d28d50df496d030bb1dc5275bbb657643 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 5894566ec480..99cc391e4afb 100644 +--- a/drivers/net/wireless/marvell/mwifiex/main.c ++++ b/drivers/net/wireless/marvell/mwifiex/main.c +@@ -1453,7 +1453,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) + { +@@ -1481,7 +1481,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 263d918767bd..bd6791dc3a0f 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 8129314ab33e169a93c943d01b286156fd183551 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 bd6791dc3a0f..d7ff898c1767 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 9a7695152a4e6a911655f78dc8cad996710cb6cc 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 d7ff898c1767..5249b209eb02 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 07b927908d6034e00fb5109b0713f73aeef2df42 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 9e6dc289ec3e..20f5ee3fe7e3 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 043a356af095e1eaebda74fddba83be8bdc2b621 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 20f5ee3fe7e3..8020a2929069 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 eeab41594e4e420118326788215d102d8b5d1684 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/5.4/0004-ipts.patch b/patches/5.4/0004-ipts.patch index cd3c6dae5..2494ed732 100644 --- a/patches/5.4/0004-ipts.patch +++ b/patches/5.4/0004-ipts.patch @@ -1,8 +1,91 @@ -From 5f39b676103581dcfa4702ea3f921729c4c9a982 Mon Sep 17 00:00:00 2001 +From 4596b258b819644d212a9f8e4d20ebc4456c187d Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Mon, 27 Jan 2020 21:16:20 +0100 -Subject: [PATCH 4/8] ipts +Subject: [PATCH] mei: Add IPTS device IDs +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + drivers/misc/mei/hw-me-regs.h | 2 ++ + drivers/misc/mei/pci-me.c | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index e56dc4754064..a55c61c89238 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -59,6 +59,7 @@ + + #define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */ + #define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */ ++#define MEI_DEV_ID_SPT_4 0x9D3E /* Sunrise Point 4 (iTouch) */ + #define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */ + #define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */ + +@@ -90,6 +91,7 @@ + #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ + + #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ ++#define MEI_DEV_ID_ICP_LP_4 0x34E4 /* Ice Lake Point LP 4 (iTouch) */ + + #define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */ + +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 75ab2ffbf235..78790904d77c 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -77,6 +77,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)}, + {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)}, +@@ -103,6 +104,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { + {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, ++ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_4, MEI_ME_PCH12_CFG)}, + + {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)}, + +-- +2.28.0 + +From 87fea2c77d752224b06dc4beee817fa26f2b1356 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Fri, 20 Dec 2019 23:15:58 +0100 +Subject: [PATCH] uapi: Add MEI bus ID + +Signed-off-by: Dorian Stoll +Patchset: ipts +--- + include/uapi/linux/input.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h +index 9a61c28ed3ae..47fc20975245 100644 +--- a/include/uapi/linux/input.h ++++ b/include/uapi/linux/input.h +@@ -271,6 +271,7 @@ struct input_mask { + #define BUS_RMI 0x1D + #define BUS_CEC 0x1E + #define BUS_INTEL_ISHTP 0x1F ++#define BUS_MEI 0x44 + + /* + * MT_TOOL types +-- +2.28.0 + +From 8c1f8a2a71c1c382d8b1606ff57a9f72cba1e5a6 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +Date: Mon, 27 Jan 2020 21:22:42 +0100 +Subject: [PATCH] input: Add support for Intel Precise Touch & Stylus + +Signed-off-by: Dorian Stoll +Patchset: ipts --- drivers/input/touchscreen/Kconfig | 2 + drivers/input/touchscreen/Makefile | 1 + @@ -38,10 +121,7 @@ Subject: [PATCH 4/8] ipts drivers/input/touchscreen/ipts/singletouch.h | 14 + drivers/input/touchscreen/ipts/stylus.c | 179 ++++++++++++ drivers/input/touchscreen/ipts/stylus.h | 14 + - drivers/misc/mei/hw-me-regs.h | 2 + - drivers/misc/mei/pci-me.c | 2 + - include/uapi/linux/input.h | 1 + - 37 files changed, 1722 insertions(+) + 34 files changed, 1717 insertions(+) create mode 100644 drivers/input/touchscreen/ipts/Kconfig create mode 100644 drivers/input/touchscreen/ipts/Makefile create mode 100644 drivers/input/touchscreen/ipts/context.h @@ -2004,58 +2084,6 @@ index 000000000000..5b93add1eac2 +void ipts_stylus_free(struct ipts_context *ipts); + +#endif /* _IPTS_STYLUS_H_ */ -diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h -index e56dc4754064..a55c61c89238 100644 ---- a/drivers/misc/mei/hw-me-regs.h -+++ b/drivers/misc/mei/hw-me-regs.h -@@ -59,6 +59,7 @@ - - #define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */ - #define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */ -+#define MEI_DEV_ID_SPT_4 0x9D3E /* Sunrise Point 4 (iTouch) */ - #define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */ - #define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */ - -@@ -90,6 +91,7 @@ - #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */ - - #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */ -+#define MEI_DEV_ID_ICP_LP_4 0x34E4 /* Ice Lake Point LP 4 (iTouch) */ - - #define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */ - -diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c -index 75ab2ffbf235..78790904d77c 100644 ---- a/drivers/misc/mei/pci-me.c -+++ b/drivers/misc/mei/pci-me.c -@@ -77,6 +77,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { - - {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)}, - {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)}, -@@ -103,6 +104,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = { - {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)}, -+ {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_4, MEI_ME_PCH12_CFG)}, - - {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)}, - -diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h -index 9a61c28ed3ae..47fc20975245 100644 ---- a/include/uapi/linux/input.h -+++ b/include/uapi/linux/input.h -@@ -271,6 +271,7 @@ struct input_mask { - #define BUS_RMI 0x1D - #define BUS_CEC 0x1E - #define BUS_INTEL_ISHTP 0x1F -+#define BUS_MEI 0x44 - - /* - * MT_TOOL types -- 2.28.0 diff --git a/patches/5.4/0007-surface-gpe.patch b/patches/5.4/0005-surface-gpe.patch similarity index 84% rename from patches/5.4/0007-surface-gpe.patch rename to patches/5.4/0005-surface-gpe.patch index 034fc52cc..8ce4bcd4e 100644 --- a/patches/5.4/0007-surface-gpe.patch +++ b/patches/5.4/0005-surface-gpe.patch @@ -1,8 +1,35 @@ -From f2720bcc54e287b7c7158e9b57553720ed9eab3b Mon Sep 17 00:00:00 2001 +From ea2243f30da79e2b97bab0140a9b28c049e5ca25 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sun, 16 Aug 2020 23:39:56 +0200 -Subject: [PATCH 7/8] 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 7/8] surface-gpe create mode 100644 drivers/platform/x86/surface_gpe.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig -index 9fc01f255cbf..f5623ec8eda5 100644 +index 56b1cf96ff57..12cf0d723f21 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig -@@ -1224,6 +1224,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. +@@ -1217,6 +1217,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 9fc01f255cbf..f5623ec8eda5 100644 tristate "Intel P-Unit IPC Driver" ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index b3e0a2c6924b..c6e934a73a8d 100644 +index 6dd955ad9bf1..5db303f43bda 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile -@@ -87,6 +87,7 @@ obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o +@@ -86,6 +86,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/5.4/0006-surface-sam-over-hid.patch b/patches/5.4/0006-surface-sam-over-hid.patch index b19229c3a..f4f511bb4 100644 --- a/patches/5.4/0006-surface-sam-over-hid.patch +++ b/patches/5.4/0006-surface-sam-over-hid.patch @@ -1,15 +1,57 @@ -From a813aa2d1afcf8c4ca1eb6c200d6bb847da547ac Mon Sep 17 00:00:00 2001 +From 2f88ea832d68be4bd47a3702389371dcfab92dd5 Mon Sep 17 00:00:00 2001 From: Maximilian Luz Date: Sat, 25 Jul 2020 17:19:53 +0200 -Subject: [PATCH 6/8] 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 ce70b5288472..5df647c4d9a5 100644 @@ -64,13 +106,38 @@ index ce70b5288472..5df647c4d9a5 100644 default: dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", accessor_type, client->addr); +-- +2.28.0 + +From 94a75b92c382a5b72e7114f8b4bb593a5734534e 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 56b1cf96ff57..9fc01f255cbf 100644 +index 12cf0d723f21..f06a0bf92890 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig -@@ -1217,6 +1217,13 @@ config SURFACE_3_POWER_OPREGION - Select this option to enable support for ACPI operation - region of the Surface 3 battery platform driver. +@@ -1226,6 +1226,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 56b1cf96ff57..9fc01f255cbf 100644 tristate "Intel P-Unit IPC Driver" ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile -index 6dd955ad9bf1..b3e0a2c6924b 100644 +index 5db303f43bda..a1e70973257c 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile -@@ -86,6 +86,7 @@ obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o - obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o +@@ -87,6 +87,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/5.4/0005-surface-sam.patch b/patches/5.4/0007-surface-sam.patch similarity index 93% rename from patches/5.4/0005-surface-sam.patch rename to patches/5.4/0007-surface-sam.patch index bcd6b268b..69156271a 100644 --- a/patches/5.4/0005-surface-sam.patch +++ b/patches/5.4/0007-surface-sam.patch @@ -1,22 +1,384 @@ -From 27fed7448770dd0b153c1f6220bf0bb74985b1c2 Mon Sep 17 00:00:00 2001 +From 04ed5900788dccac4296278208874e58452be706 Mon Sep 17 00:00:00 2001 From: qzed Date: Mon, 26 Aug 2019 01:11:08 +0200 -Subject: [PATCH 5/8] 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 | 12 +++++++++--- + 2 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c +index 10f32b62608e..7b2a4987f050 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 d3d2dbfba680..0b7f617a6e9b 100644 +--- a/drivers/acpi/acpica/exfield.c ++++ b/drivers/acpi/acpica/exfield.c +@@ -109,6 +109,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + union acpi_operand_object *buffer_desc; + void *buffer; + u32 buffer_length; ++ u8 field_flags; + + ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); + +@@ -157,11 +158,16 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + * Note: Field.length is in bits. + */ + buffer_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 (buffer_length > acpi_gbl_integer_byte_width) { ++ if (buffer_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(buffer_length); + if (!buffer_desc) { +-- +2.28.0 + +From 65ad00e9a18e592127f00fdd17b5b58fef13d8f2 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 a9719858c950..ce5309d00280 100644 +--- a/drivers/tty/serdev/core.c ++++ b/drivers/tty/serdev/core.c +@@ -552,16 +552,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", +@@ -589,7 +670,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; +@@ -597,26 +678,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 5a29607b9de9a2a278b7f431c242734ba00511c0 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 4c56404e53a7..33c0eb774f3e 100644 +--- a/include/linux/mod_devicetable.h ++++ b/include/linux/mod_devicetable.h +@@ -827,4 +827,21 @@ struct wmi_device_id { + const void *context; + }; + ++/* 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 054405b90ba4..5978f02202a3 100644 +--- a/scripts/mod/devicetable-offsets.c ++++ b/scripts/mod/devicetable-offsets.c +@@ -231,5 +231,12 @@ int main(void) + DEVID(wmi_device_id); + DEVID_FIELD(wmi_device_id, guid_string); + ++ 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 c91eba751804..bc06f7631200 100644 +--- a/scripts/mod/file2alias.c ++++ b/scripts/mod/file2alias.c +@@ -1335,6 +1335,26 @@ static int do_wmi_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) + { +@@ -1407,6 +1427,7 @@ static const struct devtable devtable[] = { + {"typec", SIZE_typec_device_id, do_typec_entry}, + {"tee", SIZE_tee_client_device_id, do_tee_entry}, + {"wmi", SIZE_wmi_device_id, do_wmi_entry}, ++ {"ssam", SIZE_ssam_device_id, do_ssam_entry}, + }; + + /* Create MODULE_ALIAS() statements. +-- +2.28.0 + +From f0aeeaafb0ac9d8638030a29e3bf3987abe3ec37 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 | 12 +- drivers/misc/Kconfig | 1 + drivers/misc/Makefile | 1 + drivers/misc/surface_aggregator/Kconfig | 67 + @@ -29,7 +391,7 @@ Subject: [PATCH 5/8] surface-sam .../clients/surface_aggregator_cdev.c | 299 ++ .../clients/surface_aggregator_registry.c | 605 ++++ .../clients/surface_battery.c | 1196 ++++++++ - .../surface_aggregator/clients/surface_dtx.c | 1129 ++++++++ + .../surface_aggregator/clients/surface_dtx.c | 1270 ++++++++ .../surface_aggregator/clients/surface_hid.c | 925 ++++++ .../clients/surface_hotplug.c | 1285 +++++++++ .../clients/surface_perfmode.c | 122 + @@ -44,19 +406,20 @@ Subject: [PATCH 5/8] 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 | 659 +++++ include/uapi/linux/surface_aggregator/cdev.h | 58 + - scripts/mod/devicetable-offsets.c | 8 + - scripts/mod/file2alias.c | 23 + - 49 files changed, 18921 insertions(+), 16 deletions(-) + include/uapi/linux/surface_aggregator/dtx.h | 150 + + scripts/mod/devicetable-offsets.c | 3 +- + scripts/mod/file2alias.c | 10 +- + 48 files changed, 19778 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 +457,7 @@ Subject: [PATCH 5/8] 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 38e638abe3eb..130ee3353fc6 100644 @@ -642,12 +1006,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 +1743,7 @@ index 000000000000..3ccabce23271 + :maxdepth: 1 + + cdev ++ dtx + san + +.. only:: subproject and html @@ -1306,51 +2389,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 10f32b62608e..7b2a4987f050 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 d3d2dbfba680..0b7f617a6e9b 100644 ---- a/drivers/acpi/acpica/exfield.c -+++ b/drivers/acpi/acpica/exfield.c -@@ -109,6 +109,7 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, - union acpi_operand_object *buffer_desc; - void *buffer; - u32 buffer_length; -+ u8 field_flags; - - ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc); - -@@ -157,11 +158,16 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, - * Note: Field.length is in bits. - */ - buffer_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 (buffer_length > acpi_gbl_integer_byte_width) { -+ if (buffer_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(buffer_length); - if (!buffer_desc) { diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index c55b63750757..b8626bef683c 100644 --- a/drivers/misc/Kconfig @@ -5114,10 +6152,10 @@ index 000000000000..21ee212a945a +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..3b4cfe639509 +index 000000000000..1ac1208edd13 --- /dev/null +++ b/drivers/misc/surface_aggregator/clients/surface_dtx.c -@@ -0,0 +1,1129 @@ +@@ -0,0 +1,1270 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Surface Book (gen. 2 and later) detachment system (DTX) driver. @@ -5149,98 +6187,7 @@ index 000000000000..3b4cfe639509 + +#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. ------------------------------------------------------- */ @@ -5252,35 +6199,34 @@ index 000000000000..3b4cfe639509 + 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; + -+static_assert(sizeof(struct ssam_dtx_base_info) == 2); ++static_assert(sizeof(struct ssam_bas_base_info) == 2); + +static SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, { + .target_category = SSAM_SSH_TC_BAS, @@ -5324,7 +6270,7 @@ index 000000000000..3b4cfe639509 + .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, @@ -5349,7 +6295,10 @@ index 000000000000..3b4cfe639509 +/* -- 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 { @@ -5358,35 +6307,39 @@ index 000000000000..3b4cfe639509 + + 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); +}; + @@ -5415,13 +6368,13 @@ index 000000000000..3b4cfe639509 +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: @@ -5433,19 +6386,19 @@ index 000000000000..3b4cfe639509 +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: @@ -5457,19 +6410,19 @@ index 000000000000..3b4cfe639509 +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: @@ -5484,7 +6437,7 @@ index 000000000000..3b4cfe639509 +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; + @@ -5532,11 +6485,11 @@ index 000000000000..3b4cfe639509 + + 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: @@ -5581,7 +6534,7 @@ index 000000000000..3b4cfe639509 + 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; + } @@ -5612,7 +6565,6 @@ index 000000000000..3b4cfe639509 + INIT_LIST_HEAD(&client->node); + + mutex_init(&client->read_lock); -+ spin_lock_init(&client->write_lock); + INIT_KFIFO(client->buffer); + + file->private_data = client; @@ -5621,7 +6573,7 @@ index 000000000000..3b4cfe639509 + 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); @@ -5662,7 +6614,7 @@ index 000000000000..3b4cfe639509 + 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; + } @@ -5677,8 +6629,8 @@ index 000000000000..3b4cfe639509 + + 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; + @@ -5686,7 +6638,7 @@ index 000000000000..3b4cfe639509 + 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; + } @@ -5725,7 +6677,7 @@ index 000000000000..3b4cfe639509 + 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; + } @@ -5775,12 +6727,12 @@ index 000000000000..3b4cfe639509 +#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 { @@ -5794,6 +6746,7 @@ index 000000000000..3b4cfe639509 + 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; @@ -5801,18 +6754,13 @@ index 000000000000..3b4cfe639509 + + 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); + } @@ -5856,11 +6804,23 @@ index 000000000000..3b4cfe639509 + 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; @@ -5871,14 +6831,22 @@ index 000000000000..3b4cfe639509 + 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; + } @@ -5890,27 +6858,31 @@ index 000000000000..3b4cfe639509 + 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); @@ -5935,19 +6907,89 @@ index 000000000000..3b4cfe639509 + * 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); @@ -5958,14 +7000,97 @@ index 000000000000..3b4cfe639509 + 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); @@ -5986,17 +7111,35 @@ index 000000000000..3b4cfe639509 + 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(); @@ -6008,8 +7151,9 @@ index 000000000000..3b4cfe639509 + 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) { @@ -6028,13 +7172,10 @@ index 000000000000..3b4cfe639509 + 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: @@ -6081,7 +7222,7 @@ index 000000000000..3b4cfe639509 + * 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); @@ -6114,6 +7255,43 @@ index 000000000000..3b4cfe639509 +} + + ++/* -- 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) @@ -6153,6 +7331,7 @@ index 000000000000..3b4cfe639509 + .driver = { + .name = "surface_dtx_pltf", + .acpi_match_table = surface_dtx_acpi_match, ++ .pm = &surface_dtx_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; @@ -17140,188 +18319,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 a9719858c950..ce5309d00280 100644 ---- a/drivers/tty/serdev/core.c -+++ b/drivers/tty/serdev/core.c -@@ -552,16 +552,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", -@@ -589,7 +670,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; -@@ -597,26 +678,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 4c56404e53a7..3e2fe1c6631c 100644 +index 33c0eb774f3e..3e2fe1c6631c 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h -@@ -827,4 +827,22 @@ struct wmi_device_id { - const void *context; - }; +@@ -829,15 +829,16 @@ struct wmi_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 @@ -19291,7 +20311,7 @@ index 000000000000..376313f402b2 +#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 @@ @@ -19309,8 +20329,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. @@ -19353,65 +20373,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 054405b90ba4..0d66f07989c4 100644 +index 5978f02202a3..0d66f07989c4 100644 --- a/scripts/mod/devicetable-offsets.c +++ b/scripts/mod/devicetable-offsets.c -@@ -231,5 +231,13 @@ int main(void) - DEVID(wmi_device_id); - DEVID_FIELD(wmi_device_id, guid_string); +@@ -233,8 +233,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 c91eba751804..c86de633d7ea 100644 +index bc06f7631200..c86de633d7ea 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c -@@ -1335,6 +1335,28 @@ static int do_wmi_entry(const char *filename, void *symval, char *alias) +@@ -1335,20 +1335,22 @@ static int do_wmi_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) - { -@@ -1407,6 +1429,7 @@ static const struct devtable devtable[] = { - {"typec", SIZE_typec_device_id, do_typec_entry}, - {"tee", SIZE_tee_client_device_id, do_tee_entry}, - {"wmi", SIZE_wmi_device_id, do_wmi_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/5.4/0008-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch b/patches/5.4/0008-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch index edba69dcd..0c234a587 100644 --- a/patches/5.4/0008-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch +++ b/patches/5.4/0008-i2c-core-Restore-acpi_walk_dep_device_list-getting-c.patch @@ -1,8 +1,8 @@ -From c7cd4ee28f95e353406fdb98ffcb168974ecf638 Mon Sep 17 00:00:00 2001 +From 7e11df4d0af5a21f93c8af446bcfd24432a2bfa6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 14 Oct 2020 16:41:58 +0200 -Subject: [PATCH 8/8] 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