Linux USB
 help / color / mirror / Atom feed
* [Bug 221318] mice behind ASMedia ASM1042A via Thunderbolt 2 never produce input, most likely due to interrupt pipe idle window during enumeration
From: bugzilla-daemon @ 2026-04-07 13:18 UTC (permalink / raw)
  To: linux-usb
In-Reply-To: <bug-221318-208809@https.bugzilla.kernel.org/>

https://bugzilla.kernel.org/show_bug.cgi?id=221318

--- Comment #20 from manauer.uel@gmail.com ---
> The "spurious event" noise is likely from SuperSpeed device 4-1.1.2 whose
> Bulk IN URBs may trigger it even on properly working hardware.
Good to know. I looked up 4-1.1.2, it turned out to be the Ethernet adapter
from the USB dongle.

> I see nothing obviously wrong here, it looks like some weird HW problem.
The sequence looks correct on paper, the cancellation goes through cleanly and
the endpoint is left in running state with the dequeue pointer advanced past
the old URB. Yet no new transfer ever arrives.

> BTW, I see that the endpoint of interest has 1ms interval too, longer
> interval is on the second endpoint of this mouse.
Yes, that matches the lsusb output.

> If you would like to play with intervals, see drivers/usb/host/xhci-mem.c
> function xhci_parse_frame_interval(). Replace ep->desc.bInterval with any
> number like 1 or 10, units are milliseconds.
I built and tested two patched kernels.

Forcing 10ms: the mouse works without any workaround at all.
Forcing 1ms: the mouse does not work. The udev workaround still fixes it.

So the interval does matter. With 10ms the problem does not occur in the first
place, with 1ms it behaves the same as on the stock kernel.

One thing that does not fit this pattern: the Logitech Lightspeed Receiver
(046d:c539) has 3 interfaces all polling at 1ms, yet it works on its own
without any workaround. It also makes wired mice work alongside it on the stock
kernel.

I looked into this a bit. The receiver is not handled by usbhid but by the
logitech-djreceiver driver (hid-logitech-dj). That driver has its own
hid_ll_driver with open and close callbacks that are essentially empty. When
udev opens and closes the hidraw device, nothing happens at the USB level, so
no URB is cancelled. This might be why the ASM1042A never gets into the broken
state.

-- 
You may reply to this email to add a comment.

You are receiving this mail because:
You are watching the assignee of the bug.

^ permalink raw reply

* [PATCH] usb: ulpi: fix memory leak on ulpi_register() error paths
From: Felix Gu @ 2026-04-07 13:21 UTC (permalink / raw)
  To: Heikki Krogerus, Greg Kroah-Hartman, Guangshuo Li
  Cc: linux-usb, linux-kernel, Felix Gu

Commit 01af542392b5 ("usb: ulpi: fix double free in
ulpi_register_interface() error path") removed kfree(ulpi) from
ulpi_register_interface() to fix a double-free when device_register()
fails.

But when ulpi_of_register() or ulpi_read_id() fail before
device_register() is called, the ulpi allocation is leaked.

Add kfree(ulpi) on both error paths to properly clean up the allocation.

Fixes: 01af542392b5 ("usb: ulpi: fix double free in ulpi_register_interface() error path")
Signed-off-by: Felix Gu <ustc.gu@gmail.com>
---
 drivers/usb/common/ulpi.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c
index b34fb65813c4..9b69148128e5 100644
--- a/drivers/usb/common/ulpi.c
+++ b/drivers/usb/common/ulpi.c
@@ -286,12 +286,15 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
 	ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
 
 	ret = ulpi_of_register(ulpi);
-	if (ret)
+	if (ret) {
+		kfree(ulpi);
 		return ret;
+	}
 
 	ret = ulpi_read_id(ulpi);
 	if (ret) {
 		of_node_put(ulpi->dev.of_node);
+		kfree(ulpi);
 		return ret;
 	}
 

---
base-commit: 816f193dd0d95246f208590924dd962b192def78
change-id: 20260407-ulpi-25d4859c0954

Best regards,
-- 
Felix Gu <ustc.gu@gmail.com>


^ permalink raw reply related

* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
From: Alan Stern @ 2026-04-07 15:23 UTC (permalink / raw)
  To: Thinh Nguyen
  Cc: Mathias Nyman, linux-usb@vger.kernel.org, michal.pecio@gmail.com,
	oneukum@suse.com, niklas.neronin@linux.intel.com
In-Reply-To: <20260405030954.32jbg3fphi5xdla3@synopsys.com>

It's been a while now, and nobody has objected to the proposed plan for 
handling this issue, so I'm going to assume that everyone is on board 
with the idea.

There is a loose end still to be straightened out.  It concerns handling 
of -EREMOTEIO errors (short packet received with URB_SHORT_NOT_OK set).  
While some HCDs -- especially those supporting SG -- may not stop the 
endpoint queue when this error occurs, other HCDs will do so.  The 
question is how the core should tell them to start it up again.  This 
shouldn't happen until after the completion handler returns.

Short packets don't cause any loss of synchronization between the 
endpoint state on the host and on the device, so -EREMOTEIO doesn't 
require usb_clear_halt() or usb_reset_endpoint() for recovery.  This 
means we need to find some other way to tell the HCD when the queue can 
restart.  Should we create a new hc_driver callback specifically for 
this purpose?

Related question: Although URB_SHORT_NOT_OK is allowed for all types of 
IN URB other than isochronous, does its queue-stopping property make 
sense for control or interrupt URBs?  As far as I know, no kernel code 
uses it for them, although some userspace code might (via usbfs).

Alan Stern

^ permalink raw reply

* Re: [PATCH v4 2/5] dt-bindings: usb: generic-ohci: add AT91RM9200 OHCI binding support
From: Rob Herring (Arm) @ 2026-04-07 19:08 UTC (permalink / raw)
  To: Charan Pedumuru
  Cc: linux-arm-kernel, Conor Dooley, linux-usb, Claudiu Beznea,
	Herve Codina, Krzysztof Kozlowski, Greg Kroah-Hartman,
	linux-kernel, Alexandre Belloni, Nicolas Ferre, devicetree
In-Reply-To: <20260327-atmel-usb-v4-2-eb8b6e49b29d@gmail.com>


On Fri, 27 Mar 2026 16:47:43 +0000, Charan Pedumuru wrote:
> Convert the Atmel AT91RM9200 OHCI USB host controller binding to DT schema
> by defining it in the existing generic OHCI schema.
> 
> Signed-off-by: Charan Pedumuru <charan.pedumuru@gmail.com>
> ---
>  .../devicetree/bindings/usb/atmel-usb.txt          | 27 --------------
>  .../devicetree/bindings/usb/generic-ohci.yaml      | 41 ++++++++++++++++++++++
>  2 files changed, 41 insertions(+), 27 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply

* Re: [PATCH v4 5/5] dt-bindings: usb: atmel,at91sam9rl-udc: convert to DT schema
From: Rob Herring (Arm) @ 2026-04-07 19:11 UTC (permalink / raw)
  To: Charan Pedumuru
  Cc: Greg Kroah-Hartman, Conor Dooley, Krzysztof Kozlowski,
	linux-arm-kernel, Claudiu Beznea, Nicolas Ferre, Herve Codina,
	devicetree, linux-kernel, linux-usb, Alexandre Belloni
In-Reply-To: <20260327-atmel-usb-v4-5-eb8b6e49b29d@gmail.com>


On Fri, 27 Mar 2026 16:47:46 +0000, Charan Pedumuru wrote:
> Convert Atmel High-Speed USB Device Controller (USBA) binding to DT schema.
> Changes during conversion:
> - Make the "clock-names" property flexible enough to accept the items
>   in any order as the existing in tree DTS nodes doesn't follow an order.
> 
> Signed-off-by: Charan Pedumuru <charan.pedumuru@gmail.com>
> ---
>  .../bindings/usb/atmel,at91sam9rl-udc.yaml         | 74 ++++++++++++++++++++++
>  .../devicetree/bindings/usb/atmel-usb.txt          | 46 --------------
>  2 files changed, 74 insertions(+), 46 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh@kernel.org>


^ permalink raw reply

* [PATCH] USB: serial: iuu_phoenix: fix iuutool author name
From: Thorsten Blum @ 2026-04-07 19:23 UTC (permalink / raw)
  To: Johan Hovold, Greg Kroah-Hartman; +Cc: Thorsten Blum, linux-usb, linux-kernel

The original iuutool author is Juan Carlos Borrás - fix the spelling.

Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
---
https://github.com/jcborras/iuutool/blob/master/AUTHORS
---
 drivers/usb/serial/iuu_phoenix.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 1b2418dc7a77..e9c712df755f 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -6,7 +6,7 @@
 
  * Copyright (C) 2007 Alain Degreffe (eczema@ecze.com)
  *
- * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
+ * Original code taken from iuutool (Copyright (C) 2006 Juan Carlos Borrás)
  *
  *  And tested with help of WB Electronics
  */

^ permalink raw reply related

* [westeri-thunderbolt:next] BUILD SUCCESS 498c05821bb42f70e9bf6512c3dec4aa821815d0
From: kernel test robot @ 2026-04-07 19:23 UTC (permalink / raw)
  To: Mika Westerberg; +Cc: linux-usb

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git next
branch HEAD: 498c05821bb42f70e9bf6512c3dec4aa821815d0  thunderbolt: tunnel: Simplify allocation

elapsed time: 731m

configs tested: 202
configs skipped: 8

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    clang-16
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    clang-23
arc                                 defconfig    gcc-15.2.0
arc                   randconfig-001-20260407    clang-23
arc                   randconfig-002-20260407    clang-23
arm                               allnoconfig    gcc-15.2.0
arm                              allyesconfig    clang-16
arm                                 defconfig    gcc-15.2.0
arm                   randconfig-001-20260407    clang-23
arm                   randconfig-002-20260407    clang-23
arm                   randconfig-003-20260407    clang-23
arm                   randconfig-004-20260407    clang-23
arm                           sama5_defconfig    gcc-15.2.0
arm64                            allmodconfig    clang-23
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                 randconfig-001-20260407    gcc-9.5.0
arm64                 randconfig-002-20260407    gcc-13.4.0
arm64                 randconfig-002-20260407    gcc-9.5.0
arm64                 randconfig-003-20260407    gcc-8.5.0
arm64                 randconfig-003-20260407    gcc-9.5.0
arm64                 randconfig-004-20260407    clang-23
arm64                 randconfig-004-20260407    gcc-9.5.0
csky                             allmodconfig    gcc-15.2.0
csky                              allnoconfig    gcc-15.2.0
csky                                defconfig    gcc-15.2.0
csky                  randconfig-001-20260407    gcc-13.4.0
csky                  randconfig-001-20260407    gcc-9.5.0
csky                  randconfig-002-20260407    gcc-9.5.0
hexagon                          allmodconfig    gcc-15.2.0
hexagon                           allnoconfig    gcc-15.2.0
hexagon                             defconfig    gcc-15.2.0
hexagon               randconfig-001-20260407    clang-23
hexagon               randconfig-002-20260407    clang-23
i386                             allmodconfig    clang-20
i386                              allnoconfig    gcc-15.2.0
i386                             allyesconfig    clang-20
i386        buildonly-randconfig-001-20260407    clang-20
i386        buildonly-randconfig-002-20260407    clang-20
i386        buildonly-randconfig-003-20260407    clang-20
i386        buildonly-randconfig-004-20260407    clang-20
i386        buildonly-randconfig-005-20260407    clang-20
i386        buildonly-randconfig-006-20260407    clang-20
i386                                defconfig    gcc-15.2.0
i386                  randconfig-001-20260407    clang-20
i386                  randconfig-001-20260407    gcc-14
i386                  randconfig-002-20260407    gcc-14
i386                  randconfig-003-20260407    clang-20
i386                  randconfig-003-20260407    gcc-14
i386                  randconfig-004-20260407    gcc-14
i386                  randconfig-005-20260407    clang-20
i386                  randconfig-005-20260407    gcc-14
i386                  randconfig-006-20260407    gcc-14
i386                  randconfig-007-20260407    gcc-14
i386                  randconfig-011-20260407    clang-20
i386                  randconfig-011-20260407    gcc-14
i386                  randconfig-012-20260407    clang-20
i386                  randconfig-013-20260407    clang-20
i386                  randconfig-014-20260407    clang-20
i386                  randconfig-015-20260407    clang-20
i386                  randconfig-015-20260407    gcc-14
i386                  randconfig-016-20260407    clang-20
i386                  randconfig-017-20260407    clang-20
i386                  randconfig-017-20260407    gcc-14
loongarch                        allmodconfig    clang-23
loongarch                         allnoconfig    gcc-15.2.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20260407    clang-23
loongarch             randconfig-002-20260407    clang-23
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    clang-16
m68k                                defconfig    clang-19
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    clang-19
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    clang-23
nios2                             allnoconfig    clang-23
nios2                               defconfig    clang-19
nios2                 randconfig-001-20260407    clang-23
nios2                 randconfig-002-20260407    clang-23
openrisc                         allmodconfig    clang-23
openrisc                          allnoconfig    clang-23
openrisc                   de0_nano_defconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    clang-23
parisc                           allyesconfig    clang-19
parisc                              defconfig    gcc-15.2.0
parisc                randconfig-001-20260407    gcc-10.5.0
parisc                randconfig-001-20260407    gcc-8.5.0
parisc                randconfig-002-20260407    gcc-10.5.0
parisc                randconfig-002-20260407    gcc-8.5.0
parisc64                            defconfig    clang-19
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    clang-23
powerpc                      chrp32_defconfig    clang-19
powerpc                     mpc512x_defconfig    clang-23
powerpc               randconfig-001-20260407    gcc-10.5.0
powerpc               randconfig-001-20260407    gcc-13.4.0
powerpc               randconfig-002-20260407    gcc-10.5.0
powerpc               randconfig-002-20260407    gcc-8.5.0
powerpc64             randconfig-001-20260407    gcc-10.5.0
powerpc64             randconfig-001-20260407    gcc-12.5.0
powerpc64             randconfig-002-20260407    gcc-10.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    clang-23
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.2.0
riscv                 randconfig-001-20260407    clang-23
riscv                 randconfig-001-20260407    gcc-14.3.0
riscv                 randconfig-002-20260407    gcc-12.5.0
riscv                 randconfig-002-20260407    gcc-14.3.0
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    gcc-15.2.0
s390                  randconfig-001-20260407    gcc-14.3.0
s390                  randconfig-002-20260407    clang-20
s390                  randconfig-002-20260407    gcc-14.3.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    clang-23
sh                               allyesconfig    clang-19
sh                                  defconfig    gcc-14
sh                    randconfig-001-20260407    gcc-13.4.0
sh                    randconfig-001-20260407    gcc-14.3.0
sh                    randconfig-002-20260407    gcc-14.3.0
sh                    randconfig-002-20260407    gcc-15.2.0
sparc                             allnoconfig    clang-23
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260407    gcc-12
sparc                 randconfig-001-20260407    gcc-15.2.0
sparc                 randconfig-002-20260407    gcc-12
sparc                 randconfig-002-20260407    gcc-15.2.0
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20260407    clang-23
sparc64               randconfig-001-20260407    gcc-12
sparc64               randconfig-002-20260407    clang-20
sparc64               randconfig-002-20260407    gcc-12
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-15.2.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260407    gcc-12
um                    randconfig-002-20260407    gcc-12
um                    randconfig-002-20260407    gcc-14
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-23
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260407    gcc-14
x86_64      buildonly-randconfig-002-20260407    gcc-14
x86_64      buildonly-randconfig-003-20260407    gcc-14
x86_64      buildonly-randconfig-004-20260407    clang-20
x86_64      buildonly-randconfig-004-20260407    gcc-14
x86_64      buildonly-randconfig-005-20260407    gcc-14
x86_64      buildonly-randconfig-006-20260407    gcc-14
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20260407    gcc-14
x86_64                randconfig-002-20260407    gcc-14
x86_64                randconfig-003-20260407    gcc-14
x86_64                randconfig-004-20260407    gcc-14
x86_64                randconfig-005-20260407    gcc-14
x86_64                randconfig-006-20260407    gcc-14
x86_64                randconfig-011-20260407    clang-20
x86_64                randconfig-011-20260407    gcc-14
x86_64                randconfig-012-20260407    clang-20
x86_64                randconfig-013-20260407    clang-20
x86_64                randconfig-014-20260407    clang-20
x86_64                randconfig-015-20260407    clang-20
x86_64                randconfig-015-20260407    gcc-14
x86_64                randconfig-016-20260407    clang-20
x86_64                randconfig-016-20260407    gcc-14
x86_64                randconfig-071-20260407    clang-20
x86_64                randconfig-072-20260407    clang-20
x86_64                randconfig-073-20260407    clang-20
x86_64                randconfig-074-20260407    clang-20
x86_64                randconfig-075-20260407    clang-20
x86_64                randconfig-076-20260407    clang-20
x86_64                               rhel-9.4    clang-20
x86_64                           rhel-9.4-bpf    gcc-14
x86_64                          rhel-9.4-func    clang-20
x86_64                    rhel-9.4-kselftests    clang-20
x86_64                         rhel-9.4-kunit    gcc-14
x86_64                           rhel-9.4-ltp    gcc-14
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    clang-23
xtensa                           allyesconfig    clang-23
xtensa                randconfig-001-20260407    gcc-12
xtensa                randconfig-001-20260407    gcc-12.5.0
xtensa                randconfig-002-20260407    gcc-12
xtensa                randconfig-002-20260407    gcc-8.5.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [RFC PATCH 1/2] xhci: prevent automatic endpoint restart after stall or error
From: Mathias Nyman @ 2026-04-07 20:24 UTC (permalink / raw)
  To: Alan Stern, Thinh Nguyen
  Cc: linux-usb@vger.kernel.org, michal.pecio@gmail.com,
	oneukum@suse.com, niklas.neronin@linux.intel.com
In-Reply-To: <74ac9ea2-34d1-4999-9048-c03a0f978b5d@rowland.harvard.edu>

On 4/7/26 18:23, Alan Stern wrote:
> It's been a while now, and nobody has objected to the proposed plan for
> handling this issue, so I'm going to assume that everyone is on board
> with the idea.

Yes, I support this

So basically usb core will call usb_clear_halt() after EPROTO URB completion
handler finishes, and xhci-hcd needs to prevent bulk/interrupt endpoint
from restarting after returning a EPROTO URB up until usb_reset_endpoint()
is called

I also support adding usb_purge_endpoint_queue(), but it doesn't have to
be done at the same time as the EPROTO changes.

> 
> There is a loose end still to be straightened out.  It concerns handling
> of -EREMOTEIO errors (short packet received with URB_SHORT_NOT_OK set).
> While some HCDs -- especially those supporting SG -- may not stop the
> endpoint queue when this error occurs, other HCDs will do so.  The
> question is how the core should tell them to start it up again.  This
> shouldn't happen until after the completion handler returns.
> 
> Short packets don't cause any loss of synchronization between the
> endpoint state on the host and on the device, so -EREMOTEIO doesn't
> require usb_clear_halt() or usb_reset_endpoint() for recovery.  This
> means we need to find some other way to tell the HCD when the queue can
> restart.  Should we create a new hc_driver callback specifically for
> this purpose?

For xHC the issue is the other way around as Michal pointed out.

Can't find a way to stop the endpoint on short packets.
Can only manually stop the endpoint when xhci-hcd detects the short transfer
event, when xHC likely already processing the next URB.

Thanks
Mathias


^ permalink raw reply

* [syzbot] [media?] general protection fault in em28xx_resolution_set (2)
From: syzbot @ 2026-04-07 20:35 UTC (permalink / raw)
  To: linux-kernel, linux-media, linux-usb, mchehab, syzkaller-bugs

Hello,

syzbot found the following issue on:

HEAD commit:    81ebd43cc0d6 usb: gadget: f_hid: don't call cdev_init whil..
git tree:       https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
console output: https://syzkaller.appspot.com/x/log.txt?x=140d45ca580000
kernel config:  https://syzkaller.appspot.com/x/.config?x=36a2baf561dcdf64
dashboard link: https://syzkaller.appspot.com/bug?extid=755151a86449f029bae0
compiler:       gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44

Unfortunately, I don't have any reproducer for this issue yet.

Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/59aca7fb2d65/disk-81ebd43c.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/87180154ea1a/vmlinux-81ebd43c.xz
kernel image: https://storage.googleapis.com/syzbot-assets/862a7fc58ad2/bzImage-81ebd43c.xz

IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+755151a86449f029bae0@syzkaller.appspotmail.com

Oops: general protection fault, probably for non-canonical address 0xdffffc0000000354: 0000 [#1] SMP KASAN PTI
KASAN: probably user-memory-access in range [0x0000000000001aa0-0x0000000000001aa7]
CPU: 0 UID: 0 PID: 5637 Comm: v4l_id Not tainted syzkaller #0 PREEMPT(full) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 02/12/2026
RIP: 0010:norm_maxh drivers/media/usb/em28xx/em28xx-video.c:149 [inline]
RIP: 0010:em28xx_resolution_set.isra.0+0xe4/0x730 drivers/media/usb/em28xx/em28xx-video.c:317
Code: 0f 85 d5 05 00 00 48 8d bd a0 1a 00 00 44 0f b6 bb 3c 01 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 41 83 e7 10 <80> 3c 02 00 0f 85 e9 05 00 00 31 ff 44 89 fe 4c 8b a5 a0 1a 00 00
RSP: 0018:ffffc90002027798 EFLAGS: 00010246

RAX: dffffc0000000000 RBX: ffff88811f368000 RCX: ffffffff85a50292
RDX: 0000000000000354 RSI: ffffffff85a4f799 RDI: 0000000000001aa0
RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000002
R10: 0000000000000000 R11: 0000000000000000 R12: ffff88812bc88000
R13: 1ffff92000404ef7 R14: ffff88811f36813c R15: 0000000000000000
FS:  00007f8c837eb880(0000) GS:ffff8882686f6000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f8c839e455a CR3: 000000010735c000 CR4: 00000000003506f0
Call Trace:
 <TASK>
 em28xx_v4l2_open+0x457/0x570 drivers/media/usb/em28xx/em28xx-video.c:2166
 v4l2_open+0x1d2/0x490 drivers/media/v4l2-core/v4l2-dev.c:433
 chrdev_open+0x234/0x6a0 fs/char_dev.c:411
 do_dentry_open+0x68b/0x14b0 fs/open.c:949
 vfs_open+0x82/0x3f0 fs/open.c:1081
 do_open fs/namei.c:4671 [inline]
 path_openat+0x208c/0x31a0 fs/namei.c:4830
 do_file_open+0x20e/0x430 fs/namei.c:4859
 do_sys_openat2+0x10d/0x1e0 fs/open.c:1366
 do_sys_open fs/open.c:1372 [inline]
 __do_sys_openat fs/open.c:1388 [inline]
 __se_sys_openat fs/open.c:1383 [inline]
 __x64_sys_openat+0x12d/0x210 fs/open.c:1383
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0x106/0x7b0 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f8c838d9407
Code: 48 89 fa 4c 89 df e8 38 aa 00 00 8b 93 08 03 00 00 59 5e 48 83 f8 fc 74 1a 5b c3 0f 1f 84 00 00 00 00 00 48 8b 44 24 10 0f 05 <5b> c3 0f 1f 80 00 00 00 00 83 e2 39 83 fa 08 75 de e8 23 ff ff ff
RSP: 002b:00007ffe5cd9fa90 EFLAGS: 00000202
 ORIG_RAX: 0000000000000101
RAX: ffffffffffffffda RBX: 00007f8c837eb880 RCX: 00007f8c838d9407
RDX: 0000000000000000 RSI: 00007ffe5cda0f21 RDI: ffffffffffffff9c
RBP: 0000000000000002 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000000000
R13: 00007ffe5cd9fce0 R14: 00007f8c8406f000 R15: 0000555f3c43e4d8
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:norm_maxh drivers/media/usb/em28xx/em28xx-video.c:149 [inline]
RIP: 0010:em28xx_resolution_set.isra.0+0xe4/0x730 drivers/media/usb/em28xx/em28xx-video.c:317
Code: 0f 85 d5 05 00 00 48 8d bd a0 1a 00 00 44 0f b6 bb 3c 01 00 00 48 b8 00 00 00 00 00 fc ff df 48 89 fa 48 c1 ea 03 41 83 e7 10 <80> 3c 02 00 0f 85 e9 05 00 00 31 ff 44 89 fe 4c 8b a5 a0 1a 00 00
RSP: 0018:ffffc90002027798 EFLAGS: 00010246

RAX: dffffc0000000000 RBX: ffff88811f368000 RCX: ffffffff85a50292
RDX: 0000000000000354 RSI: ffffffff85a4f799 RDI: 0000000000001aa0
RBP: 0000000000000000 R08: 0000000000000005 R09: 0000000000000002
----------------
Code disassembly (best guess):
   0:	0f 85 d5 05 00 00    	jne    0x5db
   6:	48 8d bd a0 1a 00 00 	lea    0x1aa0(%rbp),%rdi
   d:	44 0f b6 bb 3c 01 00 	movzbl 0x13c(%rbx),%r15d
  14:	00
  15:	48 b8 00 00 00 00 00 	movabs $0xdffffc0000000000,%rax
  1c:	fc ff df
  1f:	48 89 fa             	mov    %rdi,%rdx
  22:	48 c1 ea 03          	shr    $0x3,%rdx
  26:	41 83 e7 10          	and    $0x10,%r15d
* 2a:	80 3c 02 00          	cmpb   $0x0,(%rdx,%rax,1) <-- trapping instruction
  2e:	0f 85 e9 05 00 00    	jne    0x61d
  34:	31 ff                	xor    %edi,%edi
  36:	44 89 fe             	mov    %r15d,%esi
  39:	4c 8b a5 a0 1a 00 00 	mov    0x1aa0(%rbp),%r12


---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.

syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.

If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title

If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)

If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report

If you want to undo deduplication, reply with:
#syz undup

^ permalink raw reply

* Re: [PATCH v5 0/9] driver core: Fix some race conditions
From: Danilo Krummrich @ 2026-04-07 22:58 UTC (permalink / raw)
  To: Douglas Anderson, m.szyprowski, Robin Murphy
  Cc: Greg Kroah-Hartman, Rafael J . Wysocki, Alan Stern,
	Alexey Kardashevskiy, Johan Hovold, Eric Dumazet, Leon Romanovsky,
	Christoph Hellwig, maz, Alexander Lobakin, Saravana Kannan,
	Andrew Morton, Frank.Li, Jason Gunthorpe, alex, alexander.stein,
	andre.przywara, andrew, andrew, andriy.shevchenko, aou, ardb,
	astewart, bhelgaas, brgl, broonie, catalin.marinas, chleroy,
	davem, david, devicetree, dmaengine, driver-core, gbatra,
	gregory.clement, hkallweit1, iommu, jirislaby, joel, joro, kees,
	kevin.brodsky, kuba, lenb, lgirdwood, linux-acpi,
	linux-arm-kernel, linux-aspeed, linux-cxl, linux-kernel,
	linux-mips, linux-mm, linux-pci, linux-riscv, linux-serial,
	linux-snps-arc, linux-usb, linux, linuxppc-dev, maddy, mani,
	miko.lenczewski, mpe, netdev, npiggin, osalvador, oupton, pabeni,
	palmer, peter.ujfalusi, peterz, pjw, robh, sebastian.hesselbarth,
	tglx, tsbogend, vgupta, vkoul, will, willy, yangyicong,
	yeoreum.yun
In-Reply-To: <20260406232444.3117516-1-dianders@chromium.org>

On Tue Apr 7, 2026 at 1:22 AM CEST, Douglas Anderson wrote:

Applied to driver-core-testing, thanks!

> Douglas Anderson (9):
>   driver core: Don't let a device probe until it's ready
>   driver core: Replace dev->can_match with dev_can_match()
>   driver core: Replace dev->dma_iommu with dev_dma_iommu()
>   driver core: Replace dev->dma_skip_sync with dev_dma_skip_sync()
>   driver core: Replace dev->dma_ops_bypass with dev_dma_ops_bypass()
>   driver core: Replace dev->state_synced with dev_state_synced()
>   driver core: Replace dev->dma_coherent with dev_dma_coherent()

    [ Since all DEV_FLAG_DMA_COHERENT accessors are exposed unconditionally,
      also drop the CONFIG guards around dev_assign_dma_coherent() in
      device_initialize() to ensure a correct default value. - Danilo ]

>   driver core: Replace dev->of_node_reused with dev_of_node_reused()
>   driver core: Replace dev->offline + ->offline_disabled with accessors

^ permalink raw reply

* [PATCH] usb: dwc3: avoid probe deferral when USB power supply is not available
From: Elson Serrao @ 2026-04-07 23:24 UTC (permalink / raw)
  To: Thinh Nguyen, Greg Kroah-Hartman
  Cc: linux-usb, linux-kernel, jack.pham, wesley.cheng

The dwc3 driver currently defers probe if the USB power supply is not yet
registered. On some platforms, even though charging and power supply
functionality is available during normal operation, there may exist
minimal booting modes (such as recovery or diagnostic environments) where
the relevant USB power supply device is not registered. In such cases,
probe deferral prevents USB gadget operation entirely.

USB data functionality for basic operation does not inherently depend on
the power supply framework, which is only required for enforcing VBUS
current control. The configured VBUS current limit is typically enforced
through the charger or PMIC power path. When charging functionality is
unavailable, applying a current limit has no practical effect, reducing
the benefit of strict probe-time enforcement in these environments.

Instead of deferring probe, register a power supply notifier when the
USB power supply is not yet available. Cache the requested VBUS current
limit and apply it once the matching power supply becomes available, as
notified through the registered callback.

Signed-off-by: Elson Serrao <elson.serrao@oss.qualcomm.com>
---
 drivers/usb/dwc3/core.c   | 82 ++++++++++++++++++++++++++++++++-------
 drivers/usb/dwc3/core.h   |  4 ++
 drivers/usb/dwc3/gadget.c | 10 ++++-
 3 files changed, 80 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 161a4d58b2ce..20df0b287623 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -2167,24 +2167,72 @@ static void dwc3_vbus_draw_work(struct work_struct *work)
 	if (ret < 0)
 		dev_dbg(dwc->dev, "Error (%d) setting vbus draw (%d mA)\n",
 			ret, dwc->current_limit);
+
+	/* Unregister the psy notifier now that we have the power_supply reference */
+	if (dwc->psy_nb.notifier_call) {
+		power_supply_unreg_notifier(&dwc->psy_nb);
+		dwc->psy_nb.notifier_call = NULL;
+	}
 }
 
