summaryrefslogtreecommitdiff
path: root/SOURCES
diff options
context:
space:
mode:
Diffstat (limited to 'SOURCES')
-rw-r--r--SOURCES/0001-acpi-proc-idle-skip-dummy-wait.patch125
-rw-r--r--SOURCES/Makefile.rhelver2
-rw-r--r--SOURCES/Patchlist.changelog45
-rw-r--r--SOURCES/asus-linux.patch746
-rw-r--r--SOURCES/patch-5.19-redhat.patch545
-rw-r--r--SOURCES/v3-1-7-acpi-x86-s2idle-Move-_HID-handling-for-AMD-systems-into-structures.patch150
6 files changed, 1322 insertions, 291 deletions
diff --git a/SOURCES/0001-acpi-proc-idle-skip-dummy-wait.patch b/SOURCES/0001-acpi-proc-idle-skip-dummy-wait.patch
new file mode 100644
index 0000000..63c1172
--- /dev/null
+++ b/SOURCES/0001-acpi-proc-idle-skip-dummy-wait.patch
@@ -0,0 +1,125 @@
+Processors based on the Zen microarchitecture support IOPORT based deeper
+C-states. The idle driver reads the acpi_gbl_FADT.xpm_timer_block.address
+in the IOPORT based C-state exit path which is claimed to be a
+"Dummy wait op" and has been around since ACPI introduction to Linux
+dating back to Andy Grover's Mar 14, 2002 posting [1].
+The comment above the dummy operation was elaborated by Andreas Mohr back
+in 2006 in commit b488f02156d3d ("ACPI: restore comment justifying 'extra'
+P_LVLx access") [2] where the commit log claims:
+"this dummy read was about: STPCLK# doesn't get asserted in time on
+(some) chipsets, which is why we need to have a dummy I/O read to delay
+further instruction processing until the CPU is fully stopped."
+
+However, sampling certain workloads with IBS on AMD Zen3 system shows
+that a significant amount of time is spent in the dummy op, which
+incorrectly gets accounted as C-State residency. A large C-State
+residency value can prime the cpuidle governor to recommend a deeper
+C-State during the subsequent idle instances, starting a vicious cycle,
+leading to performance degradation on workloads that rapidly switch
+between busy and idle phases.
+
+One such workload is tbench where a massive performance degradation can
+be observed during certain runs. Following are some statistics gathered
+by running tbench with 128 clients, on a dual socket (2 x 64C/128T) Zen3
+system with the baseline kernel, baseline kernel keeping C2 disabled,
+and baseline kernel with this patch applied keeping C2 enabled:
+
+baseline kernel was tip:sched/core at
+commit f3dd3f674555 ("sched: Remove the limitation of WF_ON_CPU on
+wakelist if wakee cpu is idle")
+
+Kernel : baseline baseline + C2 disabled baseline + patch
+
+Min (MB/s) : 2215.06 33072.10 (+1393.05%) 33016.10 (+1390.52%)
+Max (MB/s) : 32938.80 34399.10 34774.50
+Median (MB/s) : 32191.80 33476.60 33805.70
+AMean (MB/s) : 22448.55 33649.27 (+49.89%) 33865.43 (+50.85%)
+AMean Stddev : 17526.70 680.14 880.72
+AMean CoefVar : 78.07% 2.02% 2.60%
+
+The data shows there are edge cases that can cause massive regressions
+in case of tbench. Profiling the bad runs with IBS shows a significant
+amount of time being spent in acpi_idle_do_entry method:
+
+Overhead Command Shared Object Symbol
+ 74.76% swapper [kernel.kallsyms] [k] acpi_idle_do_entry
+ 0.71% tbench [kernel.kallsyms] [k] update_sd_lb_stats.constprop.0
+ 0.69% tbench_srv [kernel.kallsyms] [k] update_sd_lb_stats.constprop.0
+ 0.49% swapper [kernel.kallsyms] [k] psi_group_change
+ ...
+
+Annotation of acpi_idle_do_entry method reveals almost all the time in
+acpi_idle_do_entry is spent on the port I/O in wait_for_freeze():
+
+ 0.14 │ in (%dx),%al # <------ First "in" corresponding to inb(cx->address)
+ 0.51 │ mov 0x144d64d(%rip),%rax
+ 0.00 │ test $0x80000000,%eax
+ │ ↓ jne 62 # <------ Skip if running in guest
+ 0.00 │ mov 0x19800c3(%rip),%rdx
+ 99.33 │ in (%dx),%eax # <------ Second "in" corresponding to inl(acpi_gbl_FADT.xpm_timer_block.address)
+ 0.00 │62: mov -0x8(%rbp),%r12
+ 0.00 │ leave
+ 0.00 │ ← ret
+
+This overhead is reflected in the C2 residency on the test system where
+C2 is an IOPORT based C-State. The total C-state residency reported by
+"cpupower idle-info" on CPU0 for good and bad case over the 80s tbench
+run is as follows (all numbers are in microseconds):
+
+ Good Run Bad Run
+ (Baseline)
+
+POLL: 43338 6231 (-85.62%)
+C1 (MWAIT Based): 23576156 363861 (-98.45%)
+C2 (IOPORT Based): 10781218 77027280 (+614.45%)
+
+The larger residency value in bad case leads to the system recommending
+C2 state again for subsequent idle instances. The pattern lasts till the
+end of the tbench run. Following is the breakdown of "entry_method"
+passed to acpi_idle_do_entry during good run and bad run:
+
+ Good Run Bad Run
+ (Baseline)
+
+Number of times acpi_idle_do_entry was called: 6149573 6149050 (-0.01%)
+ |-> Number of times entry_method was "ACPI_CSTATE_FFH": 6141494 88144 (-98.56%)
+ |-> Number of times entry_method was "ACPI_CSTATE_HALT": 0 0 (+0.00%)
+ |-> Number of times entry_method was "ACPI_CSTATE_SYSTEMIO": 8079 6060906 (+74920.49%)
+
+For processors based on the Zen microarchitecture, this dummy wait op is
+unnecessary and can be skipped when choosing IOPORT based C-States to
+avoid polluting the C-state residency information.
+
+Link: https://git.kernel.org/pub/scm/linux/kernel/git/mpe/linux-fullhistory.git/commit/?id=972c16130d9dc182cedcdd408408d9eacc7d6a2d [1]
+Link: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b488f02156d3deb08f5ad7816d565c370a8cc6f1 [2]
+
+Suggested-by: Calvin Ong <calvin.ong@amd.com>
+Cc: stable@vger.kernel.org
+Cc: regressions@lists.linux.dev
+Signed-off-by: K Prateek Nayak <kprateek.nayak@amd.com>
+---
+ drivers/acpi/processor_idle.c | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
+index 16a1663d02d4..18850aa2b79b 100644
+--- a/drivers/acpi/processor_idle.c
++++ b/drivers/acpi/processor_idle.c
+@@ -527,9 +527,11 @@
+ static void wait_for_freeze(void)
+ {
+ #ifdef CONFIG_X86
+- /* No delay is needed if we are in guest */
+- if (boot_cpu_has(X86_FEATURE_HYPERVISOR))
+- return;
++ /*
++ * No delay is needed if we are in guest or on a processor
++ * based on the Zen microarchitecture.
++ */
++ if (boot_cpu_has(X86_FEATURE_HYPERVISOR) || boot_cpu_has(X86_FEATURE_ZEN))
+ /*
+ * Modern (>=Nehalem) Intel systems use ACPI via intel_idle,
+ * not this code. Assume that any Intel systems using this
+
+--
+2.25.1
diff --git a/SOURCES/Makefile.rhelver b/SOURCES/Makefile.rhelver
index bedf1e2..aa26893 100644
--- a/SOURCES/Makefile.rhelver
+++ b/SOURCES/Makefile.rhelver
@@ -12,7 +12,7 @@ RHEL_MINOR = 99
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
-RHEL_RELEASE = 0
+RHEL_RELEASE = 1
#
# ZSTREAM
diff --git a/SOURCES/Patchlist.changelog b/SOURCES/Patchlist.changelog
index f3e996a..f135fb3 100644
--- a/SOURCES/Patchlist.changelog
+++ b/SOURCES/Patchlist.changelog
@@ -1,3 +1,48 @@
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/b7ac3893a05dddcf85e47e0f9fc3868bb80cba8e
+ b7ac3893a05dddcf85e47e0f9fc3868bb80cba8e mctp: prevent double key removal and unref
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/f41667878d605b0df50332ec1bb91b3c58b0a2b6
+ f41667878d605b0df50332ec1bb91b3c58b0a2b6 wifi: cfg80211: update hidden BSSes to avoid WARN_ON
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/2c047ea0b747055e5afc74d6ee24d0e1a6fd045b
+ 2c047ea0b747055e5afc74d6ee24d0e1a6fd045b wifi: mac80211: fix crash in beacon protection for P2P-device
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/0ceb5de271ef569e73ff55fc45e4c858c4e90a8f
+ 0ceb5de271ef569e73ff55fc45e4c858c4e90a8f wifi: mac80211_hwsim: avoid mac80211 warning on bad rate
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/99b388fa0f89350475a015ced6ea091137708a85
+ 99b388fa0f89350475a015ced6ea091137708a85 wifi: cfg80211: avoid nontransmitted BSS list corruption
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/d9250a0c289718402eae31b58425c280e6fb42d9
+ d9250a0c289718402eae31b58425c280e6fb42d9 wifi: cfg80211: fix BSS refcounting bugs
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/15d4d3f11fc53ff4789c9c2a5f0a874d64671146
+ 15d4d3f11fc53ff4789c9c2a5f0a874d64671146 wifi: cfg80211: ensure length byte is present before access
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/1c57f15727fb63f7f0bfdcc9f032501804c93de4
+ 1c57f15727fb63f7f0bfdcc9f032501804c93de4 wifi: mac80211: fix MBSSID parsing use-after-free
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/1a9ee89eb2c3d3a4e1a5786650a83419acdc1de2
+ 1a9ee89eb2c3d3a4e1a5786650a83419acdc1de2 wifi: cfg80211/mac80211: reject bad MBSSID elements
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/828022c8d93a3c2a1d98a134910682ed0f961d0c
+ 828022c8d93a3c2a1d98a134910682ed0f961d0c wifi: cfg80211: fix u8 overflow in cfg80211_update_notlisted_nontrans()
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/01e0ad5ed5f0788f9688daacd4695df17e1174e9
+ 01e0ad5ed5f0788f9688daacd4695df17e1174e9 drm/vc4: hdmi: Check the HSM rate at runtime_resume
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/0d9cf6806f3be0d0a2adad69ddc50192ca38285b
+ 0d9cf6806f3be0d0a2adad69ddc50192ca38285b drm/vc4: hdmi: Enforce the minimum rate at runtime_resume
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/482f7491ba5a1106e8b7d5ca0accc353f2c0d55a
+ 482f7491ba5a1106e8b7d5ca0accc353f2c0d55a phy: rockchip-inno-usb2: Return zero after otg sync
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/3401107a6fbe13ef6eb6a9a8b6d6dbec04fbf234
+ 3401107a6fbe13ef6eb6a9a8b6d6dbec04fbf234 scsi: stex: Properly zero out the passthrough command structure
+
+"https://gitlab.com/cki-project/kernel-ark/-/commit"/d88ada87e783422a5e31b8e4c6dd376f58553cb1
+ d88ada87e783422a5e31b8e4c6dd376f58553cb1 ipv4: Handle attempt to delete multipath route when fib_info contains an nh reference
+
"https://gitlab.com/cki-project/kernel-ark/-/commit"/9d5fb7eaaa7db6a9952531d029dc9c3fb16a8eee
9d5fb7eaaa7db6a9952531d029dc9c3fb16a8eee kbuild: Add skip_encoding_btf_enum64 option to pahole
diff --git a/SOURCES/asus-linux.patch b/SOURCES/asus-linux.patch
index 565a7c7..cc36d1b 100644
--- a/SOURCES/asus-linux.patch
+++ b/SOURCES/asus-linux.patch
@@ -1,196 +1,3 @@
-From e6529e0ad6942bb0eadc5f5ad0590124153e0a8c Mon Sep 17 00:00:00 2001
-From: "Luke D. Jones" <luke@ljones.dev>
-Date: Wed, 3 Aug 2022 11:02:05 +1200
-Subject: [PATCH 1/1] HID: amd_sfh: Add keyguard for ASUS ROG X13 tablet
-
-Add support for ROG X13 Flow 2-in-1 to disable the keyboard when
-the lid is flipped.
-
-Signed-off-by: Luke D. Jones <luke@ljones.dev>
----
- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 7 ++++-
- drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 +
- .../hid_descriptor/amd_sfh_hid_desc.c | 27 +++++++++++++++++++
- .../hid_descriptor/amd_sfh_hid_desc.h | 9 +++++++
- .../hid_descriptor/amd_sfh_hid_report_desc.h | 19 +++++++++++++
- 5 files changed, 62 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
-index dadc491bbf6b..243541d426d8 100644
---- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
-+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
-@@ -26,6 +26,7 @@
- #define ACEL_EN BIT(0)
- #define GYRO_EN BIT(1)
- #define MAGNO_EN BIT(2)
-+#define KBGUARD_EN BIT(15)
- #define HPD_EN BIT(16)
- #define ALS_EN BIT(19)
-
-@@ -232,6 +233,9 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
- if (HPD_EN & activestatus)
- sensor_id[num_of_sensors++] = HPD_IDX;
-
-+ if (KBGUARD_EN & activestatus)
-+ sensor_id[num_of_sensors++] = KBGUARD_IDX;
-+
- return num_of_sensors;
- }
-
-@@ -373,7 +377,8 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
-
- for (i = 0; i < cl_data->num_hid_devices; i++) {
- if (cl_data->sensor_idx[i] != HPD_IDX &&
-- cl_data->sensor_sts[i] == SENSOR_ENABLED) {
-+ cl_data->sensor_idx[i] != KBGUARD_IDX &&
-+ cl_data->sensor_sts[i] == SENSOR_ENABLED) {
- mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
- status = amd_sfh_wait_for_response
- (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
-diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
-index 8c760526132a..4a86bc6038a2 100644
---- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
-+++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
-@@ -36,6 +36,7 @@
- #define SENSOR_DISABLED 5
-
- #define HPD_IDX 16
-+#define KBGUARD_IDX 15
-
- #define AMD_SFH_IDLE_LOOP 200
-
-diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
-index 76095bd53c65..f41d28ea7b93 100644
---- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
-+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
-@@ -57,6 +57,11 @@ int get_report_descriptor(int sensor_idx, u8 *rep_desc)
- memcpy(rep_desc, hpd_report_descriptor,
- sizeof(hpd_report_descriptor));
- break;
-+ case KBGUARD_IDX: /* kbguard ? */
-+ memset(rep_desc, 0, sizeof(kbguard_report_descriptor));
-+ memcpy(rep_desc, kbguard_report_descriptor,
-+ sizeof(kbguard_report_descriptor));
-+ break;
- default:
- break;
- }
-@@ -116,6 +121,16 @@ u32 get_descr_sz(int sensor_idx, int descriptor_name)
- return sizeof(struct hpd_feature_report);
- }
- break;
-+ case KBGUARD_IDX:
-+ switch (descriptor_name) {
-+ case descr_size:
-+ return sizeof(kbguard_report_descriptor);
-+ case input_size:
-+ return sizeof(struct kbguard_input_report);
-+ case feature_size:
-+ return sizeof(struct kbguard_feature_report);
-+ }
-+ break;
-
- default:
- break;
-@@ -139,6 +154,7 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
- struct gyro_feature_report gyro_feature;
- struct magno_feature_report magno_feature;
- struct hpd_feature_report hpd_feature;
-+ struct kbguard_feature_report kbguard_feature;
- struct als_feature_report als_feature;
- u8 report_size = 0;
-
-@@ -186,6 +202,11 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
- memcpy(feature_report, &hpd_feature, sizeof(hpd_feature));
- report_size = sizeof(hpd_feature);
- break;
-+ case KBGUARD_IDX: /* auto disable keyboard when flip out */
-+ get_common_features(&kbguard_feature.common_property, report_id);
-+ memcpy(feature_report, &kbguard_feature, sizeof(kbguard_feature));
-+ report_size = sizeof(kbguard_feature);
-+ break;
-
- default:
- break;
-@@ -210,6 +231,7 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
- struct accel3_input_report acc_input;
- struct gyro_input_report gyro_input;
- struct hpd_input_report hpd_input;
-+ struct kbguard_input_report kbguard_input;
- struct als_input_report als_input;
- struct hpd_status hpdstatus;
- u8 report_size = 0;
-@@ -262,6 +284,11 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
- report_size = sizeof(hpd_input);
- memcpy(input_report, &hpd_input, sizeof(hpd_input));
- break;
-+ case KBGUARD_IDX: /* kb guard */
-+ get_common_inputs(&kbguard_input.common_property, report_id);
-+ report_size = sizeof(kbguard_input);
-+ memcpy(input_report, &kbguard_input, sizeof(kbguard_input));
-+break;
- default:
- break;
- }
-diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
-index 70b1b7abe2c6..98571a8597b3 100644
---- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
-+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
-@@ -105,12 +105,21 @@ struct hpd_feature_report {
- struct common_feature_property common_property;
- } __packed;
-
-+struct kbguard_feature_report {
-+ struct common_feature_property common_property;
-+} __packed;
-+
- struct hpd_input_report {
- struct common_input_property common_property;
- /* values specific to human presence sensor */
- u8 human_presence;
- } __packed;
-
-+struct kbguard_input_report {
-+ struct common_input_property common_property;
-+} __packed;
-+
-+
- int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
- u32 get_descr_sz(int sensor_idx, int descriptor_name);
- u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
-diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
-index 697f2791ea9c..7a62fcec2c73 100644
---- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
-+++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
-@@ -644,6 +644,25 @@ static const u8 als_report_descriptor[] = {
- 0xC0 /* HID end collection */
- };
-
-+
-+static const u8 kbguard_report_descriptor[] = {
-+0x06, 0x43, 0xFF, // Usage Page (Vendor Defined 0xFF43)
-+0x0A, 0x02, 0x02, // Usage (0x0202)
-+0xA1, 0x01, // Collection (Application)
-+0x85, 0x11, // Report ID (17)
-+0x15, 0x00, // Logical Minimum (0)
-+0x25, 0x01, // Logical Maximum (1)
-+0x35, 0x00, // Physical Minimum (0)
-+0x45, 0x01, // Physical Maximum (1)
-+0x65, 0x00, // Unit (None)
-+0x55, 0x00, // Unit Exponent (0)
-+0x75, 0x01, // Report Size (1)
-+0x95, 0x98, // Report Count (-104)
-+0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
-+0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
-+0xC1, 0x00, // End Collection
-+};
-+
- /* BIOMETRIC PRESENCE*/
- static const u8 hpd_report_descriptor[] = {
- 0x05, 0x20, /* Usage page */
---
-2.37.1
-
From 170f0da25dac630dacb920d043fb20e12c287520 Mon Sep 17 00:00:00 2001
From: "Luke D. Jones" <luke@ljones.dev>
Date: Tue, 9 Aug 2022 14:50:53 +1200
@@ -2118,6 +1925,199 @@ index 3d861477cb20..7dd580fdc61c 100644
--
2.37.2
+From e6529e0ad6942bb0eadc5f5ad0590124153e0a8c Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Wed, 3 Aug 2022 11:02:05 +1200
+Subject: [PATCH 1/1] HID: amd_sfh: Add keyguard for ASUS ROG X13 tablet
+
+Add support for ROG X13 Flow 2-in-1 to disable the keyboard when
+the lid is flipped.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 7 ++++-
+ drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 +
+ .../hid_descriptor/amd_sfh_hid_desc.c | 27 +++++++++++++++++++
+ .../hid_descriptor/amd_sfh_hid_desc.h | 9 +++++++
+ .../hid_descriptor/amd_sfh_hid_report_desc.h | 19 +++++++++++++
+ 5 files changed, 62 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+index dadc491bbf6b..243541d426d8 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
+@@ -26,6 +26,7 @@
+ #define ACEL_EN BIT(0)
+ #define GYRO_EN BIT(1)
+ #define MAGNO_EN BIT(2)
++#define KBGUARD_EN BIT(15)
+ #define HPD_EN BIT(16)
+ #define ALS_EN BIT(19)
+
+@@ -232,6 +233,9 @@ int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id)
+ if (HPD_EN & activestatus)
+ sensor_id[num_of_sensors++] = HPD_IDX;
+
++ if (KBGUARD_EN & activestatus)
++ sensor_id[num_of_sensors++] = KBGUARD_IDX;
++
+ return num_of_sensors;
+ }
+
+@@ -373,7 +377,8 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
+
+ for (i = 0; i < cl_data->num_hid_devices; i++) {
+ if (cl_data->sensor_idx[i] != HPD_IDX &&
+- cl_data->sensor_sts[i] == SENSOR_ENABLED) {
++ cl_data->sensor_idx[i] != KBGUARD_IDX &&
++ cl_data->sensor_sts[i] == SENSOR_ENABLED) {
+ mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]);
+ status = amd_sfh_wait_for_response
+ (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED);
+diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+index 8c760526132a..4a86bc6038a2 100644
+--- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
++++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
+@@ -36,6 +36,7 @@
+ #define SENSOR_DISABLED 5
+
+ #define HPD_IDX 16
++#define KBGUARD_IDX 15
+
+ #define AMD_SFH_IDLE_LOOP 200
+
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+index 76095bd53c65..f41d28ea7b93 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
+@@ -57,6 +57,11 @@ int get_report_descriptor(int sensor_idx, u8 *rep_desc)
+ memcpy(rep_desc, hpd_report_descriptor,
+ sizeof(hpd_report_descriptor));
+ break;
++ case KBGUARD_IDX: /* kbguard ? */
++ memset(rep_desc, 0, sizeof(kbguard_report_descriptor));
++ memcpy(rep_desc, kbguard_report_descriptor,
++ sizeof(kbguard_report_descriptor));
++ break;
+ default:
+ break;
+ }
+@@ -116,6 +121,16 @@ u32 get_descr_sz(int sensor_idx, int descriptor_name)
+ return sizeof(struct hpd_feature_report);
+ }
+ break;
++ case KBGUARD_IDX:
++ switch (descriptor_name) {
++ case descr_size:
++ return sizeof(kbguard_report_descriptor);
++ case input_size:
++ return sizeof(struct kbguard_input_report);
++ case feature_size:
++ return sizeof(struct kbguard_feature_report);
++ }
++ break;
+
+ default:
+ break;
+@@ -139,6 +154,7 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+ struct gyro_feature_report gyro_feature;
+ struct magno_feature_report magno_feature;
+ struct hpd_feature_report hpd_feature;
++ struct kbguard_feature_report kbguard_feature;
+ struct als_feature_report als_feature;
+ u8 report_size = 0;
+
+@@ -186,6 +202,11 @@ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report)
+ memcpy(feature_report, &hpd_feature, sizeof(hpd_feature));
+ report_size = sizeof(hpd_feature);
+ break;
++ case KBGUARD_IDX: /* auto disable keyboard when flip out */
++ get_common_features(&kbguard_feature.common_property, report_id);
++ memcpy(feature_report, &kbguard_feature, sizeof(kbguard_feature));
++ report_size = sizeof(kbguard_feature);
++ break;
+
+ default:
+ break;
+@@ -210,6 +231,7 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
+ struct accel3_input_report acc_input;
+ struct gyro_input_report gyro_input;
+ struct hpd_input_report hpd_input;
++ struct kbguard_input_report kbguard_input;
+ struct als_input_report als_input;
+ struct hpd_status hpdstatus;
+ u8 report_size = 0;
+@@ -262,6 +284,11 @@ u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_
+ report_size = sizeof(hpd_input);
+ memcpy(input_report, &hpd_input, sizeof(hpd_input));
+ break;
++ case KBGUARD_IDX: /* kb guard */
++ get_common_inputs(&kbguard_input.common_property, report_id);
++ report_size = sizeof(kbguard_input);
++ memcpy(input_report, &kbguard_input, sizeof(kbguard_input));
++break;
+ default:
+ break;
+ }
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+index 70b1b7abe2c6..98571a8597b3 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
+@@ -105,12 +105,21 @@ struct hpd_feature_report {
+ struct common_feature_property common_property;
+ } __packed;
+
++struct kbguard_feature_report {
++ struct common_feature_property common_property;
++} __packed;
++
+ struct hpd_input_report {
+ struct common_input_property common_property;
+ /* values specific to human presence sensor */
+ u8 human_presence;
+ } __packed;
+
++struct kbguard_input_report {
++ struct common_input_property common_property;
++} __packed;
++
++
+ int get_report_descriptor(int sensor_idx, u8 rep_desc[]);
+ u32 get_descr_sz(int sensor_idx, int descriptor_name);
+ u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report);
+diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+index 697f2791ea9c..7a62fcec2c73 100644
+--- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
++++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h
+@@ -644,6 +644,25 @@ static const u8 als_report_descriptor[] = {
+ 0xC0 /* HID end collection */
+ };
+
++
++static const u8 kbguard_report_descriptor[] = {
++0x06, 0x43, 0xFF, // Usage Page (Vendor Defined 0xFF43)
++0x0A, 0x02, 0x02, // Usage (0x0202)
++0xA1, 0x01, // Collection (Application)
++0x85, 0x11, // Report ID (17)
++0x15, 0x00, // Logical Minimum (0)
++0x25, 0x01, // Logical Maximum (1)
++0x35, 0x00, // Physical Minimum (0)
++0x45, 0x01, // Physical Maximum (1)
++0x65, 0x00, // Unit (None)
++0x55, 0x00, // Unit Exponent (0)
++0x75, 0x01, // Report Size (1)
++0x95, 0x98, // Report Count (-104)
++0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
++0x91, 0x03, // Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
++0xC1, 0x00, // End Collection
++};
++
+ /* BIOMETRIC PRESENCE*/
+ static const u8 hpd_report_descriptor[] = {
+ 0x05, 0x20, /* Usage page */
+--
+2.37.1
+
From 3f73788b14ada783657e5e6303c4e5de5e096be5 Mon Sep 17 00:00:00 2001
From: "Luke D. Jones" <luke@ljones.dev>
Date: Fri, 26 Aug 2022 12:32:24 +1200
@@ -2179,27 +2179,17 @@ index f608a4467d99..ea45e10302f7 100644
--
2.37.2
-From fe443cc4ff4e12652af1cdae63cff354a2467b67 Mon Sep 17 00:00:00 2001
-From: "Luke D. Jones" <luke@ljones.dev>
-Date: Fri, 26 Aug 2022 12:34:02 +1200
-Subject: [PATCH 21/21] asus-wmi: Support the GPU fan on TUF laptops
-
-Add support for TUF laptops which have the ability to control
-the GPU fan. This will show as a second fan in hwmon, and has
-the ability to run as boost (fullspeed), or auto.
-
-Signed-off-by: Luke D. Jones <luke@ljones.dev>
---
drivers/platform/x86/asus-wmi.c | 71 ++++++++++++++++++++++
include/linux/platform_data/x86/asus-wmi.h | 1 +
2 files changed, 72 insertions(+)
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
-index ea45e10302f7..d05684194f2d 100644
+index ac06fec0565c..2a74e468591a 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
-@@ -226,7 +226,9 @@ struct asus_wmi {
- u32 tablet_switch_dev_id;
+@@ -221,7 +221,9 @@ struct asus_wmi {
+ struct asus_rfkill uwb;
enum fan_type fan_type;
+ enum fan_type gpu_fan_type;
@@ -2208,12 +2198,12 @@ index ea45e10302f7..d05684194f2d 100644
int agfn_pwm;
bool fan_boost_mode_available;
-@@ -1861,6 +1863,18 @@ static int asus_fan_set_auto(struct asus_wmi *asus)
+@@ -1757,6 +1759,18 @@ static int asus_fan_set_auto(struct asus_wmi *asus)
return -ENXIO;
}
+ /*
-+ * Modern models like the G713 also have GPU fan control (this is not AGFN)
++ * Modern models like G713 also have GPU fan control. This is not AGFN.
+ */
+ if (asus->gpu_fan_type == FAN_TYPE_SPEC83) {
+ status = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_FAN_CTRL,
@@ -2227,7 +2217,7 @@ index ea45e10302f7..d05684194f2d 100644
return 0;
}
-@@ -2063,9 +2077,57 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
+@@ -1959,9 +1973,57 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
deci_kelvin_to_millicelsius(value & 0xFFFF));
}
@@ -2238,7 +2228,7 @@ index ea45e10302f7..d05684194f2d 100644
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
-+ return sysfs_emit(buf, "%d\n", asus->gpu_fan_pwm_mode);
++ return sprintf(buf, "%d\n", asus->gpu_fan_pwm_mode);
+}
+
+static ssize_t pwm2_enable_store(struct device *dev,
@@ -2285,7 +2275,7 @@ index ea45e10302f7..d05684194f2d 100644
static DEVICE_ATTR_RO(fan1_input);
static DEVICE_ATTR_RO(fan1_label);
-@@ -2075,6 +2137,7 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
+@@ -1971,6 +2033,7 @@ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
static struct attribute *hwmon_attributes[] = {
&dev_attr_pwm1.attr,
&dev_attr_pwm1_enable.attr,
@@ -2293,7 +2283,7 @@ index ea45e10302f7..d05684194f2d 100644
&dev_attr_fan1_input.attr,
&dev_attr_fan1_label.attr,
-@@ -2097,6 +2160,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
+@@ -1993,6 +2056,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
|| attr == &dev_attr_pwm1_enable.attr) {
if (asus->fan_type == FAN_TYPE_NONE)
return 0;
@@ -2303,7 +2293,7 @@ index ea45e10302f7..d05684194f2d 100644
} else if (attr == &dev_attr_temp1_input.attr) {
int err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_THERMAL_CTRL,
-@@ -2139,6 +2205,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
+@@ -2035,6 +2101,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
static int asus_wmi_fan_init(struct asus_wmi *asus)
{
@@ -2311,7 +2301,7 @@ index ea45e10302f7..d05684194f2d 100644
asus->fan_type = FAN_TYPE_NONE;
asus->agfn_pwm = -1;
-@@ -2147,6 +2214,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
+@@ -2043,6 +2110,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
else if (asus_wmi_has_agfn_fan(asus))
asus->fan_type = FAN_TYPE_AGFN;
@@ -2323,10 +2313,10 @@ index ea45e10302f7..d05684194f2d 100644
return -ENODEV;
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
-index 7dd580fdc61c..28234dc9fa6a 100644
+index a571b47ff362..bcffb77371be 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
-@@ -79,6 +79,7 @@
+@@ -77,6 +77,7 @@
#define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011
#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */
#define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013
@@ -2335,5 +2325,327 @@ index 7dd580fdc61c..28234dc9fa6a 100644
#define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
--
-2.37.2
+2.37.1
+
+ From ded47e7197a4ce9d6c34c0c96c6551ecaca0b6bd Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 16 Sep 2022 11:17:16 +1200
+Subject: [PATCH] asus-wmi: Expand support of GPU fan to read RPM and label
+
+The previously added patch to add support for pwm change for TUF laptops
+also is usuable for more than TUF. The same method `0x00110014` is
+used to read the fan RPM.
+
+Add two extra attributes for reading fan2 plus fan2 label.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 36 +++++++++++++++++++++++++++++++--
+ 1 file changed, 34 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index ae46af731de9..7fe6ce25da0a 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -72,6 +72,7 @@ module_param(fnlock_default, bool, 0444);
+
+ #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
+
++#define ASUS_GPU_FAN_DESC "gpu_fan"
+ #define ASUS_FAN_DESC "cpu_fan"
+ #define ASUS_FAN_MFUN 0x13
+ #define ASUS_FAN_SFUN_READ 0x06
+@@ -2078,6 +2079,30 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
+ }
+
+ /* GPU fan on modern ROG laptops */
++static ssize_t fan2_input_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct asus_wmi *asus = dev_get_drvdata(dev);
++ int value;
++ int ret;
++
++ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL, &value);
++ if (ret < 0)
++ return ret;
++
++ value &= 0xffff;
++
++ return sysfs_emit(buf, "%d\n", value < 0 ? -1 : value * 100);
++}
++
++static ssize_t fan2_label_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ return sprintf(buf, "%s\n", ASUS_GPU_FAN_DESC);
++}
++
+ static ssize_t pwm2_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+@@ -2127,9 +2152,12 @@ static ssize_t pwm2_enable_store(struct device *dev,
+ /* Fan1 */
+ static DEVICE_ATTR_RW(pwm1);
+ static DEVICE_ATTR_RW(pwm1_enable);
+-static DEVICE_ATTR_RW(pwm2_enable);
+ static DEVICE_ATTR_RO(fan1_input);
+ static DEVICE_ATTR_RO(fan1_label);
++/* Fan2 - GPU fan */
++static DEVICE_ATTR_RW(pwm2_enable);
++static DEVICE_ATTR_RO(fan2_input);
++static DEVICE_ATTR_RO(fan2_label);
+
+ /* Temperature */
+ static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
+@@ -2140,6 +2168,8 @@ static struct attribute *hwmon_attributes[] = {
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_label.attr,
++ &dev_attr_fan2_input.attr,
++ &dev_attr_fan2_label.attr,
+
+ &dev_attr_temp1_input.attr,
+ NULL
+@@ -2160,7 +2190,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
+ || attr == &dev_attr_pwm1_enable.attr) {
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return 0;
+- } else if (attr == &dev_attr_pwm2_enable.attr) {
++ } else if (attr == &dev_attr_fan2_input.attr
++ || attr == &dev_attr_fan2_label.attr
++ || attr == &dev_attr_pwm2_enable.attr) {
+ if (asus->gpu_fan_type == FAN_TYPE_NONE)
+ return 0;
+ } else if (attr == &dev_attr_temp1_input.attr) {
+--
+2.37.3
+
+From c104c26a25de7faf6c1fce3d05806d1766721798 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Mon, 10 Oct 2022 20:00:26 +1300
+Subject: [PATCH] ALSA: hda/realtek: Add quirk for ASUS GV601R laptop
+
+The ASUS ROG X16 (GV601R) series laptop has the same node-to-DAC pairs
+as early models and the G14, this includes bass speakers which are by
+default mapped incorrectly to the 0x06 node.
+
+Add a quirk to use the same DAC pairs as the G14.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ sound/pci/hda/patch_realtek.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index bce82b834cec..1ffea762ba57 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -9422,6 +9422,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
++ SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
+ SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
+ SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
+ SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
+--
+2.37.3
+
+From 4e55d420b8f311a5d93367e8598c7d1590eff4cf Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Mon, 10 Oct 2022 19:51:57 +1300
+Subject: [PATCH] Fixes bc2c23549ccd ("ALSA: hda/realtek: Add pincfg for ASUS
+ G533Z HP jack")
+
+The initial fix for ASUS G533Z was based on faulty information. This
+fixes the pincfg to values that have been verified with no existing
+module options or other hacks enabled.
+
+Enables headphone jack, and 5.1 surround.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ sound/pci/hda/patch_realtek.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
+index bce82b834cec..24406f81da27 100644
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -8449,11 +8449,13 @@ static const struct hda_fixup alc269_fixups[] = {
+ [ALC285_FIXUP_ASUS_G533Z_PINS] = {
+ .type = HDA_FIXUP_PINS,
+ .v.pins = (const struct hda_pintbl[]) {
+- { 0x14, 0x90170120 },
+- { }
++ { 0x14, 0x90170152 }, /* Speaker Surround Playback Switch */
++ { 0x19, 0x03a19020 }, /* Mic Boost Volume */
++ { 0x1a, 0x03a11c30 }, /* Mic Boost Volume */
++ { 0x1e, 0x90170151 }, /* Rear jack, IN OUT EAPD Detect */
++ { 0x21, 0x03211420 },
++ { }
+ },
+- .chained = true,
+- .chain_id = ALC294_FIXUP_ASUS_G513_PINS,
+ },
+ [ALC294_FIXUP_ASUS_COEF_1B] = {
+ .type = HDA_FIXUP_VERBS,
+--
+2.37.3
+
+From ef5a27e01610251d6b91e3bdcf297246414b40ce Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Mon, 10 Oct 2022 19:27:51 +1300
+Subject: [PATCH] platform/x86: asus-wmi: Add support for ROG X16 tablet mode
+
+Add quirk for ASUS ROG X16 Flow 2-in-1 to enable tablet mode with
+lid flip (all screen rotations).
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
+index 613c45c9fbe3..c685a705b73d 100644
+--- a/drivers/platform/x86/asus-nb-wmi.c
++++ b/drivers/platform/x86/asus-nb-wmi.c
+@@ -464,6 +464,15 @@ static const struct dmi_system_id asus_quirks[] = {
+ },
+ .driver_data = &quirk_asus_tablet_mode,
+ },
++ {
++ .callback = dmi_matched,
++ .ident = "ASUS ROG FLOW X16",
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "GV601R"),
++ },
++ .driver_data = &quirk_asus_tablet_mode,
++ },
+ {},
+ };
+
+--
+2.37.3
+
+From 9eccb147466f00a13c593ac078d8639e1eafe3a2 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 14 Oct 2022 10:43:09 +1300
+Subject: [PATCH] platform/x86: asus-wmi: Add safety checks to dgpu/egpu/mux
+ methods
+
+The WMI methods for dgpu_disable, egpu_enable, and gpu_mux_mode have
+no internal safety checks. This means it is possible for a user to
+set the gpu mux to discreet mode and then disable the dgpu, resulting
+in the user having no screen and very little chance of recovery.
+
+This commit adds checks to dgpu_disable and egpu_enable to ensure that
+the dgpu can not be disabled if the MUX is in discreet mode, and a
+check to gpu_mux_mode to prevent switching to discreet mode if
+dgpu_disable is set.
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 38 +++++++++++++++++++++++++++++++++
+ 1 file changed, 38 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 6e8e093f96b3..1afc4d40fa1a 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -615,6 +615,18 @@ static ssize_t dgpu_disable_store(struct device *dev,
+ if (disable > 1)
+ return -EINVAL;
+
++ /*
++ * The GPU MUX must be checked first, if it is in discreet mode the
++ * dgpu_disable cannot be set to on or users can end up with no screen.
++ */
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
++ if (result < 0)
++ return result;
++ if (!result && disable) {
++ pr_warn("ASUS MUX is in discreet mode, can not set dgpu_disable on\n");
++ return -EINVAL;
++ }
++
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
+ if (err) {
+ pr_warn("Failed to set dgpu disable: %d\n", err);
+@@ -663,6 +675,19 @@ static ssize_t egpu_enable_store(struct device *dev,
+ if (enable > 1)
+ return -EINVAL;
+
++ /*
++ * The GPU MUX must be checked first, if it is in discreet mode the
++ * egpu_enable cannot be set to on or users can end up with no screen.
++ * Note: egpu_enable method in WMI also sets dgpu_disable to on.
++ */
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
++ if (result < 0)
++ return result;
++ if (!result && enable) {
++ pr_warn("ASUS MUX is in discreet mode, can not set egpu_enable on\n");
++ return -EINVAL;
++ }
++
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
+ if (err) {
+ pr_warn("Failed to set egpu disable: %d\n", err);
+@@ -709,6 +734,19 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
+ if (optimus > 1)
+ return -EINVAL;
+
++ /*
++ * The dgpu_disable must be checked first, if it is enabled the
++ * gpu MUX can not be set to 0 or users can end up with no screen.
++ * Note: egpu_enable also switches dgpu_disable to 1 if enabled.
++ */
++ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU);
++ if (result < 0)
++ return result;
++ if (result && !optimus) {
++ pr_warn("ASUS dgpu_disable is set, can not switch MUX to discreet mode\n");
++ return -EINVAL;
++ }
++
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result);
+ if (err) {
+ dev_err(dev, "Failed to set GPU MUX mode: %d\n", err);
+--
+2.37.3
+
+From f1c38428ff75d0f3956615bea69a43b8b6812414 Mon Sep 17 00:00:00 2001
+From: "Luke D. Jones" <luke@ljones.dev>
+Date: Fri, 14 Oct 2022 13:03:36 +1300
+Subject: [PATCH] platform/x86: asus-wmi: Check for reboot required in
+ dgpu_disable methods
+
+Signed-off-by: Luke D. Jones <luke@ljones.dev>
+---
+ drivers/platform/x86/asus-wmi.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
+index 1afc4d40fa1a..5d5c473541bd 100644
+--- a/drivers/platform/x86/asus-wmi.c
++++ b/drivers/platform/x86/asus-wmi.c
+@@ -633,6 +633,11 @@ static ssize_t dgpu_disable_store(struct device *dev,
+ return err;
+ }
+
++ if (result == 2) {
++ pr_warn("Failed to set dgpu disable, reboot is required\n");
++ return -2;
++ }
++
+ if (result > 1) {
+ pr_warn("Failed to set dgpu disable (result): 0x%x\n", result);
+ return -EIO;
+--
+2.37.3
diff --git a/SOURCES/patch-5.19-redhat.patch b/SOURCES/patch-5.19-redhat.patch
index 64174be..2012e45 100644
--- a/SOURCES/patch-5.19-redhat.patch
+++ b/SOURCES/patch-5.19-redhat.patch
@@ -33,6 +33,7 @@
drivers/gpu/drm/v3d/v3d_debugfs.c | 18 +-
drivers/gpu/drm/v3d/v3d_drv.c | 12 +-
drivers/gpu/drm/v3d/v3d_gem.c | 12 +-
+ drivers/gpu/drm/vc4/vc4_hdmi.c | 29 +
drivers/hid/hid-rmi.c | 64 --
drivers/hwtracing/coresight/coresight-etm4x-core.c | 19 +
drivers/input/rmi4/rmi_driver.c | 124 +--
@@ -43,7 +44,10 @@
drivers/net/phy/bcm-phy-lib.h | 19 +
drivers/net/phy/bcm-phy-ptp.c | 944 +++++++++++++++++++++
drivers/net/phy/broadcom.c | 33 +-
+ drivers/net/wireless/mac80211_hwsim.c | 2 +
drivers/pci/quirks.c | 24 +
+ drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 10 +-
+ drivers/scsi/stex.c | 17 +-
drivers/soc/bcm/bcm2835-power.c | 72 +-
drivers/usb/core/hub.c | 7 +
include/linux/efi.h | 22 +-
@@ -52,16 +56,25 @@
include/linux/mfd/bcm2835-pm.h | 1 +
include/linux/rmi.h | 1 +
include/linux/security.h | 5 +
+ include/scsi/scsi_cmnd.h | 2 +-
init/Kconfig | 2 +-
kernel/module/signing.c | 9 +-
net/bluetooth/hci_event.c | 20 +
+ net/ipv4/fib_semantics.c | 8 +-
+ net/mac80211/ieee80211_i.h | 8 +
+ net/mac80211/rx.c | 12 +-
+ net/mac80211/util.c | 34 +-
+ net/mctp/af_mctp.c | 23 +-
+ net/mctp/route.c | 10 +-
+ net/wireless/scan.c | 77 +-
scripts/pahole-flags.sh | 4 +
scripts/tags.sh | 2 +
security/integrity/platform_certs/load_uefi.c | 6 +-
security/lockdown/Kconfig | 13 +
security/lockdown/lockdown.c | 1 +
security/security.c | 6 +
- 63 files changed, 1779 insertions(+), 348 deletions(-)
+ tools/testing/selftests/net/fib_nexthops.sh | 5 +
+ 76 files changed, 1939 insertions(+), 425 deletions(-)
diff --git a/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml b/Documentation/devicetree/bindings/gpu/brcm,bcm-v3d.yaml
index e6485f7b046f..217c42874f41 100644
@@ -253,7 +266,7 @@ index 000000000000..733a26bd887a
+
+endmenu
diff --git a/Makefile b/Makefile
-index ff4a15867145..975c3f82db13 100644
+index af05237987ef..ec594b2177f0 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,10 @@ $(if $(filter __%, $(MAKECMDGOALS)), \
@@ -1296,6 +1309,59 @@ index 2352e9640922..725a252e837b 100644
fail:
kfree(*container);
*container = NULL;
+diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
+index 199bc398817f..eb3aaaca2b80 100644
+--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
+@@ -2889,12 +2889,37 @@ static int vc4_hdmi_runtime_resume(struct device *dev)
+ struct vc4_hdmi *vc4_hdmi = dev_get_drvdata(dev);
+ unsigned long __maybe_unused flags;
+ u32 __maybe_unused value;
++ unsigned long rate;
+ int ret;
+
++ /*
++ * The HSM clock is in the HDMI power domain, so we need to set
++ * its frequency while the power domain is active so that it
++ * keeps its rate.
++ */
++ ret = clk_set_min_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ);
++ if (ret)
++ return ret;
++
+ ret = clk_prepare_enable(vc4_hdmi->hsm_clock);
+ if (ret)
+ return ret;
+
++ /*
++ * Whenever the RaspberryPi boots without an HDMI monitor
++ * plugged in, the firmware won't have initialized the HSM clock
++ * rate and it will be reported as 0.
++ *
++ * If we try to access a register of the controller in such a
++ * case, it will lead to a silent CPU stall. Let's make sure we
++ * prevent such a case.
++ */
++ rate = clk_get_rate(vc4_hdmi->hsm_clock);
++ if (!rate) {
++ ret = -EINVAL;
++ goto err_disable_clk;
++ }
++
+ if (vc4_hdmi->variant->reset)
+ vc4_hdmi->variant->reset(vc4_hdmi);
+
+@@ -2916,6 +2941,10 @@ static int vc4_hdmi_runtime_resume(struct device *dev)
+ #endif
+
+ return 0;
++
++err_disable_clk:
++ clk_disable_unprepare(vc4_hdmi->hsm_clock);
++ return ret;
+ }
+
+ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 311eee599ce9..2460c6bd46f8 100644
--- a/drivers/hid/hid-rmi.c
@@ -2881,6 +2947,19 @@ index e36809aa6d30..876bc45ede60 100644
return 0;
}
+diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
+index b511e705a46e..6c81422fd226 100644
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -4251,6 +4251,8 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
+
+ rx_status.band = channel->band;
+ rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
++ if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates)
++ goto out;
+ rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
+
+ hdr = (void *)skb->data;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 2e68f50bc7ae..00e1d5bc83a5 100644
--- a/drivers/pci/quirks.c
@@ -2916,6 +2995,68 @@ index 2e68f50bc7ae..00e1d5bc83a5 100644
/*
* Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero)
* class code. Fix it.
+diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+index 5223d4c9afdf..39f14a5b78cd 100644
+--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
++++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+@@ -1124,7 +1124,7 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
+ struct rockchip_usb2phy_port *rport,
+ struct device_node *child_np)
+ {
+- int ret;
++ int ret, id;
+
+ rport->port_id = USB2PHY_PORT_OTG;
+ rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_OTG];
+@@ -1162,13 +1162,15 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
+
+ ret = devm_extcon_register_notifier(rphy->dev, rphy->edev,
+ EXTCON_USB_HOST, &rport->event_nb);
+- if (ret)
++ if (ret) {
+ dev_err(rphy->dev, "register USB HOST notifier failed\n");
++ goto out;
++ }
+
+ if (!of_property_read_bool(rphy->dev->of_node, "extcon")) {
+ /* do initial sync of usb state */
+- ret = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
+- extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !ret);
++ id = property_enabled(rphy->grf, &rport->port_cfg->utmi_id);
++ extcon_set_state_sync(rphy->edev, EXTCON_USB_HOST, !id);
+ }
+ }
+
+diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
+index e6420f2127ce..8def242675ef 100644
+--- a/drivers/scsi/stex.c
++++ b/drivers/scsi/stex.c
+@@ -665,16 +665,17 @@ static int stex_queuecommand_lck(struct scsi_cmnd *cmd)
+ return 0;
+ case PASSTHRU_CMD:
+ if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
+- struct st_drvver ver;
++ const struct st_drvver ver = {
++ .major = ST_VER_MAJOR,
++ .minor = ST_VER_MINOR,
++ .oem = ST_OEM,
++ .build = ST_BUILD_VER,
++ .signature[0] = PASSTHRU_SIGNATURE,
++ .console_id = host->max_id - 1,
++ .host_no = hba->host->host_no,
++ };
+ size_t cp_len = sizeof(ver);
+
+- ver.major = ST_VER_MAJOR;
+- ver.minor = ST_VER_MINOR;
+- ver.oem = ST_OEM;
+- ver.build = ST_BUILD_VER;
+- ver.signature[0] = PASSTHRU_SIGNATURE;
+- ver.console_id = host->max_id - 1;
+- ver.host_no = hba->host->host_no;
+ cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len);
+ if (sizeof(ver) == cp_len)
+ cmd->result = DID_OK << 16;
diff --git a/drivers/soc/bcm/bcm2835-power.c b/drivers/soc/bcm/bcm2835-power.c
index 1e0041ec8132..5bcd047768b6 100644
--- a/drivers/soc/bcm/bcm2835-power.c
@@ -3217,6 +3358,19 @@ index 3cc127bb5bfd..2fecdfb03eb5 100644
#endif /* CONFIG_SECURITY */
#if defined(CONFIG_SECURITY) && defined(CONFIG_WATCH_QUEUE)
+diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
+index 1e80e70dfa92..5ce1aac64edd 100644
+--- a/include/scsi/scsi_cmnd.h
++++ b/include/scsi/scsi_cmnd.h
+@@ -201,7 +201,7 @@ static inline unsigned int scsi_get_resid(struct scsi_cmnd *cmd)
+ for_each_sg(scsi_sglist(cmd), sg, nseg, __i)
+
+ static inline int scsi_sg_copy_from_buffer(struct scsi_cmnd *cmd,
+- void *buf, int buflen)
++ const void *buf, int buflen)
+ {
+ return sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ buf, buflen);
diff --git a/init/Kconfig b/init/Kconfig
index c7900e8975f1..ea721c12c251 100644
--- a/init/Kconfig
@@ -3254,10 +3408,10 @@ index a2ff4242e623..f0d2be1ee4f1 100644
int module_sig_check(struct load_info *info, int flags)
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
-index 2c320a8fe70d..e097bf4ce549 100644
+index 81e5bcdbbe94..ff74e2a55e8f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
-@@ -3997,6 +3997,26 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
+@@ -3999,6 +3999,26 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, void *data,
break;
}
}
@@ -3284,6 +3438,373 @@ index 2c320a8fe70d..e097bf4ce549 100644
if (i == ARRAY_SIZE(hci_cc_table)) {
/* Unknown opcode, assume byte 0 contains the status, so
+diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
+index db7b2503f068..36653cd5964a 100644
+--- a/net/ipv4/fib_semantics.c
++++ b/net/ipv4/fib_semantics.c
+@@ -888,13 +888,13 @@ int fib_nh_match(struct net *net, struct fib_config *cfg, struct fib_info *fi,
+ return 1;
+ }
+
++ /* cannot match on nexthop object attributes */
++ if (fi->nh)
++ return 1;
++
+ if (cfg->fc_oif || cfg->fc_gw_family) {
+ struct fib_nh *nh;
+
+- /* cannot match on nexthop object attributes */
+- if (fi->nh)
+- return 1;
+-
+ nh = fib_info_nh(fi, 0);
+ if (cfg->fc_encap) {
+ if (fib_encap_match(net, cfg->fc_encap_type,
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index 48fbccbf2a54..44c8701af95c 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1640,6 +1640,14 @@ struct ieee802_11_elems {
+
+ /* whether a parse error occurred while retrieving these elements */
+ bool parse_error;
++
++ /*
++ * scratch buffer that can be used for various element parsing related
++ * tasks, e.g., element de-fragmentation etc.
++ */
++ size_t scratch_len;
++ u8 *scratch_pos;
++ u8 scratch[];
+ };
+
+ static inline struct ieee80211_local *hw_to_local(
+diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
+index b938806a5184..2d584a86dbf3 100644
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1988,10 +1988,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
+
+ if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
+ mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
+- NUM_DEFAULT_BEACON_KEYS) {
+- cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+- skb->data,
+- skb->len);
++ NUM_DEFAULT_BEACON_KEYS) {
++ if (rx->sdata->dev)
++ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
++ skb->data,
++ skb->len);
+ return RX_DROP_MONITOR; /* unexpected BIP keyidx */
+ }
+
+@@ -2139,7 +2140,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
+ /* either the frame has been decrypted or will be dropped */
+ status->flag |= RX_FLAG_DECRYPTED;
+
+- if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
++ if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
++ rx->sdata->dev))
+ cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+ skb->data, skb->len);
+
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index 3f698e508dd7..8f36ab8fcfb2 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -1439,6 +1439,8 @@ static size_t ieee802_11_find_bssid_profile(const u8 *start, size_t len,
+ for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
+ if (elem->datalen < 2)
+ continue;
++ if (elem->data[0] < 1 || elem->data[0] > 8)
++ continue;
+
+ for_each_element(sub, elem->data + 1, elem->datalen - 1) {
+ u8 new_bssid[ETH_ALEN];
+@@ -1501,25 +1503,27 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
+ const struct element *non_inherit = NULL;
+ u8 *nontransmitted_profile;
+ int nontransmitted_profile_len = 0;
++ size_t scratch_len = len;
+
+- elems = kzalloc(sizeof(*elems), GFP_ATOMIC);
++ elems = kzalloc(sizeof(*elems) + scratch_len, GFP_ATOMIC);
+ if (!elems)
+ return NULL;
+ elems->ie_start = start;
+ elems->total_len = len;
+-
+- nontransmitted_profile = kmalloc(len, GFP_ATOMIC);
+- if (nontransmitted_profile) {
+- nontransmitted_profile_len =
+- ieee802_11_find_bssid_profile(start, len, elems,
+- transmitter_bssid,
+- bss_bssid,
+- nontransmitted_profile);
+- non_inherit =
+- cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
+- nontransmitted_profile,
+- nontransmitted_profile_len);
+- }
++ elems->scratch_len = scratch_len;
++ elems->scratch_pos = elems->scratch;
++
++ nontransmitted_profile = elems->scratch_pos;
++ nontransmitted_profile_len =
++ ieee802_11_find_bssid_profile(start, len, elems,
++ transmitter_bssid,
++ bss_bssid,
++ nontransmitted_profile);
++ elems->scratch_pos += nontransmitted_profile_len;
++ elems->scratch_len -= nontransmitted_profile_len;
++ non_inherit = cfg80211_find_ext_elem(WLAN_EID_EXT_NON_INHERITANCE,
++ nontransmitted_profile,
++ nontransmitted_profile_len);
+
+ crc = _ieee802_11_parse_elems_crc(start, len, action, elems, filter,
+ crc, non_inherit);
+@@ -1548,8 +1552,6 @@ struct ieee802_11_elems *ieee802_11_parse_elems_crc(const u8 *start, size_t len,
+ offsetofend(struct ieee80211_bssid_index, dtim_count))
+ elems->dtim_count = elems->bssid_index->dtim_count;
+
+- kfree(nontransmitted_profile);
+-
+ elems->crc = crc;
+
+ return elems;
+diff --git a/net/mctp/af_mctp.c b/net/mctp/af_mctp.c
+index c2fc2a7b2528..b6b5e496fa40 100644
+--- a/net/mctp/af_mctp.c
++++ b/net/mctp/af_mctp.c
+@@ -295,11 +295,12 @@ __must_hold(&net->mctp.keys_lock)
+ mctp_dev_release_key(key->dev, key);
+ spin_unlock_irqrestore(&key->lock, flags);
+
+- hlist_del(&key->hlist);
+- hlist_del(&key->sklist);
+-
+- /* unref for the lists */
+- mctp_key_unref(key);
++ if (!hlist_unhashed(&key->hlist)) {
++ hlist_del_init(&key->hlist);
++ hlist_del_init(&key->sklist);
++ /* unref for the lists */
++ mctp_key_unref(key);
++ }
+
+ kfree_skb(skb);
+ }
+@@ -373,9 +374,17 @@ static int mctp_ioctl_alloctag(struct mctp_sock *msk, unsigned long arg)
+
+ ctl.tag = tag | MCTP_TAG_OWNER | MCTP_TAG_PREALLOC;
+ if (copy_to_user((void __user *)arg, &ctl, sizeof(ctl))) {
+- spin_lock_irqsave(&key->lock, flags);
+- __mctp_key_remove(key, net, flags, MCTP_TRACE_KEY_DROPPED);
++ unsigned long fl2;
++ /* Unwind our key allocation: the keys list lock needs to be
++ * taken before the individual key locks, and we need a valid
++ * flags value (fl2) to pass to __mctp_key_remove, hence the
++ * second spin_lock_irqsave() rather than a plain spin_lock().
++ */
++ spin_lock_irqsave(&net->mctp.keys_lock, flags);
++ spin_lock_irqsave(&key->lock, fl2);
++ __mctp_key_remove(key, net, fl2, MCTP_TRACE_KEY_DROPPED);
+ mctp_key_unref(key);
++ spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
+ return -EFAULT;
+ }
+
+diff --git a/net/mctp/route.c b/net/mctp/route.c
+index 3b24b8d18b5b..2155f15a074c 100644
+--- a/net/mctp/route.c
++++ b/net/mctp/route.c
+@@ -228,12 +228,12 @@ __releases(&key->lock)
+
+ if (!key->manual_alloc) {
+ spin_lock_irqsave(&net->mctp.keys_lock, flags);
+- hlist_del(&key->hlist);
+- hlist_del(&key->sklist);
++ if (!hlist_unhashed(&key->hlist)) {
++ hlist_del_init(&key->hlist);
++ hlist_del_init(&key->sklist);
++ mctp_key_unref(key);
++ }
+ spin_unlock_irqrestore(&net->mctp.keys_lock, flags);
+-
+- /* unref for the lists */
+- mctp_key_unref(key);
+ }
+
+ /* and one for the local reference */
+diff --git a/net/wireless/scan.c b/net/wireless/scan.c
+index 0134e5d5c81a..39fb9cc25cdc 100644
+--- a/net/wireless/scan.c
++++ b/net/wireless/scan.c
+@@ -143,18 +143,12 @@ static inline void bss_ref_get(struct cfg80211_registered_device *rdev,
+ lockdep_assert_held(&rdev->bss_lock);
+
+ bss->refcount++;
+- if (bss->pub.hidden_beacon_bss) {
+- bss = container_of(bss->pub.hidden_beacon_bss,
+- struct cfg80211_internal_bss,
+- pub);
+- bss->refcount++;
+- }
+- if (bss->pub.transmitted_bss) {
+- bss = container_of(bss->pub.transmitted_bss,
+- struct cfg80211_internal_bss,
+- pub);
+- bss->refcount++;
+- }
++
++ if (bss->pub.hidden_beacon_bss)
++ bss_from_pub(bss->pub.hidden_beacon_bss)->refcount++;
++
++ if (bss->pub.transmitted_bss)
++ bss_from_pub(bss->pub.transmitted_bss)->refcount++;
+ }
+
+ static inline void bss_ref_put(struct cfg80211_registered_device *rdev,
+@@ -304,7 +298,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
+ tmp_old = cfg80211_find_ie(WLAN_EID_SSID, ie, ielen);
+ tmp_old = (tmp_old) ? tmp_old + tmp_old[1] + 2 : ie;
+
+- while (tmp_old + tmp_old[1] + 2 - ie <= ielen) {
++ while (tmp_old + 2 - ie <= ielen &&
++ tmp_old + tmp_old[1] + 2 - ie <= ielen) {
+ if (tmp_old[0] == 0) {
+ tmp_old++;
+ continue;
+@@ -364,7 +359,8 @@ static size_t cfg80211_gen_new_ie(const u8 *ie, size_t ielen,
+ * copied to new ie, skip ssid, capability, bssid-index ie
+ */
+ tmp_new = sub_copy;
+- while (tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
++ while (tmp_new + 2 - sub_copy <= subie_len &&
++ tmp_new + tmp_new[1] + 2 - sub_copy <= subie_len) {
+ if (!(tmp_new[0] == WLAN_EID_NON_TX_BSSID_CAP ||
+ tmp_new[0] == WLAN_EID_SSID)) {
+ memcpy(pos, tmp_new, tmp_new[1] + 2);
+@@ -427,6 +423,15 @@ cfg80211_add_nontrans_list(struct cfg80211_bss *trans_bss,
+
+ rcu_read_unlock();
+
++ /*
++ * This is a bit weird - it's not on the list, but already on another
++ * one! The only way that could happen is if there's some BSSID/SSID
++ * shared by multiple APs in their multi-BSSID profiles, potentially
++ * with hidden SSID mixed in ... ignore it.
++ */
++ if (!list_empty(&nontrans_bss->nontrans_list))
++ return -EINVAL;
++
+ /* add to the list */
+ list_add_tail(&nontrans_bss->nontrans_list, &trans_bss->nontrans_list);
+ return 0;
+@@ -1602,6 +1607,23 @@ struct cfg80211_non_tx_bss {
+ u8 bssid_index;
+ };
+
++static void cfg80211_update_hidden_bsses(struct cfg80211_internal_bss *known,
++ const struct cfg80211_bss_ies *new_ies,
++ const struct cfg80211_bss_ies *old_ies)
++{
++ struct cfg80211_internal_bss *bss;
++
++ /* Assign beacon IEs to all sub entries */
++ list_for_each_entry(bss, &known->hidden_list, hidden_list) {
++ const struct cfg80211_bss_ies *ies;
++
++ ies = rcu_access_pointer(bss->pub.beacon_ies);
++ WARN_ON(ies != old_ies);
++
++ rcu_assign_pointer(bss->pub.beacon_ies, new_ies);
++ }
++}
++
+ static bool
+ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
+ struct cfg80211_internal_bss *known,
+@@ -1625,7 +1647,6 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
+ } else if (rcu_access_pointer(new->pub.beacon_ies)) {
+ const struct cfg80211_bss_ies *old;
+- struct cfg80211_internal_bss *bss;
+
+ if (known->pub.hidden_beacon_bss &&
+ !list_empty(&known->hidden_list)) {
+@@ -1653,16 +1674,7 @@ cfg80211_update_known_bss(struct cfg80211_registered_device *rdev,
+ if (old == rcu_access_pointer(known->pub.ies))
+ rcu_assign_pointer(known->pub.ies, new->pub.beacon_ies);
+
+- /* Assign beacon IEs to all sub entries */
+- list_for_each_entry(bss, &known->hidden_list, hidden_list) {
+- const struct cfg80211_bss_ies *ies;
+-
+- ies = rcu_access_pointer(bss->pub.beacon_ies);
+- WARN_ON(ies != old);
+-
+- rcu_assign_pointer(bss->pub.beacon_ies,
+- new->pub.beacon_ies);
+- }
++ cfg80211_update_hidden_bsses(known, new->pub.beacon_ies, old);
+
+ if (old)
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
+@@ -1739,6 +1751,8 @@ cfg80211_bss_update(struct cfg80211_registered_device *rdev,
+ new->refcount = 1;
+ INIT_LIST_HEAD(&new->hidden_list);
+ INIT_LIST_HEAD(&new->pub.nontrans_list);
++ /* we'll set this later if it was non-NULL */
++ new->pub.transmitted_bss = NULL;
+
+ if (rcu_access_pointer(tmp->pub.proberesp_ies)) {
+ hidden = rb_find_bss(rdev, tmp, BSS_CMP_HIDE_ZLEN);
+@@ -2021,10 +2035,15 @@ cfg80211_inform_single_bss_data(struct wiphy *wiphy,
+ spin_lock_bh(&rdev->bss_lock);
+ if (cfg80211_add_nontrans_list(non_tx_data->tx_bss,
+ &res->pub)) {
+- if (__cfg80211_unlink_bss(rdev, res))
++ if (__cfg80211_unlink_bss(rdev, res)) {
+ rdev->bss_generation++;
++ res = NULL;
++ }
+ }
+ spin_unlock_bh(&rdev->bss_lock);
++
++ if (!res)
++ return NULL;
+ }
+
+ trace_cfg80211_return_bss(&res->pub);
+@@ -2143,6 +2162,8 @@ static void cfg80211_parse_mbssid_data(struct wiphy *wiphy,
+ for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, ie, ielen) {
+ if (elem->datalen < 4)
+ continue;
++ if (elem->data[0] < 1 || (int)elem->data[0] > 8)
++ continue;
+ for_each_element(sub, elem->data + 1, elem->datalen - 1) {
+ u8 profile_len;
+
+@@ -2279,7 +2300,7 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
+ size_t new_ie_len;
+ struct cfg80211_bss_ies *new_ies;
+ const struct cfg80211_bss_ies *old;
+- u8 cpy_len;
++ size_t cpy_len;
+
+ lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
+
+@@ -2346,6 +2367,8 @@ cfg80211_update_notlisted_nontrans(struct wiphy *wiphy,
+ } else {
+ old = rcu_access_pointer(nontrans_bss->beacon_ies);
+ rcu_assign_pointer(nontrans_bss->beacon_ies, new_ies);
++ cfg80211_update_hidden_bsses(bss_from_pub(nontrans_bss),
++ new_ies, old);
+ rcu_assign_pointer(nontrans_bss->ies, new_ies);
+ if (old)
+ kfree_rcu((struct cfg80211_bss_ies *)old, rcu_head);
diff --git a/scripts/pahole-flags.sh b/scripts/pahole-flags.sh
index 0d99ef17e4a5..d4f3d63cb434 100755
--- a/scripts/pahole-flags.sh
@@ -3387,3 +3908,19 @@ index 8b62654ff3f9..1c03d1cff35c 100644
#ifdef CONFIG_PERF_EVENTS
int security_perf_event_open(struct perf_event_attr *attr, int type)
{
+diff --git a/tools/testing/selftests/net/fib_nexthops.sh b/tools/testing/selftests/net/fib_nexthops.sh
+index d5a0dd548989..ee5e98204d3d 100755
+--- a/tools/testing/selftests/net/fib_nexthops.sh
++++ b/tools/testing/selftests/net/fib_nexthops.sh
+@@ -1223,6 +1223,11 @@ ipv4_fcnal()
+ log_test $rc 0 "Delete nexthop route warning"
+ run_cmd "$IP route delete 172.16.101.1/32 nhid 12"
+ run_cmd "$IP nexthop del id 12"
++
++ run_cmd "$IP nexthop add id 21 via 172.16.1.6 dev veth1"
++ run_cmd "$IP ro add 172.16.101.0/24 nhid 21"
++ run_cmd "$IP ro del 172.16.101.0/24 nexthop via 172.16.1.7 dev veth1 nexthop via 172.16.1.8 dev veth1"
++ log_test $? 2 "Delete multipath route with only nh id based entry"
+ }
+
+ ipv4_grp_fcnal()
diff --git a/SOURCES/v3-1-7-acpi-x86-s2idle-Move-_HID-handling-for-AMD-systems-into-structures.patch b/SOURCES/v3-1-7-acpi-x86-s2idle-Move-_HID-handling-for-AMD-systems-into-structures.patch
index 70be906..4c8a1c5 100644
--- a/SOURCES/v3-1-7-acpi-x86-s2idle-Move-_HID-handling-for-AMD-systems-into-structures.patch
+++ b/SOURCES/v3-1-7-acpi-x86-s2idle-Move-_HID-handling-for-AMD-systems-into-structures.patch
@@ -1,12 +1,8 @@
----
- drivers/acpi/x86/s2idle.c | 63 ++++++++++++++++++++++++++++-----------
- 1 file changed, 46 insertions(+), 17 deletions(-)
-
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
-index f9ac12b778e6..a7757551f750 100644
+index e10394b847af..c9ee30627b6c 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
-@@ -363,6 +363,39 @@ static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *d
+@@ -369,6 +369,39 @@ static int validate_dsm(acpi_handle handle, const char *uuid, int rev, guid_t *d
return ret;
}
@@ -46,7 +42,11 @@ index f9ac12b778e6..a7757551f750 100644
static int lps0_device_attach(struct acpi_device *adev,
const struct acpi_device_id *not_used)
{
-@@ -452,31 +452,27 @@
+diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
+index c9ee30627b6c..2d1ff7796c34 100644
+--- a/drivers/acpi/x86/s2idle.c
++++ b/drivers/acpi/x86/s2idle.c
+@@ -412,31 +412,29 @@ static int lps0_device_attach(struct acpi_device *adev,
return 0;
if (acpi_s2idle_vendor_amd()) {
@@ -72,7 +72,7 @@ index f9ac12b778e6..a7757551f750 100644
+ if (dev_id != NULL)
+ data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data;
+ else
-+ return 0;
++ data = &amd_rembrandt;
+ rev_id = data->rev_id;
lps0_dsm_func_mask = validate_dsm(adev->handle,
ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
@@ -87,36 +87,12 @@ index f9ac12b778e6..a7757551f750 100644
acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
- } else if (lps0_dsm_func_mask_microsoft > 0 && !strcmp(hid, "AMDI0007")) {
-+ } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid) {
++ } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid &&
++ (!strcmp(hid, "AMDI0007") ||
++ !strcmp(hid, "AMDI0008"))) {
lps0_dsm_func_mask_microsoft = -EINVAL;
acpi_handle_debug(adev->handle, "_DSM Using AMD method\n");
}
---
-2.34.1
-
- ---
- drivers/acpi/x86/s2idle.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
-index a7757551f750..a8256e5a0e8a 100644
---- a/drivers/acpi/x86/s2idle.c
-+++ b/drivers/acpi/x86/s2idle.c
-@@ -461,7 +461,7 @@
- if (dev_id != NULL)
- data = (const struct amd_lps0_hid_device_data *) dev_id->driver_data;
- else
-- return 0;
-+ data = &amd_rembrandt;
- rev_id = data->rev_id;
- lps0_dsm_func_mask = validate_dsm(adev->handle,
- ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
---
-2.34.1
-
- ---
- drivers/acpi/x86/s2idle.c | 16 ++++++++++------
- 1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
index a8256e5a0e8a..a9b0f2b54a1c 100644
@@ -133,8 +109,8 @@ index a8256e5a0e8a..a9b0f2b54a1c 100644
static const struct acpi_device_id lps0_device_ids[] = {
{"PNP0D80", },
{"", },
-@@ -451,6 +451,9 @@
- if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
+@@ -402,6 +406,9 @@ static int lps0_device_attach(struct acpi_device *adev,
+ if (lps0_device_handle)
return 0;
+ lps0_dsm_func_mask_microsoft = validate_dsm(adev->handle,
@@ -143,7 +119,7 @@ index a8256e5a0e8a..a9b0f2b54a1c 100644
if (acpi_s2idle_vendor_amd()) {
static const struct acpi_device_id *dev_id;
const struct amd_lps0_hid_device_data *data;
-@@ -468,14 +468,11 @@
+@@ -416,16 +423,12 @@ static int lps0_device_attach(struct acpi_device *adev,
rev_id = data->rev_id;
lps0_dsm_func_mask = validate_dsm(adev->handle,
ACPI_LPS0_DSM_UUID_AMD, rev_id, &lps0_dsm_guid);
@@ -154,8 +130,10 @@ index a8256e5a0e8a..a9b0f2b54a1c 100644
lps0_dsm_func_mask = (lps0_dsm_func_mask << 1) | 0x1;
acpi_handle_debug(adev->handle, "_DSM UUID %s: Adjusted function mask: 0x%x\n",
ACPI_LPS0_DSM_UUID_AMD, lps0_dsm_func_mask);
-- } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid) {
-+ } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid && !prefer_microsoft_guid) {
+ } else if (lps0_dsm_func_mask_microsoft > 0 && data->prefer_amd_guid &&
+- (!strcmp(hid, "AMDI0007") ||
+- !strcmp(hid, "AMDI0008"))) {
++ !prefer_microsoft_guid) {
lps0_dsm_func_mask_microsoft = -EINVAL;
acpi_handle_debug(adev->handle, "_DSM Using AMD method\n");
}
@@ -169,18 +147,8 @@ index a8256e5a0e8a..a9b0f2b54a1c 100644
}
if (lps0_dsm_func_mask < 0 && lps0_dsm_func_mask_microsoft < 0)
---
-2.34.1
-
- ---
-v1->v2:
- * Fixup for __init
----
- drivers/acpi/x86/s2idle.c | 26 +++++++++++++++++++++++++-
- 1 file changed, 25 insertions(+), 1 deletion(-)
-
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
-index a9b0f2b54a1c..9ee734e0c3c5 100644
+index a9b0f2b54a1c..6a2c94fdbeae 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -17,6 +17,7 @@
@@ -220,21 +188,18 @@ index a9b0f2b54a1c..9ee734e0c3c5 100644
static int lps0_device_attach(struct acpi_device *adev,
const struct acpi_device_id *not_used)
{
-@@ -566,8 +589,9 @@ static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
- .end = acpi_s2idle_end,
- };
+@@ -568,6 +591,7 @@ static const struct platform_s2idle_ops acpi_s2idle_ops_lps0 = {
--void acpi_s2idle_setup(void)
-+void __init acpi_s2idle_setup(void)
+ void acpi_s2idle_setup(void)
{
+ dmi_check_system(s2idle_dmi_table);
acpi_scan_add_handler(&lps0_handler);
s2idle_set_ops(&acpi_s2idle_ops_lps0);
- }
---
-2.34.1
-
- ---
+ }---
+v3-v4:
+ * Absorb tags
+v2->v3:
+ * Absorb tags
v1->v2:
* New patch
---
@@ -242,7 +207,7 @@ v1->v2:
1 file changed, 8 insertions(+)
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
-index 9ee734e0c3c5..4bdc7133d2ea 100644
+index 99eae362de6d..2cd381f6c002 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
@@ -420,6 +420,14 @@ static const struct dmi_system_id s2idle_dmi_table[] __initconst = {
@@ -262,19 +227,23 @@ index 9ee734e0c3c5..4bdc7133d2ea 100644
--
2.34.1
-
- ---
+---
+v3->v4:
+ * Fix URL for one of the bugzilla links
+v2->v3:
+ * Adjust prefix to cover multiple systems
+ * Add another Link tag
v1->v2:
* New patch
---
- drivers/acpi/x86/s2idle.c | 11 +++++++++++
- 1 file changed, 11 insertions(+)
+ drivers/acpi/x86/s2idle.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
-index 4bdc7133d2ea..8475a3915812 100644
+index 2cd381f6c002..c811eeed42cd 100644
--- a/drivers/acpi/x86/s2idle.c
+++ b/drivers/acpi/x86/s2idle.c
-@@ -428,6 +428,17 @@ static const struct dmi_system_id s2idle_dmi_table[] __initconst = {
+@@ -428,6 +428,29 @@ static const struct dmi_system_id s2idle_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "ROG Zephyrus G14 GA402"),
},
},
@@ -289,10 +258,53 @@ index 4bdc7133d2ea..8475a3915812 100644
+ DMI_MATCH(DMI_PRODUCT_NAME, "82V2"),
+ },
+ },
++ {
++ /*
++ *
++ * Hijacking patch for GV601
++ *
++ */
++ .callback = lps0_prefer_microsoft,
++ .matches = {
++ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "GV601"),
++ },
++ },
{}
};
--
2.34.1
+---
+v3->v4:
+ * Absorb tag
+v2->v3:
+ * New patch
+---
+ drivers/acpi/x86/s2idle.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
- \ No newline at end of file
+diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c
+index c811eeed42cd..eedd21d8a284 100644
+--- a/drivers/acpi/x86/s2idle.c
++++ b/drivers/acpi/x86/s2idle.c
+@@ -440,6 +440,17 @@ static const struct dmi_system_id s2idle_dmi_table[] __initconst = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "82"),
+ },
+ },
++ {
++ /*
++ * ASUSTeK COMPUTER INC. ROG Flow X13 GV301RE_GV301RE
++ * https://gitlab.freedesktop.org/drm/amd/-/issues/2148
++ */
++ .callback = lps0_prefer_microsoft,
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow X13 GV301"),
++ },
++ },
+ {}
+ };
+
+--
+2.34.1