--- /dev/null
+From 37ba91a82e3b9de35f64348c62b5ec7d74e3a41c Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 12 Nov 2023 21:36:26 +0100
+Subject: ACPI: PM: Add acpi_device_fix_up_power_children() function
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit 37ba91a82e3b9de35f64348c62b5ec7d74e3a41c upstream.
+
+In some cases it is necessary to fix-up the power-state of an ACPI
+device's children without touching the ACPI device itself add
+a new acpi_device_fix_up_power_children() function for this.
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Cc: 6.6+ <stable@vger.kernel.org> # 6.6+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/device_pm.c | 13 +++++++++++++
+ include/acpi/acpi_bus.h | 1 +
+ 2 files changed, 14 insertions(+)
+
+--- a/drivers/acpi/device_pm.c
++++ b/drivers/acpi/device_pm.c
+@@ -397,6 +397,19 @@ void acpi_device_fix_up_power_extended(s
+ }
+ EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_extended);
+
++/**
++ * acpi_device_fix_up_power_children - Force a device's children into D0.
++ * @adev: Parent device object whose children's power state is to be fixed up.
++ *
++ * Call acpi_device_fix_up_power() for @adev's children so long as they
++ * are reported as present and enabled.
++ */
++void acpi_device_fix_up_power_children(struct acpi_device *adev)
++{
++ acpi_dev_for_each_child(adev, fix_up_power_if_applicable, NULL);
++}
++EXPORT_SYMBOL_GPL(acpi_device_fix_up_power_children);
++
+ int acpi_device_update_power(struct acpi_device *device, int *state_p)
+ {
+ int state;
+--- a/include/acpi/acpi_bus.h
++++ b/include/acpi/acpi_bus.h
+@@ -539,6 +539,7 @@ int acpi_device_set_power(struct acpi_de
+ int acpi_bus_init_power(struct acpi_device *device);
+ int acpi_device_fix_up_power(struct acpi_device *device);
+ void acpi_device_fix_up_power_extended(struct acpi_device *adev);
++void acpi_device_fix_up_power_children(struct acpi_device *adev);
+ int acpi_bus_update_power(acpi_handle handle, int *state_p);
+ int acpi_device_update_power(struct acpi_device *device, int *state_p);
+ bool acpi_bus_power_manageable(acpi_handle handle);
--- /dev/null
+From 9bb69ba4c177dccaa1f5b5cbdf80b67813328348 Mon Sep 17 00:00:00 2001
+From: David Woodhouse <dwmw@amazon.co.uk>
+Date: Fri, 27 Oct 2023 19:36:51 +0100
+Subject: ACPI: processor_idle: use raw_safe_halt() in acpi_idle_play_dead()
+
+From: David Woodhouse <dwmw@amazon.co.uk>
+
+commit 9bb69ba4c177dccaa1f5b5cbdf80b67813328348 upstream.
+
+Xen HVM guests were observed taking triple-faults when attempting to
+online a previously offlined vCPU.
+
+Investigation showed that the fault was coming from a failing call
+to lockdep_assert_irqs_disabled(), in load_current_idt() which was
+too early in the CPU bringup to actually catch the exception and
+report the failure cleanly.
+
+This was a false positive, caused by acpi_idle_play_dead() setting
+the per-cpu hardirqs_enabled flag by calling safe_halt(). Switch it
+to use raw_safe_halt() instead, which doesn't do so.
+
+Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
+Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
+Cc: 6.6+ <stable@vger.kernel.org> # 6.6+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/processor_idle.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
+index 3a34a8c425fe..55437f5e0c3a 100644
+--- a/drivers/acpi/processor_idle.c
++++ b/drivers/acpi/processor_idle.c
+@@ -592,7 +592,7 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
+ while (1) {
+
+ if (cx->entry_method == ACPI_CSTATE_HALT)
+- safe_halt();
++ raw_safe_halt();
+ else if (cx->entry_method == ACPI_CSTATE_SYSTEMIO) {
+ io_idle(cx->address);
+ } else
+--
+2.43.0
+
--- /dev/null
+From bd911485294a6f0596e4592ed442438015cffc8a Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Wed, 15 Nov 2023 19:02:22 +0100
+Subject: ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CVA
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit bd911485294a6f0596e4592ed442438015cffc8a upstream.
+
+Like various other ASUS ExpertBook-s, the ASUS ExpertBook B1402CVA
+has an ACPI DSDT table that describes IRQ 1 as ActiveLow while
+the kernel overrides it to EdgeHigh.
+
+This prevents the keyboard from working. To fix this issue, add this laptop
+to the skip_override_table so that the kernel does not override IRQ 1.
+
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218114
+Cc: All applicable <stable@vger.kernel.org>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/resource.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+--- a/drivers/acpi/resource.c
++++ b/drivers/acpi/resource.c
+@@ -447,6 +447,13 @@ static const struct dmi_system_id asus_l
+ },
+ },
+ {
++ /* Asus ExpertBook B1402CVA */
++ .matches = {
++ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
++ DMI_MATCH(DMI_BOARD_NAME, "B1402CVA"),
++ },
++ },
++ {
+ .ident = "Asus ExpertBook B1502CBA",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
--- /dev/null
+From c93695494606326d7fd72b46a2a657139ccb0dec Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sun, 12 Nov 2023 21:36:27 +0100
+Subject: ACPI: video: Use acpi_device_fix_up_power_children()
+
+From: Hans de Goede <hdegoede@redhat.com>
+
+commit c93695494606326d7fd72b46a2a657139ccb0dec upstream.
+
+Commit 89c290ea7589 ("ACPI: video: Put ACPI video and its child devices
+into D0 on boot") introduced calling acpi_device_fix_up_power_extended()
+on the video card for which the ACPI video bus is the companion device.
+
+This unnecessarily touches the power-state of the GPU itself, while
+the issue it tries to address only requires calling _PS0 on the child
+devices.
+
+Touching the power-state of the GPU itself is causing suspend / resume
+issues on e.g. a Lenovo ThinkPad W530.
+
+Instead use acpi_device_fix_up_power_children(), which only touches
+the child devices, to fix this.
+
+Fixes: 89c290ea7589 ("ACPI: video: Put ACPI video and its child devices into D0 on boot")
+Reported-by: Owen T. Heisler <writer@owenh.net>
+Closes: https://lore.kernel.org/regressions/9f36fb06-64c4-4264-aaeb-4e1289e764c4@owenh.net/
+Closes: https://gitlab.freedesktop.org/drm/nouveau/-/issues/273
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218124
+Tested-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
+Tested-by: Owen T. Heisler <writer@owenh.net>
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+Cc: 6.6+ <stable@vger.kernel.org> # 6.6+
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/acpi_video.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
+index 0b7a01f38b65..d321ca7160d9 100644
+--- a/drivers/acpi/acpi_video.c
++++ b/drivers/acpi/acpi_video.c
+@@ -2031,7 +2031,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
+ * HP ZBook Fury 16 G10 requires ACPI video's child devices have _PS0
+ * evaluated to have functional panel brightness control.
+ */
+- acpi_device_fix_up_power_extended(device);
++ acpi_device_fix_up_power_children(device);
+
+ pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n",
+ ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
+--
+2.43.0
+
--- /dev/null
+From 2faac25d7958c4761bb8cec54adb79f806783ad6 Mon Sep 17 00:00:00 2001
+From: Mingzhe Zou <mingzhe.zou@easystack.cn>
+Date: Mon, 20 Nov 2023 13:25:00 +0800
+Subject: bcache: fixup multi-threaded bch_sectors_dirty_init() wake-up race
+
+From: Mingzhe Zou <mingzhe.zou@easystack.cn>
+
+commit 2faac25d7958c4761bb8cec54adb79f806783ad6 upstream.
+
+We get a kernel crash about "unable to handle kernel paging request":
+
+```dmesg
+[368033.032005] BUG: unable to handle kernel paging request at ffffffffad9ae4b5
+[368033.032007] PGD fc3a0d067 P4D fc3a0d067 PUD fc3a0e063 PMD 8000000fc38000e1
+[368033.032012] Oops: 0003 [#1] SMP PTI
+[368033.032015] CPU: 23 PID: 55090 Comm: bch_dirtcnt[0] Kdump: loaded Tainted: G OE --------- - - 4.18.0-147.5.1.es8_24.x86_64 #1
+[368033.032017] Hardware name: Tsinghua Tongfang THTF Chaoqiang Server/072T6D, BIOS 2.4.3 01/17/2017
+[368033.032027] RIP: 0010:native_queued_spin_lock_slowpath+0x183/0x1d0
+[368033.032029] Code: 8b 02 48 85 c0 74 f6 48 89 c1 eb d0 c1 e9 12 83 e0
+03 83 e9 01 48 c1 e0 05 48 63 c9 48 05 c0 3d 02 00 48 03 04 cd 60 68 93
+ad <48> 89 10 8b 42 08 85 c0 75 09 f3 90 8b 42 08 85 c0 74 f7 48 8b 02
+[368033.032031] RSP: 0018:ffffbb48852abe00 EFLAGS: 00010082
+[368033.032032] RAX: ffffffffad9ae4b5 RBX: 0000000000000246 RCX: 0000000000003bf3
+[368033.032033] RDX: ffff97b0ff8e3dc0 RSI: 0000000000600000 RDI: ffffbb4884743c68
+[368033.032034] RBP: 0000000000000001 R08: 0000000000000000 R09: 000007ffffffffff
+[368033.032035] R10: ffffbb486bb01000 R11: 0000000000000001 R12: ffffffffc068da70
+[368033.032036] R13: 0000000000000003 R14: 0000000000000000 R15: 0000000000000000
+[368033.032038] FS: 0000000000000000(0000) GS:ffff97b0ff8c0000(0000) knlGS:0000000000000000
+[368033.032039] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
+[368033.032040] CR2: ffffffffad9ae4b5 CR3: 0000000fc3a0a002 CR4: 00000000003626e0
+[368033.032042] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
+[368033.032043] bcache: bch_cached_dev_attach() Caching rbd479 as bcache462 on set 8cff3c36-4a76-4242-afaa-7630206bc70b
+[368033.032045] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
+[368033.032046] Call Trace:
+[368033.032054] _raw_spin_lock_irqsave+0x32/0x40
+[368033.032061] __wake_up_common_lock+0x63/0xc0
+[368033.032073] ? bch_ptr_invalid+0x10/0x10 [bcache]
+[368033.033502] bch_dirty_init_thread+0x14c/0x160 [bcache]
+[368033.033511] ? read_dirty_submit+0x60/0x60 [bcache]
+[368033.033516] kthread+0x112/0x130
+[368033.033520] ? kthread_flush_work_fn+0x10/0x10
+[368033.034505] ret_from_fork+0x35/0x40
+```
+
+The crash occurred when call wake_up(&state->wait), and then we want
+to look at the value in the state. However, bch_sectors_dirty_init()
+is not found in the stack of any task. Since state is allocated on
+the stack, we guess that bch_sectors_dirty_init() has exited, causing
+bch_dirty_init_thread() to be unable to handle kernel paging request.
+
+In order to verify this idea, we added some printing information during
+wake_up(&state->wait). We find that "wake up" is printed twice, however
+we only expect the last thread to wake up once.
+
+```dmesg
+[ 994.641004] alcache: bch_dirty_init_thread() wake up
+[ 994.641018] alcache: bch_dirty_init_thread() wake up
+[ 994.641523] alcache: bch_sectors_dirty_init() init exit
+```
+
+There is a race. If bch_sectors_dirty_init() exits after the first wake
+up, the second wake up will trigger this bug("unable to handle kernel
+paging request").
+
+Proceed as follows:
+
+bch_sectors_dirty_init
+ kthread_run ==============> bch_dirty_init_thread(bch_dirtcnt[0])
+ ... ...
+ atomic_inc(&state.started) ...
+ ... ...
+ atomic_read(&state.enough) ...
+ ... atomic_set(&state->enough, 1)
+ kthread_run ======================================================> bch_dirty_init_thread(bch_dirtcnt[1])
+ ... atomic_dec_and_test(&state->started) ...
+ atomic_inc(&state.started) ... ...
+ ... wake_up(&state->wait) ...
+ atomic_read(&state.enough) atomic_dec_and_test(&state->started)
+ ... ...
+ wait_event(state.wait, atomic_read(&state.started) == 0) ...
+ return ...
+ wake_up(&state->wait)
+
+We believe it is very common to wake up twice if there is no dirty, but
+crash is an extremely low probability event. It's hard for us to reproduce
+this issue. We attached and detached continuously for a week, with a total
+of more than one million attaches and only one crash.
+
+Putting atomic_inc(&state.started) before kthread_run() can avoid waking
+up twice.
+
+Fixes: b144e45fc576 ("bcache: make bch_sectors_dirty_init() to be multithreaded")
+Signed-off-by: Mingzhe Zou <mingzhe.zou@easystack.cn>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Coly Li <colyli@suse.de>
+Link: https://lore.kernel.org/r/20231120052503.6122-8-colyli@suse.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/bcache/writeback.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/bcache/writeback.c
++++ b/drivers/md/bcache/writeback.c
+@@ -1014,17 +1014,18 @@ void bch_sectors_dirty_init(struct bcach
+ if (atomic_read(&state.enough))
+ break;
+
++ atomic_inc(&state.started);
+ state.infos[i].state = &state;
+ state.infos[i].thread =
+ kthread_run(bch_dirty_init_thread, &state.infos[i],
+ "bch_dirtcnt[%d]", i);
+ if (IS_ERR(state.infos[i].thread)) {
+ pr_err("fails to run thread bch_dirty_init[%d]\n", i);
++ atomic_dec(&state.started);
+ for (--i; i >= 0; i--)
+ kthread_stop(state.infos[i].thread);
+ goto out;
+ }
+- atomic_inc(&state.started);
+ }
+
+ out:
--- /dev/null
+From f72f4312d4388376fc8a1f6cf37cb21a0d41758b Mon Sep 17 00:00:00 2001
+From: Coly Li <colyli@suse.de>
+Date: Mon, 20 Nov 2023 13:25:01 +0800
+Subject: bcache: replace a mistaken IS_ERR() by IS_ERR_OR_NULL() in btree_gc_coalesce()
+
+From: Coly Li <colyli@suse.de>
+
+commit f72f4312d4388376fc8a1f6cf37cb21a0d41758b upstream.
+
+Commit 028ddcac477b ("bcache: Remove unnecessary NULL point check in
+node allocations") do the following change inside btree_gc_coalesce(),
+
+31 @@ -1340,7 +1340,7 @@ static int btree_gc_coalesce(
+32 memset(new_nodes, 0, sizeof(new_nodes));
+33 closure_init_stack(&cl);
+34
+35 - while (nodes < GC_MERGE_NODES && !IS_ERR_OR_NULL(r[nodes].b))
+36 + while (nodes < GC_MERGE_NODES && !IS_ERR(r[nodes].b))
+37 keys += r[nodes++].keys;
+38
+39 blocks = btree_default_blocks(b->c) * 2 / 3;
+
+At line 35 the original r[nodes].b is not always allocatored from
+__bch_btree_node_alloc(), and possibly initialized as NULL pointer by
+caller of btree_gc_coalesce(). Therefore the change at line 36 is not
+correct.
+
+This patch replaces the mistaken IS_ERR() by IS_ERR_OR_NULL() to avoid
+potential issue.
+
+Fixes: 028ddcac477b ("bcache: Remove unnecessary NULL point check in node allocations")
+Cc: <stable@vger.kernel.org> # 6.5+
+Cc: Zheng Wang <zyytlz.wz@163.com>
+Signed-off-by: Coly Li <colyli@suse.de>
+Link: https://lore.kernel.org/r/20231120052503.6122-9-colyli@suse.de
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/bcache/btree.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/md/bcache/btree.c
++++ b/drivers/md/bcache/btree.c
+@@ -1363,7 +1363,7 @@ static int btree_gc_coalesce(struct btre
+ memset(new_nodes, 0, sizeof(new_nodes));
+ closure_init_stack(&cl);
+
+- while (nodes < GC_MERGE_NODES && !IS_ERR(r[nodes].b))
++ while (nodes < GC_MERGE_NODES && !IS_ERR_OR_NULL(r[nodes].b))
+ keys += r[nodes++].keys;
+
+ blocks = btree_default_blocks(b->c) * 2 / 3;
--- /dev/null
+From 8d6ef26501b97243ee6c16b8187c5b38cb69b77d Mon Sep 17 00:00:00 2001
+From: Thomas Zimmermann <tzimmermann@suse.de>
+Date: Thu, 16 Nov 2023 14:02:12 +0100
+Subject: drm/ast: Disconnect BMC if physical connector is connected
+
+From: Thomas Zimmermann <tzimmermann@suse.de>
+
+commit 8d6ef26501b97243ee6c16b8187c5b38cb69b77d upstream.
+
+Many user-space compositors fail with mode setting if a CRTC has
+more than one connected connector. This is the case with the BMC
+on Aspeed systems. Work around this problem by setting the BMC's
+connector status to disconnected when the physical connector has
+a display attached. This way compositors will only see one connected
+connector at a time; either the physical one or the BMC.
+
+Suggested-by: Jocelyn Falempe <jfalempe@redhat.com>
+Fixes: e329cb53b45d ("drm/ast: Add BMC virtual connector")
+Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
+Cc: <stable@vger.kernel.org> # v6.6+
+Reviewed-by: Jocelyn Falempe <jfalempe@redhat.com>
+Link: https://patchwork.freedesktop.org/patch/msgid/20231116130217.22931-1-tzimmermann@suse.de
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/ast/ast_drv.h | 13 +++++++-
+ drivers/gpu/drm/ast/ast_mode.c | 62 ++++++++++++++++++++++++++++++++++++-----
+ 2 files changed, 67 insertions(+), 8 deletions(-)
+
+--- a/drivers/gpu/drm/ast/ast_drv.h
++++ b/drivers/gpu/drm/ast/ast_drv.h
+@@ -172,6 +172,17 @@ to_ast_sil164_connector(struct drm_conne
+ return container_of(connector, struct ast_sil164_connector, base);
+ }
+
++struct ast_bmc_connector {
++ struct drm_connector base;
++ struct drm_connector *physical_connector;
++};
++
++static inline struct ast_bmc_connector *
++to_ast_bmc_connector(struct drm_connector *connector)
++{
++ return container_of(connector, struct ast_bmc_connector, base);
++}
++
+ /*
+ * Device
+ */
+@@ -216,7 +227,7 @@ struct ast_device {
+ } astdp;
+ struct {
+ struct drm_encoder encoder;
+- struct drm_connector connector;
++ struct ast_bmc_connector bmc_connector;
+ } bmc;
+ } output;
+
+--- a/drivers/gpu/drm/ast/ast_mode.c
++++ b/drivers/gpu/drm/ast/ast_mode.c
+@@ -1767,6 +1767,30 @@ static const struct drm_encoder_funcs as
+ .destroy = drm_encoder_cleanup,
+ };
+
++static int ast_bmc_connector_helper_detect_ctx(struct drm_connector *connector,
++ struct drm_modeset_acquire_ctx *ctx,
++ bool force)
++{
++ struct ast_bmc_connector *bmc_connector = to_ast_bmc_connector(connector);
++ struct drm_connector *physical_connector = bmc_connector->physical_connector;
++
++ /*
++ * Most user-space compositors cannot handle more than one connected
++ * connector per CRTC. Hence, we only mark the BMC as connected if the
++ * physical connector is disconnected. If the physical connector's status
++ * is connected or unknown, the BMC remains disconnected. This has no
++ * effect on the output of the BMC.
++ *
++ * FIXME: Remove this logic once user-space compositors can handle more
++ * than one connector per CRTC. The BMC should always be connected.
++ */
++
++ if (physical_connector && physical_connector->status == connector_status_disconnected)
++ return connector_status_connected;
++
++ return connector_status_disconnected;
++}
++
+ static int ast_bmc_connector_helper_get_modes(struct drm_connector *connector)
+ {
+ return drm_add_modes_noedid(connector, 4096, 4096);
+@@ -1774,6 +1798,7 @@ static int ast_bmc_connector_helper_get_
+
+ static const struct drm_connector_helper_funcs ast_bmc_connector_helper_funcs = {
+ .get_modes = ast_bmc_connector_helper_get_modes,
++ .detect_ctx = ast_bmc_connector_helper_detect_ctx,
+ };
+
+ static const struct drm_connector_funcs ast_bmc_connector_funcs = {
+@@ -1784,12 +1809,33 @@ static const struct drm_connector_funcs
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ };
+
+-static int ast_bmc_output_init(struct ast_device *ast)
++static int ast_bmc_connector_init(struct drm_device *dev,
++ struct ast_bmc_connector *bmc_connector,
++ struct drm_connector *physical_connector)
++{
++ struct drm_connector *connector = &bmc_connector->base;
++ int ret;
++
++ ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs,
++ DRM_MODE_CONNECTOR_VIRTUAL);
++ if (ret)
++ return ret;
++
++ drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs);
++
++ bmc_connector->physical_connector = physical_connector;
++
++ return 0;
++}
++
++static int ast_bmc_output_init(struct ast_device *ast,
++ struct drm_connector *physical_connector)
+ {
+ struct drm_device *dev = &ast->base;
+ struct drm_crtc *crtc = &ast->crtc;
+ struct drm_encoder *encoder = &ast->output.bmc.encoder;
+- struct drm_connector *connector = &ast->output.bmc.connector;
++ struct ast_bmc_connector *bmc_connector = &ast->output.bmc.bmc_connector;
++ struct drm_connector *connector = &bmc_connector->base;
+ int ret;
+
+ ret = drm_encoder_init(dev, encoder,
+@@ -1799,13 +1845,10 @@ static int ast_bmc_output_init(struct as
+ return ret;
+ encoder->possible_crtcs = drm_crtc_mask(crtc);
+
+- ret = drm_connector_init(dev, connector, &ast_bmc_connector_funcs,
+- DRM_MODE_CONNECTOR_VIRTUAL);
++ ret = ast_bmc_connector_init(dev, bmc_connector, physical_connector);
+ if (ret)
+ return ret;
+
+- drm_connector_helper_add(connector, &ast_bmc_connector_helper_funcs);
+-
+ ret = drm_connector_attach_encoder(connector, encoder);
+ if (ret)
+ return ret;
+@@ -1864,6 +1907,7 @@ static const struct drm_mode_config_func
+ int ast_mode_config_init(struct ast_device *ast)
+ {
+ struct drm_device *dev = &ast->base;
++ struct drm_connector *physical_connector = NULL;
+ int ret;
+
+ ret = drmm_mode_config_init(dev);
+@@ -1904,23 +1948,27 @@ int ast_mode_config_init(struct ast_devi
+ ret = ast_vga_output_init(ast);
+ if (ret)
+ return ret;
++ physical_connector = &ast->output.vga.vga_connector.base;
+ }
+ if (ast->tx_chip_types & AST_TX_SIL164_BIT) {
+ ret = ast_sil164_output_init(ast);
+ if (ret)
+ return ret;
++ physical_connector = &ast->output.sil164.sil164_connector.base;
+ }
+ if (ast->tx_chip_types & AST_TX_DP501_BIT) {
+ ret = ast_dp501_output_init(ast);
+ if (ret)
+ return ret;
++ physical_connector = &ast->output.dp501.connector;
+ }
+ if (ast->tx_chip_types & AST_TX_ASTDP_BIT) {
+ ret = ast_astdp_output_init(ast);
+ if (ret)
+ return ret;
++ physical_connector = &ast->output.astdp.connector;
+ }
+- ret = ast_bmc_output_init(ast);
++ ret = ast_bmc_output_init(ast, physical_connector);
+ if (ret)
+ return ret;
+
--- /dev/null
+From a33b2431d11b4df137bbcfdd5a5adfa054c2479e Mon Sep 17 00:00:00 2001
+From: Bjorn Andersson <quic_bjorande@quicinc.com>
+Date: Mon, 30 Oct 2023 16:23:20 -0700
+Subject: drm/msm/dpu: Add missing safe_lut_tbl in sc8280xp catalog
+
+From: Bjorn Andersson <quic_bjorande@quicinc.com>
+
+commit a33b2431d11b4df137bbcfdd5a5adfa054c2479e upstream.
+
+During USB transfers on the SC8280XP __arm_smmu_tlb_sync() is seen to
+typically take 1-2ms to complete. As expected this results in poor
+performance, something that has been mitigated by proposing running the
+iommu in non-strict mode (boot with iommu.strict=0).
+
+This turns out to be related to the SAFE logic, and programming the QOS
+SAFE values in the DPU (per suggestion from Rob and Doug) reduces the
+TLB sync time to below 10us, which means significant less time spent
+with interrupts disabled and a significant boost in throughput.
+
+Fixes: 4a352c2fc15a ("drm/msm/dpu: Introduce SC8280XP")
+Cc: stable@vger.kernel.org
+Suggested-by: Doug Anderson <dianders@chromium.org>
+Suggested-by: Rob Clark <robdclark@chromium.org>
+Signed-off-by: Bjorn Andersson <quic_bjorande@quicinc.com>
+Tested-by: Johan Hovold <johan+linaro@kernel.org>
+Tested-by: Steev Klimaszewski <steev@kali.org>
+Reviewed-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Patchwork: https://patchwork.freedesktop.org/patch/565094/
+Link: https://lore.kernel.org/r/20231030-sc8280xp-dpu-safe-lut-v1-1-6d485d7b428f@quicinc.com
+Signed-off-by: Abhinav Kumar <quic_abhinavk@quicinc.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h
++++ b/drivers/gpu/drm/msm/disp/dpu1/catalog/dpu_8_0_sc8280xp.h
+@@ -419,6 +419,7 @@ static const struct dpu_perf_cfg sc8280x
+ .min_llcc_ib = 0,
+ .min_dram_ib = 800000,
+ .danger_lut_tbl = {0xf, 0xffff, 0x0},
++ .safe_lut_tbl = {0xfe00, 0xfe00, 0xffff},
+ .qos_lut_tbl = {
+ {.nentry = ARRAY_SIZE(sc8180x_qos_linear),
+ .entries = sc8180x_qos_linear
--- /dev/null
+From d0c930b745cafde8e7d25d0356c648bca669556a Mon Sep 17 00:00:00 2001
+From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
+Date: Mon, 13 Nov 2023 15:59:20 +0100
+Subject: dt-bindings: usb: microchip,usb5744: Add second supply
+
+From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
+
+commit d0c930b745cafde8e7d25d0356c648bca669556a upstream.
+
+The USB5744 has two power supplies one for 3V3 and one for 1V2. Add the
+second supply to the USB5744 DT binding.
+
+Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
+Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
+Acked-by: Conor Dooley <conor.dooley@microchip.com>
+Cc: stable <stable@kernel.org>
+Link: https://lore.kernel.org/r/20231113145921.30104-2-francesco@dolcini.it
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/devicetree/bindings/usb/microchip,usb5744.yaml | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml
++++ b/Documentation/devicetree/bindings/usb/microchip,usb5744.yaml
+@@ -36,7 +36,11 @@ properties:
+
+ vdd-supply:
+ description:
+- VDD power supply to the hub
++ 3V3 power supply to the hub
++
++ vdd2-supply:
++ description:
++ 1V2 power supply to the hub
+
+ peer-hub:
+ $ref: /schemas/types.yaml#/definitions/phandle
+@@ -62,6 +66,7 @@ allOf:
+ properties:
+ reset-gpios: false
+ vdd-supply: false
++ vdd2-supply: false
+ peer-hub: false
+ i2c-bus: false
+ else:
--- /dev/null
+From d30fb712e52964f2cf9a9c14cf67078394044837 Mon Sep 17 00:00:00 2001
+From: Haiyang Zhang <haiyangz@microsoft.com>
+Date: Sun, 19 Nov 2023 08:23:41 -0800
+Subject: hv_netvsc: fix race of netvsc and VF register_netdevice
+
+From: Haiyang Zhang <haiyangz@microsoft.com>
+
+commit d30fb712e52964f2cf9a9c14cf67078394044837 upstream.
+
+The rtnl lock also needs to be held before rndis_filter_device_add()
+which advertises nvsp_2_vsc_capability / sriov bit, and triggers
+VF NIC offering and registering. If VF NIC finished register_netdev()
+earlier it may cause name based config failure.
+
+To fix this issue, move the call to rtnl_lock() before
+rndis_filter_device_add(), so VF will be registered later than netvsc
+/ synthetic NIC, and gets a name numbered (ethX) after netvsc.
+
+Cc: stable@vger.kernel.org
+Fixes: e04e7a7bbd4b ("hv_netvsc: Fix a deadlock by getting rtnl lock earlier in netvsc_probe()")
+Reported-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
+Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
+Reviewed-by: Simon Horman <horms@kernel.org>
+Reviewed-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hyperv/netvsc_drv.c | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2531,15 +2531,6 @@ static int netvsc_probe(struct hv_device
+ goto devinfo_failed;
+ }
+
+- nvdev = rndis_filter_device_add(dev, device_info);
+- if (IS_ERR(nvdev)) {
+- ret = PTR_ERR(nvdev);
+- netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
+- goto rndis_failed;
+- }
+-
+- eth_hw_addr_set(net, device_info->mac_adr);
+-
+ /* We must get rtnl lock before scheduling nvdev->subchan_work,
+ * otherwise netvsc_subchan_work() can get rtnl lock first and wait
+ * all subchannels to show up, but that may not happen because
+@@ -2547,9 +2538,23 @@ static int netvsc_probe(struct hv_device
+ * -> ... -> device_add() -> ... -> __device_attach() can't get
+ * the device lock, so all the subchannels can't be processed --
+ * finally netvsc_subchan_work() hangs forever.
++ *
++ * The rtnl lock also needs to be held before rndis_filter_device_add()
++ * which advertises nvsp_2_vsc_capability / sriov bit, and triggers
++ * VF NIC offering and registering. If VF NIC finished register_netdev()
++ * earlier it may cause name based config failure.
+ */
+ rtnl_lock();
+
++ nvdev = rndis_filter_device_add(dev, device_info);
++ if (IS_ERR(nvdev)) {
++ ret = PTR_ERR(nvdev);
++ netdev_err(net, "unable to add netvsc device (ret %d)\n", ret);
++ goto rndis_failed;
++ }
++
++ eth_hw_addr_set(net, device_info->mac_adr);
++
+ if (nvdev->num_chn > 1)
+ schedule_work(&nvdev->subchan_work);
+
+@@ -2586,9 +2591,9 @@ static int netvsc_probe(struct hv_device
+ return 0;
+
+ register_failed:
+- rtnl_unlock();
+ rndis_filter_device_remove(dev, nvdev);
+ rndis_failed:
++ rtnl_unlock();
+ netvsc_devinfo_put(device_info);
+ devinfo_failed:
+ free_percpu(net_device_ctx->vf_stats);
--- /dev/null
+From 85520856466ed6bc3b1ccb013cddac70ceb437db Mon Sep 17 00:00:00 2001
+From: Haiyang Zhang <haiyangz@microsoft.com>
+Date: Sun, 19 Nov 2023 08:23:42 -0800
+Subject: hv_netvsc: Fix race of register_netdevice_notifier and VF register
+
+From: Haiyang Zhang <haiyangz@microsoft.com>
+
+commit 85520856466ed6bc3b1ccb013cddac70ceb437db upstream.
+
+If VF NIC is registered earlier, NETDEV_REGISTER event is replayed,
+but NETDEV_POST_INIT is not.
+
+Move register_netdevice_notifier() earlier, so the call back
+function is set before probing.
+
+Cc: stable@vger.kernel.org
+Fixes: e04e7a7bbd4b ("hv_netvsc: Fix a deadlock by getting rtnl lock earlier in netvsc_probe()")
+Reported-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
+Reviewed-by: Wojciech Drewek <wojciech.drewek@intel.com>
+Reviewed-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hyperv/netvsc_drv.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2793,12 +2793,17 @@ static int __init netvsc_drv_init(void)
+ }
+ netvsc_ring_bytes = ring_size * PAGE_SIZE;
+
++ register_netdevice_notifier(&netvsc_netdev_notifier);
++
+ ret = vmbus_driver_register(&netvsc_drv);
+ if (ret)
+- return ret;
++ goto err_vmbus_reg;
+
+- register_netdevice_notifier(&netvsc_netdev_notifier);
+ return 0;
++
++err_vmbus_reg:
++ unregister_netdevice_notifier(&netvsc_netdev_notifier);
++ return ret;
+ }
+
+ MODULE_LICENSE("GPL");
--- /dev/null
+From c807d6cd089d2f4951baa838081ec5ae3e2360f8 Mon Sep 17 00:00:00 2001
+From: Long Li <longli@microsoft.com>
+Date: Sun, 19 Nov 2023 08:23:43 -0800
+Subject: hv_netvsc: Mark VF as slave before exposing it to user-mode
+
+From: Long Li <longli@microsoft.com>
+
+commit c807d6cd089d2f4951baa838081ec5ae3e2360f8 upstream.
+
+When a VF is being exposed form the kernel, it should be marked as "slave"
+before exposing to the user-mode. The VF is not usable without netvsc
+running as master. The user-mode should never see a VF without the "slave"
+flag.
+
+This commit moves the code of setting the slave flag to the time before
+VF is exposed to user-mode.
+
+Cc: stable@vger.kernel.org
+Fixes: 0c195567a8f6 ("netvsc: transparent VF management")
+Signed-off-by: Long Li <longli@microsoft.com>
+Signed-off-by: Haiyang Zhang <haiyangz@microsoft.com>
+Acked-by: Stephen Hemminger <stephen@networkplumber.org>
+Acked-by: Dexuan Cui <decui@microsoft.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/hyperv/netvsc_drv.c | 32 +++++++++++++++++++++++---------
+ 1 file changed, 23 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/hyperv/netvsc_drv.c
++++ b/drivers/net/hyperv/netvsc_drv.c
+@@ -2206,9 +2206,6 @@ static int netvsc_vf_join(struct net_dev
+ goto upper_link_failed;
+ }
+
+- /* set slave flag before open to prevent IPv6 addrconf */
+- vf_netdev->flags |= IFF_SLAVE;
+-
+ schedule_delayed_work(&ndev_ctx->vf_takeover, VF_TAKEOVER_INT);
+
+ call_netdevice_notifiers(NETDEV_JOIN, vf_netdev);
+@@ -2315,16 +2312,18 @@ static struct net_device *get_netvsc_bys
+
+ }
+
+- /* Fallback path to check synthetic vf with
+- * help of mac addr
++ /* Fallback path to check synthetic vf with help of mac addr.
++ * Because this function can be called before vf_netdev is
++ * initialized (NETDEV_POST_INIT) when its perm_addr has not been copied
++ * from dev_addr, also try to match to its dev_addr.
++ * Note: On Hyper-V and Azure, it's not possible to set a MAC address
++ * on a VF that matches to the MAC of a unrelated NETVSC device.
+ */
+ list_for_each_entry(ndev_ctx, &netvsc_dev_list, list) {
+ ndev = hv_get_drvdata(ndev_ctx->device_ctx);
+- if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr)) {
+- netdev_notice(vf_netdev,
+- "falling back to mac addr based matching\n");
++ if (ether_addr_equal(vf_netdev->perm_addr, ndev->perm_addr) ||
++ ether_addr_equal(vf_netdev->dev_addr, ndev->perm_addr))
+ return ndev;
+- }
+ }
+
+ netdev_notice(vf_netdev,
+@@ -2332,6 +2331,19 @@ static struct net_device *get_netvsc_bys
+ return NULL;
+ }
+
++static int netvsc_prepare_bonding(struct net_device *vf_netdev)
++{
++ struct net_device *ndev;
++
++ ndev = get_netvsc_byslot(vf_netdev);
++ if (!ndev)
++ return NOTIFY_DONE;
++
++ /* set slave flag before open to prevent IPv6 addrconf */
++ vf_netdev->flags |= IFF_SLAVE;
++ return NOTIFY_DONE;
++}
++
+ static int netvsc_register_vf(struct net_device *vf_netdev)
+ {
+ struct net_device_context *net_device_ctx;
+@@ -2758,6 +2770,8 @@ static int netvsc_netdev_event(struct no
+ return NOTIFY_DONE;
+
+ switch (event) {
++ case NETDEV_POST_INIT:
++ return netvsc_prepare_bonding(event_dev);
+ case NETDEV_REGISTER:
+ return netvsc_register_vf(event_dev);
+ case NETDEV_UNREGISTER:
--- /dev/null
+From d6fef34ee4d102be448146f24caf96d7b4a05401 Mon Sep 17 00:00:00 2001
+From: Keith Busch <kbusch@kernel.org>
+Date: Mon, 20 Nov 2023 14:18:31 -0800
+Subject: io_uring: fix off-by one bvec index
+
+From: Keith Busch <kbusch@kernel.org>
+
+commit d6fef34ee4d102be448146f24caf96d7b4a05401 upstream.
+
+If the offset equals the bv_len of the first registered bvec, then the
+request does not include any of that first bvec. Skip it so that drivers
+don't have to deal with a zero length bvec, which was observed to break
+NVMe's PRP list creation.
+
+Cc: stable@vger.kernel.org
+Fixes: bd11b3a391e3 ("io_uring: don't use iov_iter_advance() for fixed buffers")
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Link: https://lore.kernel.org/r/20231120221831.2646460-1-kbusch@meta.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/rsrc.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/io_uring/rsrc.c
++++ b/io_uring/rsrc.c
+@@ -1261,7 +1261,7 @@ int io_import_fixed(int ddir, struct iov
+ */
+ const struct bio_vec *bvec = imu->bvec;
+
+- if (offset <= bvec->bv_len) {
++ if (offset < bvec->bv_len) {
+ /*
+ * Note, huge pages buffers consists of one large
+ * bvec entry and should always go this way. The other
--- /dev/null
+From 8479063f1fbee201a8739130e816cc331b675838 Mon Sep 17 00:00:00 2001
+From: Charles Mirabile <cmirabil@redhat.com>
+Date: Mon, 20 Nov 2023 05:55:45 -0500
+Subject: io_uring/fs: consider link->flags when getting path for LINKAT
+
+From: Charles Mirabile <cmirabil@redhat.com>
+
+commit 8479063f1fbee201a8739130e816cc331b675838 upstream.
+
+In order for `AT_EMPTY_PATH` to work as expected, the fact
+that the user wants that behavior needs to make it to `getname_flags`
+or it will return ENOENT.
+
+Fixes: cf30da90bc3a ("io_uring: add support for IORING_OP_LINKAT")
+Cc: <stable@vger.kernel.org>
+Link: https://github.com/axboe/liburing/issues/995
+Signed-off-by: Charles Mirabile <cmirabil@redhat.com>
+Link: https://lore.kernel.org/r/20231120105545.1209530-1-cmirabil@redhat.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ io_uring/fs.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/io_uring/fs.c
++++ b/io_uring/fs.c
+@@ -254,7 +254,7 @@ int io_linkat_prep(struct io_kiocb *req,
+ newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
+ lnk->flags = READ_ONCE(sqe->hardlink_flags);
+
+- lnk->oldpath = getname(oldf);
++ lnk->oldpath = getname_uflags(oldf, lnk->flags);
+ if (IS_ERR(lnk->oldpath))
+ return PTR_ERR(lnk->oldpath);
+
--- /dev/null
+From 460e462d22542adfafd8a5bc979437df73f1cbf3 Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@kernel.org>
+Date: Thu, 16 Nov 2023 12:52:29 +0000
+Subject: kselftest/arm64: Fix output formatting for za-fork
+
+From: Mark Brown <broonie@kernel.org>
+
+commit 460e462d22542adfafd8a5bc979437df73f1cbf3 upstream.
+
+The za-fork test does not output a newline when reporting the result of
+the one test it runs, causing the counts printed by kselftest to be
+included in the test name. Add the newline.
+
+Fixes: 266679ffd867 ("kselftest/arm64: Convert za-fork to use kselftest.h")
+Cc: <stable@vger.kernel.org> # 6.4.x
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Link: https://lore.kernel.org/r/20231116-arm64-fix-za-fork-output-v1-1-42c03d4f5759@kernel.org
+Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ tools/testing/selftests/arm64/fp/za-fork.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/tools/testing/selftests/arm64/fp/za-fork.c
++++ b/tools/testing/selftests/arm64/fp/za-fork.c
+@@ -85,7 +85,7 @@ int main(int argc, char **argv)
+ */
+ ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0);
+ if (ret >= 0) {
+- ksft_test_result(fork_test(), "fork_test");
++ ksft_test_result(fork_test(), "fork_test\n");
+
+ } else {
+ ksft_print_msg("SME not supported\n");
--- /dev/null
+From 45b478951b2ba5aea70b2850c49c1aa83aedd0d2 Mon Sep 17 00:00:00 2001
+From: Song Liu <song@kernel.org>
+Date: Fri, 17 Nov 2023 15:56:30 -0800
+Subject: md: fix bi_status reporting in md_end_clone_io
+
+From: Song Liu <song@kernel.org>
+
+commit 45b478951b2ba5aea70b2850c49c1aa83aedd0d2 upstream.
+
+md_end_clone_io() may overwrite error status in orig_bio->bi_status with
+BLK_STS_OK. This could happen when orig_bio has BIO_CHAIN (split by
+md_submit_bio => bio_split_to_limits, for example). As a result, upper
+layer may miss error reported from md (or the device) and consider the
+failed IO was successful.
+
+Fix this by only update orig_bio->bi_status when current bio reports
+error and orig_bio is BLK_STS_OK. This is the same behavior as
+__bio_chain_endio().
+
+Fixes: 10764815ff47 ("md: add io accounting for raid0 and raid5")
+Cc: stable@vger.kernel.org # v5.14+
+Reported-by: Bhanu Victor DiCara <00bvd0+linux@gmail.com>
+Closes: https://lore.kernel.org/regressions/5727380.DvuYhMxLoT@bvd0/
+Signed-off-by: Song Liu <song@kernel.org>
+Tested-by: Xiao Ni <xni@redhat.com>
+Reviewed-by: Yu Kuai <yukuai3@huawei.com>
+Acked-by: Guoqing Jiang <guoqing.jiang@linux.dev>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/md/md.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/md/md.c
++++ b/drivers/md/md.c
+@@ -8669,7 +8669,8 @@ static void md_end_clone_io(struct bio *
+ struct bio *orig_bio = md_io_clone->orig_bio;
+ struct mddev *mddev = md_io_clone->mddev;
+
+- orig_bio->bi_status = bio->bi_status;
++ if (bio->bi_status && !orig_bio->bi_status)
++ orig_bio->bi_status = bio->bi_status;
+
+ if (md_io_clone->start_time)
+ bio_end_io_acct(orig_bio, md_io_clone->start_time);
--- /dev/null
+From c6ea14d557343cd3af6c6be2f5a78c98bdb281bb Mon Sep 17 00:00:00 2001
+From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Date: Thu, 16 Nov 2023 22:31:21 +0530
+Subject: platform/x86/amd/pmc: adjust getting DRAM size behavior
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+
+commit c6ea14d557343cd3af6c6be2f5a78c98bdb281bb upstream.
+
+amd_pmc_get_dram_size() is used to get the DRAM size information. But
+in the current code, mailbox command to get the DRAM size info is sent
+based on the values of dev->major and dev->minor.
+
+But dev->major and dev->minor will have either junk or zero assigned to
+them until at least once a call to amd_pmc_get_smu_version() is made
+which ideally populates dev->major and dev->minor.
+
+However, adding a amd_pmc_get_smu_version() call to
+amd_pmc_get_dram_size() has a downside of elevating the boot times.
+
+After talking to the PMFW team, it's understood that the "get dram
+size" mbox command would only be supported on specific platforms (like
+Mendocino) and not all. So, adjust getting DRAM size behavior such
+that,
+
+- if running on Rembrandt or Mendocino and the underlying PMFW knows
+how to execute the "get dram size" command it shall give the custom
+dram size.
+
+- if the underlying FW does not report the dram size, we just proceed
+further and assign the default dram size.
+
+The simplest way to address this is to remove amd_pmc_get_dram_size()
+function and directly call the "get dram size" command in the
+amd_pmc_s2d_init().
+
+Reported-by: Mark Hasemeyer <markhas@chromium.org>
+Fixes: be8325fb3d8c ("platform/x86/amd: pmc: Get STB DRAM size from PMFW")
+Cc: stable@vger.kernel.org
+Suggested-by: Sanket Goswami <Sanket.Goswami@amd.com>
+Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Link: https://lore.kernel.org/r/20231116170121.3372222-1-Shyam-sundar.S-k@amd.com
+Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/amd/pmc/pmc.c | 31 ++-----------------------------
+ 1 file changed, 2 insertions(+), 29 deletions(-)
+
+--- a/drivers/platform/x86/amd/pmc/pmc.c
++++ b/drivers/platform/x86/amd/pmc/pmc.c
+@@ -912,33 +912,6 @@ static const struct pci_device_id pmc_pc
+ { }
+ };
+
+-static int amd_pmc_get_dram_size(struct amd_pmc_dev *dev)
+-{
+- int ret;
+-
+- switch (dev->cpu_id) {
+- case AMD_CPU_ID_YC:
+- if (!(dev->major > 90 || (dev->major == 90 && dev->minor > 39))) {
+- ret = -EINVAL;
+- goto err_dram_size;
+- }
+- break;
+- default:
+- ret = -EINVAL;
+- goto err_dram_size;
+- }
+-
+- ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->s2d_msg_id, true);
+- if (ret || !dev->dram_size)
+- goto err_dram_size;
+-
+- return 0;
+-
+-err_dram_size:
+- dev_err(dev->dev, "DRAM size command not supported for this platform\n");
+- return ret;
+-}
+-
+ static int amd_pmc_s2d_init(struct amd_pmc_dev *dev)
+ {
+ u32 phys_addr_low, phys_addr_hi;
+@@ -957,8 +930,8 @@ static int amd_pmc_s2d_init(struct amd_p
+ return -EIO;
+
+ /* Get DRAM size */
+- ret = amd_pmc_get_dram_size(dev);
+- if (ret)
++ ret = amd_pmc_send_cmd(dev, S2D_DRAM_SIZE, &dev->dram_size, dev->s2d_msg_id, true);
++ if (ret || !dev->dram_size)
+ dev->dram_size = S2D_TELEMETRY_DRAMBYTES_MAX;
+
+ /* Get STB DRAM address */
--- /dev/null
+From f40f939917b2b4cbf18450096c0ce1c58ed59fae Mon Sep 17 00:00:00 2001
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Mon, 13 Nov 2023 12:07:39 -0800
+Subject: platform/x86: hp-bioscfg: Fix error handling in hp_add_other_attributes()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+
+commit f40f939917b2b4cbf18450096c0ce1c58ed59fae upstream.
+
+'attr_name_kobj' is allocated using kzalloc, but on all the error paths
+it is not freed, hence we have a memory leak.
+
+Fix the error path before kobject_init_and_add() by adding kfree().
+
+kobject_put() must be always called after passing the object to
+kobject_init_and_add(). Only the error path which is immediately next
+to kobject_init_and_add() calls kobject_put() and not any other error
+path after it.
+
+Fix the error handling after kobject_init_and_add() by moving the
+kobject_put() into the goto label err_other_attr_init that is already
+used by all the error paths after kobject_init_and_add().
+
+Fixes: a34fc329b189 ("platform/x86: hp-bioscfg: bioscfg")
+Cc: stable@vger.kernel.org # 6.6.x: c5dbf0416000: platform/x86: hp-bioscfg: Simplify return check in hp_add_other_attributes()
+Cc: stable@vger.kernel.org # 6.6.x: 5736aa9537c9: platform/x86: hp-bioscfg: move mutex_lock() down in hp_add_other_attributes()
+Reported-by: kernel test robot <lkp@intel.com>
+Reported-by: Dan Carpenter <error27@gmail.com>
+Closes: https://lore.kernel.org/r/202309201412.on0VXJGo-lkp@intel.com/
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+[ij: Added the stable dep tags]
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Link: https://lore.kernel.org/r/20231113200742.3593548-3-harshit.m.mogalapalli@oracle.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/hp/hp-bioscfg/bioscfg.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
+index a3599498c4e8..6ddca857cc4d 100644
+--- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
++++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
+@@ -613,14 +613,14 @@ static int hp_add_other_attributes(int attr_type)
+ default:
+ pr_err("Error: Unknown attr_type: %d\n", attr_type);
+ ret = -EINVAL;
+- goto err_other_attr_init;
++ kfree(attr_name_kobj);
++ goto unlock_drv_mutex;
+ }
+
+ ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,
+ NULL, "%s", attr_name);
+ if (ret) {
+ pr_err("Error encountered [%d]\n", ret);
+- kobject_put(attr_name_kobj);
+ goto err_other_attr_init;
+ }
+
+@@ -645,6 +645,8 @@ static int hp_add_other_attributes(int attr_type)
+ return 0;
+
+ err_other_attr_init:
++ kobject_put(attr_name_kobj);
++unlock_drv_mutex:
+ mutex_unlock(&bioscfg_drv.mutex);
+ kfree(obj);
+ return ret;
+--
+2.43.0
+
--- /dev/null
+From 5736aa9537c9b8927dec32d3d47c8c31fe560f62 Mon Sep 17 00:00:00 2001
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Mon, 13 Nov 2023 12:07:38 -0800
+Subject: platform/x86: hp-bioscfg: move mutex_lock() down in hp_add_other_attributes()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+
+commit 5736aa9537c9b8927dec32d3d47c8c31fe560f62 upstream.
+
+attr_name_kobj's memory allocation is done with mutex_lock() held, this
+is not needed.
+
+Move allocation outside of mutex_lock() so unlock is not needed when
+allocation fails.
+
+Suggested-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Link: https://lore.kernel.org/r/20231113200742.3593548-2-harshit.m.mogalapalli@oracle.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/hp/hp-bioscfg/bioscfg.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+--- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
++++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
+@@ -592,13 +592,11 @@ static int hp_add_other_attributes(int a
+ int ret;
+ char *attr_name;
+
+- mutex_lock(&bioscfg_drv.mutex);
+-
+ attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);
+- if (!attr_name_kobj) {
+- ret = -ENOMEM;
+- goto err_other_attr_init;
+- }
++ if (!attr_name_kobj)
++ return -ENOMEM;
++
++ mutex_lock(&bioscfg_drv.mutex);
+
+ /* Check if attribute type is supported */
+ switch (attr_type) {
--- /dev/null
+From c5dbf04160005e07e8ca7232a7faa77ab1547ae0 Mon Sep 17 00:00:00 2001
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Date: Mon, 13 Nov 2023 12:07:37 -0800
+Subject: platform/x86: hp-bioscfg: Simplify return check in hp_add_other_attributes()
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+
+commit c5dbf04160005e07e8ca7232a7faa77ab1547ae0 upstream.
+
+All cases in switch-case have a same goto on error, move the return
+check out of the switch. This is a cleanup.
+
+Signed-off-by: Harshit Mogalapalli <harshit.m.mogalapalli@oracle.com>
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Link: https://lore.kernel.org/r/20231113200742.3593548-1-harshit.m.mogalapalli@oracle.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/hp/hp-bioscfg/bioscfg.c | 8 +++-----
+ 1 file changed, 3 insertions(+), 5 deletions(-)
+
+--- a/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
++++ b/drivers/platform/x86/hp/hp-bioscfg/bioscfg.c
+@@ -630,21 +630,19 @@ static int hp_add_other_attributes(int a
+ switch (attr_type) {
+ case HPWMI_SECURE_PLATFORM_TYPE:
+ ret = hp_populate_secure_platform_data(attr_name_kobj);
+- if (ret)
+- goto err_other_attr_init;
+ break;
+
+ case HPWMI_SURE_START_TYPE:
+ ret = hp_populate_sure_start_data(attr_name_kobj);
+- if (ret)
+- goto err_other_attr_init;
+ break;
+
+ default:
+ ret = -EINVAL;
+- goto err_other_attr_init;
+ }
+
++ if (ret)
++ goto err_other_attr_init;
++
+ mutex_unlock(&bioscfg_drv.mutex);
+ return 0;
+
--- /dev/null
+From 7a3c36eef9a5d13b16aa954da54224c9c6bed339 Mon Sep 17 00:00:00 2001
+From: Stuart Hayhurst <stuart.a.hayhurst@gmail.com>
+Date: Tue, 14 Nov 2023 11:38:08 +0000
+Subject: platform/x86: ideapad-laptop: Set max_brightness before using it
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Stuart Hayhurst <stuart.a.hayhurst@gmail.com>
+
+commit 7a3c36eef9a5d13b16aa954da54224c9c6bed339 upstream.
+
+max_brightness is used in ideapad_kbd_bl_brightness_get() before it's set,
+causing ideapad_kbd_bl_brightness_get() to return -EINVAL sometimes.
+
+Fixes: ecaa1867b524 ("platform/x86: ideapad-laptop: Add support for keyboard backlights using KBLC ACPI symbol")
+Signed-off-by: Stuart Hayhurst <stuart.a.hayhurst@gmail.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Link: https://lore.kernel.org/r/20231114114055.6220-2-stuart.a.hayhurst@gmail.com
+Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/platform/x86/ideapad-laptop.c | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
+index ac037540acfc..88eefccb6ed2 100644
+--- a/drivers/platform/x86/ideapad-laptop.c
++++ b/drivers/platform/x86/ideapad-laptop.c
+@@ -1425,18 +1425,17 @@ static int ideapad_kbd_bl_init(struct ideapad_private *priv)
+ if (WARN_ON(priv->kbd_bl.initialized))
+ return -EEXIST;
+
+- brightness = ideapad_kbd_bl_brightness_get(priv);
+- if (brightness < 0)
+- return brightness;
+-
+- priv->kbd_bl.last_brightness = brightness;
+-
+ if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) {
+ priv->kbd_bl.led.max_brightness = 2;
+ } else {
+ priv->kbd_bl.led.max_brightness = 1;
+ }
+
++ brightness = ideapad_kbd_bl_brightness_get(priv);
++ if (brightness < 0)
++ return brightness;
++
++ priv->kbd_bl.last_brightness = brightness;
+ priv->kbd_bl.led.name = "platform::" LED_FUNCTION_KBD_BACKLIGHT;
+ priv->kbd_bl.led.brightness_get = ideapad_kbd_bl_led_cdev_brightness_get;
+ priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set;
+--
+2.43.0
+
--- /dev/null
+From 7a784bcdd7e54f0599da3b2360e472238412623e Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 6 Nov 2023 12:06:53 +0100
+Subject: Revert "phy: realtek: usb: Add driver for the Realtek SoC USB 2.0 PHY"
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit 7a784bcdd7e54f0599da3b2360e472238412623e upstream.
+
+This reverts commit 134e6d25f6bd06071e5aac0a7eefcea6f7713955.
+
+The recently added Realtek PHY drivers depend on the new port status
+notification mechanism which was built on the deprecated USB PHY
+implementation and devicetree binding.
+
+Specifically, using these PHYs would require describing the very same
+PHY using both the generic "phy" property and the deprecated "usb-phy"
+property which is clearly wrong.
+
+We should not be building new functionality on top of the legacy USB PHY
+implementation even if it is currently stuck in some kind of
+transitional limbo.
+
+Revert the new Realtek PHY drivers for now so that the port status
+notification interface can be reverted and replaced.
+
+Fixes: 134e6d25f6bd ("phy: realtek: usb: Add driver for the Realtek SoC USB 2.0 PHY")
+Cc: stable@vger.kernel.org # 6.6
+Cc: Stanley Chang <stanley_chang@realtek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231106110654.31090-3-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/phy/Kconfig | 1
+ drivers/phy/Makefile | 1
+ drivers/phy/realtek/Kconfig | 20
+ drivers/phy/realtek/Makefile | 2
+ drivers/phy/realtek/phy-rtk-usb2.c | 1325 -------------------------------------
+ 5 files changed, 1349 deletions(-)
+ delete mode 100644 drivers/phy/realtek/Kconfig
+ delete mode 100644 drivers/phy/realtek/Makefile
+ delete mode 100644 drivers/phy/realtek/phy-rtk-usb2.c
+
+--- a/drivers/phy/Kconfig
++++ b/drivers/phy/Kconfig
+@@ -87,7 +87,6 @@ source "drivers/phy/motorola/Kconfig"
+ source "drivers/phy/mscc/Kconfig"
+ source "drivers/phy/qualcomm/Kconfig"
+ source "drivers/phy/ralink/Kconfig"
+-source "drivers/phy/realtek/Kconfig"
+ source "drivers/phy/renesas/Kconfig"
+ source "drivers/phy/rockchip/Kconfig"
+ source "drivers/phy/samsung/Kconfig"
+--- a/drivers/phy/Makefile
++++ b/drivers/phy/Makefile
+@@ -26,7 +26,6 @@ obj-y += allwinner/ \
+ mscc/ \
+ qualcomm/ \
+ ralink/ \
+- realtek/ \
+ renesas/ \
+ rockchip/ \
+ samsung/ \
+--- a/drivers/phy/realtek/Kconfig
++++ /dev/null
+@@ -1,20 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0
+-#
+-# Phy drivers for Realtek platforms
+-#
+-
+-if ARCH_REALTEK || COMPILE_TEST
+-
+-config PHY_RTK_RTD_USB2PHY
+- tristate "Realtek RTD USB2 PHY Transceiver Driver"
+- depends on USB_SUPPORT
+- select GENERIC_PHY
+- select USB_PHY
+- select USB_COMMON
+- help
+- Enable this to support Realtek SoC USB2 phy transceiver.
+- The DHC (digital home center) RTD series SoCs used the Synopsys
+- DWC3 USB IP. This driver will do the PHY initialization
+- of the parameters.
+-
+-endif # ARCH_REALTEK || COMPILE_TEST
+--- a/drivers/phy/realtek/Makefile
++++ /dev/null
+@@ -1,2 +0,0 @@
+-# SPDX-License-Identifier: GPL-2.0
+-obj-$(CONFIG_PHY_RTK_RTD_USB2PHY) += phy-rtk-usb2.o
+--- a/drivers/phy/realtek/phy-rtk-usb2.c
++++ /dev/null
+@@ -1,1325 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * phy-rtk-usb2.c RTK usb2.0 PHY driver
+- *
+- * Copyright (C) 2023 Realtek Semiconductor Corporation
+- *
+- */
+-
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/of_address.h>
+-#include <linux/uaccess.h>
+-#include <linux/debugfs.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/regmap.h>
+-#include <linux/sys_soc.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/phy/phy.h>
+-#include <linux/usb.h>
+-#include <linux/usb/phy.h>
+-#include <linux/usb/hcd.h>
+-
+-/* GUSB2PHYACCn register */
+-#define PHY_NEW_REG_REQ BIT(25)
+-#define PHY_VSTS_BUSY BIT(23)
+-#define PHY_VCTRL_SHIFT 8
+-#define PHY_REG_DATA_MASK 0xff
+-
+-#define GET_LOW_NIBBLE(addr) ((addr) & 0x0f)
+-#define GET_HIGH_NIBBLE(addr) (((addr) & 0xf0) >> 4)
+-
+-#define EFUS_USB_DC_CAL_RATE 2
+-#define EFUS_USB_DC_CAL_MAX 7
+-
+-#define EFUS_USB_DC_DIS_RATE 1
+-#define EFUS_USB_DC_DIS_MAX 7
+-
+-#define MAX_PHY_DATA_SIZE 20
+-#define OFFEST_PHY_READ 0x20
+-
+-#define MAX_USB_PHY_NUM 4
+-#define MAX_USB_PHY_PAGE0_DATA_SIZE 16
+-#define MAX_USB_PHY_PAGE1_DATA_SIZE 16
+-#define MAX_USB_PHY_PAGE2_DATA_SIZE 8
+-
+-#define SET_PAGE_OFFSET 0xf4
+-#define SET_PAGE_0 0x9b
+-#define SET_PAGE_1 0xbb
+-#define SET_PAGE_2 0xdb
+-
+-#define PAGE_START 0xe0
+-#define PAGE0_0XE4 0xe4
+-#define PAGE0_0XE6 0xe6
+-#define PAGE0_0XE7 0xe7
+-#define PAGE1_0XE0 0xe0
+-#define PAGE1_0XE2 0xe2
+-
+-#define SENSITIVITY_CTRL (BIT(4) | BIT(5) | BIT(6))
+-#define ENABLE_AUTO_SENSITIVITY_CALIBRATION BIT(2)
+-#define DEFAULT_DC_DRIVING_VALUE (0x8)
+-#define DEFAULT_DC_DISCONNECTION_VALUE (0x6)
+-#define HS_CLK_SELECT BIT(6)
+-
+-struct phy_reg {
+- void __iomem *reg_wrap_vstatus;
+- void __iomem *reg_gusb2phyacc0;
+- int vstatus_index;
+-};
+-
+-struct phy_data {
+- u8 addr;
+- u8 data;
+-};
+-
+-struct phy_cfg {
+- int page0_size;
+- struct phy_data page0[MAX_USB_PHY_PAGE0_DATA_SIZE];
+- int page1_size;
+- struct phy_data page1[MAX_USB_PHY_PAGE1_DATA_SIZE];
+- int page2_size;
+- struct phy_data page2[MAX_USB_PHY_PAGE2_DATA_SIZE];
+-
+- int num_phy;
+-
+- bool check_efuse;
+- int check_efuse_version;
+-#define CHECK_EFUSE_V1 1
+-#define CHECK_EFUSE_V2 2
+- int efuse_dc_driving_rate;
+- int efuse_dc_disconnect_rate;
+- int dc_driving_mask;
+- int dc_disconnect_mask;
+- bool usb_dc_disconnect_at_page0;
+- int driving_updated_for_dev_dis;
+-
+- bool do_toggle;
+- bool do_toggle_driving;
+- bool use_default_parameter;
+- bool is_double_sensitivity_mode;
+-};
+-
+-struct phy_parameter {
+- struct phy_reg phy_reg;
+-
+- /* Get from efuse */
+- s8 efuse_usb_dc_cal;
+- s8 efuse_usb_dc_dis;
+-
+- /* Get from dts */
+- bool inverse_hstx_sync_clock;
+- u32 driving_level;
+- s32 driving_level_compensate;
+- s32 disconnection_compensate;
+-};
+-
+-struct rtk_phy {
+- struct usb_phy phy;
+- struct device *dev;
+-
+- struct phy_cfg *phy_cfg;
+- int num_phy;
+- struct phy_parameter *phy_parameter;
+-
+- struct dentry *debug_dir;
+-};
+-
+-/* mapping 0xE0 to 0 ... 0xE7 to 7, 0xF0 to 8 ,,, 0xF7 to 15 */
+-static inline int page_addr_to_array_index(u8 addr)
+-{
+- return (int)((((addr) - PAGE_START) & 0x7) +
+- ((((addr) - PAGE_START) & 0x10) >> 1));
+-}
+-
+-static inline u8 array_index_to_page_addr(int index)
+-{
+- return ((((index) + PAGE_START) & 0x7) +
+- ((((index) & 0x8) << 1) + PAGE_START));
+-}
+-
+-#define PHY_IO_TIMEOUT_USEC (50000)
+-#define PHY_IO_DELAY_US (100)
+-
+-static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+-{
+- int ret;
+- unsigned int val;
+-
+- ret = read_poll_timeout(readl, val, ((val & mask) == result),
+- PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
+- if (ret) {
+- pr_err("%s can't program USB phy\n", __func__);
+- return -ETIMEDOUT;
+- }
+-
+- return 0;
+-}
+-
+-static char rtk_phy_read(struct phy_reg *phy_reg, char addr)
+-{
+- void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0;
+- unsigned int val;
+- int ret = 0;
+-
+- addr -= OFFEST_PHY_READ;
+-
+- /* polling until VBusy == 0 */
+- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+- if (ret)
+- return (char)ret;
+-
+- /* VCtrl = low nibble of addr, and set PHY_NEW_REG_REQ */
+- val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+- writel(val, reg_gusb2phyacc0);
+- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+- if (ret)
+- return (char)ret;
+-
+- /* VCtrl = high nibble of addr, and set PHY_NEW_REG_REQ */
+- val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+- writel(val, reg_gusb2phyacc0);
+- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+- if (ret)
+- return (char)ret;
+-
+- val = readl(reg_gusb2phyacc0);
+-
+- return (char)(val & PHY_REG_DATA_MASK);
+-}
+-
+-static int rtk_phy_write(struct phy_reg *phy_reg, char addr, char data)
+-{
+- unsigned int val;
+- void __iomem *reg_wrap_vstatus = phy_reg->reg_wrap_vstatus;
+- void __iomem *reg_gusb2phyacc0 = phy_reg->reg_gusb2phyacc0;
+- int shift_bits = phy_reg->vstatus_index * 8;
+- int ret = 0;
+-
+- /* write data to VStatusOut2 (data output to phy) */
+- writel((u32)data << shift_bits, reg_wrap_vstatus);
+-
+- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+- if (ret)
+- return ret;
+-
+- /* VCtrl = low nibble of addr, set PHY_NEW_REG_REQ */
+- val = PHY_NEW_REG_REQ | (GET_LOW_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+-
+- writel(val, reg_gusb2phyacc0);
+- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+- if (ret)
+- return ret;
+-
+- /* VCtrl = high nibble of addr, set PHY_NEW_REG_REQ */
+- val = PHY_NEW_REG_REQ | (GET_HIGH_NIBBLE(addr) << PHY_VCTRL_SHIFT);
+-
+- writel(val, reg_gusb2phyacc0);
+- ret = utmi_wait_register(reg_gusb2phyacc0, PHY_VSTS_BUSY, 0);
+- if (ret)
+- return ret;
+-
+- return 0;
+-}
+-
+-static int rtk_phy_set_page(struct phy_reg *phy_reg, int page)
+-{
+- switch (page) {
+- case 0:
+- return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_0);
+- case 1:
+- return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_1);
+- case 2:
+- return rtk_phy_write(phy_reg, SET_PAGE_OFFSET, SET_PAGE_2);
+- default:
+- pr_err("%s error page=%d\n", __func__, page);
+- }
+-
+- return -EINVAL;
+-}
+-
+-static u8 __updated_dc_disconnect_level_page0_0xe4(struct phy_cfg *phy_cfg,
+- struct phy_parameter *phy_parameter, u8 data)
+-{
+- u8 ret;
+- s32 val;
+- s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+- int offset = 4;
+-
+- val = (s32)((data >> offset) & dc_disconnect_mask)
+- + phy_parameter->efuse_usb_dc_dis
+- + phy_parameter->disconnection_compensate;
+-
+- if (val > dc_disconnect_mask)
+- val = dc_disconnect_mask;
+- else if (val < 0)
+- val = 0;
+-
+- ret = (data & (~(dc_disconnect_mask << offset))) |
+- (val & dc_disconnect_mask) << offset;
+-
+- return ret;
+-}
+-
+-/* updated disconnect level at page0 */
+-static void update_dc_disconnect_level_at_page0(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter, bool update)
+-{
+- struct phy_cfg *phy_cfg;
+- struct phy_reg *phy_reg;
+- struct phy_data *phy_data_page;
+- struct phy_data *phy_data;
+- u8 addr, data;
+- int offset = 4;
+- s32 dc_disconnect_mask;
+- int i;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+- phy_reg = &phy_parameter->phy_reg;
+-
+- /* Set page 0 */
+- phy_data_page = phy_cfg->page0;
+- rtk_phy_set_page(phy_reg, 0);
+-
+- i = page_addr_to_array_index(PAGE0_0XE4);
+- phy_data = phy_data_page + i;
+- if (!phy_data->addr) {
+- phy_data->addr = PAGE0_0XE4;
+- phy_data->data = rtk_phy_read(phy_reg, PAGE0_0XE4);
+- }
+-
+- addr = phy_data->addr;
+- data = phy_data->data;
+- dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+-
+- if (update)
+- data = __updated_dc_disconnect_level_page0_0xe4(phy_cfg, phy_parameter, data);
+- else
+- data = (data & ~(dc_disconnect_mask << offset)) |
+- (DEFAULT_DC_DISCONNECTION_VALUE << offset);
+-
+- if (rtk_phy_write(phy_reg, addr, data))
+- dev_err(rtk_phy->dev,
+- "%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
+- __func__, addr, data);
+-}
+-
+-static u8 __updated_dc_disconnect_level_page1_0xe2(struct phy_cfg *phy_cfg,
+- struct phy_parameter *phy_parameter, u8 data)
+-{
+- u8 ret;
+- s32 val;
+- s32 dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+-
+- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+- val = (s32)(data & dc_disconnect_mask)
+- + phy_parameter->efuse_usb_dc_dis
+- + phy_parameter->disconnection_compensate;
+- } else { /* for CHECK_EFUSE_V2 or no efuse */
+- if (phy_parameter->efuse_usb_dc_dis)
+- val = (s32)(phy_parameter->efuse_usb_dc_dis +
+- phy_parameter->disconnection_compensate);
+- else
+- val = (s32)((data & dc_disconnect_mask) +
+- phy_parameter->disconnection_compensate);
+- }
+-
+- if (val > dc_disconnect_mask)
+- val = dc_disconnect_mask;
+- else if (val < 0)
+- val = 0;
+-
+- ret = (data & (~dc_disconnect_mask)) | (val & dc_disconnect_mask);
+-
+- return ret;
+-}
+-
+-/* updated disconnect level at page1 */
+-static void update_dc_disconnect_level_at_page1(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter, bool update)
+-{
+- struct phy_cfg *phy_cfg;
+- struct phy_data *phy_data_page;
+- struct phy_data *phy_data;
+- struct phy_reg *phy_reg;
+- u8 addr, data;
+- s32 dc_disconnect_mask;
+- int i;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+- phy_reg = &phy_parameter->phy_reg;
+-
+- /* Set page 1 */
+- phy_data_page = phy_cfg->page1;
+- rtk_phy_set_page(phy_reg, 1);
+-
+- i = page_addr_to_array_index(PAGE1_0XE2);
+- phy_data = phy_data_page + i;
+- if (!phy_data->addr) {
+- phy_data->addr = PAGE1_0XE2;
+- phy_data->data = rtk_phy_read(phy_reg, PAGE1_0XE2);
+- }
+-
+- addr = phy_data->addr;
+- data = phy_data->data;
+- dc_disconnect_mask = phy_cfg->dc_disconnect_mask;
+-
+- if (update)
+- data = __updated_dc_disconnect_level_page1_0xe2(phy_cfg, phy_parameter, data);
+- else
+- data = (data & ~dc_disconnect_mask) | DEFAULT_DC_DISCONNECTION_VALUE;
+-
+- if (rtk_phy_write(phy_reg, addr, data))
+- dev_err(rtk_phy->dev,
+- "%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
+- __func__, addr, data);
+-}
+-
+-static void update_dc_disconnect_level(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter, bool update)
+-{
+- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+-
+- if (phy_cfg->usb_dc_disconnect_at_page0)
+- update_dc_disconnect_level_at_page0(rtk_phy, phy_parameter, update);
+- else
+- update_dc_disconnect_level_at_page1(rtk_phy, phy_parameter, update);
+-}
+-
+-static u8 __update_dc_driving_page0_0xe4(struct phy_cfg *phy_cfg,
+- struct phy_parameter *phy_parameter, u8 data)
+-{
+- s32 driving_level_compensate = phy_parameter->driving_level_compensate;
+- s32 dc_driving_mask = phy_cfg->dc_driving_mask;
+- s32 val;
+- u8 ret;
+-
+- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+- val = (s32)(data & dc_driving_mask) + driving_level_compensate
+- + phy_parameter->efuse_usb_dc_cal;
+- } else { /* for CHECK_EFUSE_V2 or no efuse */
+- if (phy_parameter->efuse_usb_dc_cal)
+- val = (s32)((phy_parameter->efuse_usb_dc_cal & dc_driving_mask)
+- + driving_level_compensate);
+- else
+- val = (s32)(data & dc_driving_mask);
+- }
+-
+- if (val > dc_driving_mask)
+- val = dc_driving_mask;
+- else if (val < 0)
+- val = 0;
+-
+- ret = (data & (~dc_driving_mask)) | (val & dc_driving_mask);
+-
+- return ret;
+-}
+-
+-static void update_dc_driving_level(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter)
+-{
+- struct phy_cfg *phy_cfg;
+- struct phy_reg *phy_reg;
+-
+- phy_reg = &phy_parameter->phy_reg;
+- phy_cfg = rtk_phy->phy_cfg;
+- if (!phy_cfg->page0[4].addr) {
+- rtk_phy_set_page(phy_reg, 0);
+- phy_cfg->page0[4].addr = PAGE0_0XE4;
+- phy_cfg->page0[4].data = rtk_phy_read(phy_reg, PAGE0_0XE4);
+- }
+-
+- if (phy_parameter->driving_level != DEFAULT_DC_DRIVING_VALUE) {
+- u32 dc_driving_mask;
+- u8 driving_level;
+- u8 data;
+-
+- data = phy_cfg->page0[4].data;
+- dc_driving_mask = phy_cfg->dc_driving_mask;
+- driving_level = data & dc_driving_mask;
+-
+- dev_dbg(rtk_phy->dev, "%s driving_level=%d => dts driving_level=%d\n",
+- __func__, driving_level, phy_parameter->driving_level);
+-
+- phy_cfg->page0[4].data = (data & (~dc_driving_mask)) |
+- (phy_parameter->driving_level & dc_driving_mask);
+- }
+-
+- phy_cfg->page0[4].data = __update_dc_driving_page0_0xe4(phy_cfg,
+- phy_parameter,
+- phy_cfg->page0[4].data);
+-}
+-
+-static void update_hs_clk_select(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter)
+-{
+- struct phy_cfg *phy_cfg;
+- struct phy_reg *phy_reg;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+- phy_reg = &phy_parameter->phy_reg;
+-
+- if (phy_parameter->inverse_hstx_sync_clock) {
+- if (!phy_cfg->page0[6].addr) {
+- rtk_phy_set_page(phy_reg, 0);
+- phy_cfg->page0[6].addr = PAGE0_0XE6;
+- phy_cfg->page0[6].data = rtk_phy_read(phy_reg, PAGE0_0XE6);
+- }
+-
+- phy_cfg->page0[6].data = phy_cfg->page0[6].data | HS_CLK_SELECT;
+- }
+-}
+-
+-static void do_rtk_phy_toggle(struct rtk_phy *rtk_phy,
+- int index, bool connect)
+-{
+- struct phy_parameter *phy_parameter;
+- struct phy_cfg *phy_cfg;
+- struct phy_reg *phy_reg;
+- struct phy_data *phy_data_page;
+- u8 addr, data;
+- int i;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+- phy_reg = &phy_parameter->phy_reg;
+-
+- if (!phy_cfg->do_toggle)
+- goto out;
+-
+- if (phy_cfg->is_double_sensitivity_mode)
+- goto do_toggle_driving;
+-
+- /* Set page 0 */
+- rtk_phy_set_page(phy_reg, 0);
+-
+- addr = PAGE0_0XE7;
+- data = rtk_phy_read(phy_reg, addr);
+-
+- if (connect)
+- rtk_phy_write(phy_reg, addr, data & (~SENSITIVITY_CTRL));
+- else
+- rtk_phy_write(phy_reg, addr, data | (SENSITIVITY_CTRL));
+-
+-do_toggle_driving:
+-
+- if (!phy_cfg->do_toggle_driving)
+- goto do_toggle;
+-
+- /* Page 0 addr 0xE4 driving capability */
+-
+- /* Set page 0 */
+- phy_data_page = phy_cfg->page0;
+- rtk_phy_set_page(phy_reg, 0);
+-
+- i = page_addr_to_array_index(PAGE0_0XE4);
+- addr = phy_data_page[i].addr;
+- data = phy_data_page[i].data;
+-
+- if (connect) {
+- rtk_phy_write(phy_reg, addr, data);
+- } else {
+- u8 value;
+- s32 tmp;
+- s32 driving_updated =
+- phy_cfg->driving_updated_for_dev_dis;
+- s32 dc_driving_mask = phy_cfg->dc_driving_mask;
+-
+- tmp = (s32)(data & dc_driving_mask) + driving_updated;
+-
+- if (tmp > dc_driving_mask)
+- tmp = dc_driving_mask;
+- else if (tmp < 0)
+- tmp = 0;
+-
+- value = (data & (~dc_driving_mask)) | (tmp & dc_driving_mask);
+-
+- rtk_phy_write(phy_reg, addr, value);
+- }
+-
+-do_toggle:
+- /* restore dc disconnect level before toggle */
+- update_dc_disconnect_level(rtk_phy, phy_parameter, false);
+-
+- /* Set page 1 */
+- rtk_phy_set_page(phy_reg, 1);
+-
+- addr = PAGE1_0XE0;
+- data = rtk_phy_read(phy_reg, addr);
+-
+- rtk_phy_write(phy_reg, addr, data &
+- (~ENABLE_AUTO_SENSITIVITY_CALIBRATION));
+- mdelay(1);
+- rtk_phy_write(phy_reg, addr, data |
+- (ENABLE_AUTO_SENSITIVITY_CALIBRATION));
+-
+- /* update dc disconnect level after toggle */
+- update_dc_disconnect_level(rtk_phy, phy_parameter, true);
+-
+-out:
+- return;
+-}
+-
+-static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
+-{
+- struct phy_parameter *phy_parameter;
+- struct phy_cfg *phy_cfg;
+- struct phy_data *phy_data_page;
+- struct phy_reg *phy_reg;
+- int i;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+- phy_reg = &phy_parameter->phy_reg;
+-
+- if (phy_cfg->use_default_parameter) {
+- dev_dbg(rtk_phy->dev, "%s phy#%d use default parameter\n",
+- __func__, index);
+- goto do_toggle;
+- }
+-
+- /* Set page 0 */
+- phy_data_page = phy_cfg->page0;
+- rtk_phy_set_page(phy_reg, 0);
+-
+- for (i = 0; i < phy_cfg->page0_size; i++) {
+- struct phy_data *phy_data = phy_data_page + i;
+- u8 addr = phy_data->addr;
+- u8 data = phy_data->data;
+-
+- if (!addr)
+- continue;
+-
+- if (rtk_phy_write(phy_reg, addr, data)) {
+- dev_err(rtk_phy->dev,
+- "%s: Error to set page0 parameter addr=0x%x value=0x%x\n",
+- __func__, addr, data);
+- return -EINVAL;
+- }
+- }
+-
+- /* Set page 1 */
+- phy_data_page = phy_cfg->page1;
+- rtk_phy_set_page(phy_reg, 1);
+-
+- for (i = 0; i < phy_cfg->page1_size; i++) {
+- struct phy_data *phy_data = phy_data_page + i;
+- u8 addr = phy_data->addr;
+- u8 data = phy_data->data;
+-
+- if (!addr)
+- continue;
+-
+- if (rtk_phy_write(phy_reg, addr, data)) {
+- dev_err(rtk_phy->dev,
+- "%s: Error to set page1 parameter addr=0x%x value=0x%x\n",
+- __func__, addr, data);
+- return -EINVAL;
+- }
+- }
+-
+- if (phy_cfg->page2_size == 0)
+- goto do_toggle;
+-
+- /* Set page 2 */
+- phy_data_page = phy_cfg->page2;
+- rtk_phy_set_page(phy_reg, 2);
+-
+- for (i = 0; i < phy_cfg->page2_size; i++) {
+- struct phy_data *phy_data = phy_data_page + i;
+- u8 addr = phy_data->addr;
+- u8 data = phy_data->data;
+-
+- if (!addr)
+- continue;
+-
+- if (rtk_phy_write(phy_reg, addr, data)) {
+- dev_err(rtk_phy->dev,
+- "%s: Error to set page2 parameter addr=0x%x value=0x%x\n",
+- __func__, addr, data);
+- return -EINVAL;
+- }
+- }
+-
+-do_toggle:
+- do_rtk_phy_toggle(rtk_phy, index, false);
+-
+- return 0;
+-}
+-
+-static int rtk_phy_init(struct phy *phy)
+-{
+- struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+- unsigned long phy_init_time = jiffies;
+- int i, ret = 0;
+-
+- if (!rtk_phy)
+- return -EINVAL;
+-
+- for (i = 0; i < rtk_phy->num_phy; i++)
+- ret = do_rtk_phy_init(rtk_phy, i);
+-
+- dev_dbg(rtk_phy->dev, "Initialized RTK USB 2.0 PHY (take %dms)\n",
+- jiffies_to_msecs(jiffies - phy_init_time));
+- return ret;
+-}
+-
+-static int rtk_phy_exit(struct phy *phy)
+-{
+- return 0;
+-}
+-
+-static const struct phy_ops ops = {
+- .init = rtk_phy_init,
+- .exit = rtk_phy_exit,
+- .owner = THIS_MODULE,
+-};
+-
+-static void rtk_phy_toggle(struct usb_phy *usb2_phy, bool connect, int port)
+-{
+- int index = port;
+- struct rtk_phy *rtk_phy = NULL;
+-
+- rtk_phy = dev_get_drvdata(usb2_phy->dev);
+-
+- if (index > rtk_phy->num_phy) {
+- dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n",
+- __func__, index, rtk_phy->num_phy);
+- return;
+- }
+-
+- do_rtk_phy_toggle(rtk_phy, index, connect);
+-}
+-
+-static int rtk_phy_notify_port_status(struct usb_phy *x, int port,
+- u16 portstatus, u16 portchange)
+-{
+- bool connect = false;
+-
+- pr_debug("%s port=%d portstatus=0x%x portchange=0x%x\n",
+- __func__, port, (int)portstatus, (int)portchange);
+- if (portstatus & USB_PORT_STAT_CONNECTION)
+- connect = true;
+-
+- if (portchange & USB_PORT_STAT_C_CONNECTION)
+- rtk_phy_toggle(x, connect, port);
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_DEBUG_FS
+-static struct dentry *create_phy_debug_root(void)
+-{
+- struct dentry *phy_debug_root;
+-
+- phy_debug_root = debugfs_lookup("phy", usb_debug_root);
+- if (!phy_debug_root)
+- phy_debug_root = debugfs_create_dir("phy", usb_debug_root);
+-
+- return phy_debug_root;
+-}
+-
+-static int rtk_usb2_parameter_show(struct seq_file *s, void *unused)
+-{
+- struct rtk_phy *rtk_phy = s->private;
+- struct phy_cfg *phy_cfg;
+- int i, index;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+-
+- seq_puts(s, "Property:\n");
+- seq_printf(s, " check_efuse: %s\n",
+- phy_cfg->check_efuse ? "Enable" : "Disable");
+- seq_printf(s, " check_efuse_version: %d\n",
+- phy_cfg->check_efuse_version);
+- seq_printf(s, " efuse_dc_driving_rate: %d\n",
+- phy_cfg->efuse_dc_driving_rate);
+- seq_printf(s, " dc_driving_mask: 0x%x\n",
+- phy_cfg->dc_driving_mask);
+- seq_printf(s, " efuse_dc_disconnect_rate: %d\n",
+- phy_cfg->efuse_dc_disconnect_rate);
+- seq_printf(s, " dc_disconnect_mask: 0x%x\n",
+- phy_cfg->dc_disconnect_mask);
+- seq_printf(s, " usb_dc_disconnect_at_page0: %s\n",
+- phy_cfg->usb_dc_disconnect_at_page0 ? "true" : "false");
+- seq_printf(s, " do_toggle: %s\n",
+- phy_cfg->do_toggle ? "Enable" : "Disable");
+- seq_printf(s, " do_toggle_driving: %s\n",
+- phy_cfg->do_toggle_driving ? "Enable" : "Disable");
+- seq_printf(s, " driving_updated_for_dev_dis: 0x%x\n",
+- phy_cfg->driving_updated_for_dev_dis);
+- seq_printf(s, " use_default_parameter: %s\n",
+- phy_cfg->use_default_parameter ? "Enable" : "Disable");
+- seq_printf(s, " is_double_sensitivity_mode: %s\n",
+- phy_cfg->is_double_sensitivity_mode ? "Enable" : "Disable");
+-
+- for (index = 0; index < rtk_phy->num_phy; index++) {
+- struct phy_parameter *phy_parameter;
+- struct phy_reg *phy_reg;
+- struct phy_data *phy_data_page;
+-
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+- phy_reg = &phy_parameter->phy_reg;
+-
+- seq_printf(s, "PHY %d:\n", index);
+-
+- seq_puts(s, "Page 0:\n");
+- /* Set page 0 */
+- phy_data_page = phy_cfg->page0;
+- rtk_phy_set_page(phy_reg, 0);
+-
+- for (i = 0; i < phy_cfg->page0_size; i++) {
+- struct phy_data *phy_data = phy_data_page + i;
+- u8 addr = array_index_to_page_addr(i);
+- u8 data = phy_data->data;
+- u8 value = rtk_phy_read(phy_reg, addr);
+-
+- if (phy_data->addr)
+- seq_printf(s, " Page 0: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
+- addr, data, value);
+- else
+- seq_printf(s, " Page 0: addr=0x%x data=none ==> read value=0x%02x\n",
+- addr, value);
+- }
+-
+- seq_puts(s, "Page 1:\n");
+- /* Set page 1 */
+- phy_data_page = phy_cfg->page1;
+- rtk_phy_set_page(phy_reg, 1);
+-
+- for (i = 0; i < phy_cfg->page1_size; i++) {
+- struct phy_data *phy_data = phy_data_page + i;
+- u8 addr = array_index_to_page_addr(i);
+- u8 data = phy_data->data;
+- u8 value = rtk_phy_read(phy_reg, addr);
+-
+- if (phy_data->addr)
+- seq_printf(s, " Page 1: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
+- addr, data, value);
+- else
+- seq_printf(s, " Page 1: addr=0x%x data=none ==> read value=0x%02x\n",
+- addr, value);
+- }
+-
+- if (phy_cfg->page2_size == 0)
+- goto out;
+-
+- seq_puts(s, "Page 2:\n");
+- /* Set page 2 */
+- phy_data_page = phy_cfg->page2;
+- rtk_phy_set_page(phy_reg, 2);
+-
+- for (i = 0; i < phy_cfg->page2_size; i++) {
+- struct phy_data *phy_data = phy_data_page + i;
+- u8 addr = array_index_to_page_addr(i);
+- u8 data = phy_data->data;
+- u8 value = rtk_phy_read(phy_reg, addr);
+-
+- if (phy_data->addr)
+- seq_printf(s, " Page 2: addr=0x%x data=0x%02x ==> read value=0x%02x\n",
+- addr, data, value);
+- else
+- seq_printf(s, " Page 2: addr=0x%x data=none ==> read value=0x%02x\n",
+- addr, value);
+- }
+-
+-out:
+- seq_puts(s, "PHY Property:\n");
+- seq_printf(s, " efuse_usb_dc_cal: %d\n",
+- (int)phy_parameter->efuse_usb_dc_cal);
+- seq_printf(s, " efuse_usb_dc_dis: %d\n",
+- (int)phy_parameter->efuse_usb_dc_dis);
+- seq_printf(s, " inverse_hstx_sync_clock: %s\n",
+- phy_parameter->inverse_hstx_sync_clock ? "Enable" : "Disable");
+- seq_printf(s, " driving_level: %d\n",
+- phy_parameter->driving_level);
+- seq_printf(s, " driving_level_compensate: %d\n",
+- phy_parameter->driving_level_compensate);
+- seq_printf(s, " disconnection_compensate: %d\n",
+- phy_parameter->disconnection_compensate);
+- }
+-
+- return 0;
+-}
+-DEFINE_SHOW_ATTRIBUTE(rtk_usb2_parameter);
+-
+-static inline void create_debug_files(struct rtk_phy *rtk_phy)
+-{
+- struct dentry *phy_debug_root = NULL;
+-
+- phy_debug_root = create_phy_debug_root();
+- if (!phy_debug_root)
+- return;
+-
+- rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev),
+- phy_debug_root);
+-
+- debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
+- &rtk_usb2_parameter_fops);
+-
+- return;
+-}
+-
+-static inline void remove_debug_files(struct rtk_phy *rtk_phy)
+-{
+- debugfs_remove_recursive(rtk_phy->debug_dir);
+-}
+-#else
+-static inline void create_debug_files(struct rtk_phy *rtk_phy) { }
+-static inline void remove_debug_files(struct rtk_phy *rtk_phy) { }
+-#endif /* CONFIG_DEBUG_FS */
+-
+-static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter, int index)
+-{
+- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+- u8 value = 0;
+- struct nvmem_cell *cell;
+- struct soc_device_attribute rtk_soc_groot[] = {
+- { .family = "Realtek Groot",},
+- { /* empty */ } };
+-
+- if (!phy_cfg->check_efuse)
+- goto out;
+-
+- /* Read efuse for usb dc cal */
+- cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-cal");
+- if (IS_ERR(cell)) {
+- dev_dbg(rtk_phy->dev, "%s no usb-dc-cal: %ld\n",
+- __func__, PTR_ERR(cell));
+- } else {
+- unsigned char *buf;
+- size_t buf_size;
+-
+- buf = nvmem_cell_read(cell, &buf_size);
+- if (!IS_ERR(buf)) {
+- value = buf[0] & phy_cfg->dc_driving_mask;
+- kfree(buf);
+- }
+- nvmem_cell_put(cell);
+- }
+-
+- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+- int rate = phy_cfg->efuse_dc_driving_rate;
+-
+- if (value <= EFUS_USB_DC_CAL_MAX)
+- phy_parameter->efuse_usb_dc_cal = (int8_t)(value * rate);
+- else
+- phy_parameter->efuse_usb_dc_cal = -(int8_t)
+- ((EFUS_USB_DC_CAL_MAX & value) * rate);
+-
+- if (soc_device_match(rtk_soc_groot)) {
+- dev_dbg(rtk_phy->dev, "For groot IC we need a workaround to adjust efuse_usb_dc_cal\n");
+-
+- /* We don't multiple dc_cal_rate=2 for positive dc cal compensate */
+- if (value <= EFUS_USB_DC_CAL_MAX)
+- phy_parameter->efuse_usb_dc_cal = (int8_t)(value);
+-
+- /* We set max dc cal compensate is 0x8 if otp is 0x7 */
+- if (value == 0x7)
+- phy_parameter->efuse_usb_dc_cal = (int8_t)(value + 1);
+- }
+- } else { /* for CHECK_EFUSE_V2 */
+- phy_parameter->efuse_usb_dc_cal = value & phy_cfg->dc_driving_mask;
+- }
+-
+- /* Read efuse for usb dc disconnect level */
+- value = 0;
+- cell = nvmem_cell_get(rtk_phy->dev, "usb-dc-dis");
+- if (IS_ERR(cell)) {
+- dev_dbg(rtk_phy->dev, "%s no usb-dc-dis: %ld\n",
+- __func__, PTR_ERR(cell));
+- } else {
+- unsigned char *buf;
+- size_t buf_size;
+-
+- buf = nvmem_cell_read(cell, &buf_size);
+- if (!IS_ERR(buf)) {
+- value = buf[0] & phy_cfg->dc_disconnect_mask;
+- kfree(buf);
+- }
+- nvmem_cell_put(cell);
+- }
+-
+- if (phy_cfg->check_efuse_version == CHECK_EFUSE_V1) {
+- int rate = phy_cfg->efuse_dc_disconnect_rate;
+-
+- if (value <= EFUS_USB_DC_DIS_MAX)
+- phy_parameter->efuse_usb_dc_dis = (int8_t)(value * rate);
+- else
+- phy_parameter->efuse_usb_dc_dis = -(int8_t)
+- ((EFUS_USB_DC_DIS_MAX & value) * rate);
+- } else { /* for CHECK_EFUSE_V2 */
+- phy_parameter->efuse_usb_dc_dis = value & phy_cfg->dc_disconnect_mask;
+- }
+-
+-out:
+- return 0;
+-}
+-
+-static int parse_phy_data(struct rtk_phy *rtk_phy)
+-{
+- struct device *dev = rtk_phy->dev;
+- struct device_node *np = dev->of_node;
+- struct phy_parameter *phy_parameter;
+- int ret = 0;
+- int index;
+-
+- rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) *
+- rtk_phy->num_phy, GFP_KERNEL);
+- if (!rtk_phy->phy_parameter)
+- return -ENOMEM;
+-
+- for (index = 0; index < rtk_phy->num_phy; index++) {
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+-
+- phy_parameter->phy_reg.reg_wrap_vstatus = of_iomap(np, 0);
+- phy_parameter->phy_reg.reg_gusb2phyacc0 = of_iomap(np, 1) + index;
+- phy_parameter->phy_reg.vstatus_index = index;
+-
+- if (of_property_read_bool(np, "realtek,inverse-hstx-sync-clock"))
+- phy_parameter->inverse_hstx_sync_clock = true;
+- else
+- phy_parameter->inverse_hstx_sync_clock = false;
+-
+- if (of_property_read_u32_index(np, "realtek,driving-level",
+- index, &phy_parameter->driving_level))
+- phy_parameter->driving_level = DEFAULT_DC_DRIVING_VALUE;
+-
+- if (of_property_read_u32_index(np, "realtek,driving-level-compensate",
+- index, &phy_parameter->driving_level_compensate))
+- phy_parameter->driving_level_compensate = 0;
+-
+- if (of_property_read_u32_index(np, "realtek,disconnection-compensate",
+- index, &phy_parameter->disconnection_compensate))
+- phy_parameter->disconnection_compensate = 0;
+-
+- get_phy_data_by_efuse(rtk_phy, phy_parameter, index);
+-
+- update_dc_driving_level(rtk_phy, phy_parameter);
+-
+- update_hs_clk_select(rtk_phy, phy_parameter);
+- }
+-
+- return ret;
+-}
+-
+-static int rtk_usb2phy_probe(struct platform_device *pdev)
+-{
+- struct rtk_phy *rtk_phy;
+- struct device *dev = &pdev->dev;
+- struct phy *generic_phy;
+- struct phy_provider *phy_provider;
+- const struct phy_cfg *phy_cfg;
+- int ret = 0;
+-
+- phy_cfg = of_device_get_match_data(dev);
+- if (!phy_cfg) {
+- dev_err(dev, "phy config are not assigned!\n");
+- return -EINVAL;
+- }
+-
+- rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL);
+- if (!rtk_phy)
+- return -ENOMEM;
+-
+- rtk_phy->dev = &pdev->dev;
+- rtk_phy->phy.dev = rtk_phy->dev;
+- rtk_phy->phy.label = "rtk-usb2phy";
+- rtk_phy->phy.notify_port_status = rtk_phy_notify_port_status;
+-
+- rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
+-
+- memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
+-
+- rtk_phy->num_phy = phy_cfg->num_phy;
+-
+- ret = parse_phy_data(rtk_phy);
+- if (ret)
+- goto err;
+-
+- platform_set_drvdata(pdev, rtk_phy);
+-
+- generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops);
+- if (IS_ERR(generic_phy))
+- return PTR_ERR(generic_phy);
+-
+- phy_set_drvdata(generic_phy, rtk_phy);
+-
+- phy_provider = devm_of_phy_provider_register(rtk_phy->dev,
+- of_phy_simple_xlate);
+- if (IS_ERR(phy_provider))
+- return PTR_ERR(phy_provider);
+-
+- ret = usb_add_phy_dev(&rtk_phy->phy);
+- if (ret)
+- goto err;
+-
+- create_debug_files(rtk_phy);
+-
+-err:
+- return ret;
+-}
+-
+-static void rtk_usb2phy_remove(struct platform_device *pdev)
+-{
+- struct rtk_phy *rtk_phy = platform_get_drvdata(pdev);
+-
+- remove_debug_files(rtk_phy);
+-
+- usb_remove_phy(&rtk_phy->phy);
+-}
+-
+-static const struct phy_cfg rtd1295_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [0] = {0xe0, 0x90},
+- [3] = {0xe3, 0x3a},
+- [4] = {0xe4, 0x68},
+- [6] = {0xe6, 0x91},
+- [13] = {0xf5, 0x81},
+- [15] = {0xf7, 0x02}, },
+- .page1_size = 8,
+- .page1 = { /* default parameter */ },
+- .page2_size = 0,
+- .page2 = { /* no parameter */ },
+- .num_phy = 1,
+- .check_efuse = false,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = 1,
+- .dc_driving_mask = 0xf,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = true,
+- .do_toggle = true,
+- .do_toggle_driving = false,
+- .driving_updated_for_dev_dis = 0xf,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = false,
+-};
+-
+-static const struct phy_cfg rtd1395_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [4] = {0xe4, 0xac},
+- [13] = {0xf5, 0x00},
+- [15] = {0xf7, 0x02}, },
+- .page1_size = 8,
+- .page1 = { /* default parameter */ },
+- .page2_size = 0,
+- .page2 = { /* no parameter */ },
+- .num_phy = 1,
+- .check_efuse = false,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = 1,
+- .dc_driving_mask = 0xf,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = true,
+- .do_toggle = true,
+- .do_toggle_driving = false,
+- .driving_updated_for_dev_dis = 0xf,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = false,
+-};
+-
+-static const struct phy_cfg rtd1395_phy_cfg_2port = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [4] = {0xe4, 0xac},
+- [13] = {0xf5, 0x00},
+- [15] = {0xf7, 0x02}, },
+- .page1_size = 8,
+- .page1 = { /* default parameter */ },
+- .page2_size = 0,
+- .page2 = { /* no parameter */ },
+- .num_phy = 2,
+- .check_efuse = false,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = 1,
+- .dc_driving_mask = 0xf,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = true,
+- .do_toggle = true,
+- .do_toggle_driving = false,
+- .driving_updated_for_dev_dis = 0xf,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = false,
+-};
+-
+-static const struct phy_cfg rtd1619_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [4] = {0xe4, 0x68}, },
+- .page1_size = 8,
+- .page1 = { /* default parameter */ },
+- .page2_size = 0,
+- .page2 = { /* no parameter */ },
+- .num_phy = 1,
+- .check_efuse = true,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = 1,
+- .dc_driving_mask = 0xf,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = true,
+- .do_toggle = true,
+- .do_toggle_driving = false,
+- .driving_updated_for_dev_dis = 0xf,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = false,
+-};
+-
+-static const struct phy_cfg rtd1319_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [0] = {0xe0, 0x18},
+- [4] = {0xe4, 0x6a},
+- [7] = {0xe7, 0x71},
+- [13] = {0xf5, 0x15},
+- [15] = {0xf7, 0x32}, },
+- .page1_size = 8,
+- .page1 = { [3] = {0xe3, 0x44}, },
+- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+- .page2 = { [0] = {0xe0, 0x01}, },
+- .num_phy = 1,
+- .check_efuse = true,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = 1,
+- .dc_driving_mask = 0xf,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = true,
+- .do_toggle = true,
+- .do_toggle_driving = true,
+- .driving_updated_for_dev_dis = 0xf,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = true,
+-};
+-
+-static const struct phy_cfg rtd1312c_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [0] = {0xe0, 0x14},
+- [4] = {0xe4, 0x67},
+- [5] = {0xe5, 0x55}, },
+- .page1_size = 8,
+- .page1 = { [3] = {0xe3, 0x23},
+- [6] = {0xe6, 0x58}, },
+- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+- .page2 = { /* default parameter */ },
+- .num_phy = 1,
+- .check_efuse = true,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = 1,
+- .dc_driving_mask = 0xf,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = true,
+- .do_toggle = true,
+- .do_toggle_driving = true,
+- .driving_updated_for_dev_dis = 0xf,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = true,
+-};
+-
+-static const struct phy_cfg rtd1619b_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [0] = {0xe0, 0xa3},
+- [4] = {0xe4, 0x88},
+- [5] = {0xe5, 0x4f},
+- [6] = {0xe6, 0x02}, },
+- .page1_size = 8,
+- .page1 = { [3] = {0xe3, 0x64}, },
+- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+- .page2 = { [7] = {0xe7, 0x45}, },
+- .num_phy = 1,
+- .check_efuse = true,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+- .dc_driving_mask = 0x1f,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = false,
+- .do_toggle = true,
+- .do_toggle_driving = true,
+- .driving_updated_for_dev_dis = 0x8,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = true,
+-};
+-
+-static const struct phy_cfg rtd1319d_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [0] = {0xe0, 0xa3},
+- [4] = {0xe4, 0x8e},
+- [5] = {0xe5, 0x4f},
+- [6] = {0xe6, 0x02}, },
+- .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
+- .page1 = { [14] = {0xf5, 0x1}, },
+- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+- .page2 = { [7] = {0xe7, 0x44}, },
+- .check_efuse = true,
+- .num_phy = 1,
+- .check_efuse_version = CHECK_EFUSE_V1,
+- .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+- .dc_driving_mask = 0x1f,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = false,
+- .do_toggle = true,
+- .do_toggle_driving = false,
+- .driving_updated_for_dev_dis = 0x8,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = true,
+-};
+-
+-static const struct phy_cfg rtd1315e_phy_cfg = {
+- .page0_size = MAX_USB_PHY_PAGE0_DATA_SIZE,
+- .page0 = { [0] = {0xe0, 0xa3},
+- [4] = {0xe4, 0x8c},
+- [5] = {0xe5, 0x4f},
+- [6] = {0xe6, 0x02}, },
+- .page1_size = MAX_USB_PHY_PAGE1_DATA_SIZE,
+- .page1 = { [3] = {0xe3, 0x7f},
+- [14] = {0xf5, 0x01}, },
+- .page2_size = MAX_USB_PHY_PAGE2_DATA_SIZE,
+- .page2 = { [7] = {0xe7, 0x44}, },
+- .num_phy = 1,
+- .check_efuse = true,
+- .check_efuse_version = CHECK_EFUSE_V2,
+- .efuse_dc_driving_rate = EFUS_USB_DC_CAL_RATE,
+- .dc_driving_mask = 0x1f,
+- .efuse_dc_disconnect_rate = EFUS_USB_DC_DIS_RATE,
+- .dc_disconnect_mask = 0xf,
+- .usb_dc_disconnect_at_page0 = false,
+- .do_toggle = true,
+- .do_toggle_driving = false,
+- .driving_updated_for_dev_dis = 0x8,
+- .use_default_parameter = false,
+- .is_double_sensitivity_mode = true,
+-};
+-
+-static const struct of_device_id usbphy_rtk_dt_match[] = {
+- { .compatible = "realtek,rtd1295-usb2phy", .data = &rtd1295_phy_cfg },
+- { .compatible = "realtek,rtd1312c-usb2phy", .data = &rtd1312c_phy_cfg },
+- { .compatible = "realtek,rtd1315e-usb2phy", .data = &rtd1315e_phy_cfg },
+- { .compatible = "realtek,rtd1319-usb2phy", .data = &rtd1319_phy_cfg },
+- { .compatible = "realtek,rtd1319d-usb2phy", .data = &rtd1319d_phy_cfg },
+- { .compatible = "realtek,rtd1395-usb2phy", .data = &rtd1395_phy_cfg },
+- { .compatible = "realtek,rtd1395-usb2phy-2port", .data = &rtd1395_phy_cfg_2port },
+- { .compatible = "realtek,rtd1619-usb2phy", .data = &rtd1619_phy_cfg },
+- { .compatible = "realtek,rtd1619b-usb2phy", .data = &rtd1619b_phy_cfg },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
+-
+-static struct platform_driver rtk_usb2phy_driver = {
+- .probe = rtk_usb2phy_probe,
+- .remove_new = rtk_usb2phy_remove,
+- .driver = {
+- .name = "rtk-usb2phy",
+- .of_match_table = usbphy_rtk_dt_match,
+- },
+-};
+-
+-module_platform_driver(rtk_usb2phy_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform: rtk-usb2phy");
+-MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
+-MODULE_DESCRIPTION("Realtek usb 2.0 phy driver");
--- /dev/null
+From 258ea41c926b7b3a16d0d7aa210a1401c4a1601b Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 6 Nov 2023 12:06:52 +0100
+Subject: Revert "phy: realtek: usb: Add driver for the Realtek SoC USB 3.0 PHY"
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit 258ea41c926b7b3a16d0d7aa210a1401c4a1601b upstream.
+
+This reverts commit adda6e82a7de7d6d478f6c8ef127f0ac51c510a1.
+
+The recently added Realtek PHY drivers depend on the new port status
+notification mechanism which was built on the deprecated USB PHY
+implementation and devicetree binding.
+
+Specifically, using these PHYs would require describing the very same
+PHY using both the generic "phy" property and the deprecated "usb-phy"
+property which is clearly wrong.
+
+We should not be building new functionality on top of the legacy USB PHY
+implementation even if it is currently stuck in some kind of
+transitional limbo.
+
+Revert the new Realtek PHY drivers for now so that the port status
+notification interface can be reverted and replaced.
+
+Fixes: adda6e82a7de ("phy: realtek: usb: Add driver for the Realtek SoC USB 3.0 PHY")
+Cc: stable@vger.kernel.org # 6.6
+Cc: Stanley Chang <stanley_chang@realtek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231106110654.31090-2-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/phy/realtek/Kconfig | 12
+ drivers/phy/realtek/Makefile | 1
+ drivers/phy/realtek/phy-rtk-usb3.c | 761 -------------------------------------
+ 3 files changed, 774 deletions(-)
+ delete mode 100644 drivers/phy/realtek/phy-rtk-usb3.c
+
+--- a/drivers/phy/realtek/Kconfig
++++ b/drivers/phy/realtek/Kconfig
+@@ -17,16 +17,4 @@ config PHY_RTK_RTD_USB2PHY
+ DWC3 USB IP. This driver will do the PHY initialization
+ of the parameters.
+
+-config PHY_RTK_RTD_USB3PHY
+- tristate "Realtek RTD USB3 PHY Transceiver Driver"
+- depends on USB_SUPPORT
+- select GENERIC_PHY
+- select USB_PHY
+- select USB_COMMON
+- help
+- Enable this to support Realtek SoC USB3 phy transceiver.
+- The DHC (digital home center) RTD series SoCs used the Synopsys
+- DWC3 USB IP. This driver will do the PHY initialization
+- of the parameters.
+-
+ endif # ARCH_REALTEK || COMPILE_TEST
+--- a/drivers/phy/realtek/Makefile
++++ b/drivers/phy/realtek/Makefile
+@@ -1,3 +1,2 @@
+ # SPDX-License-Identifier: GPL-2.0
+ obj-$(CONFIG_PHY_RTK_RTD_USB2PHY) += phy-rtk-usb2.o
+-obj-$(CONFIG_PHY_RTK_RTD_USB3PHY) += phy-rtk-usb3.o
+--- a/drivers/phy/realtek/phy-rtk-usb3.c
++++ /dev/null
+@@ -1,761 +0,0 @@
+-// SPDX-License-Identifier: GPL-2.0
+-/*
+- * phy-rtk-usb3.c RTK usb3.0 phy driver
+- *
+- * copyright (c) 2023 realtek semiconductor corporation
+- *
+- */
+-
+-#include <linux/module.h>
+-#include <linux/of.h>
+-#include <linux/of_device.h>
+-#include <linux/of_address.h>
+-#include <linux/uaccess.h>
+-#include <linux/debugfs.h>
+-#include <linux/nvmem-consumer.h>
+-#include <linux/regmap.h>
+-#include <linux/sys_soc.h>
+-#include <linux/mfd/syscon.h>
+-#include <linux/phy/phy.h>
+-#include <linux/usb.h>
+-#include <linux/usb/hcd.h>
+-#include <linux/usb/phy.h>
+-
+-#define USB_MDIO_CTRL_PHY_BUSY BIT(7)
+-#define USB_MDIO_CTRL_PHY_WRITE BIT(0)
+-#define USB_MDIO_CTRL_PHY_ADDR_SHIFT 8
+-#define USB_MDIO_CTRL_PHY_DATA_SHIFT 16
+-
+-#define MAX_USB_PHY_DATA_SIZE 0x30
+-#define PHY_ADDR_0X09 0x09
+-#define PHY_ADDR_0X0B 0x0b
+-#define PHY_ADDR_0X0D 0x0d
+-#define PHY_ADDR_0X10 0x10
+-#define PHY_ADDR_0X1F 0x1f
+-#define PHY_ADDR_0X20 0x20
+-#define PHY_ADDR_0X21 0x21
+-#define PHY_ADDR_0X30 0x30
+-
+-#define REG_0X09_FORCE_CALIBRATION BIT(9)
+-#define REG_0X0B_RX_OFFSET_RANGE_MASK 0xc
+-#define REG_0X0D_RX_DEBUG_TEST_EN BIT(6)
+-#define REG_0X10_DEBUG_MODE_SETTING 0x3c0
+-#define REG_0X10_DEBUG_MODE_SETTING_MASK 0x3f8
+-#define REG_0X1F_RX_OFFSET_CODE_MASK 0x1e
+-
+-#define USB_U3_TX_LFPS_SWING_TRIM_SHIFT 4
+-#define USB_U3_TX_LFPS_SWING_TRIM_MASK 0xf
+-#define AMPLITUDE_CONTROL_COARSE_MASK 0xff
+-#define AMPLITUDE_CONTROL_FINE_MASK 0xffff
+-#define AMPLITUDE_CONTROL_COARSE_DEFAULT 0xff
+-#define AMPLITUDE_CONTROL_FINE_DEFAULT 0xffff
+-
+-#define PHY_ADDR_MAP_ARRAY_INDEX(addr) (addr)
+-#define ARRAY_INDEX_MAP_PHY_ADDR(index) (index)
+-
+-struct phy_reg {
+- void __iomem *reg_mdio_ctl;
+-};
+-
+-struct phy_data {
+- u8 addr;
+- u16 data;
+-};
+-
+-struct phy_cfg {
+- int param_size;
+- struct phy_data param[MAX_USB_PHY_DATA_SIZE];
+-
+- bool check_efuse;
+- bool do_toggle;
+- bool do_toggle_once;
+- bool use_default_parameter;
+- bool check_rx_front_end_offset;
+-};
+-
+-struct phy_parameter {
+- struct phy_reg phy_reg;
+-
+- /* Get from efuse */
+- u8 efuse_usb_u3_tx_lfps_swing_trim;
+-
+- /* Get from dts */
+- u32 amplitude_control_coarse;
+- u32 amplitude_control_fine;
+-};
+-
+-struct rtk_phy {
+- struct usb_phy phy;
+- struct device *dev;
+-
+- struct phy_cfg *phy_cfg;
+- int num_phy;
+- struct phy_parameter *phy_parameter;
+-
+- struct dentry *debug_dir;
+-};
+-
+-#define PHY_IO_TIMEOUT_USEC (50000)
+-#define PHY_IO_DELAY_US (100)
+-
+-static inline int utmi_wait_register(void __iomem *reg, u32 mask, u32 result)
+-{
+- int ret;
+- unsigned int val;
+-
+- ret = read_poll_timeout(readl, val, ((val & mask) == result),
+- PHY_IO_DELAY_US, PHY_IO_TIMEOUT_USEC, false, reg);
+- if (ret) {
+- pr_err("%s can't program USB phy\n", __func__);
+- return -ETIMEDOUT;
+- }
+-
+- return 0;
+-}
+-
+-static int rtk_phy3_wait_vbusy(struct phy_reg *phy_reg)
+-{
+- return utmi_wait_register(phy_reg->reg_mdio_ctl, USB_MDIO_CTRL_PHY_BUSY, 0);
+-}
+-
+-static u16 rtk_phy_read(struct phy_reg *phy_reg, char addr)
+-{
+- unsigned int tmp;
+- u32 value;
+-
+- tmp = (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT);
+-
+- writel(tmp, phy_reg->reg_mdio_ctl);
+-
+- rtk_phy3_wait_vbusy(phy_reg);
+-
+- value = readl(phy_reg->reg_mdio_ctl);
+- value = value >> USB_MDIO_CTRL_PHY_DATA_SHIFT;
+-
+- return (u16)value;
+-}
+-
+-static int rtk_phy_write(struct phy_reg *phy_reg, char addr, u16 data)
+-{
+- unsigned int val;
+-
+- val = USB_MDIO_CTRL_PHY_WRITE |
+- (addr << USB_MDIO_CTRL_PHY_ADDR_SHIFT) |
+- (data << USB_MDIO_CTRL_PHY_DATA_SHIFT);
+-
+- writel(val, phy_reg->reg_mdio_ctl);
+-
+- rtk_phy3_wait_vbusy(phy_reg);
+-
+- return 0;
+-}
+-
+-static void do_rtk_usb3_phy_toggle(struct rtk_phy *rtk_phy, int index, bool connect)
+-{
+- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+- struct phy_reg *phy_reg;
+- struct phy_parameter *phy_parameter;
+- struct phy_data *phy_data;
+- u8 addr;
+- u16 data;
+- int i;
+-
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+- phy_reg = &phy_parameter->phy_reg;
+-
+- if (!phy_cfg->do_toggle)
+- return;
+-
+- i = PHY_ADDR_MAP_ARRAY_INDEX(PHY_ADDR_0X09);
+- phy_data = phy_cfg->param + i;
+- addr = phy_data->addr;
+- data = phy_data->data;
+-
+- if (!addr && !data) {
+- addr = PHY_ADDR_0X09;
+- data = rtk_phy_read(phy_reg, addr);
+- phy_data->addr = addr;
+- phy_data->data = data;
+- }
+-
+- rtk_phy_write(phy_reg, addr, data & (~REG_0X09_FORCE_CALIBRATION));
+- mdelay(1);
+- rtk_phy_write(phy_reg, addr, data | REG_0X09_FORCE_CALIBRATION);
+-}
+-
+-static int do_rtk_phy_init(struct rtk_phy *rtk_phy, int index)
+-{
+- struct phy_cfg *phy_cfg;
+- struct phy_reg *phy_reg;
+- struct phy_parameter *phy_parameter;
+- int i = 0;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+- phy_reg = &phy_parameter->phy_reg;
+-
+- if (phy_cfg->use_default_parameter)
+- goto do_toggle;
+-
+- for (i = 0; i < phy_cfg->param_size; i++) {
+- struct phy_data *phy_data = phy_cfg->param + i;
+- u8 addr = phy_data->addr;
+- u16 data = phy_data->data;
+-
+- if (!addr && !data)
+- continue;
+-
+- rtk_phy_write(phy_reg, addr, data);
+- }
+-
+-do_toggle:
+- if (phy_cfg->do_toggle_once)
+- phy_cfg->do_toggle = true;
+-
+- do_rtk_usb3_phy_toggle(rtk_phy, index, false);
+-
+- if (phy_cfg->do_toggle_once) {
+- u16 check_value = 0;
+- int count = 10;
+- u16 value_0x0d, value_0x10;
+-
+- /* Enable Debug mode by set 0x0D and 0x10 */
+- value_0x0d = rtk_phy_read(phy_reg, PHY_ADDR_0X0D);
+- value_0x10 = rtk_phy_read(phy_reg, PHY_ADDR_0X10);
+-
+- rtk_phy_write(phy_reg, PHY_ADDR_0X0D,
+- value_0x0d | REG_0X0D_RX_DEBUG_TEST_EN);
+- rtk_phy_write(phy_reg, PHY_ADDR_0X10,
+- (value_0x10 & ~REG_0X10_DEBUG_MODE_SETTING_MASK) |
+- REG_0X10_DEBUG_MODE_SETTING);
+-
+- check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30);
+-
+- while (!(check_value & BIT(15))) {
+- check_value = rtk_phy_read(phy_reg, PHY_ADDR_0X30);
+- mdelay(1);
+- if (count-- < 0)
+- break;
+- }
+-
+- if (!(check_value & BIT(15)))
+- dev_info(rtk_phy->dev, "toggle fail addr=0x%02x, data=0x%04x\n",
+- PHY_ADDR_0X30, check_value);
+-
+- /* Disable Debug mode by set 0x0D and 0x10 to default*/
+- rtk_phy_write(phy_reg, PHY_ADDR_0X0D, value_0x0d);
+- rtk_phy_write(phy_reg, PHY_ADDR_0X10, value_0x10);
+-
+- phy_cfg->do_toggle = false;
+- }
+-
+- if (phy_cfg->check_rx_front_end_offset) {
+- u16 rx_offset_code, rx_offset_range;
+- u16 code_mask = REG_0X1F_RX_OFFSET_CODE_MASK;
+- u16 range_mask = REG_0X0B_RX_OFFSET_RANGE_MASK;
+- bool do_update = false;
+-
+- rx_offset_code = rtk_phy_read(phy_reg, PHY_ADDR_0X1F);
+- if (((rx_offset_code & code_mask) == 0x0) ||
+- ((rx_offset_code & code_mask) == code_mask))
+- do_update = true;
+-
+- rx_offset_range = rtk_phy_read(phy_reg, PHY_ADDR_0X0B);
+- if (((rx_offset_range & range_mask) == range_mask) && do_update) {
+- dev_warn(rtk_phy->dev, "Don't update rx_offset_range (rx_offset_code=0x%x, rx_offset_range=0x%x)\n",
+- rx_offset_code, rx_offset_range);
+- do_update = false;
+- }
+-
+- if (do_update) {
+- u16 tmp1, tmp2;
+-
+- tmp1 = rx_offset_range & (~range_mask);
+- tmp2 = rx_offset_range & range_mask;
+- tmp2 += (1 << 2);
+- rx_offset_range = tmp1 | (tmp2 & range_mask);
+- rtk_phy_write(phy_reg, PHY_ADDR_0X0B, rx_offset_range);
+- goto do_toggle;
+- }
+- }
+-
+- return 0;
+-}
+-
+-static int rtk_phy_init(struct phy *phy)
+-{
+- struct rtk_phy *rtk_phy = phy_get_drvdata(phy);
+- int ret = 0;
+- int i;
+- unsigned long phy_init_time = jiffies;
+-
+- for (i = 0; i < rtk_phy->num_phy; i++)
+- ret = do_rtk_phy_init(rtk_phy, i);
+-
+- dev_dbg(rtk_phy->dev, "Initialized RTK USB 3.0 PHY (take %dms)\n",
+- jiffies_to_msecs(jiffies - phy_init_time));
+-
+- return ret;
+-}
+-
+-static int rtk_phy_exit(struct phy *phy)
+-{
+- return 0;
+-}
+-
+-static const struct phy_ops ops = {
+- .init = rtk_phy_init,
+- .exit = rtk_phy_exit,
+- .owner = THIS_MODULE,
+-};
+-
+-static void rtk_phy_toggle(struct usb_phy *usb3_phy, bool connect, int port)
+-{
+- int index = port;
+- struct rtk_phy *rtk_phy = NULL;
+-
+- rtk_phy = dev_get_drvdata(usb3_phy->dev);
+-
+- if (index > rtk_phy->num_phy) {
+- dev_err(rtk_phy->dev, "%s: The port=%d is not in usb phy (num_phy=%d)\n",
+- __func__, index, rtk_phy->num_phy);
+- return;
+- }
+-
+- do_rtk_usb3_phy_toggle(rtk_phy, index, connect);
+-}
+-
+-static int rtk_phy_notify_port_status(struct usb_phy *x, int port,
+- u16 portstatus, u16 portchange)
+-{
+- bool connect = false;
+-
+- pr_debug("%s port=%d portstatus=0x%x portchange=0x%x\n",
+- __func__, port, (int)portstatus, (int)portchange);
+- if (portstatus & USB_PORT_STAT_CONNECTION)
+- connect = true;
+-
+- if (portchange & USB_PORT_STAT_C_CONNECTION)
+- rtk_phy_toggle(x, connect, port);
+-
+- return 0;
+-}
+-
+-#ifdef CONFIG_DEBUG_FS
+-static struct dentry *create_phy_debug_root(void)
+-{
+- struct dentry *phy_debug_root;
+-
+- phy_debug_root = debugfs_lookup("phy", usb_debug_root);
+- if (!phy_debug_root)
+- phy_debug_root = debugfs_create_dir("phy", usb_debug_root);
+-
+- return phy_debug_root;
+-}
+-
+-static int rtk_usb3_parameter_show(struct seq_file *s, void *unused)
+-{
+- struct rtk_phy *rtk_phy = s->private;
+- struct phy_cfg *phy_cfg;
+- int i, index;
+-
+- phy_cfg = rtk_phy->phy_cfg;
+-
+- seq_puts(s, "Property:\n");
+- seq_printf(s, " check_efuse: %s\n",
+- phy_cfg->check_efuse ? "Enable" : "Disable");
+- seq_printf(s, " do_toggle: %s\n",
+- phy_cfg->do_toggle ? "Enable" : "Disable");
+- seq_printf(s, " do_toggle_once: %s\n",
+- phy_cfg->do_toggle_once ? "Enable" : "Disable");
+- seq_printf(s, " use_default_parameter: %s\n",
+- phy_cfg->use_default_parameter ? "Enable" : "Disable");
+-
+- for (index = 0; index < rtk_phy->num_phy; index++) {
+- struct phy_reg *phy_reg;
+- struct phy_parameter *phy_parameter;
+-
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+- phy_reg = &phy_parameter->phy_reg;
+-
+- seq_printf(s, "PHY %d:\n", index);
+-
+- for (i = 0; i < phy_cfg->param_size; i++) {
+- struct phy_data *phy_data = phy_cfg->param + i;
+- u8 addr = ARRAY_INDEX_MAP_PHY_ADDR(i);
+- u16 data = phy_data->data;
+-
+- if (!phy_data->addr && !data)
+- seq_printf(s, " addr = 0x%02x, data = none ==> read value = 0x%04x\n",
+- addr, rtk_phy_read(phy_reg, addr));
+- else
+- seq_printf(s, " addr = 0x%02x, data = 0x%04x ==> read value = 0x%04x\n",
+- addr, data, rtk_phy_read(phy_reg, addr));
+- }
+-
+- seq_puts(s, "PHY Property:\n");
+- seq_printf(s, " efuse_usb_u3_tx_lfps_swing_trim: 0x%x\n",
+- (int)phy_parameter->efuse_usb_u3_tx_lfps_swing_trim);
+- seq_printf(s, " amplitude_control_coarse: 0x%x\n",
+- (int)phy_parameter->amplitude_control_coarse);
+- seq_printf(s, " amplitude_control_fine: 0x%x\n",
+- (int)phy_parameter->amplitude_control_fine);
+- }
+-
+- return 0;
+-}
+-DEFINE_SHOW_ATTRIBUTE(rtk_usb3_parameter);
+-
+-static inline void create_debug_files(struct rtk_phy *rtk_phy)
+-{
+- struct dentry *phy_debug_root = NULL;
+-
+- phy_debug_root = create_phy_debug_root();
+-
+- if (!phy_debug_root)
+- return;
+-
+- rtk_phy->debug_dir = debugfs_create_dir(dev_name(rtk_phy->dev), phy_debug_root);
+-
+- debugfs_create_file("parameter", 0444, rtk_phy->debug_dir, rtk_phy,
+- &rtk_usb3_parameter_fops);
+-
+- return;
+-}
+-
+-static inline void remove_debug_files(struct rtk_phy *rtk_phy)
+-{
+- debugfs_remove_recursive(rtk_phy->debug_dir);
+-}
+-#else
+-static inline void create_debug_files(struct rtk_phy *rtk_phy) { }
+-static inline void remove_debug_files(struct rtk_phy *rtk_phy) { }
+-#endif /* CONFIG_DEBUG_FS */
+-
+-static int get_phy_data_by_efuse(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter, int index)
+-{
+- struct phy_cfg *phy_cfg = rtk_phy->phy_cfg;
+- u8 value = 0;
+- struct nvmem_cell *cell;
+-
+- if (!phy_cfg->check_efuse)
+- goto out;
+-
+- cell = nvmem_cell_get(rtk_phy->dev, "usb_u3_tx_lfps_swing_trim");
+- if (IS_ERR(cell)) {
+- dev_dbg(rtk_phy->dev, "%s no usb_u3_tx_lfps_swing_trim: %ld\n",
+- __func__, PTR_ERR(cell));
+- } else {
+- unsigned char *buf;
+- size_t buf_size;
+-
+- buf = nvmem_cell_read(cell, &buf_size);
+- if (!IS_ERR(buf)) {
+- value = buf[0] & USB_U3_TX_LFPS_SWING_TRIM_MASK;
+- kfree(buf);
+- }
+- nvmem_cell_put(cell);
+- }
+-
+- if (value > 0 && value < 0x8)
+- phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = 0x8;
+- else
+- phy_parameter->efuse_usb_u3_tx_lfps_swing_trim = (u8)value;
+-
+-out:
+- return 0;
+-}
+-
+-static void update_amplitude_control_value(struct rtk_phy *rtk_phy,
+- struct phy_parameter *phy_parameter)
+-{
+- struct phy_cfg *phy_cfg;
+- struct phy_reg *phy_reg;
+-
+- phy_reg = &phy_parameter->phy_reg;
+- phy_cfg = rtk_phy->phy_cfg;
+-
+- if (phy_parameter->amplitude_control_coarse != AMPLITUDE_CONTROL_COARSE_DEFAULT) {
+- u16 val_mask = AMPLITUDE_CONTROL_COARSE_MASK;
+- u16 data;
+-
+- if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) {
+- phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20;
+- data = rtk_phy_read(phy_reg, PHY_ADDR_0X20);
+- } else {
+- data = phy_cfg->param[PHY_ADDR_0X20].data;
+- }
+-
+- data &= (~val_mask);
+- data |= (phy_parameter->amplitude_control_coarse & val_mask);
+-
+- phy_cfg->param[PHY_ADDR_0X20].data = data;
+- }
+-
+- if (phy_parameter->efuse_usb_u3_tx_lfps_swing_trim) {
+- u8 efuse_val = phy_parameter->efuse_usb_u3_tx_lfps_swing_trim;
+- u16 val_mask = USB_U3_TX_LFPS_SWING_TRIM_MASK;
+- int val_shift = USB_U3_TX_LFPS_SWING_TRIM_SHIFT;
+- u16 data;
+-
+- if (!phy_cfg->param[PHY_ADDR_0X20].addr && !phy_cfg->param[PHY_ADDR_0X20].data) {
+- phy_cfg->param[PHY_ADDR_0X20].addr = PHY_ADDR_0X20;
+- data = rtk_phy_read(phy_reg, PHY_ADDR_0X20);
+- } else {
+- data = phy_cfg->param[PHY_ADDR_0X20].data;
+- }
+-
+- data &= ~(val_mask << val_shift);
+- data |= ((efuse_val & val_mask) << val_shift);
+-
+- phy_cfg->param[PHY_ADDR_0X20].data = data;
+- }
+-
+- if (phy_parameter->amplitude_control_fine != AMPLITUDE_CONTROL_FINE_DEFAULT) {
+- u16 val_mask = AMPLITUDE_CONTROL_FINE_MASK;
+-
+- if (!phy_cfg->param[PHY_ADDR_0X21].addr && !phy_cfg->param[PHY_ADDR_0X21].data)
+- phy_cfg->param[PHY_ADDR_0X21].addr = PHY_ADDR_0X21;
+-
+- phy_cfg->param[PHY_ADDR_0X21].data =
+- phy_parameter->amplitude_control_fine & val_mask;
+- }
+-}
+-
+-static int parse_phy_data(struct rtk_phy *rtk_phy)
+-{
+- struct device *dev = rtk_phy->dev;
+- struct phy_parameter *phy_parameter;
+- int ret = 0;
+- int index;
+-
+- rtk_phy->phy_parameter = devm_kzalloc(dev, sizeof(struct phy_parameter) *
+- rtk_phy->num_phy, GFP_KERNEL);
+- if (!rtk_phy->phy_parameter)
+- return -ENOMEM;
+-
+- for (index = 0; index < rtk_phy->num_phy; index++) {
+- phy_parameter = &((struct phy_parameter *)rtk_phy->phy_parameter)[index];
+-
+- phy_parameter->phy_reg.reg_mdio_ctl = of_iomap(dev->of_node, 0) + index;
+-
+- /* Amplitude control address 0x20 bit 0 to bit 7 */
+- if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-coarse-tuning",
+- &phy_parameter->amplitude_control_coarse))
+- phy_parameter->amplitude_control_coarse = AMPLITUDE_CONTROL_COARSE_DEFAULT;
+-
+- /* Amplitude control address 0x21 bit 0 to bit 16 */
+- if (of_property_read_u32(dev->of_node, "realtek,amplitude-control-fine-tuning",
+- &phy_parameter->amplitude_control_fine))
+- phy_parameter->amplitude_control_fine = AMPLITUDE_CONTROL_FINE_DEFAULT;
+-
+- get_phy_data_by_efuse(rtk_phy, phy_parameter, index);
+-
+- update_amplitude_control_value(rtk_phy, phy_parameter);
+- }
+-
+- return ret;
+-}
+-
+-static int rtk_usb3phy_probe(struct platform_device *pdev)
+-{
+- struct rtk_phy *rtk_phy;
+- struct device *dev = &pdev->dev;
+- struct phy *generic_phy;
+- struct phy_provider *phy_provider;
+- const struct phy_cfg *phy_cfg;
+- int ret;
+-
+- phy_cfg = of_device_get_match_data(dev);
+- if (!phy_cfg) {
+- dev_err(dev, "phy config are not assigned!\n");
+- return -EINVAL;
+- }
+-
+- rtk_phy = devm_kzalloc(dev, sizeof(*rtk_phy), GFP_KERNEL);
+- if (!rtk_phy)
+- return -ENOMEM;
+-
+- rtk_phy->dev = &pdev->dev;
+- rtk_phy->phy.dev = rtk_phy->dev;
+- rtk_phy->phy.label = "rtk-usb3phy";
+- rtk_phy->phy.notify_port_status = rtk_phy_notify_port_status;
+-
+- rtk_phy->phy_cfg = devm_kzalloc(dev, sizeof(*phy_cfg), GFP_KERNEL);
+-
+- memcpy(rtk_phy->phy_cfg, phy_cfg, sizeof(*phy_cfg));
+-
+- rtk_phy->num_phy = 1;
+-
+- ret = parse_phy_data(rtk_phy);
+- if (ret)
+- goto err;
+-
+- platform_set_drvdata(pdev, rtk_phy);
+-
+- generic_phy = devm_phy_create(rtk_phy->dev, NULL, &ops);
+- if (IS_ERR(generic_phy))
+- return PTR_ERR(generic_phy);
+-
+- phy_set_drvdata(generic_phy, rtk_phy);
+-
+- phy_provider = devm_of_phy_provider_register(rtk_phy->dev, of_phy_simple_xlate);
+- if (IS_ERR(phy_provider))
+- return PTR_ERR(phy_provider);
+-
+- ret = usb_add_phy_dev(&rtk_phy->phy);
+- if (ret)
+- goto err;
+-
+- create_debug_files(rtk_phy);
+-
+-err:
+- return ret;
+-}
+-
+-static void rtk_usb3phy_remove(struct platform_device *pdev)
+-{
+- struct rtk_phy *rtk_phy = platform_get_drvdata(pdev);
+-
+- remove_debug_files(rtk_phy);
+-
+- usb_remove_phy(&rtk_phy->phy);
+-}
+-
+-static const struct phy_cfg rtd1295_phy_cfg = {
+- .param_size = MAX_USB_PHY_DATA_SIZE,
+- .param = { [0] = {0x01, 0x4008}, [1] = {0x01, 0xe046},
+- [2] = {0x02, 0x6046}, [3] = {0x03, 0x2779},
+- [4] = {0x04, 0x72f5}, [5] = {0x05, 0x2ad3},
+- [6] = {0x06, 0x000e}, [7] = {0x07, 0x2e00},
+- [8] = {0x08, 0x3591}, [9] = {0x09, 0x525c},
+- [10] = {0x0a, 0xa600}, [11] = {0x0b, 0xa904},
+- [12] = {0x0c, 0xc000}, [13] = {0x0d, 0xef1c},
+- [14] = {0x0e, 0x2000}, [15] = {0x0f, 0x0000},
+- [16] = {0x10, 0x000c}, [17] = {0x11, 0x4c00},
+- [18] = {0x12, 0xfc00}, [19] = {0x13, 0x0c81},
+- [20] = {0x14, 0xde01}, [21] = {0x15, 0x0000},
+- [22] = {0x16, 0x0000}, [23] = {0x17, 0x0000},
+- [24] = {0x18, 0x0000}, [25] = {0x19, 0x4004},
+- [26] = {0x1a, 0x1260}, [27] = {0x1b, 0xff00},
+- [28] = {0x1c, 0xcb00}, [29] = {0x1d, 0xa03f},
+- [30] = {0x1e, 0xc2e0}, [31] = {0x1f, 0x2807},
+- [32] = {0x20, 0x947a}, [33] = {0x21, 0x88aa},
+- [34] = {0x22, 0x0057}, [35] = {0x23, 0xab66},
+- [36] = {0x24, 0x0800}, [37] = {0x25, 0x0000},
+- [38] = {0x26, 0x040a}, [39] = {0x27, 0x01d6},
+- [40] = {0x28, 0xf8c2}, [41] = {0x29, 0x3080},
+- [42] = {0x2a, 0x3082}, [43] = {0x2b, 0x2078},
+- [44] = {0x2c, 0xffff}, [45] = {0x2d, 0xffff},
+- [46] = {0x2e, 0x0000}, [47] = {0x2f, 0x0040}, },
+- .check_efuse = false,
+- .do_toggle = true,
+- .do_toggle_once = false,
+- .use_default_parameter = false,
+- .check_rx_front_end_offset = false,
+-};
+-
+-static const struct phy_cfg rtd1619_phy_cfg = {
+- .param_size = MAX_USB_PHY_DATA_SIZE,
+- .param = { [8] = {0x08, 0x3591},
+- [38] = {0x26, 0x840b},
+- [40] = {0x28, 0xf842}, },
+- .check_efuse = false,
+- .do_toggle = true,
+- .do_toggle_once = false,
+- .use_default_parameter = false,
+- .check_rx_front_end_offset = false,
+-};
+-
+-static const struct phy_cfg rtd1319_phy_cfg = {
+- .param_size = MAX_USB_PHY_DATA_SIZE,
+- .param = { [1] = {0x01, 0xac86},
+- [6] = {0x06, 0x0003},
+- [9] = {0x09, 0x924c},
+- [10] = {0x0a, 0xa608},
+- [11] = {0x0b, 0xb905},
+- [14] = {0x0e, 0x2010},
+- [32] = {0x20, 0x705a},
+- [33] = {0x21, 0xf645},
+- [34] = {0x22, 0x0013},
+- [35] = {0x23, 0xcb66},
+- [41] = {0x29, 0xff00}, },
+- .check_efuse = true,
+- .do_toggle = true,
+- .do_toggle_once = false,
+- .use_default_parameter = false,
+- .check_rx_front_end_offset = false,
+-};
+-
+-static const struct phy_cfg rtd1619b_phy_cfg = {
+- .param_size = MAX_USB_PHY_DATA_SIZE,
+- .param = { [1] = {0x01, 0xac8c},
+- [6] = {0x06, 0x0017},
+- [9] = {0x09, 0x724c},
+- [10] = {0x0a, 0xb610},
+- [11] = {0x0b, 0xb90d},
+- [13] = {0x0d, 0xef2a},
+- [15] = {0x0f, 0x9050},
+- [16] = {0x10, 0x000c},
+- [32] = {0x20, 0x70ff},
+- [34] = {0x22, 0x0013},
+- [35] = {0x23, 0xdb66},
+- [38] = {0x26, 0x8609},
+- [41] = {0x29, 0xff13},
+- [42] = {0x2a, 0x3070}, },
+- .check_efuse = true,
+- .do_toggle = false,
+- .do_toggle_once = true,
+- .use_default_parameter = false,
+- .check_rx_front_end_offset = false,
+-};
+-
+-static const struct phy_cfg rtd1319d_phy_cfg = {
+- .param_size = MAX_USB_PHY_DATA_SIZE,
+- .param = { [1] = {0x01, 0xac89},
+- [4] = {0x04, 0xf2f5},
+- [6] = {0x06, 0x0017},
+- [9] = {0x09, 0x424c},
+- [10] = {0x0a, 0x9610},
+- [11] = {0x0b, 0x9901},
+- [12] = {0x0c, 0xf000},
+- [13] = {0x0d, 0xef2a},
+- [14] = {0x0e, 0x1000},
+- [15] = {0x0f, 0x9050},
+- [32] = {0x20, 0x7077},
+- [35] = {0x23, 0x0b62},
+- [37] = {0x25, 0x10ec},
+- [42] = {0x2a, 0x3070}, },
+- .check_efuse = true,
+- .do_toggle = false,
+- .do_toggle_once = true,
+- .use_default_parameter = false,
+- .check_rx_front_end_offset = true,
+-};
+-
+-static const struct of_device_id usbphy_rtk_dt_match[] = {
+- { .compatible = "realtek,rtd1295-usb3phy", .data = &rtd1295_phy_cfg },
+- { .compatible = "realtek,rtd1319-usb3phy", .data = &rtd1319_phy_cfg },
+- { .compatible = "realtek,rtd1319d-usb3phy", .data = &rtd1319d_phy_cfg },
+- { .compatible = "realtek,rtd1619-usb3phy", .data = &rtd1619_phy_cfg },
+- { .compatible = "realtek,rtd1619b-usb3phy", .data = &rtd1619b_phy_cfg },
+- {},
+-};
+-MODULE_DEVICE_TABLE(of, usbphy_rtk_dt_match);
+-
+-static struct platform_driver rtk_usb3phy_driver = {
+- .probe = rtk_usb3phy_probe,
+- .remove_new = rtk_usb3phy_remove,
+- .driver = {
+- .name = "rtk-usb3phy",
+- .of_match_table = usbphy_rtk_dt_match,
+- },
+-};
+-
+-module_platform_driver(rtk_usb3phy_driver);
+-
+-MODULE_LICENSE("GPL");
+-MODULE_ALIAS("platform: rtk-usb3phy");
+-MODULE_AUTHOR("Stanley Chang <stanley_chang@realtek.com>");
+-MODULE_DESCRIPTION("Realtek usb 3.0 phy driver");
--- /dev/null
+From 1a229d8690a0f8951fc4aa8b76a7efab0d8de342 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan+linaro@kernel.org>
+Date: Mon, 6 Nov 2023 12:06:54 +0100
+Subject: Revert "usb: phy: add usb phy notify port status API"
+
+From: Johan Hovold <johan+linaro@kernel.org>
+
+commit 1a229d8690a0f8951fc4aa8b76a7efab0d8de342 upstream.
+
+This reverts commit a08799cf17c22375752abfad3b4a2b34b3acb287.
+
+The recently added Realtek PHY drivers depend on the new port status
+notification mechanism which was built on the deprecated USB PHY
+implementation and devicetree binding.
+
+Specifically, using these PHYs would require describing the very same
+PHY using both the generic "phy" property and the deprecated "usb-phy"
+property which is clearly wrong.
+
+We should not be building new functionality on top of the legacy USB PHY
+implementation even if it is currently stuck in some kind of
+transitional limbo.
+
+Revert the new notification interface which is broken by design.
+
+Fixes: a08799cf17c2 ("usb: phy: add usb phy notify port status API")
+Cc: stable@vger.kernel.org # 6.6
+Cc: Stanley Chang <stanley_chang@realtek.com>
+Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
+Link: https://lore.kernel.org/r/20231106110654.31090-4-johan+linaro@kernel.org
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/core/hub.c | 23 -----------------------
+ include/linux/usb/phy.h | 13 -------------
+ 2 files changed, 36 deletions(-)
+
+diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
+index b4584a0cd484..87480a6e6d93 100644
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -622,29 +622,6 @@ static int hub_ext_port_status(struct usb_hub *hub, int port1, int type,
+ ret = 0;
+ }
+ mutex_unlock(&hub->status_mutex);
+-
+- /*
+- * There is no need to lock status_mutex here, because status_mutex
+- * protects hub->status, and the phy driver only checks the port
+- * status without changing the status.
+- */
+- if (!ret) {
+- struct usb_device *hdev = hub->hdev;
+-
+- /*
+- * Only roothub will be notified of port state changes,
+- * since the USB PHY only cares about changes at the next
+- * level.
+- */
+- if (is_root_hub(hdev)) {
+- struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
+-
+- if (hcd->usb_phy)
+- usb_phy_notify_port_status(hcd->usb_phy,
+- port1 - 1, *status, *change);
+- }
+- }
+-
+ return ret;
+ }
+
+diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h
+index b513749582d7..e4de6bc1f69b 100644
+--- a/include/linux/usb/phy.h
++++ b/include/linux/usb/phy.h
+@@ -144,10 +144,6 @@ struct usb_phy {
+ */
+ int (*set_wakeup)(struct usb_phy *x, bool enabled);
+
+- /* notify phy port status change */
+- int (*notify_port_status)(struct usb_phy *x, int port,
+- u16 portstatus, u16 portchange);
+-
+ /* notify phy connect status change */
+ int (*notify_connect)(struct usb_phy *x,
+ enum usb_device_speed speed);
+@@ -320,15 +316,6 @@ usb_phy_set_wakeup(struct usb_phy *x, bool enabled)
+ return 0;
+ }
+
+-static inline int
+-usb_phy_notify_port_status(struct usb_phy *x, int port, u16 portstatus, u16 portchange)
+-{
+- if (x && x->notify_port_status)
+- return x->notify_port_status(x, port, portstatus, portchange);
+- else
+- return 0;
+-}
+-
+ static inline int
+ usb_phy_notify_connect(struct usb_phy *x, enum usb_device_speed speed)
+ {
+--
+2.43.0
+
--- /dev/null
+From db46cd1e0426f52999d50fa72cfa97fa39952885 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Jan=20H=C3=B6ppner?= <hoeppner@linux.ibm.com>
+Date: Wed, 25 Oct 2023 15:24:37 +0200
+Subject: s390/dasd: protect device queue against concurrent access
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Jan Höppner <hoeppner@linux.ibm.com>
+
+commit db46cd1e0426f52999d50fa72cfa97fa39952885 upstream.
+
+In dasd_profile_start() the amount of requests on the device queue are
+counted. The access to the device queue is unprotected against
+concurrent access. With a lot of parallel I/O, especially with alias
+devices enabled, the device queue can change while dasd_profile_start()
+is accessing the queue. In the worst case this leads to a kernel panic
+due to incorrect pointer accesses.
+
+Fix this by taking the device lock before accessing the queue and
+counting the requests. Additionally the check for a valid profile data
+pointer can be done earlier to avoid unnecessary locking in a hot path.
+
+Cc: <stable@vger.kernel.org>
+Fixes: 4fa52aa7a82f ("[S390] dasd: add enhanced DASD statistics interface")
+Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
+Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
+Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
+Link: https://lore.kernel.org/r/20231025132437.1223363-3-sth@linux.ibm.com
+Signed-off-by: Jens Axboe <axboe@kernel.dk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/s390/block/dasd.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+--- a/drivers/s390/block/dasd.c
++++ b/drivers/s390/block/dasd.c
+@@ -674,18 +674,20 @@ static void dasd_profile_start(struct da
+ * we count each request only once.
+ */
+ device = cqr->startdev;
+- if (device->profile.data) {
+- counter = 1; /* request is not yet queued on the start device */
+- list_for_each(l, &device->ccw_queue)
+- if (++counter >= 31)
+- break;
+- }
++ if (!device->profile.data)
++ return;
++
++ spin_lock(get_ccwdev_lock(device->cdev));
++ counter = 1; /* request is not yet queued on the start device */
++ list_for_each(l, &device->ccw_queue)
++ if (++counter >= 31)
++ break;
++ spin_unlock(get_ccwdev_lock(device->cdev));
++
+ spin_lock(&device->profile.lock);
+- if (device->profile.data) {
+- device->profile.data->dasd_io_nr_req[counter]++;
+- if (rq_data_dir(req) == READ)
+- device->profile.data->dasd_read_nr_req[counter]++;
+- }
++ device->profile.data->dasd_io_nr_req[counter]++;
++ if (rq_data_dir(req) == READ)
++ device->profile.data->dasd_read_nr_req[counter]++;
+ spin_unlock(&device->profile.lock);
+ }
+
lockdep-fix-block-chain-corruption.patch
mm-add-a-no_inherit-flag-to-the-pr_set_mdwe-prctl.patch
prctl-disable-prctl-pr_set_mdwe-on-parisc.patch
+kselftest-arm64-fix-output-formatting-for-za-fork.patch
+drm-msm-dpu-add-missing-safe_lut_tbl-in-sc8280xp-catalog.patch
+drm-ast-disconnect-bmc-if-physical-connector-is-connected.patch
+thunderbolt-set-lane-bonding-bit-only-for-downstream-port.patch
+acpi-video-use-acpi_device_fix_up_power_children.patch
+acpi-processor_idle-use-raw_safe_halt-in-acpi_idle_play_dead.patch
+acpi-resource-skip-irq-override-on-asus-expertbook-b1402cva.patch
+acpi-pm-add-acpi_device_fix_up_power_children-function.patch
+swiotlb-xen-provide-the-max_mapping_size-method.patch
+tls-fix-null-deref-on-tls_sw_splice_eof-with-empty-record.patch
+io_uring-fix-off-by-one-bvec-index.patch
+bcache-replace-a-mistaken-is_err-by-is_err_or_null-in-btree_gc_coalesce.patch
+md-fix-bi_status-reporting-in-md_end_clone_io.patch
+bcache-fixup-multi-threaded-bch_sectors_dirty_init-wake-up-race.patch
+io_uring-fs-consider-link-flags-when-getting-path-for-linkat.patch
+s390-dasd-protect-device-queue-against-concurrent-access.patch
+platform-x86-hp-bioscfg-simplify-return-check-in-hp_add_other_attributes.patch
+platform-x86-hp-bioscfg-move-mutex_lock-down-in-hp_add_other_attributes.patch
+platform-x86-hp-bioscfg-fix-error-handling-in-hp_add_other_attributes.patch
+dt-bindings-usb-microchip-usb5744-add-second-supply.patch
+usb-misc-onboard-hub-add-support-for-microchip-usb5744.patch
+usb-serial-option-add-luat-air72-u-series-products.patch
+platform-x86-amd-pmc-adjust-getting-dram-size-behavior.patch
+platform-x86-ideapad-laptop-set-max_brightness-before-using-it.patch
+hv_netvsc-fix-race-of-netvsc-and-vf-register_netdevice.patch
+hv_netvsc-fix-race-of-register_netdevice_notifier-and-vf-register.patch
+hv_netvsc-mark-vf-as-slave-before-exposing-it-to-user-mode.patch
+revert-usb-phy-add-usb-phy-notify-port-status-api.patch
+revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-3.0-phy.patch
+revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-2.0-phy.patch
cifs-distribute-channels-across-interfaces-based-on-.patch
cifs-account-for-primary-channel-in-the-interface-li.patch
cifs-fix-leak-of-iface-for-primary-channel.patch
--- /dev/null
+From bff2a2d453a1b683378b4508b86b84389f551a00 Mon Sep 17 00:00:00 2001
+From: Keith Busch <kbusch@kernel.org>
+Date: Mon, 6 Nov 2023 18:12:30 +0100
+Subject: swiotlb-xen: provide the "max_mapping_size" method
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+From: Keith Busch <kbusch@kernel.org>
+
+commit bff2a2d453a1b683378b4508b86b84389f551a00 upstream.
+
+There's a bug that when using the XEN hypervisor with bios with large
+multi-page bio vectors on NVMe, the kernel deadlocks [1].
+
+The deadlocks are caused by inability to map a large bio vector -
+dma_map_sgtable always returns an error, this gets propagated to the block
+layer as BLK_STS_RESOURCE and the block layer retries the request
+indefinitely.
+
+XEN uses the swiotlb framework to map discontiguous pages into contiguous
+runs that are submitted to the PCIe device. The swiotlb framework has a
+limitation on the length of a mapping - this needs to be announced with
+the max_mapping_size method to make sure that the hardware drivers do not
+create larger mappings.
+
+Without max_mapping_size, the NVMe block driver would create large
+mappings that overrun the maximum mapping size.
+
+Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
+Link: https://lore.kernel.org/stable/ZTNH0qtmint%2FzLJZ@mail-itl/ [1]
+Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
+Suggested-by: Christoph Hellwig <hch@lst.de>
+Cc: stable@vger.kernel.org
+Signed-off-by: Keith Busch <kbusch@kernel.org>
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Acked-by: Stefano Stabellini <sstabellini@kernel.org>
+Reviewed-by: Christoph Hellwig <hch@lst.de>
+Link: https://lore.kernel.org/r/151bef41-e817-aea9-675-a35fdac4ed@redhat.com
+Signed-off-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/xen/swiotlb-xen.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/xen/swiotlb-xen.c
++++ b/drivers/xen/swiotlb-xen.c
+@@ -405,4 +405,5 @@ const struct dma_map_ops xen_swiotlb_dma
+ .get_sgtable = dma_common_get_sgtable,
+ .alloc_pages = dma_common_alloc_pages,
+ .free_pages = dma_common_free_pages,
++ .max_mapping_size = swiotlb_max_mapping_size,
+ };
--- /dev/null
+From 24d85bb3be373b5831699bddf698b392bd2b904d Mon Sep 17 00:00:00 2001
+From: Gil Fine <gil.fine@linux.intel.com>
+Date: Tue, 7 Nov 2023 12:22:40 +0200
+Subject: thunderbolt: Set lane bonding bit only for downstream port
+
+From: Gil Fine <gil.fine@linux.intel.com>
+
+commit 24d85bb3be373b5831699bddf698b392bd2b904d upstream.
+
+Fix the lane bonding procedure to follow the steps described in USB4
+Connection Manager guide. Hence, set the lane bonding bit only for
+downstream port. This is needed for certain ASMedia device, otherwise
+lane bonding fails and the device disconnects.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Gil Fine <gil.fine@linux.intel.com>
+Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/thunderbolt/switch.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/thunderbolt/switch.c
++++ b/drivers/thunderbolt/switch.c
+@@ -1082,7 +1082,7 @@ int tb_port_lane_bonding_enable(struct t
+ * Only set bonding if the link was not already bonded. This
+ * avoids the lane adapter to re-enter bonding state.
+ */
+- if (width == TB_LINK_WIDTH_SINGLE) {
++ if (width == TB_LINK_WIDTH_SINGLE && !tb_is_upstream_port(port)) {
+ ret = tb_port_set_lane_bonding(port, true);
+ if (ret)
+ goto err_lane1;
--- /dev/null
+From 53f2cb491b500897a619ff6abd72f565933760f0 Mon Sep 17 00:00:00 2001
+From: Jann Horn <jannh@google.com>
+Date: Wed, 22 Nov 2023 22:44:47 +0100
+Subject: tls: fix NULL deref on tls_sw_splice_eof() with empty record
+
+From: Jann Horn <jannh@google.com>
+
+commit 53f2cb491b500897a619ff6abd72f565933760f0 upstream.
+
+syzkaller discovered that if tls_sw_splice_eof() is executed as part of
+sendfile() when the plaintext/ciphertext sk_msg are empty, the send path
+gets confused because the empty ciphertext buffer does not have enough
+space for the encryption overhead. This causes tls_push_record() to go on
+the `split = true` path (which is only supposed to be used when interacting
+with an attached BPF program), and then get further confused and hit the
+tls_merge_open_record() path, which then assumes that there must be at
+least one populated buffer element, leading to a NULL deref.
+
+It is possible to have empty plaintext/ciphertext buffers if we previously
+bailed from tls_sw_sendmsg_locked() via the tls_trim_both_msgs() path.
+tls_sw_push_pending_record() already handles this case correctly; let's do
+the same check in tls_sw_splice_eof().
+
+Fixes: df720d288dbb ("tls/sw: Use splice_eof() to flush")
+Cc: stable@vger.kernel.org
+Reported-by: syzbot+40d43509a099ea756317@syzkaller.appspotmail.com
+Signed-off-by: Jann Horn <jannh@google.com>
+Link: https://lore.kernel.org/r/20231122214447.675768-1-jannh@google.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/tls/tls_sw.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
+index a78e8e722409..316f76187962 100644
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -1232,11 +1232,14 @@ void tls_sw_splice_eof(struct socket *sock)
+ lock_sock(sk);
+
+ retry:
++ /* same checks as in tls_sw_push_pending_record() */
+ rec = ctx->open_rec;
+ if (!rec)
+ goto unlock;
+
+ msg_pl = &rec->msg_plaintext;
++ if (msg_pl->sg.size == 0)
++ goto unlock;
+
+ /* Check the BPF advisor and perform transmission. */
+ ret = bpf_exec_tx_verdict(msg_pl, sk, false, TLS_RECORD_TYPE_DATA,
+--
+2.43.0
+
--- /dev/null
+From 6972b38ca05235f6142715db7062ecc87a422e22 Mon Sep 17 00:00:00 2001
+From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
+Date: Mon, 13 Nov 2023 15:59:21 +0100
+Subject: usb: misc: onboard-hub: add support for Microchip USB5744
+
+From: Stefan Eichenberger <stefan.eichenberger@toradex.com>
+
+commit 6972b38ca05235f6142715db7062ecc87a422e22 upstream.
+
+Add support for the Microchip USB5744 USB3.0 and USB2.0 Hub.
+
+The Microchip USB5744 supports two power supplies, one for 1V2 and one
+for 3V3. According to the datasheet there is no need for a delay between
+power on and reset, so this value is set to 0.
+
+Signed-off-by: Stefan Eichenberger <stefan.eichenberger@toradex.com>
+Signed-off-by: Francesco Dolcini <francesco.dolcini@toradex.com>
+Cc: stable <stable@kernel.org>
+Acked-by: Matthias Kaehlcke <mka@chromium.org>
+Link: https://lore.kernel.org/r/20231113145921.30104-3-francesco@dolcini.it
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/misc/onboard_usb_hub.c | 2 ++
+ drivers/usb/misc/onboard_usb_hub.h | 7 +++++++
+ 2 files changed, 9 insertions(+)
+
+--- a/drivers/usb/misc/onboard_usb_hub.c
++++ b/drivers/usb/misc/onboard_usb_hub.c
+@@ -437,6 +437,8 @@ static const struct usb_device_id onboar
+ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2412) }, /* USB2412 USB 2.0 */
+ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2514) }, /* USB2514B USB 2.0 */
+ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2517) }, /* USB2517 USB 2.0 */
++ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x2744) }, /* USB5744 USB 2.0 */
++ { USB_DEVICE(VENDOR_ID_MICROCHIP, 0x5744) }, /* USB5744 USB 3.0 */
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0411) }, /* RTS5411 USB 3.1 */
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x5411) }, /* RTS5411 USB 2.1 */
+ { USB_DEVICE(VENDOR_ID_REALTEK, 0x0414) }, /* RTS5414 USB 3.2 */
+--- a/drivers/usb/misc/onboard_usb_hub.h
++++ b/drivers/usb/misc/onboard_usb_hub.h
+@@ -16,6 +16,11 @@ static const struct onboard_hub_pdata mi
+ .num_supplies = 1,
+ };
+
++static const struct onboard_hub_pdata microchip_usb5744_data = {
++ .reset_us = 0,
++ .num_supplies = 2,
++};
++
+ static const struct onboard_hub_pdata realtek_rts5411_data = {
+ .reset_us = 0,
+ .num_supplies = 1,
+@@ -50,6 +55,8 @@ static const struct of_device_id onboard
+ { .compatible = "usb424,2412", .data = µchip_usb424_data, },
+ { .compatible = "usb424,2514", .data = µchip_usb424_data, },
+ { .compatible = "usb424,2517", .data = µchip_usb424_data, },
++ { .compatible = "usb424,2744", .data = µchip_usb5744_data, },
++ { .compatible = "usb424,5744", .data = µchip_usb5744_data, },
+ { .compatible = "usb451,8140", .data = &ti_tusb8041_data, },
+ { .compatible = "usb451,8142", .data = &ti_tusb8041_data, },
+ { .compatible = "usb4b4,6504", .data = &cypress_hx3_data, },
--- /dev/null
+From da90e45d5afc4da2de7cd3ea7943d0f1baa47cc2 Mon Sep 17 00:00:00 2001
+From: Asuna Yang <spriteovo@gmail.com>
+Date: Wed, 22 Nov 2023 22:18:03 +0800
+Subject: USB: serial: option: add Luat Air72*U series products
+
+From: Asuna Yang <spriteovo@gmail.com>
+
+commit da90e45d5afc4da2de7cd3ea7943d0f1baa47cc2 upstream.
+
+Update the USB serial option driver support for Luat Air72*U series
+products.
+
+ID 1782:4e00 Spreadtrum Communications Inc. UNISOC-8910
+
+T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 13 Spd=480 MxCh= 0
+D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1
+P: Vendor=1782 ProdID=4e00 Rev=00.00
+S: Manufacturer=UNISOC
+S: Product=UNISOC-8910
+C: #Ifs= 5 Cfg#= 1 Atr=e0 MxPwr=400mA
+I: If#= 0 Alt= 0 #EPs= 1 Cls=e0(wlcon) Sub=01 Prot=03 Driver=rndis_host
+E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=4096ms
+I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=rndis_host
+E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I: If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option
+E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I: If#= 3 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option
+E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E: Ad=84(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+I: If#= 4 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=00 Prot=00 Driver=option
+E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
+
+If#= 2: AT
+If#= 3: PPP + AT
+If#= 4: Debug
+
+Co-developed-by: Yangyu Chen <cyy@cyyself.name>
+Signed-off-by: Yangyu Chen <cyy@cyyself.name>
+Signed-off-by: Asuna Yang <SpriteOvO@gmail.com>
+Cc: stable@vger.kernel.org
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/serial/option.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -609,6 +609,8 @@ static void option_instat_callback(struc
+ #define UNISOC_VENDOR_ID 0x1782
+ /* TOZED LT70-C based on UNISOC SL8563 uses UNISOC's vendor ID */
+ #define TOZED_PRODUCT_LT70C 0x4055
++/* Luat Air72*U series based on UNISOC UIS8910 uses UNISOC's vendor ID */
++#define LUAT_PRODUCT_AIR720U 0x4e00
+
+ /* Device flags */
+
+@@ -2271,6 +2273,7 @@ static const struct usb_device_id option
+ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0xff, 0x40) },
+ { USB_DEVICE_AND_INTERFACE_INFO(SIERRA_VENDOR_ID, SIERRA_PRODUCT_EM9191, 0xff, 0, 0) },
+ { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, TOZED_PRODUCT_LT70C, 0xff, 0, 0) },
++ { USB_DEVICE_AND_INTERFACE_INFO(UNISOC_VENDOR_ID, LUAT_PRODUCT_AIR720U, 0xff, 0, 0) },
+ { } /* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE(usb, option_ids);