-static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
+static int dwc3_psy_notifier(struct notifier_block *nb,
+			     unsigned long event, void *data)
+{
+	struct dwc3 *dwc = container_of(nb, struct dwc3, psy_nb);
+	struct power_supply *psy = data;
+	unsigned long flags;
+
+	if (strcmp(psy->desc->name, dwc->usb_psy_name) != 0)
+		return NOTIFY_DONE;
+
+	/* Explicitly get the reference for this psy */
+	psy = power_supply_get_by_name(dwc->usb_psy_name);
+	if (!psy)
+		return NOTIFY_DONE;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	/*
+	 * The USB power_supply may already be set. This can happen if notifier
+	 * callbacks for the USB power_supply race, or if a previous notifier
+	 * callback has already successfully fetched and associated the instance.
+	 * In such cases, release the newly acquired reference and ignore
+	 * subsequent notifications until the notifier is unregistered.
+	 */
+	if (dwc->usb_psy) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		power_supply_put(psy);
+		return NOTIFY_DONE;
+	}
+
+	dwc->usb_psy = psy;
+	if (dwc->current_limit != UINT_MAX)
+		schedule_work(&dwc->vbus_draw_work);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return NOTIFY_OK;
+}
+
+static void dwc3_get_usb_power_supply(struct dwc3 *dwc)
 {
-	struct power_supply *usb_psy;
-	const char *usb_psy_name;
 	int ret;
 
-	ret = device_property_read_string(dwc->dev, "usb-psy-name", &usb_psy_name);
+	ret = device_property_read_string(dwc->dev, "usb-psy-name", &dwc->usb_psy_name);
 	if (ret < 0)
-		return NULL;
-
-	usb_psy = power_supply_get_by_name(usb_psy_name);
-	if (!usb_psy)
-		return ERR_PTR(-EPROBE_DEFER);
+		return;
 
 	INIT_WORK(&dwc->vbus_draw_work, dwc3_vbus_draw_work);
-	return usb_psy;
+
+	dwc->usb_psy = power_supply_get_by_name(dwc->usb_psy_name);
+	if (!dwc->usb_psy) {
+		dwc->current_limit = UINT_MAX;
+		dwc->psy_nb.notifier_call = dwc3_psy_notifier;
+		ret = power_supply_reg_notifier(&dwc->psy_nb);
+		if (ret) {
+			dev_err(dwc->dev, "Failed to register power supply notifier: %d\n", ret);
+			dwc->psy_nb.notifier_call = NULL;
+			return;
+		}
+	}
 }
 
 int dwc3_core_probe(const struct dwc3_probe_data *data)
@@ -2232,9 +2280,9 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
 
 	dwc3_get_software_properties(dwc, &data->properties);
 
-	dwc->usb_psy = dwc3_get_usb_power_supply(dwc);
-	if (IS_ERR(dwc->usb_psy))
-		return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power supply\n");
+	spin_lock_init(&dwc->lock);
+
+	dwc3_get_usb_power_supply(dwc);
 
 	if (!data->ignore_clocks_and_resets) {
 		dwc->reset = devm_reset_control_array_get_optional_shared(dev);
@@ -2286,7 +2334,6 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
 		dwc->num_usb3_ports = 1;
 	}
 
