]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.18
authorSasha Levin <sashal@kernel.org>
Mon, 13 Jun 2022 05:20:42 +0000 (01:20 -0400)
committerSasha Levin <sashal@kernel.org>
Mon, 13 Jun 2022 05:20:42 +0000 (01:20 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.18/platform-x86-barco-p50-gpio-add-check-for-platform_d.patch [new file with mode: 0644]
queue-5.18/platform-x86-hp-wmi-resolve-wmi-query-failures-on-so.patch [new file with mode: 0644]
queue-5.18/platform-x86-hp-wmi-use-zero-insize-parameter-only-w.patch [new file with mode: 0644]
queue-5.18/scripts-gdb-change-kernel-config-dumping-method.patch [new file with mode: 0644]
queue-5.18/scsi-lpfc-correct-bde-type-for-xmit_seq64_wqe-in-lpf.patch [new file with mode: 0644]
queue-5.18/series
queue-5.18/vringh-fix-loop-descriptors-check-in-the-indirect-ca.patch [new file with mode: 0644]

diff --git a/queue-5.18/platform-x86-barco-p50-gpio-add-check-for-platform_d.patch b/queue-5.18/platform-x86-barco-p50-gpio-add-check-for-platform_d.patch
new file mode 100644 (file)
index 0000000..8dcde18
--- /dev/null
@@ -0,0 +1,46 @@
+From 5137a26dae6ef0f81239c83a86d379b2d642009f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 26 May 2022 17:03:45 +0800
+Subject: platform/x86: barco-p50-gpio: Add check for platform_driver_register
+
+From: Jiasheng Jiang <jiasheng@iscas.ac.cn>
+
+[ Upstream commit 011881b80ebe773914b59905bce0f5e0ef93e7ba ]
+
+As platform_driver_register() could fail, it should be better
+to deal with the return value in order to maintain the code
+consisitency.
+
+Fixes: 86af1d02d458 ("platform/x86: Support for EC-connected GPIOs for identify LED/button on Barco P50 board")
+Signed-off-by: Jiasheng Jiang <jiasheng@iscas.ac.cn>
+Acked-by: Peter Korsgaard <peter.korsgaard@barco.com>
+Link: https://lore.kernel.org/r/20220526090345.1444172-1-jiasheng@iscas.ac.cn
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/barco-p50-gpio.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/platform/x86/barco-p50-gpio.c b/drivers/platform/x86/barco-p50-gpio.c
+index 05534287bc26..8dd672339485 100644
+--- a/drivers/platform/x86/barco-p50-gpio.c
++++ b/drivers/platform/x86/barco-p50-gpio.c
+@@ -405,11 +405,14 @@ MODULE_DEVICE_TABLE(dmi, dmi_ids);
+ static int __init p50_module_init(void)
+ {
+       struct resource res = DEFINE_RES_IO(P50_GPIO_IO_PORT_BASE, P50_PORT_CMD + 1);
++      int ret;
+       if (!dmi_first_match(dmi_ids))
+               return -ENODEV;
+-      platform_driver_register(&p50_gpio_driver);
++      ret = platform_driver_register(&p50_gpio_driver);
++      if (ret)
++              return ret;
+       gpio_pdev = platform_device_register_simple(DRIVER_NAME, PLATFORM_DEVID_NONE, &res, 1);
+       if (IS_ERR(gpio_pdev)) {
+-- 
+2.35.1
+
diff --git a/queue-5.18/platform-x86-hp-wmi-resolve-wmi-query-failures-on-so.patch b/queue-5.18/platform-x86-hp-wmi-resolve-wmi-query-failures-on-so.patch
new file mode 100644 (file)
index 0000000..5c3d908
--- /dev/null
@@ -0,0 +1,79 @@
+From c26d5ba6038158f0a556db4bd84c70756379fc44 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 8 Jun 2022 16:29:23 -0500
+Subject: platform/x86: hp-wmi: Resolve WMI query failures on some devices
+
+From: Jorge Lopez <jorge.lopez2@hp.com>
+
+[ Upstream commit dc6a6ab58379f25bf991d8e4a13b001ed806e881 ]
+
+WMI queries fail on some devices where the ACPI method HWMC
+unconditionally attempts to create Fields beyond the buffer
+if the buffer is too small, this breaks essential features
+such as power profiles:
+
+         CreateByteField (Arg1, 0x10, D008)
+         CreateByteField (Arg1, 0x11, D009)
+         CreateByteField (Arg1, 0x12, D010)
+         CreateDWordField (Arg1, 0x10, D032)
+         CreateField (Arg1, 0x80, 0x0400, D128)
+
+In cases where args->data had zero length, ACPI BIOS Error
+(bug): AE_AML_BUFFER_LIMIT, Field [D008] at bit
+offset/length 128/8 exceeds size of target Buffer (128 bits)
+(20211217/dsopcode-198) was obtained.
+
+ACPI BIOS Error (bug): AE_AML_BUFFER_LIMIT, Field [D009] at bit
+offset/length 136/8 exceeds size of target Buffer (136bits)
+(20211217/dsopcode-198)
+
+The original code created a buffer size of 128 bytes regardless if
+the WMI call required a smaller buffer or not.  This particular
+behavior occurs in older BIOS and reproduced in OMEN laptops.  Newer
+BIOS handles buffer sizes properly and meets the latest specification
+requirements.  This is the reason why testing with a dynamically
+allocated buffer did not uncover any failures with the test systems at
+hand.
+
+This patch was tested on several OMEN, Elite, and Zbooks.  It was
+confirmed the patch resolves HPWMI_FAN GET/SET calls in an OMEN
+Laptop 15-ek0xxx.  No problems were reported when testing on several Elite
+and Zbooks notebooks.
+
+Fixes: 4b4967cbd268 ("platform/x86: hp-wmi: Changing bios_args.data to be dynamically allocated")
+Signed-off-by: Jorge Lopez <jorge.lopez2@hp.com>
+Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
+Link: https://lore.kernel.org/r/20220608212923.8585-2-jorge.lopez2@hp.com
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/hp-wmi.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
+index 0e9a25b56e0e..d3540dd62d06 100644
+--- a/drivers/platform/x86/hp-wmi.c
++++ b/drivers/platform/x86/hp-wmi.c
+@@ -290,14 +290,16 @@ static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
+       struct bios_return *bios_return;
+       union acpi_object *obj = NULL;
+       struct bios_args *args = NULL;
+-      int mid, actual_outsize, ret;
++      int mid, actual_insize, actual_outsize;
+       size_t bios_args_size;
++      int ret;
+       mid = encode_outsize_for_pvsz(outsize);
+       if (WARN_ON(mid < 0))
+               return mid;
+-      bios_args_size = struct_size(args, data, insize);
++      actual_insize = max(insize, 128);
++      bios_args_size = struct_size(args, data, actual_insize);
+       args = kmalloc(bios_args_size, GFP_KERNEL);
+       if (!args)
+               return -ENOMEM;
+-- 
+2.35.1
+
diff --git a/queue-5.18/platform-x86-hp-wmi-use-zero-insize-parameter-only-w.patch b/queue-5.18/platform-x86-hp-wmi-use-zero-insize-parameter-only-w.patch
new file mode 100644 (file)
index 0000000..fa20866
--- /dev/null
@@ -0,0 +1,138 @@
+From 69dc772cd3b207a8659b1562e437c3da03386c33 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 9 Jun 2022 00:58:43 +0530
+Subject: platform/x86: hp-wmi: Use zero insize parameter only when supported
+
+From: Bedant Patnaik <bedant.patnaik@gmail.com>
+
+[ Upstream commit 65f936f3535950d2643eac5bf34a735a0e428cdd ]
+
+commit be9d73e64957 ("platform/x86: hp-wmi: Fix 0x05 error code reported by
+several WMI calls") and commit 12b19f14a21a ("platform/x86: hp-wmi: Fix
+hp_wmi_read_int() reporting error (0x05)") cause ACPI BIOS Error (bug):
+Attempt to CreateField of length zero (20211217/dsopcode-133) because of
+the ACPI method HWMC, which unconditionally creates a Field of
+size (insize*8) bits:
+       CreateField (Arg1, 0x80, (Local5 * 0x08), DAIN)
+In cases where args->insize = 0, the Field size is 0, resulting in
+an error.
+
+Fix this by using zero insize only if 0x5 error code is returned
+
+Tested on Omen 15 AMD (2020) board ID: 8786.
+
+Fixes: be9d73e64957 ("platform/x86: hp-wmi: Fix 0x05 error code reported by several WMI calls")
+Signed-off-by: Bedant Patnaik <bedant.patnaik@gmail.com>
+Tested-by: Jorge Lopez <jorge.lopez2@hp.com>
+Link: https://lore.kernel.org/r/41be46743d21c78741232a47bbb5f1cdbcc3d21e.camel@gmail.com
+Reviewed-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/platform/x86/hp-wmi.c | 23 +++++++++++++++--------
+ 1 file changed, 15 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
+index d3540dd62d06..0e6ed75c70f3 100644
+--- a/drivers/platform/x86/hp-wmi.c
++++ b/drivers/platform/x86/hp-wmi.c
+@@ -38,6 +38,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
+ #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
+ #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
+ #define HP_OMEN_EC_THERMAL_PROFILE_OFFSET 0x95
++#define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required
+ /* DMI board names of devices that should use the omen specific path for
+  * thermal profiles.
+@@ -220,6 +221,7 @@ static struct input_dev *hp_wmi_input_dev;
+ static struct platform_device *hp_wmi_platform_dev;
+ static struct platform_profile_handler platform_profile_handler;
+ static bool platform_profile_support;
++static bool zero_insize_support;
+ static struct rfkill *wifi_rfkill;
+ static struct rfkill *bluetooth_rfkill;
+@@ -376,7 +378,7 @@ static int hp_wmi_read_int(int query)
+       int val = 0, ret;
+       ret = hp_wmi_perform_query(query, HPWMI_READ, &val,
+-                                 0, sizeof(val));
++                                 zero_if_sup(val), sizeof(val));
+       if (ret)
+               return ret < 0 ? ret : -EINVAL;
+@@ -412,7 +414,8 @@ static int hp_wmi_get_tablet_mode(void)
+               return -ENODEV;
+       ret = hp_wmi_perform_query(HPWMI_SYSTEM_DEVICE_MODE, HPWMI_READ,
+-                                 system_device_mode, 0, sizeof(system_device_mode));
++                                 system_device_mode, zero_if_sup(system_device_mode),
++                                 sizeof(system_device_mode));
+       if (ret < 0)
+               return ret;
+@@ -499,7 +502,7 @@ static int hp_wmi_fan_speed_max_get(void)
+       int val = 0, ret;
+       ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_GET_QUERY, HPWMI_GM,
+-                                 &val, 0, sizeof(val));
++                                 &val, zero_if_sup(val), sizeof(val));
+       if (ret)
+               return ret < 0 ? ret : -EINVAL;
+@@ -511,7 +514,7 @@ static int __init hp_wmi_bios_2008_later(void)
+ {
+       int state = 0;
+       int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state,
+-                                     0, sizeof(state));
++                                     zero_if_sup(state), sizeof(state));
+       if (!ret)
+               return 1;
+@@ -522,7 +525,7 @@ static int __init hp_wmi_bios_2009_later(void)
+ {
+       u8 state[128];
+       int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,
+-                                     0, sizeof(state));
++                                     zero_if_sup(state), sizeof(state));
+       if (!ret)
+               return 1;
+@@ -600,7 +603,7 @@ static int hp_wmi_rfkill2_refresh(void)
+       int err, i;
+       err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
+-                                 0, sizeof(state));
++                                 zero_if_sup(state), sizeof(state));
+       if (err)
+               return err;
+@@ -1002,7 +1005,7 @@ static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
+       int err, i;
+       err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
+-                                 0, sizeof(state));
++                                 zero_if_sup(state), sizeof(state));
+       if (err)
+               return err < 0 ? err : -EINVAL;
+@@ -1477,11 +1480,15 @@ static int __init hp_wmi_init(void)
+ {
+       int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
+       int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
+-      int err;
++      int err, tmp = 0;
+       if (!bios_capable && !event_capable)
+               return -ENODEV;
++      if (hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_READ, &tmp,
++                               sizeof(tmp), sizeof(tmp)) == HPWMI_RET_INVALID_PARAMETERS)
++              zero_insize_support = true;
++
+       if (event_capable) {
+               err = hp_wmi_input_setup();
+               if (err)
+-- 
+2.35.1
+
diff --git a/queue-5.18/scripts-gdb-change-kernel-config-dumping-method.patch b/queue-5.18/scripts-gdb-change-kernel-config-dumping-method.patch
new file mode 100644 (file)
index 0000000..f84666b
--- /dev/null
@@ -0,0 +1,43 @@
+From 98191ba0ae499723bb27e16095ec47dea01fada6 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 10 Jun 2022 15:14:57 +0800
+Subject: scripts/gdb: change kernel config dumping method
+
+From: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>
+
+[ Upstream commit 1f7a6cf6b07c74a17343c2559cd5f5018a245961 ]
+
+MAGIC_START("IKCFG_ST") and MAGIC_END("IKCFG_ED") are moved out
+from the kernel_config_data variable.
+
+Thus, we parse kernel_config_data directly instead of considering
+offset of MAGIC_START and MAGIC_END.
+
+Fixes: 13610aa908dc ("kernel/configs: use .incbin directive to embed config_data.gz")
+Signed-off-by: Kuan-Ying Lee <Kuan-Ying.Lee@mediatek.com>
+Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ scripts/gdb/linux/config.py | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/scripts/gdb/linux/config.py b/scripts/gdb/linux/config.py
+index 90e1565b1967..8843ab3cbadd 100644
+--- a/scripts/gdb/linux/config.py
++++ b/scripts/gdb/linux/config.py
+@@ -24,9 +24,9 @@ class LxConfigDump(gdb.Command):
+             filename = arg
+         try:
+-            py_config_ptr = gdb.parse_and_eval("kernel_config_data + 8")
+-            py_config_size = gdb.parse_and_eval(
+-                    "sizeof(kernel_config_data) - 1 - 8 * 2")
++            py_config_ptr = gdb.parse_and_eval("&kernel_config_data")
++            py_config_ptr_end = gdb.parse_and_eval("&kernel_config_data_end")
++            py_config_size = py_config_ptr_end - py_config_ptr
+         except gdb.error as e:
+             raise gdb.GdbError("Can't find config, enable CONFIG_IKCONFIG?")
+-- 
+2.35.1
+
diff --git a/queue-5.18/scsi-lpfc-correct-bde-type-for-xmit_seq64_wqe-in-lpf.patch b/queue-5.18/scsi-lpfc-correct-bde-type-for-xmit_seq64_wqe-in-lpf.patch
new file mode 100644 (file)
index 0000000..1d90fba
--- /dev/null
@@ -0,0 +1,44 @@
+From f525940db9593bf6ad1486510b2f35bb54cb54de Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 3 Jun 2022 10:43:21 -0700
+Subject: scsi: lpfc: Correct BDE type for XMIT_SEQ64_WQE in
+ lpfc_ct_reject_event()
+
+From: James Smart <jsmart2021@gmail.com>
+
+[ Upstream commit 44ba9786b67345dc4e5eabe537c9ef2bfd889888 ]
+
+A previous commit assumed all XMIT_SEQ64_WQEs are prepped with the correct
+BDE type in word 0-2.  However, lpfc_ct_reject_event() routine was missed
+and is still filling out the incorrect BDE type.
+
+Fix lpfc_ct_reject_event() routine so that type BUFF_TYPE_BDE_64 is set
+instead of BUFF_TYPE_BLP_64.
+
+Link: https://lore.kernel.org/r/20220603174329.63777-2-jsmart2021@gmail.com
+Fixes: 596fc8adb171 ("scsi: lpfc: Fix dmabuf ptr assignment in lpfc_ct_reject_event()")
+Co-developed-by: Justin Tee <justin.tee@broadcom.com>
+Signed-off-by: Justin Tee <justin.tee@broadcom.com>
+Signed-off-by: James Smart <jsmart2021@gmail.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/scsi/lpfc/lpfc_ct.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
+index 4b024aa03c1b..87124fd65272 100644
+--- a/drivers/scsi/lpfc/lpfc_ct.c
++++ b/drivers/scsi/lpfc/lpfc_ct.c
+@@ -197,7 +197,7 @@ lpfc_ct_reject_event(struct lpfc_nodelist *ndlp,
+       memset(bpl, 0, sizeof(struct ulp_bde64));
+       bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys));
+       bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys));
+-      bpl->tus.f.bdeFlags = BUFF_TYPE_BLP_64;
++      bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64;
+       bpl->tus.f.bdeSize = (LPFC_CT_PREAMBLE - 4);
+       bpl->tus.w = le32_to_cpu(bpl->tus.w);
+-- 
+2.35.1
+
index 48ab4423078979f5641f1c510311076ab6076f06..ba4f05486b62ea577a5edd13d15cd19be3e21b27 100644 (file)
@@ -285,3 +285,9 @@ s390-gmap-voluntarily-schedule-during-key-setting.patch
 cifs-version-operations-for-smb20-unneeded-when-lega.patch
 drm-amd-pm-use-bitmap_-from-to-_arr32-where-appropri.patch
 nodemask-fix-return-values-to-be-unsigned.patch
+scsi-lpfc-correct-bde-type-for-xmit_seq64_wqe-in-lpf.patch
+vringh-fix-loop-descriptors-check-in-the-indirect-ca.patch
+platform-x86-barco-p50-gpio-add-check-for-platform_d.patch
+scripts-gdb-change-kernel-config-dumping-method.patch
+platform-x86-hp-wmi-resolve-wmi-query-failures-on-so.patch
+platform-x86-hp-wmi-use-zero-insize-parameter-only-w.patch
diff --git a/queue-5.18/vringh-fix-loop-descriptors-check-in-the-indirect-ca.patch b/queue-5.18/vringh-fix-loop-descriptors-check-in-the-indirect-ca.patch
new file mode 100644 (file)
index 0000000..186c882
--- /dev/null
@@ -0,0 +1,63 @@
+From 7a41be2979d29b71655a6f7710d01beaae06a8ef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 5 May 2022 18:09:10 +0800
+Subject: vringh: Fix loop descriptors check in the indirect cases
+
+From: Xie Yongji <xieyongji@bytedance.com>
+
+[ Upstream commit dbd29e0752286af74243cf891accf472b2f3edd8 ]
+
+We should use size of descriptor chain to test loop condition
+in the indirect case. And another statistical count is also introduced
+for indirect descriptors to avoid conflict with the statistical count
+of direct descriptors.
+
+Fixes: f87d0fbb5798 ("vringh: host-side implementation of virtio rings.")
+Signed-off-by: Xie Yongji <xieyongji@bytedance.com>
+Signed-off-by: Fam Zheng <fam.zheng@bytedance.com>
+Message-Id: <20220505100910.137-1-xieyongji@bytedance.com>
+Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
+Acked-by: Jason Wang <jasowang@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/vhost/vringh.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c
+index 14e2043d7685..eab55accf381 100644
+--- a/drivers/vhost/vringh.c
++++ b/drivers/vhost/vringh.c
+@@ -292,7 +292,7 @@ __vringh_iov(struct vringh *vrh, u16 i,
+            int (*copy)(const struct vringh *vrh,
+                        void *dst, const void *src, size_t len))
+ {
+-      int err, count = 0, up_next, desc_max;
++      int err, count = 0, indirect_count = 0, up_next, desc_max;
+       struct vring_desc desc, *descs;
+       struct vringh_range range = { -1ULL, 0 }, slowrange;
+       bool slow = false;
+@@ -349,7 +349,12 @@ __vringh_iov(struct vringh *vrh, u16 i,
+                       continue;
+               }
+-              if (count++ == vrh->vring.num) {
++              if (up_next == -1)
++                      count++;
++              else
++                      indirect_count++;
++
++              if (count > vrh->vring.num || indirect_count > desc_max) {
+                       vringh_bad("Descriptor loop in %p", descs);
+                       err = -ELOOP;
+                       goto fail;
+@@ -411,6 +416,7 @@ __vringh_iov(struct vringh *vrh, u16 i,
+                               i = return_from_indirect(vrh, &up_next,
+                                                        &descs, &desc_max);
+                               slow = false;
++                              indirect_count = 0;
+                       } else
+                               break;
+               }
+-- 
+2.35.1
+