From: Greg Kroah-Hartman Date: Thu, 30 Nov 2023 14:37:43 +0000 (+0000) Subject: 6.6-stable patches X-Git-Tag: v5.15.141~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d2741bf5aa9c76bf88236fe31beead25a8700530;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: acpi-pm-add-acpi_device_fix_up_power_children-function.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-video-use-acpi_device_fix_up_power_children.patch bcache-fixup-multi-threaded-bch_sectors_dirty_init-wake-up-race.patch bcache-replace-a-mistaken-is_err-by-is_err_or_null-in-btree_gc_coalesce.patch drm-ast-disconnect-bmc-if-physical-connector-is-connected.patch drm-msm-dpu-add-missing-safe_lut_tbl-in-sc8280xp-catalog.patch dt-bindings-usb-microchip-usb5744-add-second-supply.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 io_uring-fix-off-by-one-bvec-index.patch io_uring-fs-consider-link-flags-when-getting-path-for-linkat.patch kselftest-arm64-fix-output-formatting-for-za-fork.patch md-fix-bi_status-reporting-in-md_end_clone_io.patch platform-x86-amd-pmc-adjust-getting-dram-size-behavior.patch platform-x86-hp-bioscfg-fix-error-handling-in-hp_add_other_attributes.patch platform-x86-hp-bioscfg-move-mutex_lock-down-in-hp_add_other_attributes.patch platform-x86-hp-bioscfg-simplify-return-check-in-hp_add_other_attributes.patch platform-x86-ideapad-laptop-set-max_brightness-before-using-it.patch revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-2.0-phy.patch revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-3.0-phy.patch revert-usb-phy-add-usb-phy-notify-port-status-api.patch s390-dasd-protect-device-queue-against-concurrent-access.patch swiotlb-xen-provide-the-max_mapping_size-method.patch thunderbolt-set-lane-bonding-bit-only-for-downstream-port.patch tls-fix-null-deref-on-tls_sw_splice_eof-with-empty-record.patch usb-misc-onboard-hub-add-support-for-microchip-usb5744.patch usb-serial-option-add-luat-air72-u-series-products.patch --- diff --git a/queue-6.6/acpi-pm-add-acpi_device_fix_up_power_children-function.patch b/queue-6.6/acpi-pm-add-acpi_device_fix_up_power_children-function.patch new file mode 100644 index 00000000000..a2e999ff819 --- /dev/null +++ b/queue-6.6/acpi-pm-add-acpi_device_fix_up_power_children-function.patch @@ -0,0 +1,54 @@ +From 37ba91a82e3b9de35f64348c62b5ec7d74e3a41c Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 12 Nov 2023 21:36:26 +0100 +Subject: ACPI: PM: Add acpi_device_fix_up_power_children() function + +From: Hans de Goede + +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 +Cc: 6.6+ # 6.6+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-6.6/acpi-processor_idle-use-raw_safe_halt-in-acpi_idle_play_dead.patch b/queue-6.6/acpi-processor_idle-use-raw_safe_halt-in-acpi_idle_play_dead.patch new file mode 100644 index 00000000000..80bb8c1b880 --- /dev/null +++ b/queue-6.6/acpi-processor_idle-use-raw_safe_halt-in-acpi_idle_play_dead.patch @@ -0,0 +1,46 @@ +From 9bb69ba4c177dccaa1f5b5cbdf80b67813328348 Mon Sep 17 00:00:00 2001 +From: David Woodhouse +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 + +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 +Acked-by: Peter Zijlstra (Intel) +Cc: 6.6+ # 6.6+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/queue-6.6/acpi-resource-skip-irq-override-on-asus-expertbook-b1402cva.patch b/queue-6.6/acpi-resource-skip-irq-override-on-asus-expertbook-b1402cva.patch new file mode 100644 index 00000000000..433ba59d14a --- /dev/null +++ b/queue-6.6/acpi-resource-skip-irq-override-on-asus-expertbook-b1402cva.patch @@ -0,0 +1,41 @@ +From bd911485294a6f0596e4592ed442438015cffc8a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 15 Nov 2023 19:02:22 +0100 +Subject: ACPI: resource: Skip IRQ override on ASUS ExpertBook B1402CVA + +From: Hans de Goede + +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 +Signed-off-by: Hans de Goede +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + 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."), diff --git a/queue-6.6/acpi-video-use-acpi_device_fix_up_power_children.patch b/queue-6.6/acpi-video-use-acpi_device_fix_up_power_children.patch new file mode 100644 index 00000000000..4997c43dae9 --- /dev/null +++ b/queue-6.6/acpi-video-use-acpi_device_fix_up_power_children.patch @@ -0,0 +1,54 @@ +From c93695494606326d7fd72b46a2a657139ccb0dec Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 12 Nov 2023 21:36:27 +0100 +Subject: ACPI: video: Use acpi_device_fix_up_power_children() + +From: Hans de Goede + +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 +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 +Tested-by: Owen T. Heisler +Signed-off-by: Hans de Goede +Cc: 6.6+ # 6.6+ +Signed-off-by: Rafael J. Wysocki +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/queue-6.6/bcache-fixup-multi-threaded-bch_sectors_dirty_init-wake-up-race.patch b/queue-6.6/bcache-fixup-multi-threaded-bch_sectors_dirty_init-wake-up-race.patch new file mode 100644 index 00000000000..f836691f1ea --- /dev/null +++ b/queue-6.6/bcache-fixup-multi-threaded-bch_sectors_dirty_init-wake-up-race.patch @@ -0,0 +1,124 @@ +From 2faac25d7958c4761bb8cec54adb79f806783ad6 Mon Sep 17 00:00:00 2001 +From: Mingzhe Zou +Date: Mon, 20 Nov 2023 13:25:00 +0800 +Subject: bcache: fixup multi-threaded bch_sectors_dirty_init() wake-up race + +From: Mingzhe Zou + +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 +Cc: +Signed-off-by: Coly Li +Link: https://lore.kernel.org/r/20231120052503.6122-8-colyli@suse.de +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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: diff --git a/queue-6.6/bcache-replace-a-mistaken-is_err-by-is_err_or_null-in-btree_gc_coalesce.patch b/queue-6.6/bcache-replace-a-mistaken-is_err-by-is_err_or_null-in-btree_gc_coalesce.patch new file mode 100644 index 00000000000..c332c1d1e84 --- /dev/null +++ b/queue-6.6/bcache-replace-a-mistaken-is_err-by-is_err_or_null-in-btree_gc_coalesce.patch @@ -0,0 +1,52 @@ +From f72f4312d4388376fc8a1f6cf37cb21a0d41758b Mon Sep 17 00:00:00 2001 +From: Coly Li +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 + +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: # 6.5+ +Cc: Zheng Wang +Signed-off-by: Coly Li +Link: https://lore.kernel.org/r/20231120052503.6122-9-colyli@suse.de +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-6.6/drm-ast-disconnect-bmc-if-physical-connector-is-connected.patch b/queue-6.6/drm-ast-disconnect-bmc-if-physical-connector-is-connected.patch new file mode 100644 index 00000000000..97270d0a438 --- /dev/null +++ b/queue-6.6/drm-ast-disconnect-bmc-if-physical-connector-is-connected.patch @@ -0,0 +1,186 @@ +From 8d6ef26501b97243ee6c16b8187c5b38cb69b77d Mon Sep 17 00:00:00 2001 +From: Thomas Zimmermann +Date: Thu, 16 Nov 2023 14:02:12 +0100 +Subject: drm/ast: Disconnect BMC if physical connector is connected + +From: Thomas Zimmermann + +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 +Fixes: e329cb53b45d ("drm/ast: Add BMC virtual connector") +Signed-off-by: Thomas Zimmermann +Cc: # v6.6+ +Reviewed-by: Jocelyn Falempe +Link: https://patchwork.freedesktop.org/patch/msgid/20231116130217.22931-1-tzimmermann@suse.de +Signed-off-by: Greg Kroah-Hartman +--- + 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; + diff --git a/queue-6.6/drm-msm-dpu-add-missing-safe_lut_tbl-in-sc8280xp-catalog.patch b/queue-6.6/drm-msm-dpu-add-missing-safe_lut_tbl-in-sc8280xp-catalog.patch new file mode 100644 index 00000000000..4e45616c952 --- /dev/null +++ b/queue-6.6/drm-msm-dpu-add-missing-safe_lut_tbl-in-sc8280xp-catalog.patch @@ -0,0 +1,45 @@ +From a33b2431d11b4df137bbcfdd5a5adfa054c2479e Mon Sep 17 00:00:00 2001 +From: Bjorn Andersson +Date: Mon, 30 Oct 2023 16:23:20 -0700 +Subject: drm/msm/dpu: Add missing safe_lut_tbl in sc8280xp catalog + +From: Bjorn Andersson + +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 +Suggested-by: Rob Clark +Signed-off-by: Bjorn Andersson +Tested-by: Johan Hovold +Tested-by: Steev Klimaszewski +Reviewed-by: Abhinav Kumar +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 diff --git a/queue-6.6/dt-bindings-usb-microchip-usb5744-add-second-supply.patch b/queue-6.6/dt-bindings-usb-microchip-usb5744-add-second-supply.patch new file mode 100644 index 00000000000..09a7feb6409 --- /dev/null +++ b/queue-6.6/dt-bindings-usb-microchip-usb5744-add-second-supply.patch @@ -0,0 +1,45 @@ +From d0c930b745cafde8e7d25d0356c648bca669556a Mon Sep 17 00:00:00 2001 +From: Stefan Eichenberger +Date: Mon, 13 Nov 2023 15:59:20 +0100 +Subject: dt-bindings: usb: microchip,usb5744: Add second supply + +From: Stefan Eichenberger + +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 +Signed-off-by: Francesco Dolcini +Acked-by: Conor Dooley +Cc: stable +Link: https://lore.kernel.org/r/20231113145921.30104-2-francesco@dolcini.it +Signed-off-by: Greg Kroah-Hartman +--- + 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: diff --git a/queue-6.6/hv_netvsc-fix-race-of-netvsc-and-vf-register_netdevice.patch b/queue-6.6/hv_netvsc-fix-race-of-netvsc-and-vf-register_netdevice.patch new file mode 100644 index 00000000000..4ff4266a5d0 --- /dev/null +++ b/queue-6.6/hv_netvsc-fix-race-of-netvsc-and-vf-register_netdevice.patch @@ -0,0 +1,84 @@ +From d30fb712e52964f2cf9a9c14cf67078394044837 Mon Sep 17 00:00:00 2001 +From: Haiyang Zhang +Date: Sun, 19 Nov 2023 08:23:41 -0800 +Subject: hv_netvsc: fix race of netvsc and VF register_netdevice + +From: Haiyang Zhang + +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 +Signed-off-by: Haiyang Zhang +Reviewed-by: Wojciech Drewek +Reviewed-by: Simon Horman +Reviewed-by: Dexuan Cui +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-6.6/hv_netvsc-fix-race-of-register_netdevice_notifier-and-vf-register.patch b/queue-6.6/hv_netvsc-fix-race-of-register_netdevice_notifier-and-vf-register.patch new file mode 100644 index 00000000000..8f881d1bef7 --- /dev/null +++ b/queue-6.6/hv_netvsc-fix-race-of-register_netdevice_notifier-and-vf-register.patch @@ -0,0 +1,49 @@ +From 85520856466ed6bc3b1ccb013cddac70ceb437db Mon Sep 17 00:00:00 2001 +From: Haiyang Zhang +Date: Sun, 19 Nov 2023 08:23:42 -0800 +Subject: hv_netvsc: Fix race of register_netdevice_notifier and VF register + +From: Haiyang Zhang + +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 +Signed-off-by: Haiyang Zhang +Reviewed-by: Wojciech Drewek +Reviewed-by: Dexuan Cui +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + 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"); diff --git a/queue-6.6/hv_netvsc-mark-vf-as-slave-before-exposing-it-to-user-mode.patch b/queue-6.6/hv_netvsc-mark-vf-as-slave-before-exposing-it-to-user-mode.patch new file mode 100644 index 00000000000..b9d3d923553 --- /dev/null +++ b/queue-6.6/hv_netvsc-mark-vf-as-slave-before-exposing-it-to-user-mode.patch @@ -0,0 +1,95 @@ +From c807d6cd089d2f4951baa838081ec5ae3e2360f8 Mon Sep 17 00:00:00 2001 +From: Long Li +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 + +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 +Signed-off-by: Haiyang Zhang +Acked-by: Stephen Hemminger +Acked-by: Dexuan Cui +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + 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: diff --git a/queue-6.6/io_uring-fix-off-by-one-bvec-index.patch b/queue-6.6/io_uring-fix-off-by-one-bvec-index.patch new file mode 100644 index 00000000000..2598b5c5c5f --- /dev/null +++ b/queue-6.6/io_uring-fix-off-by-one-bvec-index.patch @@ -0,0 +1,35 @@ +From d6fef34ee4d102be448146f24caf96d7b4a05401 Mon Sep 17 00:00:00 2001 +From: Keith Busch +Date: Mon, 20 Nov 2023 14:18:31 -0800 +Subject: io_uring: fix off-by one bvec index + +From: Keith Busch + +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 +Link: https://lore.kernel.org/r/20231120221831.2646460-1-kbusch@meta.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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 diff --git a/queue-6.6/io_uring-fs-consider-link-flags-when-getting-path-for-linkat.patch b/queue-6.6/io_uring-fs-consider-link-flags-when-getting-path-for-linkat.patch new file mode 100644 index 00000000000..2ce747e4001 --- /dev/null +++ b/queue-6.6/io_uring-fs-consider-link-flags-when-getting-path-for-linkat.patch @@ -0,0 +1,35 @@ +From 8479063f1fbee201a8739130e816cc331b675838 Mon Sep 17 00:00:00 2001 +From: Charles Mirabile +Date: Mon, 20 Nov 2023 05:55:45 -0500 +Subject: io_uring/fs: consider link->flags when getting path for LINKAT + +From: Charles Mirabile + +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: +Link: https://github.com/axboe/liburing/issues/995 +Signed-off-by: Charles Mirabile +Link: https://lore.kernel.org/r/20231120105545.1209530-1-cmirabil@redhat.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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); + diff --git a/queue-6.6/kselftest-arm64-fix-output-formatting-for-za-fork.patch b/queue-6.6/kselftest-arm64-fix-output-formatting-for-za-fork.patch new file mode 100644 index 00000000000..60b6aa1a507 --- /dev/null +++ b/queue-6.6/kselftest-arm64-fix-output-formatting-for-za-fork.patch @@ -0,0 +1,34 @@ +From 460e462d22542adfafd8a5bc979437df73f1cbf3 Mon Sep 17 00:00:00 2001 +From: Mark Brown +Date: Thu, 16 Nov 2023 12:52:29 +0000 +Subject: kselftest/arm64: Fix output formatting for za-fork + +From: Mark Brown + +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: # 6.4.x +Signed-off-by: Mark Brown +Link: https://lore.kernel.org/r/20231116-arm64-fix-za-fork-output-v1-1-42c03d4f5759@kernel.org +Signed-off-by: Catalin Marinas +Signed-off-by: Greg Kroah-Hartman +--- + 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"); diff --git a/queue-6.6/md-fix-bi_status-reporting-in-md_end_clone_io.patch b/queue-6.6/md-fix-bi_status-reporting-in-md_end_clone_io.patch new file mode 100644 index 00000000000..12206ba8b9c --- /dev/null +++ b/queue-6.6/md-fix-bi_status-reporting-in-md_end_clone_io.patch @@ -0,0 +1,44 @@ +From 45b478951b2ba5aea70b2850c49c1aa83aedd0d2 Mon Sep 17 00:00:00 2001 +From: Song Liu +Date: Fri, 17 Nov 2023 15:56:30 -0800 +Subject: md: fix bi_status reporting in md_end_clone_io + +From: Song Liu + +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 +Tested-by: Xiao Ni +Reviewed-by: Yu Kuai +Acked-by: Guoqing Jiang +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-6.6/platform-x86-amd-pmc-adjust-getting-dram-size-behavior.patch b/queue-6.6/platform-x86-amd-pmc-adjust-getting-dram-size-behavior.patch new file mode 100644 index 00000000000..84cd09f6845 --- /dev/null +++ b/queue-6.6/platform-x86-amd-pmc-adjust-getting-dram-size-behavior.patch @@ -0,0 +1,100 @@ +From c6ea14d557343cd3af6c6be2f5a78c98bdb281bb Mon Sep 17 00:00:00 2001 +From: Shyam Sundar S K +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 + +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 +Fixes: be8325fb3d8c ("platform/x86/amd: pmc: Get STB DRAM size from PMFW") +Cc: stable@vger.kernel.org +Suggested-by: Sanket Goswami +Signed-off-by: Shyam Sundar S K +Link: https://lore.kernel.org/r/20231116170121.3372222-1-Shyam-sundar.S-k@amd.com +Reviewed-by: Mario Limonciello +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + 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 */ diff --git a/queue-6.6/platform-x86-hp-bioscfg-fix-error-handling-in-hp_add_other_attributes.patch b/queue-6.6/platform-x86-hp-bioscfg-fix-error-handling-in-hp_add_other_attributes.patch new file mode 100644 index 00000000000..641a5288b84 --- /dev/null +++ b/queue-6.6/platform-x86-hp-bioscfg-fix-error-handling-in-hp_add_other_attributes.patch @@ -0,0 +1,75 @@ +From f40f939917b2b4cbf18450096c0ce1c58ed59fae Mon Sep 17 00:00:00 2001 +From: Harshit Mogalapalli +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 + +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 +Reported-by: Dan Carpenter +Closes: https://lore.kernel.org/r/202309201412.on0VXJGo-lkp@intel.com/ +Signed-off-by: Harshit Mogalapalli +[ij: Added the stable dep tags] +Reviewed-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20231113200742.3593548-3-harshit.m.mogalapalli@oracle.com +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/queue-6.6/platform-x86-hp-bioscfg-move-mutex_lock-down-in-hp_add_other_attributes.patch b/queue-6.6/platform-x86-hp-bioscfg-move-mutex_lock-down-in-hp_add_other_attributes.patch new file mode 100644 index 00000000000..9f54d5717e5 --- /dev/null +++ b/queue-6.6/platform-x86-hp-bioscfg-move-mutex_lock-down-in-hp_add_other_attributes.patch @@ -0,0 +1,48 @@ +From 5736aa9537c9b8927dec32d3d47c8c31fe560f62 Mon Sep 17 00:00:00 2001 +From: Harshit Mogalapalli +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 + +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 +Signed-off-by: Harshit Mogalapalli +Reviewed-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20231113200742.3593548-2-harshit.m.mogalapalli@oracle.com +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + 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) { diff --git a/queue-6.6/platform-x86-hp-bioscfg-simplify-return-check-in-hp_add_other_attributes.patch b/queue-6.6/platform-x86-hp-bioscfg-simplify-return-check-in-hp_add_other_attributes.patch new file mode 100644 index 00000000000..d4d7f9f842f --- /dev/null +++ b/queue-6.6/platform-x86-hp-bioscfg-simplify-return-check-in-hp_add_other_attributes.patch @@ -0,0 +1,51 @@ +From c5dbf04160005e07e8ca7232a7faa77ab1547ae0 Mon Sep 17 00:00:00 2001 +From: Harshit Mogalapalli +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 + +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 +Reviewed-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20231113200742.3593548-1-harshit.m.mogalapalli@oracle.com +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + 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; + diff --git a/queue-6.6/platform-x86-ideapad-laptop-set-max_brightness-before-using-it.patch b/queue-6.6/platform-x86-ideapad-laptop-set-max_brightness-before-using-it.patch new file mode 100644 index 00000000000..779b4d49c79 --- /dev/null +++ b/queue-6.6/platform-x86-ideapad-laptop-set-max_brightness-before-using-it.patch @@ -0,0 +1,57 @@ +From 7a3c36eef9a5d13b16aa954da54224c9c6bed339 Mon Sep 17 00:00:00 2001 +From: Stuart Hayhurst +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 + +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 +Cc: stable@vger.kernel.org +Reviewed-by: Ilpo Järvinen +Link: https://lore.kernel.org/r/20231114114055.6220-2-stuart.a.hayhurst@gmail.com +Signed-off-by: Ilpo Järvinen +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/queue-6.6/revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-2.0-phy.patch b/queue-6.6/revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-2.0-phy.patch new file mode 100644 index 00000000000..583dc881522 --- /dev/null +++ b/queue-6.6/revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-2.0-phy.patch @@ -0,0 +1,1420 @@ +From 7a784bcdd7e54f0599da3b2360e472238412623e Mon Sep 17 00:00:00 2001 +From: Johan Hovold +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 + +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 +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20231106110654.31090-3-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-/* 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 "); +-MODULE_DESCRIPTION("Realtek usb 2.0 phy driver"); diff --git a/queue-6.6/revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-3.0-phy.patch b/queue-6.6/revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-3.0-phy.patch new file mode 100644 index 00000000000..4dfbb6c2784 --- /dev/null +++ b/queue-6.6/revert-phy-realtek-usb-add-driver-for-the-realtek-soc-usb-3.0-phy.patch @@ -0,0 +1,829 @@ +From 258ea41c926b7b3a16d0d7aa210a1401c4a1601b Mon Sep 17 00:00:00 2001 +From: Johan Hovold +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 + +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 +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20231106110654.31090-2-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#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 "); +-MODULE_DESCRIPTION("Realtek usb 3.0 phy driver"); diff --git a/queue-6.6/revert-usb-phy-add-usb-phy-notify-port-status-api.patch b/queue-6.6/revert-usb-phy-add-usb-phy-notify-port-status-api.patch new file mode 100644 index 00000000000..b85b5746d75 --- /dev/null +++ b/queue-6.6/revert-usb-phy-add-usb-phy-notify-port-status-api.patch @@ -0,0 +1,105 @@ +From 1a229d8690a0f8951fc4aa8b76a7efab0d8de342 Mon Sep 17 00:00:00 2001 +From: Johan Hovold +Date: Mon, 6 Nov 2023 12:06:54 +0100 +Subject: Revert "usb: phy: add usb phy notify port status API" + +From: Johan Hovold + +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 +Signed-off-by: Johan Hovold +Link: https://lore.kernel.org/r/20231106110654.31090-4-johan+linaro@kernel.org +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/queue-6.6/s390-dasd-protect-device-queue-against-concurrent-access.patch b/queue-6.6/s390-dasd-protect-device-queue-against-concurrent-access.patch new file mode 100644 index 00000000000..a3ee2270539 --- /dev/null +++ b/queue-6.6/s390-dasd-protect-device-queue-against-concurrent-access.patch @@ -0,0 +1,69 @@ +From db46cd1e0426f52999d50fa72cfa97fa39952885 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jan=20H=C3=B6ppner?= +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 + +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: +Fixes: 4fa52aa7a82f ("[S390] dasd: add enhanced DASD statistics interface") +Reviewed-by: Stefan Haberland +Signed-off-by: Jan Höppner +Signed-off-by: Stefan Haberland +Link: https://lore.kernel.org/r/20231025132437.1223363-3-sth@linux.ibm.com +Signed-off-by: Jens Axboe +Signed-off-by: Greg Kroah-Hartman +--- + 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); + } + diff --git a/queue-6.6/series b/queue-6.6/series index 3c78523897a..b266b57c8c6 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -56,6 +56,36 @@ usb-dwc3-qcom-fix-acpi-platform-device-leak.patch 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 diff --git a/queue-6.6/swiotlb-xen-provide-the-max_mapping_size-method.patch b/queue-6.6/swiotlb-xen-provide-the-max_mapping_size-method.patch new file mode 100644 index 00000000000..3a57f90136b --- /dev/null +++ b/queue-6.6/swiotlb-xen-provide-the-max_mapping_size-method.patch @@ -0,0 +1,53 @@ +From bff2a2d453a1b683378b4508b86b84389f551a00 Mon Sep 17 00:00:00 2001 +From: Keith Busch +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 + +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 +Link: https://lore.kernel.org/stable/ZTNH0qtmint%2FzLJZ@mail-itl/ [1] +Tested-by: Marek Marczykowski-Górecki +Suggested-by: Christoph Hellwig +Cc: stable@vger.kernel.org +Signed-off-by: Keith Busch +Signed-off-by: Mikulas Patocka +Acked-by: Stefano Stabellini +Reviewed-by: Christoph Hellwig +Link: https://lore.kernel.org/r/151bef41-e817-aea9-675-a35fdac4ed@redhat.com +Signed-off-by: Juergen Gross +Signed-off-by: Greg Kroah-Hartman +--- + 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, + }; diff --git a/queue-6.6/thunderbolt-set-lane-bonding-bit-only-for-downstream-port.patch b/queue-6.6/thunderbolt-set-lane-bonding-bit-only-for-downstream-port.patch new file mode 100644 index 00000000000..6be772056a2 --- /dev/null +++ b/queue-6.6/thunderbolt-set-lane-bonding-bit-only-for-downstream-port.patch @@ -0,0 +1,33 @@ +From 24d85bb3be373b5831699bddf698b392bd2b904d Mon Sep 17 00:00:00 2001 +From: Gil Fine +Date: Tue, 7 Nov 2023 12:22:40 +0200 +Subject: thunderbolt: Set lane bonding bit only for downstream port + +From: Gil Fine + +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 +Signed-off-by: Mika Westerberg +Signed-off-by: Greg Kroah-Hartman +--- + 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; diff --git a/queue-6.6/tls-fix-null-deref-on-tls_sw_splice_eof-with-empty-record.patch b/queue-6.6/tls-fix-null-deref-on-tls_sw_splice_eof-with-empty-record.patch new file mode 100644 index 00000000000..585b57c56b0 --- /dev/null +++ b/queue-6.6/tls-fix-null-deref-on-tls_sw_splice_eof-with-empty-record.patch @@ -0,0 +1,56 @@ +From 53f2cb491b500897a619ff6abd72f565933760f0 Mon Sep 17 00:00:00 2001 +From: Jann Horn +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 + +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 +Link: https://lore.kernel.org/r/20231122214447.675768-1-jannh@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Greg Kroah-Hartman +--- + 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 + diff --git a/queue-6.6/usb-misc-onboard-hub-add-support-for-microchip-usb5744.patch b/queue-6.6/usb-misc-onboard-hub-add-support-for-microchip-usb5744.patch new file mode 100644 index 00000000000..a0c6f044ca2 --- /dev/null +++ b/queue-6.6/usb-misc-onboard-hub-add-support-for-microchip-usb5744.patch @@ -0,0 +1,60 @@ +From 6972b38ca05235f6142715db7062ecc87a422e22 Mon Sep 17 00:00:00 2001 +From: Stefan Eichenberger +Date: Mon, 13 Nov 2023 15:59:21 +0100 +Subject: usb: misc: onboard-hub: add support for Microchip USB5744 + +From: Stefan Eichenberger + +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 +Signed-off-by: Francesco Dolcini +Cc: stable +Acked-by: Matthias Kaehlcke +Link: https://lore.kernel.org/r/20231113145921.30104-3-francesco@dolcini.it +Signed-off-by: Greg Kroah-Hartman +--- + 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, }, diff --git a/queue-6.6/usb-serial-option-add-luat-air72-u-series-products.patch b/queue-6.6/usb-serial-option-add-luat-air72-u-series-products.patch new file mode 100644 index 00000000000..ca56d1ec0d9 --- /dev/null +++ b/queue-6.6/usb-serial-option-add-luat-air72-u-series-products.patch @@ -0,0 +1,68 @@ +From da90e45d5afc4da2de7cd3ea7943d0f1baa47cc2 Mon Sep 17 00:00:00 2001 +From: Asuna Yang +Date: Wed, 22 Nov 2023 22:18:03 +0800 +Subject: USB: serial: option: add Luat Air72*U series products + +From: Asuna Yang + +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 +Signed-off-by: Yangyu Chen +Signed-off-by: Asuna Yang +Cc: stable@vger.kernel.org +Signed-off-by: Johan Hovold +Signed-off-by: Greg Kroah-Hartman +--- + 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);