-	spin_lock_init(&dwc->lock);
 	mutex_init(&dwc->mutex);
 
 	pm_runtime_get_noresume(dev);
@@ -2354,6 +2401,8 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
 err_assert_reset:
 	reset_control_assert(dwc->reset);
 err_put_psy:
+	if (dwc->psy_nb.notifier_call)
+		power_supply_unreg_notifier(&dwc->psy_nb);
 	if (dwc->usb_psy)
 		power_supply_put(dwc->usb_psy);
 
@@ -2410,6 +2459,11 @@ void dwc3_core_remove(struct dwc3 *dwc)
 
 	dwc3_free_event_buffers(dwc);
 
+	if (dwc->psy_nb.notifier_call) {
+		power_supply_unreg_notifier(&dwc->psy_nb);
+		dwc->psy_nb.notifier_call = NULL;
+	}
+
 	if (dwc->usb_psy) {
 		cancel_work_sync(&dwc->vbus_draw_work);
 		power_supply_put(dwc->usb_psy);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index a35b3db1f9f3..68171629c7bf 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -1058,6 +1058,8 @@ struct dwc3_glue_ops {
  * @role_switch_default_mode: default operation mode of controller while
  *			usb role is USB_ROLE_NONE.
  * @usb_psy: pointer to power supply interface.
+ * @usb_psy_name: name of the USB power supply
+ * @psy_nb: power supply notifier block
  * @vbus_draw_work: Work to set the vbus drawing limit
  * @current_limit: How much current to draw from vbus, in milliAmperes.
  * @usb2_phy: pointer to USB2 PHY
@@ -1246,6 +1248,8 @@ struct dwc3 {
 	enum usb_dr_mode	role_switch_default_mode;
 
 	struct power_supply	*usb_psy;
+	const char		*usb_psy_name;
+	struct notifier_block	psy_nb;
 	struct work_struct	vbus_draw_work;
 	unsigned int		current_limit;
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 0a688904ce8c..4717c251596d 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -3124,15 +3124,21 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,
 static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
 {
 	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
 
 	if (dwc->usb2_phy)
 		return usb_phy_set_power(dwc->usb2_phy, mA);
 
-	if (!dwc->usb_psy)
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc->current_limit = mA;
+	if (!dwc->usb_psy) {
+		spin_unlock_irqrestore(&dwc->lock, flags);
+		dev_dbg(dwc->dev, "Stored VBUS draw: %u mA (power supply not ready)\n", mA);
 		return -EOPNOTSUPP;
+	}
 
-	dwc->current_limit = mA;
 	schedule_work(&dwc->vbus_draw_work);
+	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return 0;
 }
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH v2 1/3] usb: chipidea: core: refactor ci_usb_role_switch_set()
From: Peter Chen (CIX) @ 2026-04-08  5:24 UTC (permalink / raw)
  To: Xu Yang; +Cc: gregkh, jun.li, linux-usb, linux-kernel, imx
In-Reply-To: <20260402071457.2516021-1-xu.yang_2@nxp.com>

On 26-04-02 15:14:55, Xu Yang wrote:
> Current code is redundant, refactor the code, no function change.
> 
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>

Acked-by: Peter Chen <peter.chen@kernel.org>

Peter
> 
> ---
> Changes in v2:
>  - new patch
> ---
>  drivers/usb/chipidea/core.c | 29 +++++++----------------------
>  1 file changed, 7 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> index fac11f20cf0a..87be716dff3e 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -618,28 +618,13 @@ static int ci_usb_role_switch_set(struct usb_role_switch *sw,
>  	struct ci_hdrc *ci = usb_role_switch_get_drvdata(sw);
>  	struct ci_hdrc_cable *cable;
>  
> -	if (role == USB_ROLE_HOST) {
> -		cable = &ci->platdata->id_extcon;
> -		cable->changed = true;
> -		cable->connected = true;
> -		cable = &ci->platdata->vbus_extcon;
> -		cable->changed = true;
> -		cable->connected = false;
> -	} else if (role == USB_ROLE_DEVICE) {
> -		cable = &ci->platdata->id_extcon;
> -		cable->changed = true;
> -		cable->connected = false;
> -		cable = &ci->platdata->vbus_extcon;
> -		cable->changed = true;
> -		cable->connected = true;
> -	} else {
> -		cable = &ci->platdata->id_extcon;
> -		cable->changed = true;
> -		cable->connected = false;
> -		cable = &ci->platdata->vbus_extcon;
> -		cable->changed = true;
> -		cable->connected = false;
> -	}
> +	cable = &ci->platdata->id_extcon;
> +	cable->changed = true;
> +	cable->connected = (role == USB_ROLE_HOST);
> +
> +	cable = &ci->platdata->vbus_extcon;
> +	cable->changed = true;
> +	cable->connected = (role == USB_ROLE_DEVICE);
>  
>  	ci_irq(ci);
>  	return 0;
> -- 
> 2.34.1
> 

-- 

Best regards,
Peter

^ permalink raw reply

* [PATCH v2 0/2] mfd: nct6694: Refactor transport layer and add HIF (eSPI) support
From: a0282524688 @ 2026-04-08  5:30 UTC (permalink / raw)
  To: tmyu0, linusw, brgl, linux, andi.shyti, lee, mkl, mailhol,
	alexandre.belloni, wim
  Cc: linux-kernel, linux-gpio, linux-i2c, linux-can, netdev,
	linux-watchdog, linux-hwmon, linux-rtc, linux-usb, Ming Yu

From: Ming Yu <a0282524688@gmail.com>

The Nuvoton NCT6694 is a peripheral expander that provides GPIO, I2C,
CAN-FD, Watchdog, HWMON, PWM, and RTC sub-devices. Currently, the
driver only supports USB as the host transport interface.

This series refactors the NCT6694 MFD core to support multiple transport
backends and adds a new Host Interface (HIF) transport driver that
communicates over eSPI using Super-I/O shared memory.

Changes since version 1:
- Reworked the Super-I/O access helpers.

Ming Yu (2):
  mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA
  mfd: Add Host Interface (HIF) support for Nuvoton NCT6694

 MAINTAINERS                         |   1 +
 drivers/gpio/gpio-nct6694.c         |  26 +-
 drivers/hwmon/nct6694-hwmon.c       |  21 -
 drivers/i2c/busses/i2c-nct6694.c    |  26 +-
 drivers/mfd/Kconfig                 |  47 ++-
 drivers/mfd/Makefile                |   3 +-
 drivers/mfd/nct6694-hif.c           | 634 ++++++++++++++++++++++++++++
 drivers/mfd/nct6694.c               | 180 ++++----
 drivers/net/can/usb/nct6694_canfd.c |  18 +-
 drivers/rtc/rtc-nct6694.c           |   7 -
 drivers/watchdog/nct6694_wdt.c      |  27 +-
 include/linux/mfd/nct6694.h         |  57 ++-
 12 files changed, 814 insertions(+), 233 deletions(-)
 create mode 100644 drivers/mfd/nct6694-hif.c

-- 
2.34.1


^ permalink raw reply

* [PATCH v2 1/2] mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA
From: a0282524688 @ 2026-04-08  5:30 UTC (permalink / raw)
  To: tmyu0, linusw, brgl, linux, andi.shyti, lee, mkl, mailhol,
	alexandre.belloni, wim
  Cc: linux-kernel, linux-gpio, linux-i2c, linux-can, netdev,
	linux-watchdog, linux-hwmon, linux-rtc, linux-usb, Ming Yu
In-Reply-To: <20260408053037.1867092-1-a0282524688@gmail.com>

From: Ming Yu <a0282524688@gmail.com>

Currently, the nct6694 core driver uses mfd_add_hotplug_devices()
and an IDA to manage subdevice IDs.

Switch the core implementation to use the managed
devm_mfd_add_devices() API, which simplifies the error handling and
device lifecycle management. Concurrently, drop the custom IDA
implementation and transition to using pdev->id.

Signed-off-by: Ming Yu <a0282524688@gmail.com>
---
 drivers/gpio/gpio-nct6694.c         | 19 +------
 drivers/i2c/busses/i2c-nct6694.c    | 19 +------
 drivers/mfd/nct6694.c               | 83 ++++++++++++-----------------
 drivers/net/can/usb/nct6694_canfd.c | 12 +----
 drivers/watchdog/nct6694_wdt.c      | 20 +------
 include/linux/mfd/nct6694.h         |  8 +--
 6 files changed, 43 insertions(+), 118 deletions(-)

diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c
index a8607f0d9915..3703a61209e6 100644
--- a/drivers/gpio/gpio-nct6694.c
+++ b/drivers/gpio/gpio-nct6694.c
@@ -7,7 +7,6 @@
 
 #include <linux/bits.h>
 #include <linux/gpio/driver.h>
-#include <linux/idr.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/nct6694.h>
 #include <linux/module.h>
@@ -381,14 +380,6 @@ static void nct6694_irq_dispose_mapping(void *d)
 	irq_dispose_mapping(data->irq);
 }
 
-static void nct6694_gpio_ida_free(void *d)
-{
-	struct nct6694_gpio_data *data = d;
-	struct nct6694 *nct6694 = data->nct6694;
-
-	ida_free(&nct6694->gpio_ida, data->group);
-}
-
 static int nct6694_gpio_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -403,15 +394,7 @@ static int nct6694_gpio_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	data->nct6694 = nct6694;
-
-	ret = ida_alloc(&nct6694->gpio_ida, GFP_KERNEL);
-	if (ret < 0)
-		return ret;
-	data->group = ret;
-
-	ret = devm_add_action_or_reset(dev, nct6694_gpio_ida_free, data);
-	if (ret)
-		return ret;
+	data->group = pdev->id;
 
 	names = devm_kcalloc(dev, NCT6694_NR_GPIO, sizeof(char *),
 			     GFP_KERNEL);
diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c
index 1413ab6f9462..7d8ad997f6d2 100644
--- a/drivers/i2c/busses/i2c-nct6694.c
+++ b/drivers/i2c/busses/i2c-nct6694.c
@@ -6,7 +6,6 @@
  */
 
 #include <linux/i2c.h>
-#include <linux/idr.h>
 #include <linux/kernel.h>
 #include <linux/mfd/nct6694.h>
 #include <linux/module.h>
@@ -134,14 +133,6 @@ static int nct6694_i2c_set_baudrate(struct nct6694_i2c_data *data)
 	return 0;
 }
 
-static void nct6694_i2c_ida_free(void *d)
-{
-	struct nct6694_i2c_data *data = d;
-	struct nct6694 *nct6694 = data->nct6694;
-
-	ida_free(&nct6694->i2c_ida, data->port);
-}
-
 static int nct6694_i2c_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -155,15 +146,7 @@ static int nct6694_i2c_probe(struct platform_device *pdev)
 
 	data->dev = dev;
 	data->nct6694 = nct6694;
-
-	ret = ida_alloc(&nct6694->i2c_ida, GFP_KERNEL);
-	if (ret < 0)
-		return ret;
-	data->port = ret;
-
-	ret = devm_add_action_or_reset(dev, nct6694_i2c_ida_free, data);
-	if (ret)
-		return ret;
+	data->port = pdev->id;
 
 	ret = nct6694_i2c_set_baudrate(data);
 	if (ret)
diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c
index 308b2fda3055..8ce2c4985aab 100644
--- a/drivers/mfd/nct6694.c
+++ b/drivers/mfd/nct6694.c
@@ -11,7 +11,6 @@
 
 #include <linux/bits.h>
 #include <linux/interrupt.h>
-#include <linux/idr.h>
 #include <linux/irq.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
@@ -23,35 +22,35 @@
 #include <linux/usb.h>
 
 static const struct mfd_cell nct6694_devs[] = {
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-	MFD_CELL_NAME("nct6694-gpio"),
-
-	MFD_CELL_NAME("nct6694-i2c"),
-	MFD_CELL_NAME("nct6694-i2c"),
-	MFD_CELL_NAME("nct6694-i2c"),
-	MFD_CELL_NAME("nct6694-i2c"),
-	MFD_CELL_NAME("nct6694-i2c"),
-	MFD_CELL_NAME("nct6694-i2c"),
-
-	MFD_CELL_NAME("nct6694-canfd"),
-	MFD_CELL_NAME("nct6694-canfd"),
-
-	MFD_CELL_NAME("nct6694-wdt"),
-	MFD_CELL_NAME("nct6694-wdt"),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 0),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 1),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 2),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 3),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 4),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 5),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 6),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 7),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 8),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 9),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 10),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 11),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 12),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 13),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 14),
+	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 15),
+
+	MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 0),
+	MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 1),
+	MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 2),
+	MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 3),
+	MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 4),
+	MFD_CELL_BASIC("nct6694-i2c", NULL, NULL, 0, 5),
+
+	MFD_CELL_BASIC("nct6694-canfd", NULL, NULL, 0, 0),
+	MFD_CELL_BASIC("nct6694-canfd", NULL, NULL, 0, 1),
+
+	MFD_CELL_BASIC("nct6694-wdt", NULL, NULL, 0, 0),
+	MFD_CELL_BASIC("nct6694-wdt", NULL, NULL, 0, 1),
 
 	MFD_CELL_NAME("nct6694-hwmon"),
 
@@ -307,23 +306,18 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 	nct6694->dev = dev;
 	nct6694->udev = udev;
 
-	ida_init(&nct6694->gpio_ida);
-	ida_init(&nct6694->i2c_ida);
-	ida_init(&nct6694->canfd_ida);
-	ida_init(&nct6694->wdt_ida);
-
 	spin_lock_init(&nct6694->irq_lock);
 
 	ret = devm_mutex_init(dev, &nct6694->access_lock);
 	if (ret)
-		goto err_ida;
+		goto err_irq_domain;
 
 	interface = iface->cur_altsetting;
 
 	int_endpoint = &interface->endpoint[0].desc;
 	if (!usb_endpoint_is_int_in(int_endpoint)) {
 		ret = -ENODEV;
-		goto err_ida;
+		goto err_irq_domain;
 	}
 
 	usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
@@ -332,11 +326,11 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 
 	ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL);
 	if (ret)
-		goto err_ida;
+		goto err_irq_domain;
 
 	usb_set_intfdata(iface, nct6694);
 
-	ret = mfd_add_hotplug_devices(dev, nct6694_devs, ARRAY_SIZE(nct6694_devs));
+	ret = devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_devs), NULL, 0, NULL);
 	if (ret)
 		goto err_mfd;
 
@@ -344,11 +338,7 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 
 err_mfd:
 	usb_kill_urb(nct6694->int_in_urb);
-err_ida:
-	ida_destroy(&nct6694->wdt_ida);
-	ida_destroy(&nct6694->canfd_ida);
-	ida_destroy(&nct6694->i2c_ida);
-	ida_destroy(&nct6694->gpio_ida);
+err_irq_domain:
 	irq_domain_remove(nct6694->domain);
 err_urb:
 	usb_free_urb(nct6694->int_in_urb);
@@ -359,12 +349,7 @@ static void nct6694_usb_disconnect(struct usb_interface *iface)
 {
 	struct nct6694 *nct6694 = usb_get_intfdata(iface);
 
-	mfd_remove_devices(nct6694->dev);
 	usb_kill_urb(nct6694->int_in_urb);
-	ida_destroy(&nct6694->wdt_ida);
-	ida_destroy(&nct6694->canfd_ida);
-	ida_destroy(&nct6694->i2c_ida);
-	ida_destroy(&nct6694->gpio_ida);
 	irq_domain_remove(nct6694->domain);
 	usb_free_urb(nct6694->int_in_urb);
 }
diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6694_canfd.c
index e5f7f8849a73..29282c56430f 100644
--- a/drivers/net/can/usb/nct6694_canfd.c
+++ b/drivers/net/can/usb/nct6694_canfd.c
@@ -8,7 +8,6 @@
 #include <linux/can/dev.h>
 #include <linux/can/rx-offload.h>
 #include <linux/ethtool.h>
-#include <linux/idr.h>
 #include <linux/irqdomain.h>
 #include <linux/kernel.h>
 #include <linux/mfd/nct6694.h>
@@ -725,15 +724,13 @@ static int nct6694_canfd_probe(struct platform_device *pdev)
 	struct net_device *ndev;
 	int port, irq, ret, can_clk;
 
-	port = ida_alloc(&nct6694->canfd_ida, GFP_KERNEL);
-	if (port < 0)
-		return port;
+	port = pdev->id;
 
 	irq = irq_create_mapping(nct6694->domain,
 				 NCT6694_IRQ_CAN0 + port);
 	if (!irq) {
 		ret = -EINVAL;
-		goto free_ida;
+		return ret;
 	}
 
 	ndev = alloc_candev(sizeof(struct nct6694_canfd_priv), 1);
@@ -796,24 +793,19 @@ static int nct6694_canfd_probe(struct platform_device *pdev)
 	free_candev(ndev);
 dispose_irq:
 	irq_dispose_mapping(irq);
-free_ida:
-	ida_free(&nct6694->canfd_ida, port);
 	return ret;
 }
 
 static void nct6694_canfd_remove(struct platform_device *pdev)
 {
 	struct nct6694_canfd_priv *priv = platform_get_drvdata(pdev);
-	struct nct6694 *nct6694 = priv->nct6694;
 	struct net_device *ndev = priv->ndev;
-	int port = ndev->dev_port;
 	int irq = ndev->irq;
 
 	unregister_candev(ndev);
 	can_rx_offload_del(&priv->offload);
 	free_candev(ndev);
 	irq_dispose_mapping(irq);
-	ida_free(&nct6694->canfd_ida, port);
 }
 
 static struct platform_driver nct6694_canfd_driver = {
diff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c
index bc3689bd4b6b..2b4b804a1739 100644
--- a/drivers/watchdog/nct6694_wdt.c
+++ b/drivers/watchdog/nct6694_wdt.c
@@ -5,7 +5,6 @@
  * Copyright (C) 2025 Nuvoton Technology Corp.
  */
 
-#include <linux/idr.h>
 #include <linux/kernel.h>
 #include <linux/mfd/nct6694.h>
 #include <linux/module.h>
@@ -233,21 +232,12 @@ static const struct watchdog_ops nct6694_wdt_ops = {
 	.ping = nct6694_wdt_ping,
 };
 
-static void nct6694_wdt_ida_free(void *d)
-{
-	struct nct6694_wdt_data *data = d;
-	struct nct6694 *nct6694 = data->nct6694;
-
-	ida_free(&nct6694->wdt_ida, data->wdev_idx);
-}
-
 static int nct6694_wdt_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct nct6694 *nct6694 = dev_get_drvdata(dev->parent);
 	struct nct6694_wdt_data *data;
 	struct watchdog_device *wdev;
-	int ret;
 
 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -260,15 +250,7 @@ static int nct6694_wdt_probe(struct platform_device *pdev)
 
 	data->dev = dev;
 	data->nct6694 = nct6694;
-
-	ret = ida_alloc(&nct6694->wdt_ida, GFP_KERNEL);
-	if (ret < 0)
-		return ret;
-	data->wdev_idx = ret;
-
-	ret = devm_add_action_or_reset(dev, nct6694_wdt_ida_free, data);
-	if (ret)
-		return ret;
+	data->wdev_idx = pdev->id;
 
 	wdev = &data->wdev;
 	wdev->info = &nct6694_wdt_info;
diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h
index 6eb9be2cd4a0..496da72949d9 100644
--- a/include/linux/mfd/nct6694.h
+++ b/include/linux/mfd/nct6694.h
@@ -8,6 +8,10 @@
 #ifndef __MFD_NCT6694_H
 #define __MFD_NCT6694_H
 
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
 #define NCT6694_VENDOR_ID	0x0416
 #define NCT6694_PRODUCT_ID	0x200B
 #define NCT6694_INT_IN_EP	0x81
@@ -82,10 +86,6 @@ union __packed nct6694_usb_msg {
 
 struct nct6694 {
 	struct device *dev;
-	struct ida gpio_ida;
-	struct ida i2c_ida;
-	struct ida canfd_ida;
-	struct ida wdt_ida;
 	struct irq_domain *domain;
 	struct mutex access_lock;
 	spinlock_t irq_lock;
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 2/2] mfd: Add Host Interface (HIF) support for Nuvoton NCT6694
From: a0282524688 @ 2026-04-08  5:30 UTC (permalink / raw)
  To: tmyu0, linusw, brgl, linux, andi.shyti, lee, mkl, mailhol,
	alexandre.belloni, wim
  Cc: linux-kernel, linux-gpio, linux-i2c, linux-can, netdev,
	linux-watchdog, linux-hwmon, linux-rtc, linux-usb, Ming Yu
In-Reply-To: <20260408053037.1867092-1-a0282524688@gmail.com>

From: Ming Yu <a0282524688@gmail.com>

The Nuvoton NCT6694 also provides a Host Interface (HIF) via eSPI
to the host to access its features.

Sub-devices can use the common functions nct6694_read_msg() and
nct6694_write_msg() to issue a command. They can also request
interrupts that will be called when the HIF device triggers a
shared memory interrupt.

To support multiple transports, the driver configuration is
updated to allow selecting between the USB and HIF interfaces.

Signed-off-by: Ming Yu <a0282524688@gmail.com>
---
Changes since version 1:
- Drop function pointers from Super-I/O access and use static inline
  helpers with proper types.

 MAINTAINERS                         |   1 +
 drivers/gpio/gpio-nct6694.c         |   7 -
 drivers/hwmon/nct6694-hwmon.c       |  21 -
 drivers/i2c/busses/i2c-nct6694.c    |   7 -
 drivers/mfd/Kconfig                 |  47 ++-
 drivers/mfd/Makefile                |   3 +-
 drivers/mfd/nct6694-hif.c           | 634 ++++++++++++++++++++++++++++
 drivers/mfd/nct6694.c               |  97 +++--
 drivers/net/can/usb/nct6694_canfd.c |   6 -
 drivers/rtc/rtc-nct6694.c           |   7 -
 drivers/watchdog/nct6694_wdt.c      |   7 -
 include/linux/mfd/nct6694.h         |  51 ++-
 12 files changed, 772 insertions(+), 116 deletions(-)
 create mode 100644 drivers/mfd/nct6694-hif.c

diff --git a/MAINTAINERS b/MAINTAINERS
index c3fe46d7c4bc..7b6241faa6df 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18899,6 +18899,7 @@ S:	Supported
 F:	drivers/gpio/gpio-nct6694.c
 F:	drivers/hwmon/nct6694-hwmon.c
 F:	drivers/i2c/busses/i2c-nct6694.c
+F:	drivers/mfd/nct6694-hif.c
 F:	drivers/mfd/nct6694.c
 F:	drivers/net/can/usb/nct6694_canfd.c
 F:	drivers/rtc/rtc-nct6694.c
diff --git a/drivers/gpio/gpio-nct6694.c b/drivers/gpio/gpio-nct6694.c
index 3703a61209e6..a279510ece89 100644
--- a/drivers/gpio/gpio-nct6694.c
+++ b/drivers/gpio/gpio-nct6694.c
@@ -12,13 +12,6 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-/*
- * USB command module type for NCT6694 GPIO controller.
- * This defines the module type used for communication with the NCT6694
- * GPIO controller over the USB interface.
- */
-#define NCT6694_GPIO_MOD	0xFF
-
 #define NCT6694_GPIO_VER	0x90
 #define NCT6694_GPIO_VALID	0x110
 #define NCT6694_GPI_DATA	0x120
diff --git a/drivers/hwmon/nct6694-hwmon.c b/drivers/hwmon/nct6694-hwmon.c
index 6dcf22ca5018..581451875f2c 100644
--- a/drivers/hwmon/nct6694-hwmon.c
+++ b/drivers/hwmon/nct6694-hwmon.c
@@ -15,13 +15,6 @@
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 
-/*
- * USB command module type for NCT6694 report channel
- * This defines the module type used for communication with the NCT6694
- * report channel over the USB interface.
- */
-#define NCT6694_RPT_MOD			0xFF
-
 /* Report channel */
 /*
  * The report channel is used to report the status of the hardware monitor
@@ -38,13 +31,6 @@
 #define NCT6694_TIN_STS(x)		(0x6A + (x))
 #define NCT6694_FIN_STS(x)		(0x6E + (x))
 
-/*
- * USB command module type for NCT6694 HWMON controller.
- * This defines the module type used for communication with the NCT6694
- * HWMON controller over the USB interface.
- */
-#define NCT6694_HWMON_MOD		0x00
-
 /* Command 00h - Hardware Monitor Control */
 #define NCT6694_HWMON_CONTROL		0x00
 #define NCT6694_HWMON_CONTROL_SEL	0x00
@@ -53,13 +39,6 @@
 #define NCT6694_HWMON_ALARM		0x02
 #define NCT6694_HWMON_ALARM_SEL		0x00
 
-/*
- * USB command module type for NCT6694 PWM controller.
- * This defines the module type used for communication with the NCT6694
- * PWM controller over the USB interface.
- */
-#define NCT6694_PWM_MOD			0x01
-
 /* PWM Command - Manual Control */
 #define NCT6694_PWM_CONTROL		0x01
 #define NCT6694_PWM_CONTROL_SEL		0x00
diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c
index 7d8ad997f6d2..7ee209a04d16 100644
--- a/drivers/i2c/busses/i2c-nct6694.c
+++ b/drivers/i2c/busses/i2c-nct6694.c
@@ -11,13 +11,6 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
-/*
- * USB command module type for NCT6694 I2C controller.
- * This defines the module type used for communication with the NCT6694
- * I2C controller over the USB interface.
- */
-#define NCT6694_I2C_MOD			0x03
-
 /* Command 00h - I2C Deliver */
 #define NCT6694_I2C_DELIVER		0x00
 #define NCT6694_I2C_DELIVER_SEL		0x00
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 7192c9d1d268..8a715ec2f79f 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -1164,19 +1164,46 @@ config MFD_MENF21BMC
 	  will be called menf21bmc.
 
 config MFD_NCT6694
-	tristate "Nuvoton NCT6694 support"
+	tristate
 	select MFD_CORE
+	help
+	  Core MFD support for the Nuvoton NCT6694 peripheral expander.
+	  This provides the common APIs and shared structures used by all
+	  interfaces (USB, HIF) to access the NCT6694 hardware features
+	  such as GPIO, I2C, CAN-FD, Watchdog, ADC, PWM, and RTC.
+
+	  It is selected automatically by the transport interface drivers.
+
+config MFD_NCT6694_HIF
+	tristate "Nuvoton NCT6694 HIF (eSPI) interface support"
+	depends on HAS_IOPORT && ACPI
+	select MFD_NCT6694
+	select REGMAP_MMIO
+	help
+	  This enables support for the Nuvoton NCT6694 peripheral expander
+	  connected via the Host Interface (HIF) using eSPI transport.
+
+	  The transport driver uses Super-I/O mapping and shared memory to
+	  communicate with the NCT6694 firmware. Enable this option if you
+	  are using the NCT6694 over an eSPI interface on an ACPI platform.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called nct6694-hif.
+
+config MFD_NCT6694_USB
+	tristate "Nuvoton NCT6694 USB interface support"
+	select MFD_NCT6694
 	depends on USB
 	help
-	  This enables support for the Nuvoton USB device NCT6694, which shares
-	  peripherals.
-	  The Nuvoton NCT6694 is a peripheral expander with 16 GPIO chips,
-	  6 I2C controllers, 2 CANfd controllers, 2 Watchdog timers, ADC,
-	  PWM, and RTC.
-	  This driver provides core APIs to access the NCT6694 hardware
-	  monitoring and control features.
-	  Additional drivers must be enabled to utilize the specific
-	  functionalities of the device.
+	  This enables support for the Nuvoton NCT6694 peripheral expander
+	  connected via the USB interface.
+
+	  The transport driver uses USB bulk and interrupt transfers to
+	  communicate with the NCT6694 firmware. Enable this option if you
+	  are using the NCT6694 via a USB connection.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called nct6694.
 
 config MFD_OCELOT
 	tristate "Microsemi Ocelot External Control Support"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index e75e8045c28a..4cee9b74978c 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -124,7 +124,8 @@ obj-$(CONFIG_MFD_MC13XXX_I2C)	+= mc13xxx-i2c.o
 
 obj-$(CONFIG_MFD_PF1550)	+= pf1550.o
 
-obj-$(CONFIG_MFD_NCT6694)	+= nct6694.o
+obj-$(CONFIG_MFD_NCT6694_HIF)	+= nct6694-hif.o
+obj-$(CONFIG_MFD_NCT6694_USB)	+= nct6694.o
 
 obj-$(CONFIG_MFD_CORE)		+= mfd-core.o
 
diff --git a/drivers/mfd/nct6694-hif.c b/drivers/mfd/nct6694-hif.c
new file mode 100644
index 000000000000..7560754e7481
--- /dev/null
+++ b/drivers/mfd/nct6694-hif.c
@@ -0,0 +1,634 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2026 Nuvoton Technology Corp.
+ *
+ * Nuvoton NCT6694 host-interface (eSPI) transport driver.
+ */
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/nct6694.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/unaligned.h>
+
+#define DRVNAME "nct6694-hif"
+
+#define NCT6694_POLL_INTERVAL_US	10
+#define NCT6694_POLL_TIMEOUT_US		10000
+
+/*
+ * Super-I/O registers
+ */
+#define SIO_REG_LDSEL		0x07	/* Logical device select */
+#define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
+#define SIO_REG_LD_SHM		0x0F	/* Logical device shared memory control */
+
+#define SIO_REG_SHM_ENABLE	0x30	/* Enable shared memory */
+#define SIO_REG_SHM_BASE_ADDR	0x60	/* Shared memory base address (2 bytes) */
+#define SIO_REG_SHM_IRQ_NR	0x70	/* Shared memory interrupt number */
+
+#define SIO_REG_UNLOCK_KEY	0x87	/* Key to enable Super-I/O */
+#define SIO_REG_LOCK_KEY	0xAA	/* Key to disable Super-I/O */
+
+#define SIO_NCT6694B_ID		0xD029
+#define SIO_NCT6694D_ID		0x5832
+
+/*
+ * Super-I/O Shared Memory Logical Device registers
+ */
+#define NCT6694_SHM_COFS_STS			0x2E
+#define NCT6694_SHM_COFS_STS_COFS4W		BIT(7)
+
+#define NCT6694_SHM_COFS_CTL2			0x3B
+#define NCT6694_SHM_COFS_CTL2_COFS4W_IE		BIT(3)
+
+#define NCT6694_SHM_INTR_STATUS			0x9C	/* Interrupt status register (4 bytes) */
+
+enum nct6694_chips {
+	NCT6694B = 0,
+	NCT6694D,
+};
+
+enum nct6694_module_id {
+	NCT6694_GPIO0 = 0,
+	NCT6694_GPIO1,
+	NCT6694_GPIO2,
+	NCT6694_GPIO3,
+	NCT6694_GPIO4,
+	NCT6694_GPIO5,
+	NCT6694_GPIO6,
+	NCT6694_GPIO7,
+	NCT6694_GPIO8,
+	NCT6694_GPIO9,
+	NCT6694_GPIOA,
+	NCT6694_GPIOB,
+	NCT6694_GPIOC,
+	NCT6694_GPIOD,
+	NCT6694_GPIOE,
+	NCT6694_GPIOF,
+	NCT6694_I2C0,
+	NCT6694_I2C1,
+	NCT6694_I2C2,
+	NCT6694_I2C3,
+	NCT6694_I2C4,
+	NCT6694_I2C5,
+	NCT6694_CAN0,
+	NCT6694_CAN1,
+};
+
+struct __packed nct6694_msg {
+	struct nct6694_cmd_header cmd_header;
+	struct nct6694_response_header response_header;
+	unsigned char *data;
+};
+
+struct nct6694_sio_data {
+	enum nct6694_chips chip;
+	int sioreg;	/* Super-I/O index port */
+};
+
+struct nct6694_hif_data {
+	struct regmap *regmap;
+	struct mutex msg_lock;
+	struct nct6694_sio_data *sio_data;
+	void __iomem *msg_base;
+	unsigned int shm_base;
+};
+
+static const char * const nct6694_chip_names[] = {
+	"NCT6694D",
+	"NCT6694B"
+};
+
+/*
+ * Super-I/O functions.
+ */
+static inline int superio_enter(struct nct6694_sio_data *sio_data)
+{
+	int ioreg = sio_data->sioreg;
+
+	/*
+	 * Try to reserve <ioreg> and <ioreg + 1> for exclusive access.
+	 */
+	if (!request_muxed_region(ioreg, 2, DRVNAME))
+		return -EBUSY;
+
+	outb(SIO_REG_UNLOCK_KEY, ioreg);
+	outb(SIO_REG_UNLOCK_KEY, ioreg);
+
+	return 0;
+}
+
+static inline void superio_exit(struct nct6694_sio_data *sio_data)
+{
+	int ioreg = sio_data->sioreg;
+
+	outb(SIO_REG_LOCK_KEY, ioreg);
+
+	release_region(ioreg, 2);
+}
+
+static inline void superio_select(struct nct6694_sio_data *sio_data, int ld)
+{
+	int ioreg = sio_data->sioreg;
+
+	outb(SIO_REG_LDSEL, ioreg);
+	outb(ld, ioreg + 1);
+}
+
+static inline int superio_inb(struct nct6694_sio_data *sio_data, int reg)
+{
+	int ioreg = sio_data->sioreg;
+
+	outb(reg, ioreg);
+	return inb(ioreg + 1);
+}
+
+static inline int superio_inw(struct nct6694_sio_data *sio_data, int reg)
+{
+	int ioreg = sio_data->sioreg;
+	int val;
+
+	outb(reg++, ioreg);
+	val = inb(ioreg + 1) << 8;
+	outb(reg, ioreg);
+	val |= inb(ioreg + 1);
+
+	return val;
+}
+
+static inline void superio_outb(struct nct6694_sio_data *sio_data, int reg, u8 val)
+{
+	int ioreg = sio_data->sioreg;
+
+	outb(reg, ioreg);
+	outb(val, ioreg + 1);
+}
+
+static int nct6694_sio_find(struct nct6694_sio_data *sio_data, u8 sioreg)
+{
+	int ret;
+	u16 devid;
+
+	sio_data->sioreg = sioreg;
+
+	ret = superio_enter(sio_data);
+	if (ret)
+		return ret;
+
+	/* Check Chip ID */
+	devid = superio_inw(sio_data, SIO_REG_DEVID);
+	switch (devid) {
+	case SIO_NCT6694B_ID:
+		sio_data->chip = NCT6694B;
+		break;
+	case SIO_NCT6694D_ID:
+		sio_data->chip = NCT6694D;
+		break;
+	default:
+		pr_err("Unsupported device 0x%04x\n", devid);
+		goto err;
+	}
+
+	pr_info("Found %s at %#x\n", nct6694_chip_names[sio_data->chip], sio_data->sioreg);
+
+	superio_exit(sio_data);
+
+	return 0;
+
+err:
+	superio_exit(sio_data);
+	return -ENODEV;
+}
+
+static const struct mfd_cell_acpi_match nct6694_acpi_match_gpio[] = {
+	{ .adr = NCT6694_GPIO0 },
+	{ .adr = NCT6694_GPIO1 },
+	{ .adr = NCT6694_GPIO2 },
+	{ .adr = NCT6694_GPIO3 },
+	{ .adr = NCT6694_GPIO4 },
+	{ .adr = NCT6694_GPIO5 },
+	{ .adr = NCT6694_GPIO6 },
+	{ .adr = NCT6694_GPIO7 },
+	{ .adr = NCT6694_GPIO8 },
+	{ .adr = NCT6694_GPIO9 },
+	{ .adr = NCT6694_GPIOA },
+	{ .adr = NCT6694_GPIOB },
+	{ .adr = NCT6694_GPIOC },
+	{ .adr = NCT6694_GPIOD },
+	{ .adr = NCT6694_GPIOE },
+	{ .adr = NCT6694_GPIOF },
+};
+
+static const struct mfd_cell_acpi_match nct6694_acpi_match_i2c[] = {
+	{ .adr = NCT6694_I2C0 },
+	{ .adr = NCT6694_I2C1 },
+	{ .adr = NCT6694_I2C2 },
+	{ .adr = NCT6694_I2C3 },
+	{ .adr = NCT6694_I2C4 },
+	{ .adr = NCT6694_I2C5 },
+};
+
+static const struct mfd_cell_acpi_match nct6694_acpi_match_can[] = {
+	{ .adr = NCT6694_CAN0 },
+	{ .adr = NCT6694_CAN1 },
+};
+
+static const struct mfd_cell nct6694_devs[] = {
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 0, &nct6694_acpi_match_gpio[0]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 1, &nct6694_acpi_match_gpio[1]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 2, &nct6694_acpi_match_gpio[2]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 3, &nct6694_acpi_match_gpio[3]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 4, &nct6694_acpi_match_gpio[4]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 5, &nct6694_acpi_match_gpio[5]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 6, &nct6694_acpi_match_gpio[6]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 7, &nct6694_acpi_match_gpio[7]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 8, &nct6694_acpi_match_gpio[8]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 9, &nct6694_acpi_match_gpio[9]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 10, &nct6694_acpi_match_gpio[10]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 11, &nct6694_acpi_match_gpio[11]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 12, &nct6694_acpi_match_gpio[12]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 13, &nct6694_acpi_match_gpio[13]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 14, &nct6694_acpi_match_gpio[14]),
+	MFD_CELL_ACPI("nct6694-gpio", NULL, NULL, 0, 15, &nct6694_acpi_match_gpio[15]),
+
+	MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 0, &nct6694_acpi_match_i2c[0]),
+	MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 1, &nct6694_acpi_match_i2c[1]),
+	MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 2, &nct6694_acpi_match_i2c[2]),
+	MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 3, &nct6694_acpi_match_i2c[3]),
+	MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 4, &nct6694_acpi_match_i2c[4]),
+	MFD_CELL_ACPI("nct6694-i2c", NULL, NULL, 0, 5, &nct6694_acpi_match_i2c[5]),
+
+	MFD_CELL_ACPI("nct6694-canfd", NULL, NULL, 0, 0, &nct6694_acpi_match_can[0]),
+	MFD_CELL_ACPI("nct6694-canfd", NULL, NULL, 0, 1, &nct6694_acpi_match_can[1]),
+};
+
+static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status)
+{
+	switch (err_status) {
+	case NCT6694_NO_ERROR:
+		return 0;
+	case NCT6694_NOT_SUPPORT_ERROR:
+		dev_err(nct6694->dev, "Command is not supported!\n");
+		break;
+	case NCT6694_NO_RESPONSE_ERROR:
+		dev_warn(nct6694->dev, "Command received no response!\n");
+		break;
+	case NCT6694_TIMEOUT_ERROR:
+		dev_warn(nct6694->dev, "Command timed out!\n");
+		break;
+	case NCT6694_PENDING:
+		dev_err(nct6694->dev, "Command is pending!\n");
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return -EIO;
+}
+
+static int nct6694_xfer_msg(struct nct6694 *nct6694,
+			    const struct nct6694_cmd_header *cmd_hd,
+			    u8 hctrl, void *buf)
+{
+	struct nct6694_hif_data *hdata = nct6694->priv;
+	void __iomem *hdr = hdata->msg_base + offsetof(struct nct6694_msg, cmd_header);
+	struct nct6694_cmd_header cmd = *cmd_hd;
+	struct nct6694_response_header resp;
+	u16 len = le16_to_cpu(cmd.len);
+	u8 status;
+	int ret;
+
+	guard(mutex)(&hdata->msg_lock);
+
+	/* Wait until the previous command is completed */
+	ret = readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctrl),
+				 status, status == 0, NCT6694_POLL_INTERVAL_US,
+				 NCT6694_POLL_TIMEOUT_US);
+	if (ret)
+		return ret;
+
+	/*
+	 * Write cmd header fields, but skip hctrl — writing to it triggers
+	 * firmware command processing and must be deferred until data is ready.
+	 */
+	memcpy_toio(hdr, &cmd, offsetof(struct nct6694_cmd_header, hctrl));
+	memcpy_toio(hdr + offsetof(struct nct6694_cmd_header, rsv2), &cmd.rsv2,
+		    sizeof(cmd) - offsetof(struct nct6694_cmd_header, rsv2));
+
+	if (hctrl == NCT6694_HCTRL_SET && len)
+		memcpy_toio(hdata->msg_base + offsetof(struct nct6694_msg, data),
+			    buf, len);
+
+	/* Write hctrl last to trigger command processing */
+	writeb(hctrl, hdr + offsetof(struct nct6694_cmd_header, hctrl));
+
+	ret = readb_poll_timeout(hdr + offsetof(struct nct6694_cmd_header, hctrl),
+				 status, status == 0, NCT6694_POLL_INTERVAL_US,
+				 NCT6694_POLL_TIMEOUT_US);
+	if (ret)
+		return ret;
+
+	memcpy_fromio(&resp, hdata->msg_base + offsetof(struct nct6694_msg, response_header),
+		      sizeof(resp));
+
+	ret = nct6694_response_err_handling(nct6694, resp.sts);
+	if (ret)
+		return ret;
+
+	if (le16_to_cpu(resp.len))
+		memcpy_fromio(buf, hdata->msg_base + offsetof(struct nct6694_msg, data),
+			      min(len, le16_to_cpu(resp.len)));
+
+	return 0;
+}
+
+/**
+ * nct6694_hif_read_msg() - Send a command and read response data via HIF
+ * @nct6694: NCT6694 device data
+ * @cmd_hd: command header
+ * @buf: buffer to store response data
+ *
+ * Return: 0 on success or negative errno on failure.
+ */
+static int nct6694_hif_read_msg(struct nct6694 *nct6694,
+				const struct nct6694_cmd_header *cmd_hd,
+				void *buf)
+{
+	struct nct6694_hif_data *hdata = nct6694->priv;
+
+	if (cmd_hd->mod == NCT6694_RPT_MOD)
+		return regmap_bulk_read(hdata->regmap,
+					le16_to_cpu(cmd_hd->offset),
+					buf, le16_to_cpu(cmd_hd->len));
+	return nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_GET, buf);
+}
+
+/**
+ * nct6694_hif_write_msg() - Send a command with data payload via HIF
+ * @nct6694: NCT6694 device data
+ * @cmd_hd: command header
+ * @buf: buffer containing data to send
+ *
+ * Return: 0 on success or negative errno on failure.
+ */
+static int nct6694_hif_write_msg(struct nct6694 *nct6694,
+				 const struct nct6694_cmd_header *cmd_hd,
+				 void *buf)
+{
+	struct nct6694_hif_data *hdata = nct6694->priv;
+
+	if (cmd_hd->mod == NCT6694_RPT_MOD)
+		return regmap_bulk_write(hdata->regmap,
+					 le16_to_cpu(cmd_hd->offset),
+					 buf, le16_to_cpu(cmd_hd->len));
+	return nct6694_xfer_msg(nct6694, cmd_hd, NCT6694_HCTRL_SET, buf);
+}
+
+static const struct regmap_config nct6694_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.reg_stride = 1,
+};
+
+static irqreturn_t nct6694_irq_handler(int irq, void *data)
+{
+	struct nct6694 *nct6694 = data;
+	struct nct6694_hif_data *hdata = nct6694->priv;
+	u8 reg_data[4];
+	u32 intr_status;
+	int ret;
+
+	/* Check interrupt status is set */
+	if (!(inb(hdata->shm_base + NCT6694_SHM_COFS_STS) & NCT6694_SHM_COFS_STS_COFS4W))
+		return IRQ_NONE;
+
+	/* Clear interrupt status */
+	outb(NCT6694_SHM_COFS_STS_COFS4W, hdata->shm_base + NCT6694_SHM_COFS_STS);
+
+	ret = regmap_bulk_read(hdata->regmap, NCT6694_SHM_INTR_STATUS,
+			       reg_data, ARRAY_SIZE(reg_data));
+	if (ret)
+		return IRQ_NONE;
+
+	intr_status = get_unaligned_le32(reg_data);
+
+	while (intr_status) {
+		int irq = __ffs(intr_status);
+
+		generic_handle_irq_safe(irq_find_mapping(nct6694->domain, irq));
+		intr_status &= ~BIT(irq);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static void nct6694_irq_release(void *data)
+{
+	struct nct6694 *nct6694 = data;
+	struct nct6694_hif_data *hdata = nct6694->priv;
+	unsigned char cofs_ctl2;
+
+	/* Disable SIRQ interrupt */
+	cofs_ctl2 = inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+	cofs_ctl2 &= ~NCT6694_SHM_COFS_CTL2_COFS4W_IE;
+	outb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+}
+
+static int nct6694_irq_init(struct nct6694 *nct6694, int irq)
+{
+	struct nct6694_hif_data *hdata = nct6694->priv;
+	struct nct6694_sio_data *sio_data = hdata->sio_data;
+	unsigned char cofs_ctl2;
+
+	/* Set SIRQ number */
+	superio_enter(sio_data);
+	superio_select(sio_data, SIO_REG_LD_SHM);
+	if (!superio_inb(sio_data, SIO_REG_SHM_ENABLE)) {
+		superio_exit(sio_data);
+		return -EIO;
+	}
+	hdata->shm_base = superio_inw(sio_data, SIO_REG_SHM_BASE_ADDR);
+
+	superio_outb(sio_data, SIO_REG_SHM_IRQ_NR, irq);
+
+	superio_exit(sio_data);
+
+	/* Enable SIRQ interrupt */
+	cofs_ctl2 = inb(hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+	cofs_ctl2 |= NCT6694_SHM_COFS_CTL2_COFS4W_IE;
+	outb(cofs_ctl2, hdata->shm_base + NCT6694_SHM_COFS_CTL2);
+
+	return 0;
+}
+
+static void nct6694_irq_enable(struct irq_data *data)
+{
+	struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
+	irq_hw_number_t hwirq = irqd_to_hwirq(data);
+
+	guard(spinlock_irqsave)(&nct6694->irq_lock);
+
+	nct6694->irq_enable |= BIT(hwirq);
+}
+
+static void nct6694_irq_disable(struct irq_data *data)
+{
+	struct nct6694 *nct6694 = irq_data_get_irq_chip_data(data);
+	irq_hw_number_t hwirq = irqd_to_hwirq(data);
+
+	guard(spinlock_irqsave)(&nct6694->irq_lock);
+
+	nct6694->irq_enable &= ~BIT(hwirq);
+}
+
+static const struct irq_chip nct6694_irq_chip = {
+	.name = "nct6694-irq",
+	.flags = IRQCHIP_SKIP_SET_WAKE,
+	.irq_enable = nct6694_irq_enable,
+	.irq_disable = nct6694_irq_disable,
+};
+
+static void nct6694_irq_domain_remove(void *data)
+{
+	struct nct6694 *nct6694 = data;
+
+	irq_domain_remove(nct6694->domain);
+}
+
+static int nct6694_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+	struct nct6694 *nct6694 = d->host_data;
+
+	irq_set_chip_data(irq, nct6694);
+	irq_set_chip_and_handler(irq, &nct6694_irq_chip, handle_simple_irq);
+
+	return 0;
+}
+
+static void nct6694_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
+{
+	irq_set_chip_and_handler(irq, NULL, NULL);
+	irq_set_chip_data(irq, NULL);
+}
+
+static const struct irq_domain_ops nct6694_irq_domain_ops = {
+	.map	= nct6694_irq_domain_map,
+	.unmap	= nct6694_irq_domain_unmap,
+};
+
+static const u8 sio_addrs[] = { 0x2e, 0x4e };
+
+static int nct6694_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct nct6694_sio_data *sio_data;
+	struct nct6694_hif_data *hdata;
+	struct nct6694 *data;
+	void __iomem *rpt_base, *msg_base;
+	int ret, i, irq;
+
+	sio_data = devm_kzalloc(dev, sizeof(*sio_data), GFP_KERNEL);
+	if (!sio_data)
+		return -ENOMEM;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	hdata = devm_kzalloc(dev, sizeof(*hdata), GFP_KERNEL);
+	if (!hdata)
+		return -ENOMEM;
+
+	rpt_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(rpt_base))
+		return PTR_ERR(rpt_base);
+	msg_base = devm_platform_ioremap_resource(pdev, 1);
+	if (IS_ERR(msg_base))
+		return PTR_ERR(msg_base);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	for (i = 0; i < ARRAY_SIZE(sio_addrs); i++) {
+		ret = nct6694_sio_find(sio_data, sio_addrs[i]);
+		if (!ret)
+			break;
+	}
+	if (ret)
+		return ret;
+
+	hdata->sio_data = sio_data;
+	hdata->msg_base = msg_base;
+	hdata->regmap = devm_regmap_init_mmio(dev, rpt_base,
+					      &nct6694_regmap_config);
+	if (IS_ERR(hdata->regmap))
+		return PTR_ERR(hdata->regmap);
+
+	data->dev = dev;
+	data->priv = hdata;
+	data->read_msg = nct6694_hif_read_msg;
+	data->write_msg = nct6694_hif_write_msg;
+
+	spin_lock_init(&data->irq_lock);
+
+	data->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,
+						&nct6694_irq_domain_ops,
+						data);
+	if (!data->domain)
+		return -ENODEV;
+
+	ret = devm_add_action_or_reset(dev, nct6694_irq_domain_remove, data);
+	if (ret)
+		return ret;
+
+	ret = nct6694_irq_init(data, irq);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(dev, nct6694_irq_release, data);
+	if (ret)
+		return ret;
+
+	ret = devm_request_threaded_irq(dev, irq, NULL, nct6694_irq_handler,
+					IRQF_ONESHOT | IRQF_SHARED,
+					dev_name(dev), data);
+	if (ret)
+		return ret;
+
+	ret = devm_mutex_init(dev, &hdata->msg_lock);
+	if (ret)
+		return ret;
+
+	platform_set_drvdata(pdev, data);
+
+	return devm_mfd_add_devices(dev, 0, nct6694_devs, ARRAY_SIZE(nct6694_devs), NULL, 0, NULL);
+}
+
+static const struct acpi_device_id nct6694_acpi_ids[] = {
+	{ "NTN0538", 0 },
+	{}
+};
+
+static struct platform_driver nct6694_driver = {
+	.driver = {
+		.name = DRVNAME,
+		.acpi_match_table = nct6694_acpi_ids,
+	},
+	.probe	= nct6694_probe,
+};
+module_platform_driver(nct6694_driver);
+
+MODULE_DESCRIPTION("Nuvoton NCT6694 host-interface transport driver");
+MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/nct6694.c b/drivers/mfd/nct6694.c
index 8ce2c4985aab..903a0a7f0694 100644
--- a/drivers/mfd/nct6694.c
+++ b/drivers/mfd/nct6694.c
@@ -21,6 +21,27 @@
 #include <linux/spinlock.h>
 #include <linux/usb.h>
 
+#define NCT6694_VENDOR_ID	0x0416
+#define NCT6694_PRODUCT_ID	0x200B
+#define NCT6694_INT_IN_EP	0x81
+#define NCT6694_BULK_IN_EP	0x02
+#define NCT6694_BULK_OUT_EP	0x03
+
+#define NCT6694_URB_TIMEOUT	1000
+
+union __packed nct6694_usb_msg {
+	struct nct6694_cmd_header cmd_header;
+	struct nct6694_response_header response_header;
+};
+
+struct nct6694_usb_data {
+	struct mutex access_lock;
+	struct urb *int_in_urb;
+	struct usb_device *udev;
+	union nct6694_usb_msg *usb_msg;
+	__le32 *int_buffer;
+};
+
 static const struct mfd_cell nct6694_devs[] = {
 	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 0),
 	MFD_CELL_BASIC("nct6694-gpio", NULL, NULL, 0, 1),
@@ -57,7 +78,8 @@ static const struct mfd_cell nct6694_devs[] = {
 	MFD_CELL_NAME("nct6694-rtc"),
 };
 
-static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char err_status)
+static int nct6694_usb_err_handling(struct nct6694 *nct6694,
+				    unsigned char err_status)
 {
 	switch (err_status) {
 	case NCT6694_NO_ERROR:
@@ -82,7 +104,7 @@ static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char
 }
 
 /**
- * nct6694_read_msg() - Read message from NCT6694 device
+ * nct6694_usb_read_msg() - Read message from NCT6694 device via USB
  * @nct6694: NCT6694 device pointer
  * @cmd_hd: command header structure
  * @buf: buffer to store the response data
@@ -93,13 +115,16 @@ static int nct6694_response_err_handling(struct nct6694 *nct6694, unsigned char
  *
  * Return: Negative value on error or 0 on success.
  */
-int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf)
+static int nct6694_usb_read_msg(struct nct6694 *nct6694,
+				const struct nct6694_cmd_header *cmd_hd,
+				void *buf)
 {
-	union nct6694_usb_msg *msg = nct6694->usb_msg;
-	struct usb_device *udev = nct6694->udev;
+	struct nct6694_usb_data *udata = nct6694->priv;
+	union nct6694_usb_msg *msg = udata->usb_msg;
+	struct usb_device *udev = udata->udev;
 	int tx_len, rx_len, ret;
 
-	guard(mutex)(&nct6694->access_lock);
+	guard(mutex)(&udata->access_lock);
 
 	memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd));
 	msg->cmd_header.hctrl = NCT6694_HCTRL_GET;
@@ -128,12 +153,11 @@ int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *c
 		return -EIO;
 	}
 
-	return nct6694_response_err_handling(nct6694, msg->response_header.sts);
+	return nct6694_usb_err_handling(nct6694, msg->response_header.sts);
 }
-EXPORT_SYMBOL_GPL(nct6694_read_msg);
 
 /**
- * nct6694_write_msg() - Write message to NCT6694 device
+ * nct6694_usb_write_msg() - Write message to NCT6694 device via USB
  * @nct6694: NCT6694 device pointer
  * @cmd_hd: command header structure
  * @buf: buffer containing the data to be sent
@@ -143,13 +167,16 @@ EXPORT_SYMBOL_GPL(nct6694_read_msg);
  *
  * Return: Negative value on error or 0 on success.
  */
-int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf)
+static int nct6694_usb_write_msg(struct nct6694 *nct6694,
+				 const struct nct6694_cmd_header *cmd_hd,
+				 void *buf)
 {
-	union nct6694_usb_msg *msg = nct6694->usb_msg;
-	struct usb_device *udev = nct6694->udev;
+	struct nct6694_usb_data *udata = nct6694->priv;
+	union nct6694_usb_msg *msg = udata->usb_msg;
+	struct usb_device *udev = udata->udev;
 	int tx_len, rx_len, ret;
 
-	guard(mutex)(&nct6694->access_lock);
+	guard(mutex)(&udata->access_lock);
 
 	memcpy(&msg->cmd_header, cmd_hd, sizeof(*cmd_hd));
 	msg->cmd_header.hctrl = NCT6694_HCTRL_SET;
@@ -184,9 +211,8 @@ int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *
 		return -EIO;
 	}
 
-	return nct6694_response_err_handling(nct6694, msg->response_header.sts);
+	return nct6694_usb_err_handling(nct6694, msg->response_header.sts);
 }
-EXPORT_SYMBOL_GPL(nct6694_write_msg);
 
 static void usb_int_callback(struct urb *urb)
 {
@@ -276,6 +302,7 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 	struct usb_endpoint_descriptor *int_endpoint;
 	struct usb_host_interface *interface;
 	struct device *dev = &iface->dev;
+	struct nct6694_usb_data *udata;
 	struct nct6694 *nct6694;
 	int ret;
 
@@ -283,18 +310,28 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 	if (!nct6694)
 		return -ENOMEM;
 
-	nct6694->usb_msg = devm_kzalloc(dev, sizeof(union nct6694_usb_msg), GFP_KERNEL);
-	if (!nct6694->usb_msg)
+	udata = devm_kzalloc(dev, sizeof(*udata), GFP_KERNEL);
+	if (!udata)
+		return -ENOMEM;
+
+	udata->usb_msg = devm_kzalloc(dev, sizeof(*udata->usb_msg), GFP_KERNEL);
+	if (!udata->usb_msg)
 		return -ENOMEM;
 
-	nct6694->int_buffer = devm_kzalloc(dev, sizeof(*nct6694->int_buffer), GFP_KERNEL);
-	if (!nct6694->int_buffer)
+	udata->int_buffer = devm_kzalloc(dev, sizeof(*udata->int_buffer), GFP_KERNEL);
+	if (!udata->int_buffer)
 		return -ENOMEM;
 
-	nct6694->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!nct6694->int_in_urb)
+	udata->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+	if (!udata->int_in_urb)
 		return -ENOMEM;
 
+	udata->udev = udev;
+
+	nct6694->priv = udata;
+	nct6694->read_msg = nct6694_usb_read_msg;
+	nct6694->write_msg = nct6694_usb_write_msg;
+
 	nct6694->domain = irq_domain_create_simple(NULL, NCT6694_NR_IRQS, 0,
 						   &nct6694_irq_domain_ops,
 						   nct6694);
@@ -304,11 +341,10 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 	}
 
 	nct6694->dev = dev;
-	nct6694->udev = udev;
 
 	spin_lock_init(&nct6694->irq_lock);
 
-	ret = devm_mutex_init(dev, &nct6694->access_lock);
+	ret = devm_mutex_init(dev, &udata->access_lock);
 	if (ret)
 		goto err_irq_domain;
 
@@ -320,11 +356,11 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 		goto err_irq_domain;
 	}
 
-	usb_fill_int_urb(nct6694->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
-			 nct6694->int_buffer, sizeof(*nct6694->int_buffer), usb_int_callback,
+	usb_fill_int_urb(udata->int_in_urb, udev, usb_rcvintpipe(udev, NCT6694_INT_IN_EP),
+			 udata->int_buffer, sizeof(*udata->int_buffer), usb_int_callback,
 			 nct6694, int_endpoint->bInterval);
 
-	ret = usb_submit_urb(nct6694->int_in_urb, GFP_KERNEL);
+	ret = usb_submit_urb(udata->int_in_urb, GFP_KERNEL);
 	if (ret)
 		goto err_irq_domain;
 
@@ -337,21 +373,22 @@ static int nct6694_usb_probe(struct usb_interface *iface,
 	return 0;
 
 err_mfd:
-	usb_kill_urb(nct6694->int_in_urb);
+	usb_kill_urb(udata->int_in_urb);
 err_irq_domain:
 	irq_domain_remove(nct6694->domain);
 err_urb:
-	usb_free_urb(nct6694->int_in_urb);
+	usb_free_urb(udata->int_in_urb);
 	return ret;
 }
 
 static void nct6694_usb_disconnect(struct usb_interface *iface)
 {
 	struct nct6694 *nct6694 = usb_get_intfdata(iface);
+	struct nct6694_usb_data *udata = nct6694->priv;
 
-	usb_kill_urb(nct6694->int_in_urb);
+	usb_kill_urb(udata->int_in_urb);
 	irq_domain_remove(nct6694->domain);
-	usb_free_urb(nct6694->int_in_urb);
+	usb_free_urb(udata->int_in_urb);
 }
 
 static const struct usb_device_id nct6694_ids[] = {
diff --git a/drivers/net/can/usb/nct6694_canfd.c b/drivers/net/can/usb/nct6694_canfd.c
index 29282c56430f..05db00455f63 100644
--- a/drivers/net/can/usb/nct6694_canfd.c
+++ b/drivers/net/can/usb/nct6694_canfd.c
@@ -17,12 +17,6 @@
 
 #define DEVICE_NAME "nct6694-canfd"
 
-/* USB command module type for NCT6694 CANfd controller.
- * This defines the module type used for communication with the NCT6694
- * CANfd controller over the USB interface.
- */
-#define NCT6694_CANFD_MOD			0x05
-
 /* Command 00h - CAN Setting and Initialization */
 #define NCT6694_CANFD_SETTING			0x00
 #define NCT6694_CANFD_SETTING_ACTIVE_CTRL1	BIT(0)
diff --git a/drivers/rtc/rtc-nct6694.c b/drivers/rtc/rtc-nct6694.c
index 35401a0d9cf5..c06902f150c9 100644
--- a/drivers/rtc/rtc-nct6694.c
+++ b/drivers/rtc/rtc-nct6694.c
@@ -14,13 +14,6 @@
 #include <linux/rtc.h>
 #include <linux/slab.h>
 
-/*
- * USB command module type for NCT6694 RTC controller.
- * This defines the module type used for communication with the NCT6694
- * RTC controller over the USB interface.
- */
-#define NCT6694_RTC_MOD		0x08
-
 /* Command 00h - RTC Time */
 #define NCT6694_RTC_TIME	0x0000
 #define NCT6694_RTC_TIME_SEL	0x00
diff --git a/drivers/watchdog/nct6694_wdt.c b/drivers/watchdog/nct6694_wdt.c
index 2b4b804a1739..847d8f1d1830 100644
--- a/drivers/watchdog/nct6694_wdt.c
+++ b/drivers/watchdog/nct6694_wdt.c
@@ -19,13 +19,6 @@
 
 #define NCT6694_WDT_MAX_DEVS		2
 
-/*
- * USB command module type for NCT6694 WDT controller.
- * This defines the module type used for communication with the NCT6694
- * WDT controller over the USB interface.
- */
-#define NCT6694_WDT_MOD			0x07
-
 /* Command 00h - WDT Setup */
 #define NCT6694_WDT_SETUP		0x00
 #define NCT6694_WDT_SETUP_SEL(idx)	(idx ? 0x01 : 0x00)
diff --git a/include/linux/mfd/nct6694.h b/include/linux/mfd/nct6694.h
index 496da72949d9..ff0814dc82d4 100644
--- a/include/linux/mfd/nct6694.h
+++ b/include/linux/mfd/nct6694.h
@@ -2,7 +2,8 @@
 /*
  * Copyright (C) 2025 Nuvoton Technology Corp.
  *
- * Nuvoton NCT6694 USB transaction and data structure.
+ * Nuvoton NCT6694 core definitions shared by all transport drivers
+ * and sub-device drivers.
  */
 
 #ifndef __MFD_NCT6694_H
@@ -12,16 +13,17 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 
-#define NCT6694_VENDOR_ID	0x0416
-#define NCT6694_PRODUCT_ID	0x200B
-#define NCT6694_INT_IN_EP	0x81
-#define NCT6694_BULK_IN_EP	0x02
-#define NCT6694_BULK_OUT_EP	0x03
-
 #define NCT6694_HCTRL_SET	0x40
 #define NCT6694_HCTRL_GET	0x80
 
-#define NCT6694_URB_TIMEOUT	1000
+#define NCT6694_HWMON_MOD	0x00
+#define NCT6694_PWM_MOD		0x01
+#define NCT6694_I2C_MOD		0x03
+#define NCT6694_CANFD_MOD	0x05
+#define NCT6694_WDT_MOD		0x07
+#define NCT6694_RTC_MOD		0x08
+#define NCT6694_RPT_MOD		0xFF
+#define NCT6694_GPIO_MOD	NCT6694_RPT_MOD
 
 enum nct6694_irq_id {
 	NCT6694_IRQ_GPIO0 = 0,
@@ -79,24 +81,33 @@ struct __packed nct6694_response_header {
 	__le16 len;
 };
 
-union __packed nct6694_usb_msg {
-	struct nct6694_cmd_header cmd_header;
-	struct nct6694_response_header response_header;
-};
-
 struct nct6694 {
 	struct device *dev;
 	struct irq_domain *domain;
-	struct mutex access_lock;
 	spinlock_t irq_lock;
-	struct urb *int_in_urb;
-	struct usb_device *udev;
-	union nct6694_usb_msg *usb_msg;
-	__le32 *int_buffer;
 	unsigned int irq_enable;
+
+	void *priv;
+	int (*read_msg)(struct nct6694 *nct6694,
+			const struct nct6694_cmd_header *cmd_hd,
+			void *buf);
+	int (*write_msg)(struct nct6694 *nct6694,
+			 const struct nct6694_cmd_header *cmd_hd,
+			 void *buf);
 };
 
-int nct6694_read_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf);
-int nct6694_write_msg(struct nct6694 *nct6694, const struct nct6694_cmd_header *cmd_hd, void *buf);
+static inline int nct6694_read_msg(struct nct6694 *nct6694,
+				   const struct nct6694_cmd_header *cmd_hd,
+				   void *buf)
+{
+	return nct6694->read_msg(nct6694, cmd_hd, buf);
+}
+
+static inline int nct6694_write_msg(struct nct6694 *nct6694,
+				    const struct nct6694_cmd_header *cmd_hd,
+				    void *buf)
+{
+	return nct6694->write_msg(nct6694, cmd_hd, buf);
+}
 
 #endif
-- 
2.34.1


^ permalink raw reply related

* USB4v2 BAR resizing problems - hotplug gpu via razor tb5 dock - Intel Barlow Ridge
From: Geramy Loveless @ 2026-04-08  5:32 UTC (permalink / raw)
  To: linux-usb; +Cc: linux-pci

Hello,

I am hoping someone here can help me; I'm currently having some issues
with a Razor thunderbolt 5 / USB4v2 Dock connected to a Halo Strix or
AMD Ryzen AI 395+ Max machine.
Specifically a Minisforum MS-S1 with a Host controller: Intel
8086:5780 — Barlow Ridge Host 80G (rev 84) and the Dock hub: Intel
8086:5786 — Barlow Ridge Hub 80G (rev 85) These are the JHL9580 (host)
and JHL9586 (hub) — Intel's Barlow Ridge TB5 80Gbps silicon.
The specific problem I'm having, which I think is the largest issue
besides power management causing havoc which i can fix with kernel
parameters but the one I cannot "fix" granted not kernel params are
not a fix is that on thunderbolt driver it will not expand its bar
size to the parent size.
so when setting hpmmiopresize to 64G it gets split between the two
usb4v2 ports giving me 32G on each port and then the memory space is
not aligned so when amdgpu tries to resize it cant. I would think the
ideal situation at least in my head and not being a linux kernel
expert is that the thunderbolt driver should request the pcie device
max memory size and then create the bar at the correct sizes or at the
least let me resize it which might be a difficult and bad path to let
the "user" resize it.

Current kernel image is: 6.18.7-061807-generic

Custom Parameters:
 pcie_port_pm=off pcie_aspm=off
pci=hpmemsize=2G,realloc,hpmmioprefsize=64G amdgpu.dc=0

This was required to get the kernel to stop powering down the
thunderbolt link on the amd gfx1201 device because it goes into a low
power state when there is no display connected.
For my application thats okay, i'm using it for compute based workloads anyways.

Thank you for taking a look at this here are some log snippets have a great day!

Here is my amdgpu issue with full logs
https://gitlab.freedesktop.org/drm/amd/-/work_items/4978#note_3339645

Here are more recent logs after running the kernel parameters.

System: MinisForum MS-S1 (AMD Ryzen AI 395+ Max / Strix Halo) + Razer
Core X V2 via Intel Barlow Ridge TB5 (JHL9580/JHL9586)
GPU: AMD Radeon AI PRO R9700 [1002:7551] (RDNA 4 / gfx1201, 32GB GDDR6)
Kernel: 6.18.7 (Ubuntu mainline)
Cmdline: pcie_port_pm=off pcie_aspm=off
pci=hpmemsize=2G,realloc,hpmmioprefsize=64G amdgpu.dc=0

--- Boot-time TB5 bridge layout (host-side, before tunnel) ---
pci 0000:65:00.0: [8086:5780] type 01 class 0x060400 PCIe Switch Upstream Port
pci 0000:65:00.0: PCI bridge to [bus 66-bc]
pci 0000:65:00.0:   bridge window [mem 0x8880000000-0x98800fffff 64bit pref]
pci 0000:66:01.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:66:01.0: PCI bridge to [bus 68-91]
pci 0000:66:01.0:   bridge window [mem 0x9080000000-0x987fffffff 64bit pref]
pci 0000:66:03.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:66:03.0: PCI bridge to [bus 93-bc]
pci 0000:66:03.0:   bridge window [mem 0x8880000000-0x907fffffff 64bit pref]

--- Dock hot-plug enumeration (after TB tunnel up + PCI rescan) ---
pci 0000:93:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Upstream Port
pci 0000:93:00.0: PCI bridge to [bus 00]
pci 0000:93:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]
pci 0000:93:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
pci 0000:94:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:94:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]

--- Kernel resource allocation: cannot fit rebar + hotplug reserves ---
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x1000000000 required for 0000:94:01.0 bridging to [bus 98-a4]
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x1000000000 required for 0000:94:02.0 bridging to [bus a5-b1]
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x1000000000 required for 0000:94:03.0 bridging to [bus b2-bc]
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x3018000000 required for 0000:93:00.0 bridging to [bus 94-bc]
pci 0000:93:00.0: bridge window [mem 0x04000000-0x1fffffff 64bit pref]
to [bus 94-bc] requires relaxed alignment rules
pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
can't assign; no space
pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
failed to assign
pci 0000:93:00.0: bridge window [mem 0x8880000000-0x889bffffff 64bit
pref]: assigned

--- GPU BAR enumeration ---
pci 0000:97:00.0: [1002:7551] type 00 class 0x030000 PCIe Legacy Endpoint
pci 0000:97:00.0: BAR 0 [mem 0x00000000-0x0fffffff 64bit pref]
pci 0000:97:00.0: 8.000 Gb/s available PCIe bandwidth, limited by 2.5
GT/s PCIe x4 link at 0000:66:03.0 (capable of 504.112 Gb/s with 32.0
GT/s PCIe x16 link)
pci 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
pci 0000:97:00.0: BAR 4 [io  size 0x0100]: can't assign; no space

--- amdgpu rebar attempt and failure ---
amdgpu 0000:97:00.0: amdgpu: PCIE atomic ops is not supported
amdgpu 0000:97:00.0: BAR 2 [mem 0x8890000000-0x88901fffff 64bit pref]: releasing
amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: releasing
amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: can't
assign; no space
amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: failed to assign
amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: can't
assign; no space
amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: failed to assign
amdgpu 0000:97:00.0: amdgpu: Not enough PCI address space for a large BAR.
amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
amdgpu 0000:97:00.0: amdgpu: VRAM: 32624M 0x0000008000000000 -
0x00000087F6FFFFFF (32624M used)

System: MinisForum MS-S1 (AMD Ryzen AI 395+ Max / Strix Halo) + Razer
Core X V2 via Intel Barlow Ridge TB5 (JHL9580/JHL9586)
GPU: AMD Radeon AI PRO R9700 [1002:7551] (RDNA 4 / gfx1201, 32GB GDDR6)
Kernel: 6.18.7 (Ubuntu mainline)
Cmdline: pcie_port_pm=off pcie_aspm=off
pci=hpmemsize=2G,realloc,hpmmioprefsize=64G amdgpu.dc=0

--- Boot-time TB5 bridge layout (host-side, before tunnel) ---
pci 0000:65:00.0: [8086:5780] type 01 class 0x060400 PCIe Switch Upstream Port
pci 0000:65:00.0: PCI bridge to [bus 66-bc]
pci 0000:65:00.0:   bridge window [mem 0x8880000000-0x98800fffff 64bit pref]
pci 0000:66:01.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:66:01.0: PCI bridge to [bus 68-91]
pci 0000:66:01.0:   bridge window [mem 0x9080000000-0x987fffffff 64bit pref]
pci 0000:66:03.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:66:03.0: PCI bridge to [bus 93-bc]
pci 0000:66:03.0:   bridge window [mem 0x8880000000-0x907fffffff 64bit pref]

--- Dock hot-plug enumeration (after TB tunnel up + PCI rescan) ---
pci 0000:93:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Upstream Port
pci 0000:93:00.0: PCI bridge to [bus 00]
pci 0000:93:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]
pci 0000:93:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
pci 0000:94:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Downstream Port
pci 0000:94:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]

--- Kernel resource allocation: cannot fit rebar + hotplug reserves ---
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x1000000000 required for 0000:94:01.0 bridging to [bus 98-a4]
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x1000000000 required for 0000:94:02.0 bridging to [bus a5-b1]
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x1000000000 required for 0000:94:03.0 bridging to [bus b2-bc]
pcieport 0000:66:03.0: Assigned bridge window [mem
0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
0x3018000000 required for 0000:93:00.0 bridging to [bus 94-bc]
pci 0000:93:00.0: bridge window [mem 0x04000000-0x1fffffff 64bit pref]
to [bus 94-bc] requires relaxed alignment rules
pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
can't assign; no space
pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
failed to assign
pci 0000:93:00.0: bridge window [mem 0x8880000000-0x889bffffff 64bit
pref]: assigned

--- GPU BAR enumeration ---
pci 0000:97:00.0: [1002:7551] type 00 class 0x030000 PCIe Legacy Endpoint
pci 0000:97:00.0: BAR 0 [mem 0x00000000-0x0fffffff 64bit pref]
pci 0000:97:00.0: 8.000 Gb/s available PCIe bandwidth, limited by 2.5
GT/s PCIe x4 link at 0000:66:03.0 (capable of 504.112 Gb/s with 32.0
GT/s PCIe x16 link)
pci 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
pci 0000:97:00.0: BAR 4 [io  size 0x0100]: can't assign; no space

--- amdgpu rebar attempt and failure ---
amdgpu 0000:97:00.0: amdgpu: PCIE atomic ops is not supported
amdgpu 0000:97:00.0: BAR 2 [mem 0x8890000000-0x88901fffff 64bit pref]: releasing
amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: releasing
amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: can't
assign; no space
amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: failed to assign
amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: can't
assign; no space
amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: failed to assign
amdgpu 0000:97:00.0: amdgpu: Not enough PCI address space for a large BAR.
amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
amdgpu 0000:97:00.0: amdgpu: VRAM: 32624M 0x0000008000000000 -
0x00000087F6FFFFFF (32624M used)



Geramy L. Loveless

^ permalink raw reply

* Re: [PATCH v2 2/3] usb: chipidea: core: allow ci_irq_handler() handle both ID and VBUS change
From: Peter Chen (CIX) @ 2026-04-08  5:39 UTC (permalink / raw)
  To: Xu Yang; +Cc: gregkh, jun.li, linux-usb, linux-kernel, imx
In-Reply-To: <20260402071457.2516021-2-xu.yang_2@nxp.com>

On 26-04-02 15:14:56, Xu Yang wrote:
> For USB role switch-triggered IRQ, ID and VBUS change come together, for
> example when switching from host to device mode. ID indicate a role switch
> and VBUS is required to determine whether the device controller can start
> operating. Currently, ci_irq_handler() handles only a single event per
> invocation. This can cause an issue where switching to device mode results
> in the device controller not working at all. Allowing ci_irq_handler() to
> handle both ID and VBUS change in one call resolves this issue.
> 
> Meanwhile, this change also affects the VBUS event handling logic.
> Previously, if an ID event indicated host mode the VBUS IRQ will be
> ignored as the device disable BSE when stop() is called. With the new
> behavior, if ID and VBUS IRQ occur together and the target mode is host,
> the VBUS event is queued and ci_handle_vbus_change() will call
> usb_gadget_vbus_connect(), after which USBMODE is switched to device mode,
> causing host mode to stop working. To prevent this, an additional check is
> added to skip handling VBUS event when current role is not device mode.
> 
> Suggested-by: Peter Chen <peter.chen@kernel.org>
> Fixes: e1b5d2bed67c ("usb: chipidea: core: handle usb role switch in a common way")
> Cc: stable@vger.kernel.org
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
> 
> ---
> Changes in v2:
>  - change ci_irq_handler() instead of assign id_event/b_sess_valid_event
>    as true and queue otg work directly
> ---
>  drivers/usb/chipidea/core.c | 45 +++++++++++++++++++------------------
>  drivers/usb/chipidea/otg.c  |  3 +++
>  2 files changed, 26 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> index 87be716dff3e..7cfabb04a4fb 100644
> --- a/drivers/usb/chipidea/core.c
> +++ b/drivers/usb/chipidea/core.c
> @@ -544,30 +544,31 @@ static irqreturn_t ci_irq_handler(int irq, void *data)
>  			if (ret == IRQ_HANDLED)
>  				return ret;
>  		}
> -	}
>  
> -	/*
> -	 * Handle id change interrupt, it indicates device/host function
> -	 * switch.
> -	 */
> -	if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
> -		ci->id_event = true;
> -		/* Clear ID change irq status */
> -		hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
> -		ci_otg_queue_work(ci);
> -		return IRQ_HANDLED;
> -	}
> +		/*
> +		 * Handle id change interrupt, it indicates device/host function
> +		 * switch.
> +		 */
> +		if ((otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
> +			ci->id_event = true;
> +			/* Clear ID change irq status */
> +			hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS);
> +		}
>  
> -	/*
> -	 * Handle vbus change interrupt, it indicates device connection
> -	 * and disconnection events.
> -	 */
> -	if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
> -		ci->b_sess_valid_event = true;
> -		/* Clear BSV irq */
> -		hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
> -		ci_otg_queue_work(ci);
> -		return IRQ_HANDLED;
> +		/*
> +		 * Handle vbus change interrupt, it indicates device connection
> +		 * and disconnection events.
> +		 */
> +		if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
> +			ci->b_sess_valid_event = true;
> +			/* Clear BSV irq */
> +			hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS);
> +		}
> +
> +		if (ci->id_event || ci->b_sess_valid_event) {
> +			ci_otg_queue_work(ci);
> +			return IRQ_HANDLED;
> +		}
>  	}
>  
>  	/* Handle device/host interrupt */
> diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
> index 647e98f4e351..def933b73a90 100644
> --- a/drivers/usb/chipidea/otg.c
> +++ b/drivers/usb/chipidea/otg.c
> @@ -130,6 +130,9 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)
>  
>  void ci_handle_vbus_change(struct ci_hdrc *ci)
>  {
> +	if (ci->role != CI_ROLE_GADGET)
> +		return;
> +

Are there the situations that the ci->role is not CI_ROLE_GADGET, but
it needs to handle VBUS? Eg, ci->role is CI_ROLE_NONE, and VBUS event
occurs?

-- 

Best regards,
Peter

^ permalink raw reply

* Re: [PATCH v2 1/2] mfd: nct6694: Switch to devm_mfd_add_devices() and drop IDA
From: Bartosz Golaszewski @ 2026-04-08  7:25 UTC (permalink / raw)
  To: a0282524688
  Cc: tmyu0, linusw, linux, andi.shyti, lee, mkl, mailhol,
	alexandre.belloni, wim, linux-kernel, linux-gpio, linux-i2c,
	linux-can, netdev, linux-watchdog, linux-hwmon, linux-rtc,
	linux-usb
In-Reply-To: <20260408053037.1867092-2-a0282524688@gmail.com>

On Wed, Apr 8, 2026 at 7:31 AM <a0282524688@gmail.com> wrote:
>
> From: Ming Yu <a0282524688@gmail.com>
>
> Currently, the nct6694 core driver uses mfd_add_hotplug_devices()
> and an IDA to manage subdevice IDs.
>
> Switch the core implementation to use the managed
> devm_mfd_add_devices() API, which simplifies the error handling and
> device lifecycle management. Concurrently, drop the custom IDA
> implementation and transition to using pdev->id.
>
> Signed-off-by: Ming Yu <a0282524688@gmail.com>
> ---

This does result in a nice code shrink but I'd split this commit into
two: one switching to using MFD_CELL_BASIC() with hard-coded devices
IDs and one completing the transition to devres.

Bart

^ permalink raw reply

* Re: [PATCH] USB: serial: iuu_phoenix: fix iuutool author name
From: Johan Hovold @ 2026-04-08  7:40 UTC (permalink / raw)
  To: Thorsten Blum; +Cc: Greg Kroah-Hartman, linux-usb, linux-kernel
In-Reply-To: <20260407192342.1054359-3-thorsten.blum@linux.dev>

On Tue, Apr 07, 2026 at 09:23:43PM +0200, Thorsten Blum wrote:
> The original iuutool author is Juan Carlos Borrás - fix the spelling.
> 
> Signed-off-by: Thorsten Blum <thorsten.blum@linux.dev>
> ---
> https://github.com/jcborras/iuutool/blob/master/AUTHORS

Applied, thanks.

Johan

^ permalink raw reply

* Re: [PATCH v1] dt-bindings: usb: Fix EIC7700 USB reset's issue
From: Krzysztof Kozlowski @ 2026-04-08  7:48 UTC (permalink / raw)
  To: caohang
  Cc: gregkh, robh, krzk+dt, conor+dt, Thinh.Nguyen, p.zabel,
	linux-kernel, linux-usb, devicetree, ningyu, linmin,
	pinkesh.vaghela
In-Reply-To: <20260407061703.1564-1-caohang@eswincomputing.com>

On Tue, Apr 07, 2026 at 02:17:02PM +0800, caohang@eswincomputing.com wrote:
> From: Hang Cao <caohang@eswincomputing.com>
> 
> The EIC7700 USB controller requires a USB PHY RESET operation.PHY RESET

Missing space after full stop.

> operation was missed in the verification version, as it was performed in
> ESWIN's U-Boot.
> 
> If a non-ESWIN provided loader is used, this issue will occur, resulting
> in USB not work.This patch does not introduce any backward incompatibility
> since the dts is not upstream yet.

So U-Boot will be affected, no?

And even if DTS is not upstreamed, what about all out of tree DTS?
This is an already released ABI, so at least explain that driver does
not care about resets here and grabs them all.

> 
> Fixes: c640a4239db5 ("dt-bindings: usb: Add ESWIN EIC7700 USB controller")


Best regards,
Krzysztof


^ permalink raw reply

* Re: [PATCH] usb: rtl8150: avoid using uninitialized CSCR value
From: Morduan Zang @ 2026-04-08  8:18 UTC (permalink / raw)
  To: horms
  Cc: andrew+netdev, davem, edumazet, kuba, linux-kernel, linux-usb,
	netdev, pabeni, petkan, syzbot+9db6c624635564ad813c, zhangdandan
In-Reply-To: <20260403154538.GA187715@horms.kernel.org>

> I wonder if we can handle this a bit more succinctly,
> while still making it clear that the error is handled.
> Something like this:
> 
> diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c
> index 4cda0643afb6..816759ced56c 100644
> --- a/drivers/net/usb/rtl8150.c
> +++ b/drivers/net/usb/rtl8150.c
> @@ -722,7 +722,8 @@ static void set_carrier(struct net_device *netdev)
>   rtl8150_t *dev = netdev_priv(netdev);
>   short tmp;
>  
> - get_registers(dev, CSCR, 2, &tmp);
> + if (get_registers(dev, CSCR, 2, &tmp) < 0)
> + tmp = 0;
>   if (tmp & CSCR_LINK_STATUS)
>   netif_carrier_on(netdev);
>   else
Thanks for your suggestion.
I agree that errors should be handled explicitly, but I prefer not to force the carrier off
when CSCR read fails. The control transfer error here may be transient, and treating it
as a link break would cause the carrier state to toggle frequently.
Therefore, if the get_registers() call fails, should we keep the previous carrier state and
return directly? (Perhaps with a rate-limited warning as an option), while still avoiding
the use of uninitialized stack values.

If agreed, I will send a v2 incorporating the suggestions. 
 

^ permalink raw reply

* Re: [PATCH] usb: rtl8150: avoid using uninitialized CSCR value
From: Michal Pecio @ 2026-04-08  8:33 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: Petko Manolov, Simon Horman, Morduan Zang, Andrew Lunn,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	linux-usb, netdev, linux-kernel, syzbot+9db6c624635564ad813c
In-Reply-To: <76d6b341-27d5-44aa-92fb-3b8966d609df@lunn.ch>

On Mon, 6 Apr 2026 01:38:06 +0200, Andrew Lunn wrote:
> > > -	get_registers(dev, CSCR, 2, &tmp);
> > > +	if (get_registers(dev, CSCR, 2, &tmp) < 0)
> > > +		tmp = 0;
> > >  	if (tmp & CSCR_LINK_STATUS)
> > >  		netif_carrier_on(netdev);
> > >  	else  
> > 
> > I was wondering if calling netif_carrier_off() is the right thing
> > to do in case get_registers() fail.
> > 
> > There are multiple get_registers() calls that don't check the error
> > and if we do this in set_carrier() maybe we should do the same
> > thing across the whole driver?  
> 
> What does it actually mean if get_registers() fails? The device is
> gone? Hot unplugged? If so, you are going to get a cascade of errors,
> and then hopefully the USB core code removes the device?
> 
> Are there any legitimate reasons for get_registers() to fail if the
> device is still plugged in?

In principle it might be temporary EMI or a flaky cable. These errors
rarely reach drivers due to retries in USB layer, but in extreme cases
the device may be in unknown state and it may become functional later.
IIRC net layer has some operations which are presumed trivial enough
that they would never fail, so this could be annoying.

It does seem rare enough in practice that for 25 years nobody noticed
carrier status being set to a random vaule by this driver.

BTW, some functions like rtl8150_reset() pre-set data to a value which
will be safe in case of get_register() failure. But here, unhandled
set_register() error is dodgy - the 0x10 bit may never turn on.

Regards,
Michal

^ permalink raw reply

* Re: USB4v2 BAR resizing problems - hotplug gpu via razor tb5 dock - Intel Barlow Ridge
From: Ilpo Järvinen @ 2026-04-08  9:09 UTC (permalink / raw)
  To: Geramy Loveless; +Cc: linux-usb, linux-pci
In-Reply-To: <CAGpo2me5irs2znVr+dnbtNPsNPiDBqKtKSn3r6D6K5-WWEPj0g@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 13106 bytes --]

On Tue, 7 Apr 2026, Geramy Loveless wrote:

> I am hoping someone here can help me; I'm currently having some issues
> with a Razor thunderbolt 5 / USB4v2 Dock connected to a Halo Strix or
> AMD Ryzen AI 395+ Max machine.
> Specifically a Minisforum MS-S1 with a Host controller: Intel
> 8086:5780 — Barlow Ridge Host 80G (rev 84) and the Dock hub: Intel
> 8086:5786 — Barlow Ridge Hub 80G (rev 85) These are the JHL9580 (host)
> and JHL9586 (hub) — Intel's Barlow Ridge TB5 80Gbps silicon.
> The specific problem I'm having, which I think is the largest issue
> besides power management causing havoc which i can fix with kernel
> parameters but the one I cannot "fix" granted not kernel params are
> not a fix is that on thunderbolt driver it will not expand its bar
> size to the parent size.
> so when setting hpmmiopresize to 64G it gets split between the two
> usb4v2 ports giving me 32G on each port and then the memory space is
> not aligned so when amdgpu tries to resize it cant. I would think the
> ideal situation at least in my head and not being a linux kernel
> expert is that the thunderbolt driver should request the pcie device
> max memory size and then create the bar at the correct sizes or at the
> least let me resize it which might be a difficult and bad path to let
> the "user" resize it.
> 
> Current kernel image is: 6.18.7-061807-generic

Hi,

There have been significant improvements to the kernel's resource fitting 
strategy since that kernel, some of the most recent improvements are not 
yet even in Linus' tree but only in pci/resource branch slated for 7.1.

There's one fix in particular related to how hotplug memory distribution 
is handled that might be relevant here but I cannot say for sure because 
it only print a log line with dynamic debugging enabled 
(CONFIG_DYNAMIC_DEBUG=y + dyndbg="file drivers/pci/*.c +p" on kernel 
command line).

> Custom Parameters:
>  pcie_port_pm=off pcie_aspm=off
> pci=hpmemsize=2G,realloc,hpmmioprefsize=64G amdgpu.dc=0

The effect of these size parameterd may get nullified because of that bug
I mentioned.

> This was required to get the kernel to stop powering down the
> thunderbolt link on the amd gfx1201 device because it goes into a low
> power state when there is no display connected.
> For my application thats okay, i'm using it for compute based workloads anyways.
> 
> Thank you for taking a look at this here are some log snippets have a great day!

> Here is my amdgpu issue with full logs
> https://gitlab.freedesktop.org/drm/amd/-/work_items/4978#note_3339645

This is not a full log but starts in the middle.

You should pass log_buf_len=16M to kernel command line capture it from 
start.

It would also help if you capture /proc/iomem dump.

> Here are more recent logs after running the kernel parameters.
> 
> System: MinisForum MS-S1 (AMD Ryzen AI 395+ Max / Strix Halo) + Razer
> Core X V2 via Intel Barlow Ridge TB5 (JHL9580/JHL9586)
> GPU: AMD Radeon AI PRO R9700 [1002:7551] (RDNA 4 / gfx1201, 32GB GDDR6)
> Kernel: 6.18.7 (Ubuntu mainline)
> Cmdline: pcie_port_pm=off pcie_aspm=off
> pci=hpmemsize=2G,realloc,hpmmioprefsize=64G amdgpu.dc=0
> 
> --- Boot-time TB5 bridge layout (host-side, before tunnel) ---
> pci 0000:65:00.0: [8086:5780] type 01 class 0x060400 PCIe Switch Upstream Port
> pci 0000:65:00.0: PCI bridge to [bus 66-bc]
> pci 0000:65:00.0:   bridge window [mem 0x8880000000-0x98800fffff 64bit pref]
> pci 0000:66:01.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
> pci 0000:66:01.0: PCI bridge to [bus 68-91]
> pci 0000:66:01.0:   bridge window [mem 0x9080000000-0x987fffffff 64bit pref]
> pci 0000:66:03.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
> pci 0000:66:03.0: PCI bridge to [bus 93-bc]
> pci 0000:66:03.0:   bridge window [mem 0x8880000000-0x907fffffff 64bit pref]
> 
> --- Dock hot-plug enumeration (after TB tunnel up + PCI rescan) ---
> pci 0000:93:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Upstream Port
> pci 0000:93:00.0: PCI bridge to [bus 00]
> pci 0000:93:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]
> pci 0000:93:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> pci 0000:94:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Downstream Port
> pci 0000:94:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]
> 
> --- Kernel resource allocation: cannot fit rebar + hotplug reserves ---
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x1000000000 required for 0000:94:01.0 bridging to [bus 98-a4]
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x1000000000 required for 0000:94:02.0 bridging to [bus a5-b1]
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x1000000000 required for 0000:94:03.0 bridging to [bus b2-bc]
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x3018000000 required for 0000:93:00.0 bridging to [bus 94-bc]
> pci 0000:93:00.0: bridge window [mem 0x04000000-0x1fffffff 64bit pref]
> to [bus 94-bc] requires relaxed alignment rules
> pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
> can't assign; no space
> pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
> failed to assign
> pci 0000:93:00.0: bridge window [mem 0x8880000000-0x889bffffff 64bit
> pref]: assigned
> 
> --- GPU BAR enumeration ---
> pci 0000:97:00.0: [1002:7551] type 00 class 0x030000 PCIe Legacy Endpoint
> pci 0000:97:00.0: BAR 0 [mem 0x00000000-0x0fffffff 64bit pref]
> pci 0000:97:00.0: 8.000 Gb/s available PCIe bandwidth, limited by 2.5
> GT/s PCIe x4 link at 0000:66:03.0 (capable of 504.112 Gb/s with 32.0
> GT/s PCIe x16 link)
> pci 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
> pci 0000:97:00.0: BAR 4 [io  size 0x0100]: can't assign; no space
> 
> --- amdgpu rebar attempt and failure ---
> amdgpu 0000:97:00.0: amdgpu: PCIE atomic ops is not supported
> amdgpu 0000:97:00.0: BAR 2 [mem 0x8890000000-0x88901fffff 64bit pref]: releasing
> amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: releasing

Here you filtered the explanation which immediately follows:

[   58.188911] pcieport 0000:96:00.0: bridge window [mem 0x8880000000-0x8897ffffff 64bit pref]: releasing
[   58.188913] pcieport 0000:95:00.0: bridge window [mem 0x8880000000-0x8897ffffff 64bit pref]: releasing
[   58.188913] pcieport 0000:94:00.0: bridge window [mem 0x8880000000-0x8897ffffff 64bit pref]: releasing
[   58.188914] pcieport 0000:93:00.0: bridge window [mem 0x8880000000-0x889bffffff 64bit pref]: was not released (still contains assigned resources)
[   58.188915] pcieport 0000:66:03.0: bridge window [mem 0x8880000000-0x907fffffff 64bit pref]: was not released (still contains assigned resources)
[   58.188916] pcieport 0000:65:00.0: bridge window [mem 0x8880000000-0x98800fffff 64bit pref]: was not released (still contains assigned resources)
[   58.188916] pcieport 0000:00:03.2: bridge window [mem 0x8880000000-0x98800fffff 64bit pref]: was not released (still contains assigned resources)

The last 4 lines tell those upstream bridge windows are pinned by other 
(sibling) resources (effectively, it means it's too late to resize them at 
this point). When attempting BAR resize, kernel release only the resource 
of the device and then attemptes to release all bridge windows upstream 
of the device to allow them to be changed (enlarged). If there are sibling 
devices, their resources will prevent the shared bridge window from being 
released, effectively preventing enlarging the bridge window.

The resize might succeedeed, if you manually remove those sibling devices 
first, and then attempt the resize through sysfs (and rescan the bring 
back the removed devices).

I cannot say for sure what the pinning devices/resources are as your log 
is partial but you can check them from /proc/iomem yourself.

-- 
 i.

> amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: can't
> assign; no space
> amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: failed to assign
> amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: can't
> assign; no space
> amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: failed to assign
> amdgpu 0000:97:00.0: amdgpu: Not enough PCI address space for a large BAR.
> amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
> amdgpu 0000:97:00.0: amdgpu: VRAM: 32624M 0x0000008000000000 -
> 0x00000087F6FFFFFF (32624M used)
> 
> System: MinisForum MS-S1 (AMD Ryzen AI 395+ Max / Strix Halo) + Razer
> Core X V2 via Intel Barlow Ridge TB5 (JHL9580/JHL9586)
> GPU: AMD Radeon AI PRO R9700 [1002:7551] (RDNA 4 / gfx1201, 32GB GDDR6)
> Kernel: 6.18.7 (Ubuntu mainline)
> Cmdline: pcie_port_pm=off pcie_aspm=off
> pci=hpmemsize=2G,realloc,hpmmioprefsize=64G amdgpu.dc=0
> 
> --- Boot-time TB5 bridge layout (host-side, before tunnel) ---
> pci 0000:65:00.0: [8086:5780] type 01 class 0x060400 PCIe Switch Upstream Port
> pci 0000:65:00.0: PCI bridge to [bus 66-bc]
> pci 0000:65:00.0:   bridge window [mem 0x8880000000-0x98800fffff 64bit pref]
> pci 0000:66:01.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
> pci 0000:66:01.0: PCI bridge to [bus 68-91]
> pci 0000:66:01.0:   bridge window [mem 0x9080000000-0x987fffffff 64bit pref]
> pci 0000:66:03.0: [8086:5780] type 01 class 0x060400 PCIe Switch Downstream Port
> pci 0000:66:03.0: PCI bridge to [bus 93-bc]
> pci 0000:66:03.0:   bridge window [mem 0x8880000000-0x907fffffff 64bit pref]
> 
> --- Dock hot-plug enumeration (after TB tunnel up + PCI rescan) ---
> pci 0000:93:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Upstream Port
> pci 0000:93:00.0: PCI bridge to [bus 00]
> pci 0000:93:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]
> pci 0000:93:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
> pci 0000:94:00.0: [8086:5786] type 01 class 0x060400 PCIe Switch Downstream Port
> pci 0000:94:00.0:   bridge window [mem 0x00000000-0x000fffff 64bit pref]
> 
> --- Kernel resource allocation: cannot fit rebar + hotplug reserves ---
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x1000000000 required for 0000:94:01.0 bridging to [bus 98-a4]
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x1000000000 required for 0000:94:02.0 bridging to [bus a5-b1]
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x1000000000 required for 0000:94:03.0 bridging to [bus b2-bc]
> pcieport 0000:66:03.0: Assigned bridge window [mem
> 0x8880000000-0x907fffffff 64bit pref] to [bus 93-bc] cannot fit
> 0x3018000000 required for 0000:93:00.0 bridging to [bus 94-bc]
> pci 0000:93:00.0: bridge window [mem 0x04000000-0x1fffffff 64bit pref]
> to [bus 94-bc] requires relaxed alignment rules
> pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
> can't assign; no space
> pci 0000:93:00.0: bridge window [mem size 0x3018000000 64bit pref]:
> failed to assign
> pci 0000:93:00.0: bridge window [mem 0x8880000000-0x889bffffff 64bit
> pref]: assigned
> 
> --- GPU BAR enumeration ---
> pci 0000:97:00.0: [1002:7551] type 00 class 0x030000 PCIe Legacy Endpoint
> pci 0000:97:00.0: BAR 0 [mem 0x00000000-0x0fffffff 64bit pref]
> pci 0000:97:00.0: 8.000 Gb/s available PCIe bandwidth, limited by 2.5
> GT/s PCIe x4 link at 0000:66:03.0 (capable of 504.112 Gb/s with 32.0
> GT/s PCIe x16 link)
> pci 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
> pci 0000:97:00.0: BAR 4 [io  size 0x0100]: can't assign; no space
> 
> --- amdgpu rebar attempt and failure ---
> amdgpu 0000:97:00.0: amdgpu: PCIE atomic ops is not supported
> amdgpu 0000:97:00.0: BAR 2 [mem 0x8890000000-0x88901fffff 64bit pref]: releasing
> amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: releasing
> amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: can't
> assign; no space
> amdgpu 0000:97:00.0: BAR 0 [mem size 0x800000000 64bit pref]: failed to assign
> amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: can't
> assign; no space
> amdgpu 0000:97:00.0: BAR 2 [mem size 0x00200000 64bit pref]: failed to assign
> amdgpu 0000:97:00.0: amdgpu: Not enough PCI address space for a large BAR.
> amdgpu 0000:97:00.0: BAR 0 [mem 0x8880000000-0x888fffffff 64bit pref]: assigned
> amdgpu 0000:97:00.0: amdgpu: VRAM: 32624M 0x0000008000000000 -
> 0x00000087F6FFFFFF (32624M used)
> 
> 
> 
> Geramy L. Loveless
> 

^ permalink raw reply

* Re: [PATCH] usb: typec: altmode: Fix altmode to handle multiple parners
From: Heikki Krogerus @ 2026-04-08 10:00 UTC (permalink / raw)
  To: François Scala; +Cc: linux-usb
In-Reply-To: <d627d2fe-415f-4489-b4fa-ec0575a33239@scala.name>

Hi,

> I'm running Archlinux with kernel 7.0-rc7 with my patch.
> 
> Please find attached the dmesg files (with and without altmode).

Thanks. So this is a known Dell specific issue. There is already one
proposal for a workaround:
https://lore.kernel.org/linux-usb/20251224070022.4082182-1-acelan.kao@canonical.com/

Br,

-- 
heikki

^ permalink raw reply

* Re: [PATCH v3 1/3] usb: typec: ucsi: Detect and skip duplicate altmodes from buggy firmware
From: Heikki Krogerus @ 2026-04-08 10:09 UTC (permalink / raw)
  To: Dmitry Baryshkov, AceLan Kao
  Cc: Greg Kroah-Hartman, Pooja Katiyar, Abel Vesa, Andrei Kuchynski,
	Venkat Jayaraman, Christian A. Ehrhardt, Pei Xiao,
	François Scala, linux-usb, linux-kernel
In-Reply-To: <abF00-Squp-tEOKS@kuha>

+François

On Wed, Mar 11, 2026 at 03:57:41PM +0200, Heikki Krogerus wrote:
> Thu, Mar 05, 2026 at 04:58:02PM +0200, Dmitry Baryshkov kirjoitti:
> > On Wed, Feb 11, 2026 at 06:37:41AM +0100, Greg Kroah-Hartman wrote:
> > > On Wed, Feb 11, 2026 at 11:32:37AM +0800, AceLan Kao wrote:
> > > > A gentle ping.
> > > > Please help to review these patches, thanks.
> > > 
> > > Wait, no, we rejected this series and said "fix the firmware".
> > > 
> > > What happened to doing that?
> > 
> > Having a similar problem with other platforms. It's not always possible
> > to fix the firmware. I have one platform with a similar issue, but that
> > laptop is EOLed long ago (Lenovo Yoga C630, the issue has been worked
> > around in the EC driver, but I'd be really happy to switch to the
> > generic fixup). At this point it really feels that there might
> > be more UCSI implemetations having this issue. 
> 
> I would still like to get an answer from Dell for this (if this was
> the Dell case). It looks like they are using the GET_ALTMODES_COMMAND
> in some custom way. It's almost like they are first returning all the
> SVIDs without the modes, followed by something else.
> 
> So even if these products are EOL, and we will never get the firmware
> fixed, we still need to understand what exactly is being returned to
> the command, and is it returned like that intentionally or not.

François is now seeing the same issue. I guess nobody has had any
luck contacting Dell?

Chia-Lin, could you rebase and resend this?

thanks,

-- 
heikki

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox