* [PATCH] usb: dwc3: st: Propagate reset deassert failures
From: Pengpeng Hou @ 2026-06-24 5:57 UTC (permalink / raw)
To: Patrice Chotard, Thinh Nguyen, Greg Kroah-Hartman, Philipp Zabel
Cc: linux-arm-kernel, linux-usb, linux-kernel, Pengpeng Hou
The ST DWC3 glue driver treats the powerdown and softreset reset
controls as required resources, but ignores reset_control_deassert()
failures before populating the child DWC3 device. Resume ignores the
same failures before returning success.
Check the deassert operations and unwind the already deasserted
powerdown reset if softreset deassertion fails.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/usb/dwc3/dwc3-st.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-st.c b/drivers/usb/dwc3/dwc3-st.c
index 5d513decaacd..bbabfd933798 100644
--- a/drivers/usb/dwc3/dwc3-st.c
+++ b/drivers/usb/dwc3/dwc3-st.c
@@ -242,7 +242,9 @@ static int st_dwc3_probe(struct platform_device *pdev)
"could not get power controller\n");
/* Manage PowerDown */
- reset_control_deassert(dwc3_data->rstc_pwrdn);
+ ret = reset_control_deassert(dwc3_data->rstc_pwrdn);
+ if (ret)
+ return ret;
dwc3_data->rstc_rst =
devm_reset_control_get_shared(dev, "softreset");
@@ -253,7 +255,9 @@ static int st_dwc3_probe(struct platform_device *pdev)
}
/* Manage SoftReset */
- reset_control_deassert(dwc3_data->rstc_rst);
+ ret = reset_control_deassert(dwc3_data->rstc_rst);
+ if (ret)
+ goto undo_powerdown;
/* Allocate and initialize the core */
ret = of_platform_populate(node, NULL, NULL, dev);
@@ -328,8 +332,15 @@ static int st_dwc3_resume(struct device *dev)
pinctrl_pm_select_default_state(dev);
- reset_control_deassert(dwc3_data->rstc_pwrdn);
- reset_control_deassert(dwc3_data->rstc_rst);
+ ret = reset_control_deassert(dwc3_data->rstc_pwrdn);
+ if (ret)
+ return ret;
+
+ ret = reset_control_deassert(dwc3_data->rstc_rst);
+ if (ret) {
+ reset_control_assert(dwc3_data->rstc_pwrdn);
+ return ret;
+ }
ret = st_dwc3_drd_init(dwc3_data);
if (ret) {
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH] usb: dwc3: am62: Propagate USB2 refclk enable failures
From: Pengpeng Hou @ 2026-06-24 5:56 UTC (permalink / raw)
To: Thinh Nguyen, Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel, Pengpeng Hou
The AM62 wrapper requires the USB2 ref clock, but dwc3_ti_init() ignores
clk_prepare_enable() failures before marking the mode valid. Probe can
then populate the child DWC3 device even though the wrapper clock
transition failed.
Resume has the same issue after context loss or direct refclk re-enable.
Check and propagate the refclk enable errors so the wrapper does not
publish or resume a child provider without parent readiness.
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
drivers/usb/dwc3/dwc3-am62.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c
index e11d7643f966..632634d6e81e 100644
--- a/drivers/usb/dwc3/dwc3-am62.c
+++ b/drivers/usb/dwc3/dwc3-am62.c
@@ -205,7 +205,9 @@ static int dwc3_ti_init(struct dwc3_am62 *am62)
dwc3_ti_writel(am62, USBSS_PHY_CONFIG, reg);
- clk_prepare_enable(am62->usb2_refclk);
+ ret = clk_prepare_enable(am62->usb2_refclk);
+ if (ret)
+ return ret;
/* Set mode valid bit to indicate role is valid */
reg = dwc3_ti_readl(am62, USBSS_MODE_CONTROL);
@@ -361,14 +363,19 @@ static int dwc3_ti_resume_common(struct device *dev)
{
struct dwc3_am62 *am62 = dev_get_drvdata(dev);
u32 reg;
+ int ret;
reg = dwc3_ti_readl(am62, USBSS_DEBUG_CFG);
if (reg != USBSS_DEBUG_CFG_DISABLED) {
/* lost power/context */
- dwc3_ti_init(am62);
+ ret = dwc3_ti_init(am62);
+ if (ret)
+ return ret;
} else {
dwc3_ti_writel(am62, USBSS_DEBUG_CFG, USBSS_DEBUG_CFG_OFF);
- clk_prepare_enable(am62->usb2_refclk);
+ ret = clk_prepare_enable(am62->usb2_refclk);
+ if (ret)
+ return ret;
}
if (device_may_wakeup(dev)) {
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH v3] thunderbolt: fix bandwidth group reservation indexing
From: Mika Westerberg @ 2026-06-24 5:52 UTC (permalink / raw)
To: raoxu; +Cc: andreas.noever, westeri, YehezkelShB, linux-usb, linux-kernel,
stable
In-Reply-To: <BF910BF87AF1F9F7+20260624050719.4113548-1-raoxu@uniontech.com>
Hi,
On Wed, Jun 24, 2026 at 01:07:19PM +0800, raoxu wrote:
> From: Xu Rao <raoxu@uniontech.com>
>
> Group ID 0 is reserved, while valid bandwidth groups use IDs 1 through
> 7. tb_consumed_dp_bandwidth() uses the Group ID directly to index
> its group_reserved[] array.
>
> Currently group_reserved[] has only seven entries, covering indices 0
> through 6. A tunnel in Group ID 7 therefore reads and may write one
> entry past the end of the array, and that group's reserved bandwidth is
> not included in the consumed bandwidth total.
>
> Include the reserved Group ID 0 in MAX_GROUPS and map tb_cm::groups[]
> directly by Group ID. Initialize every entry with its array index, but
> skip index 0 when allocating a free group or restoring a group reported
> by the hardware. This keeps Group ID 0 reserved while making IDs 1
> through 7 valid indices in both arrays.
I looked at this again and realized that your v1 was almost okay but
instead of the -1 we should do this and just this:
tb_consumed_dp_bandwidth()
{
int group_reserved[MAX_GROUPS + 1] = {};
...
keep everything else as is. This should solve the issue, right?
^ permalink raw reply
* Re: [PATCH] usb: xhci-pci: Disable 64-bit DMA for VIA VL805
From: Xincheng Zhang @ 2026-06-24 5:26 UTC (permalink / raw)
To: Michal Pecio
Cc: Xincheng Zhang, Mathias Nyman, Greg Kroah-Hartman, linux-usb,
linux-kernel, Forest Crossman
In-Reply-To: <20260623121847.53749028.michal.pecio@gmail.com>
Hi Michal,
On 2026-06-23 12:18 +0200, Michal Pecio wrote:
> But I don't like this abuse of the quirk. Firstly, it causes
> unnecessary bouncing on systems with >4GB RAM and no IOMMU.
> I found other drivers that use DMA_BIT_MASK(36) or even weirder
> numbers, so it seems that we too could request 64 gigs exactly
> with a bit of driver refactoring.
Thanks for the review. I totally agree that using `DMA_BIT_MASK(36)` is
a much better approach to avoid bounce buffers and register width issues.
I will prepare a v2 patch with this refactoring. I'll wait a bit for
Forest's input on the ASMedia chips before sending it out, just in case
we need to handle them together.
Thanks,
Xincheng
^ permalink raw reply
* [westeri-thunderbolt:next] BUILD SUCCESS 3f8de2efbf502346ba138ecc198661515c77ce2b
From: kernel test robot @ 2026-06-24 5:08 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: 3f8de2efbf502346ba138ecc198661515c77ce2b thunderbolt: Drop comma after device id array terminator
elapsed time: 751m
configs tested: 239
configs skipped: 3
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-16.1.0
alpha allyesconfig gcc-16.1.0
alpha defconfig gcc-16.1.0
arc allmodconfig clang-23
arc allmodconfig gcc-16.1.0
arc allnoconfig gcc-16.1.0
arc allyesconfig clang-23
arc allyesconfig gcc-16.1.0
arc defconfig gcc-16.1.0
arc randconfig-001-20260624 gcc-15.2.0
arc randconfig-002-20260624 gcc-15.2.0
arm allnoconfig clang-17
arm allnoconfig gcc-16.1.0
arm allyesconfig clang-23
arm allyesconfig gcc-16.1.0
arm defconfig clang-23
arm defconfig gcc-16.1.0
arm randconfig-001-20260624 gcc-15.2.0
arm randconfig-002-20260624 gcc-15.2.0
arm randconfig-003-20260624 gcc-15.2.0
arm randconfig-004-20260624 gcc-15.2.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-16.1.0
arm64 defconfig gcc-16.1.0
arm64 randconfig-001-20260624 clang-21
arm64 randconfig-002-20260624 clang-21
arm64 randconfig-002-20260624 gcc-15.2.0
arm64 randconfig-003-20260624 clang-21
arm64 randconfig-003-20260624 clang-23
arm64 randconfig-004-20260624 clang-21
arm64 randconfig-004-20260624 clang-23
csky allmodconfig gcc-16.1.0
csky allnoconfig gcc-16.1.0
csky defconfig gcc-16.1.0
csky randconfig-001-20260624 clang-21
csky randconfig-001-20260624 gcc-16.1.0
csky randconfig-002-20260624 clang-21
csky randconfig-002-20260624 gcc-9.5.0
hexagon allmodconfig clang-23
hexagon allmodconfig gcc-16.1.0
hexagon allnoconfig clang-23
hexagon allnoconfig gcc-16.1.0
hexagon defconfig clang-23
hexagon defconfig gcc-16.1.0
hexagon randconfig-001 gcc-11.5.0
hexagon randconfig-001-20260624 clang-20
hexagon randconfig-001-20260624 gcc-11.5.0
hexagon randconfig-001-20260624 gcc-9.5.0
hexagon randconfig-002 gcc-11.5.0
hexagon randconfig-002-20260624 clang-23
hexagon randconfig-002-20260624 gcc-11.5.0
hexagon randconfig-002-20260624 gcc-9.5.0
i386 allmodconfig clang-22
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allnoconfig gcc-16.1.0
i386 allyesconfig clang-22
i386 allyesconfig gcc-14
i386 buildonly-randconfig-001-20260624 gcc-12
i386 buildonly-randconfig-001-20260624 gcc-14
i386 buildonly-randconfig-002-20260624 gcc-12
i386 buildonly-randconfig-002-20260624 gcc-14
i386 buildonly-randconfig-003-20260624 gcc-12
i386 buildonly-randconfig-004-20260624 gcc-12
i386 buildonly-randconfig-004-20260624 gcc-14
i386 buildonly-randconfig-005-20260624 gcc-12
i386 buildonly-randconfig-005-20260624 gcc-14
i386 buildonly-randconfig-006-20260624 gcc-12
i386 buildonly-randconfig-006-20260624 gcc-14
i386 defconfig clang-22
i386 defconfig gcc-16.1.0
i386 randconfig-001-20260624 clang-22
i386 randconfig-002-20260624 clang-22
i386 randconfig-003-20260624 clang-22
i386 randconfig-004-20260624 clang-22
i386 randconfig-005-20260624 clang-22
i386 randconfig-006-20260624 clang-22
i386 randconfig-007-20260624 clang-22
i386 randconfig-011-20260624 clang-22
i386 randconfig-012-20260624 clang-22
i386 randconfig-013-20260624 clang-22
i386 randconfig-014-20260624 clang-22
i386 randconfig-015-20260624 clang-22
i386 randconfig-016-20260624 clang-22
i386 randconfig-017-20260624 clang-22
loongarch allmodconfig clang-19
loongarch allmodconfig clang-23
loongarch allnoconfig clang-20
loongarch allnoconfig gcc-16.1.0
loongarch defconfig clang-23
loongarch randconfig-001 gcc-11.5.0
loongarch randconfig-001-20260624 gcc-11.5.0
loongarch randconfig-001-20260624 gcc-16.1.0
loongarch randconfig-001-20260624 gcc-9.5.0
loongarch randconfig-002 gcc-11.5.0
loongarch randconfig-002-20260624 gcc-11.5.0
loongarch randconfig-002-20260624 gcc-15.2.0
loongarch randconfig-002-20260624 gcc-9.5.0
m68k allmodconfig gcc-16.1.0
m68k allnoconfig gcc-16.1.0
m68k allyesconfig clang-23
m68k allyesconfig gcc-16.1.0
m68k defconfig clang-23
m68k stmark2_defconfig gcc-16.1.0
microblaze allnoconfig gcc-16.1.0
microblaze allyesconfig gcc-16.1.0
microblaze defconfig clang-23
mips allmodconfig gcc-16.1.0
mips allnoconfig gcc-16.1.0
mips allyesconfig gcc-16.1.0
nios2 allmodconfig clang-20
nios2 allnoconfig clang-23
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-23
nios2 randconfig-001 gcc-11.5.0
nios2 randconfig-001-20260624 gcc-11.5.0
nios2 randconfig-001-20260624 gcc-9.5.0
nios2 randconfig-002 gcc-11.5.0
nios2 randconfig-002-20260624 gcc-11.5.0
nios2 randconfig-002-20260624 gcc-9.5.0
openrisc allmodconfig clang-20
openrisc allnoconfig clang-23
openrisc allnoconfig gcc-16.1.0
openrisc defconfig gcc-16.1.0
parisc allmodconfig gcc-16.1.0
parisc allnoconfig clang-23
parisc allnoconfig gcc-16.1.0
parisc allyesconfig clang-17
parisc allyesconfig gcc-16.1.0
parisc defconfig gcc-16.1.0
parisc randconfig-001 gcc-8.5.0
parisc randconfig-001-20260624 gcc-16.1.0
parisc randconfig-002 gcc-12.5.0
parisc randconfig-002-20260624 gcc-14.3.0
parisc randconfig-002-20260624 gcc-16.1.0
parisc64 defconfig clang-23
powerpc allmodconfig gcc-16.1.0
powerpc allnoconfig clang-23
powerpc allnoconfig gcc-16.1.0
powerpc asp8347_defconfig clang-23
powerpc fsp2_defconfig gcc-16.1.0
powerpc randconfig-001 gcc-10.5.0
powerpc randconfig-001-20260624 clang-17
powerpc randconfig-001-20260624 gcc-16.1.0
powerpc randconfig-002 gcc-8.5.0
powerpc randconfig-002-20260624 gcc-16.1.0
powerpc randconfig-002-20260624 gcc-8.5.0
powerpc64 randconfig-001 clang-17
powerpc64 randconfig-001-20260624 gcc-16.1.0
powerpc64 randconfig-001-20260624 gcc-8.5.0
powerpc64 randconfig-002 clang-23
powerpc64 randconfig-002-20260624 gcc-11.5.0
powerpc64 randconfig-002-20260624 gcc-16.1.0
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allnoconfig gcc-16.1.0
riscv allyesconfig clang-23
riscv defconfig gcc-16.1.0
riscv randconfig-001-20260624 clang-18
riscv randconfig-002-20260624 clang-18
s390 allmodconfig clang-17
s390 allmodconfig clang-23
s390 allnoconfig clang-23
s390 allyesconfig gcc-16.1.0
s390 defconfig gcc-16.1.0
s390 randconfig-001-20260624 clang-18
s390 randconfig-002-20260624 clang-18
sh allmodconfig gcc-16.1.0
sh allnoconfig clang-23
sh allnoconfig gcc-16.1.0
sh allyesconfig clang-17
sh allyesconfig gcc-16.1.0
sh defconfig gcc-14
sh randconfig-001-20260624 clang-18
sh randconfig-002-20260624 clang-18
sparc allnoconfig clang-23
sparc allnoconfig gcc-16.1.0
sparc defconfig gcc-16.1.0
sparc randconfig-001-20260624 gcc-14.3.0
sparc randconfig-002-20260624 gcc-14.3.0
sparc64 allmodconfig clang-20
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260624 gcc-14.3.0
sparc64 randconfig-002-20260624 gcc-14.3.0
um allmodconfig clang-17
um allnoconfig clang-17
um allnoconfig clang-23
um allyesconfig gcc-14
um allyesconfig gcc-16.1.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260624 gcc-14.3.0
um randconfig-002-20260624 gcc-14.3.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-22
x86_64 allnoconfig clang-22
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-22
x86_64 buildonly-randconfig-001-20260624 clang-22
x86_64 buildonly-randconfig-002-20260624 clang-22
x86_64 buildonly-randconfig-003-20260624 clang-22
x86_64 buildonly-randconfig-004-20260624 clang-22
x86_64 buildonly-randconfig-005-20260624 clang-22
x86_64 buildonly-randconfig-006-20260624 clang-22
x86_64 defconfig gcc-14
x86_64 kexec clang-22
x86_64 randconfig-001-20260624 clang-22
x86_64 randconfig-002-20260624 clang-22
x86_64 randconfig-003-20260624 clang-22
x86_64 randconfig-004-20260624 clang-22
x86_64 randconfig-005-20260624 clang-22
x86_64 randconfig-006-20260624 clang-22
x86_64 randconfig-011-20260624 gcc-14
x86_64 randconfig-012-20260624 gcc-14
x86_64 randconfig-013-20260624 gcc-14
x86_64 randconfig-014-20260624 gcc-14
x86_64 randconfig-015-20260624 gcc-14
x86_64 randconfig-016-20260624 gcc-14
x86_64 randconfig-071-20260624 gcc-14
x86_64 randconfig-072-20260624 clang-22
x86_64 randconfig-072-20260624 gcc-14
x86_64 randconfig-073-20260624 gcc-14
x86_64 randconfig-074-20260624 clang-22
x86_64 randconfig-074-20260624 gcc-14
x86_64 randconfig-075-20260624 gcc-14
x86_64 randconfig-076-20260624 clang-22
x86_64 randconfig-076-20260624 gcc-14
x86_64 rhel-9.4 clang-22
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-22
x86_64 rhel-9.4-kselftests clang-22
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-22
xtensa allnoconfig clang-23
xtensa allnoconfig gcc-16.1.0
xtensa allyesconfig clang-20
xtensa randconfig-001-20260624 gcc-14.3.0
xtensa randconfig-002-20260624 gcc-14.3.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH] thunderbolt: xdomain: notify peers after enumeration
From: Mika Westerberg @ 2026-06-24 5:07 UTC (permalink / raw)
To: Rqirus
Cc: Andreas Noever, Michael Jamet, Yehezkel Bernat, linux-usb,
linux-kernel
In-Reply-To: <20260624011131.2532004-1-cmh79479@gmail.com>
Hi,
On Wed, Jun 24, 2026 at 09:11:31AM +0800, Rqirus wrote:
> Service drivers may register local XDomain properties while discovery is
> still in progress. This can cause the properties changed notification to be
> sent before the peer is ready to act on it.
>
> If the peer has already read the local property block before the service
> was registered, it may keep using the old property generation and miss the
> newly registered service. With ThunderboltIP this can leave the network
> service half-discovered after a warm reboot and the login request
> eventually times out.
>
> Queue another properties changed notification after the XDomain reaches
> ENUMERATED so the peer can re-read the final local properties.
>
> Signed-off-by: Rqirus <cmh79479@gmail.com>
You should be using your full name here.
The patch itself looks reasonable to me.
> ---
> drivers/thunderbolt/xdomain.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
> index 86b2f7474..9c068d073 100644
> --- a/drivers/thunderbolt/xdomain.c
> +++ b/drivers/thunderbolt/xdomain.c
> @@ -1811,6 +1811,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
> tb_xdomain_failed(xd);
> } else {
> xd->state = XDOMAIN_STATE_ENUMERATED;
> + tb_xdomain_queue_properties_changed(xd);
> }
> break;
>
>
> base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
> --
> 2.47.3
^ permalink raw reply
* [PATCH v3] thunderbolt: fix bandwidth group reservation indexing
From: raoxu @ 2026-06-24 5:07 UTC (permalink / raw)
To: andreas.noever
Cc: westeri, YehezkelShB, linux-usb, linux-kernel, raoxu, stable
From: Xu Rao <raoxu@uniontech.com>
Group ID 0 is reserved, while valid bandwidth groups use IDs 1 through
7. tb_consumed_dp_bandwidth() uses the Group ID directly to index
its group_reserved[] array.
Currently group_reserved[] has only seven entries, covering indices 0
through 6. A tunnel in Group ID 7 therefore reads and may write one
entry past the end of the array, and that group's reserved bandwidth is
not included in the consumed bandwidth total.
Include the reserved Group ID 0 in MAX_GROUPS and map tb_cm::groups[]
directly by Group ID. Initialize every entry with its array index, but
skip index 0 when allocating a free group or restoring a group reported
by the hardware. This keeps Group ID 0 reserved while making IDs 1
through 7 valid indices in both arrays.
Fixes: 52a4490e89d7 ("thunderbolt: Reserve released DisplayPort bandwidth for a group for 10 seconds")
Cc: stable@vger.kernel.org
Signed-off-by: Xu Rao <raoxu@uniontech.com>
---
Changes in v3:
- Keep tb_cm::groups[] sized with MAX_GROUPS and map its entries
directly to Group IDs 0 through 7.
- Initialize the reserved Group ID 0 entry, but skip it when allocating
or discovering usable bandwidth groups.
- Drop the incorrect MAX_GROUPS - 1 sizing from v2.
Changes in v2:
- Keep Group ID as the direct group_reserved[] index instead of
converting it to a zero-based index as in v1.
- Include the reserved Group ID 0 in MAX_GROUPS.
drivers/thunderbolt/tb.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index b7cc689..aad09e5 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -41,7 +41,7 @@
*/
#define TB_ASYM_THRESHOLD 45000
-#define MAX_GROUPS 7 /* max Group_ID is 7 */
+#define MAX_GROUPS (7 + 1) /* Group_ID 0 is reserved */
static unsigned int asym_threshold = TB_ASYM_THRESHOLD;
module_param_named(asym_threshold, asym_threshold, uint, 0444);
@@ -1585,7 +1585,7 @@ static void tb_init_bandwidth_groups(struct tb_cm *tcm)
struct tb_bandwidth_group *group = &tcm->groups[i];
group->tb = tcm_to_tb(tcm);
- group->index = i + 1;
+ group->index = i;
INIT_LIST_HEAD(&group->ports);
INIT_DELAYED_WORK(&group->release_work,
tb_bandwidth_group_release_work);
@@ -1608,7 +1608,7 @@ static struct tb_bandwidth_group *tb_find_free_bandwidth_group(struct tb_cm *tcm
{
int i;
- for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+ for (i = 1; i < ARRAY_SIZE(tcm->groups); i++) {
struct tb_bandwidth_group *group = &tcm->groups[i];
if (list_empty(&group->ports))
@@ -1662,7 +1662,7 @@ static void tb_discover_bandwidth_group(struct tb_cm *tcm, struct tb_port *in,
int index, i;
index = usb4_dp_port_group_id(in);
- for (i = 0; i < ARRAY_SIZE(tcm->groups); i++) {
+ for (i = 1; i < ARRAY_SIZE(tcm->groups); i++) {
if (tcm->groups[i].index == index) {
tb_bandwidth_group_attach_port(&tcm->groups[i], in);
return;
--
2.47.3
^ permalink raw reply related
* [PATCH stable 5.15] xhci: fix memory leak regression when freeing xhci vdev devices depth first
From: Justin Chen @ 2026-06-24 3:49 UTC (permalink / raw)
To: stable
Cc: gregkh, WeitaoWang-oc, linux-usb, mathias.nyman,
bcm-kernel-feedback-list, Mathias Nyman, David Wang, Michal Pecio,
Justin Chen
From: Mathias Nyman <mathias.nyman@linux.intel.com>
commit edcbe06453ddfde21f6aa763f7cab655f26133cc upstream
Suspend-resume cycle test revealed a memory leak in 6.17-rc3
Turns out the slot_id race fix changes accidentally ends up calling
xhci_free_virt_device() with an incorrect vdev parameter.
The vdev variable was reused for temporary purposes right before calling
xhci_free_virt_device().
Fix this by passing the correct vdev parameter.
The slot_id race fix that caused this regression was targeted for stable,
so this needs to be applied there as well.
Fixes: 2eb03376151b ("usb: xhci: Fix slot_id resource race conflict")
Reported-by: David Wang <00107082@163.com>
Closes: https://lore.kernel.org/linux-usb/20250829181354.4450-1-00107082@163.com
Suggested-by: Michal Pecio <michal.pecio@gmail.com>
Suggested-by: David Wang <00107082@163.com>
Cc: stable@vger.kernel.org
Tested-by: David Wang <00107082@163.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20250902105306.877476-4-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Justin Chen <justin.chen@broadcom.com>
---
drivers/usb/host/xhci-mem.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index fb81e61a599d..7f75298a09d6 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -961,7 +961,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i
out:
/* we are now at a leaf device */
xhci_debugfs_remove_slot(xhci, slot_id);
- xhci_free_virt_device(xhci, vdev, slot_id);
+ xhci_free_virt_device(xhci, xhci->devs[slot_id], slot_id);
}
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
--
2.34.1
^ permalink raw reply related
* [PATCH v4] usb: serial : option: add multiple MeiG VID/PID
From: yangsizhe @ 2026-06-24 3:35 UTC (permalink / raw)
To: johan, gregkh, linux-usb, linux-kernel, yangsizhe; +Cc: yangsizhe
Add the PID and VID to facilitate the binding of our company's module
Real name:MeiG Smart Technology Co., Ltd
Signed-off-by: yangsizhe <18392868223@163.com>
---
Changes from v3
1.Resolve the issue of compilation failure
Changes from v2
1.Adjust reserved interface mask,avoid conflicts with RNDIS driver
Changes from v1
1.Add Real name into commit changelog descriptor for device identification
---
drivers/usb/serial/option.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index a34e79cfd5b6..1bf37df4493d 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -2459,6 +2459,25 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x40) }, /* MeiG SRM813Q (AT) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d64, 0xff, 0xff, 0x60) }, /* MeiG SRM813Q (NMEA) */
+ { USB_DEVICE(0x2dee, 0x4d23), /* MeiG SLM868x*/
+ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) },
+ { USB_DEVICE(0x2dee, 0x4d62), /* MeiG SLM820x*/
+ .driver_info = RSVD(4) },
+ { USB_DEVICE(0x2dee, 0x4d30), /* MeiG SRM813Q*/
+ .driver_info = RSVD(0) | RSVD(1) },
+ { USB_DEVICE(0x2dee, 0x4d50), /* MeiG SRM811x*/
+ .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+ { USB_DEVICE(0x2dee, 0x4d51), /* MeiG SRM821x*/
+ .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+ { USB_DEVICE(0x2dee, 0x4d52), /* MeiG SRM810x*/
+ .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
+ { USB_DEVICE(0x2dee, 0x4d57), /* MeiG SLM770A*/
+ .driver_info = RSVD(0) | RSVD(1) },
+ { USB_DEVICE(0x2dee, 0x4d58), /* MeiG SLM828A*/
+ .driver_info = RSVD(0) | RSVD(1) },
+ { USB_DEVICE(0x05c6, 0xf601), /* MeiG SLM750x*/
+ .driver_info = RSVD(5) },
+
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
--
2.17.1
^ permalink raw reply related
* [PATCH v2] usb: gadget: udc: Fix use-after-free in gadget_match_driver
From: Jimmy Hu @ 2026-06-24 3:01 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: Alan Stern, linux-usb, linux-kernel, stable, Jimmy Hu
The udc structure acts as the management structure for the gadget,
but their lifecycles are decoupled. A race condition exists where
usb_del_gadget() frees the udc memory (e.g., via mode-switch work)
while gadget_match_driver() concurrently accesses the freed udc memory
(e.g., via configfs), causing a Use-After-Free (UAF) that triggers a
NULL pointer dereference when the freed memory is zeroed:
[39430.908615][ T1171] Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000
[39430.911397][ T1171] pc : __pi_strcmp+0x20/0x140
[39430.911441][ T1171] lr : gadget_match_driver+0x34/0x60
...
[39430.911890][ T1171] usb_gadget_register_driver_owner+0x50/0xf8
[39430.911910][ T1171] gadget_dev_desc_UDC_store+0xf4/0x140
[39430.931308][ T1171] configfs_write_iter+0xec/0x134
[39430.957058][ T1171] Workqueue: events_freezable __dwc3_set_mode
[39430.957287][ T1171] dwc3_gadget_exit+0x34/0x8c
[39430.957304][ T1171] __dwc3_set_mode+0xc0/0x664
Fix this by ensuring the udc structure remains allocated during the
match. To achieve this, introduce a new usb_gadget_release() routine
to the core. When the gadget is added, usb_add_gadget() stores the
gadget's release routine in the udc structure and takes a reference
to the udc. When the gadget is released, usb_gadget_release() drops
the reference to the udc and then calls the gadget's release routine.
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Cc: <stable@vger.kernel.org>
Signed-off-by: Jimmy Hu <hhhuuu@google.com>
---
V1 -> V2: Rework the fix using a new release routine in the core.
v1: https://lore.kernel.org/all/20260526070635.839701-1-hhhuuu@google.com/
drivers/usb/gadget/udc/core.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index 60340ff9edbf..f8ce8694c101 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -31,8 +31,9 @@ static const struct bus_type gadget_bus_type;
/**
* struct usb_udc - describes one usb device controller
* @driver: the gadget driver pointer. For use by the class code
- * @dev: the child device to the actual controller
* @gadget: the gadget. For use by the class code
+ * @gadget_release: the gadget's release routine
+ * @dev: the child device to the actual controller
* @list: for use by the udc class driver
* @vbus: for udcs who care about vbus status, this value is real vbus status;
* for udcs who do not care about vbus status, this value is always true
@@ -53,6 +54,7 @@ static const struct bus_type gadget_bus_type;
struct usb_udc {
struct usb_gadget_driver *driver;
struct usb_gadget *gadget;
+ void (*gadget_release)(struct device *dev);
struct device dev;
struct list_head list;
bool vbus;
@@ -1362,6 +1364,18 @@ static void usb_udc_nop_release(struct device *dev)
dev_vdbg(dev, "%s\n", __func__);
}
+static void usb_gadget_release(struct device *dev)
+{
+ struct usb_gadget *gadget = dev_to_usb_gadget(dev);
+ struct usb_udc *udc = gadget->udc;
+ /* Cache the gadget's release routine to prevent UAF */
+ void (*release)(struct device *dev) = udc->gadget_release;
+
+ put_device(&udc->dev);
+ if (release)
+ release(dev);
+}
+
/**
* usb_initialize_gadget - initialize a gadget and its embedded struct device
* @parent: the parent device to this udc. Usually the controller driver's
@@ -1418,6 +1432,9 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_init(&udc->connect_lock);
udc->started = false;
+ udc->gadget_release = gadget->dev.release;
+ gadget->dev.release = usb_gadget_release;
+ get_device(&udc->dev);
mutex_lock(&udc_lock);
list_add_tail(&udc->list, &udc_list);
@@ -1462,6 +1479,8 @@ int usb_add_gadget(struct usb_gadget *gadget)
mutex_lock(&udc_lock);
list_del(&udc->list);
mutex_unlock(&udc_lock);
+ gadget->dev.release = udc->gadget_release;
+ put_device(&udc->dev);
err_put_udc:
put_device(&udc->dev);
base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
--
2.55.0.rc0.799.gd6f94ed593-goog
^ permalink raw reply related
* Re: chipidea: usbmisc_imx: i.MX93 support
From: Xu Yang @ 2026-06-24 2:50 UTC (permalink / raw)
To: Stefan Wahren
Cc: Xu Yang, Frank Li, Jun Li, Alexander Stein, Greg Kroah-Hartman,
Linux ARM, linux-usb@vger.kernel.org
In-Reply-To: <b2fb88eb-5c5f-499f-9cee-6a69769c578c@gmx.net>
On Tue, Jun 23, 2026 at 12:23:12PM +0200, Stefan Wahren wrote:
> Hi,
>
> during debugging USB OTG on our custom i.MX93 board, we noticed remarkable
> differences between the implementation of the chipidea/usbmisc_imx and the
> official NXP i.MX93 Reference Manual [1].
>
> Is the USB OTG part including PHY of the i.MX93 officially supported in
> Linux Mainline?
Yes.
>
> According to imx91_93_common.dtsi the USB IP of the i.MX93 should be
> identical to i.MX8MM [2]
>
> usbmisc1: usbmisc@4c100200 {
>
> compatible = "fsl,imx8mm-usbmisc", "fsl,imx7d-usbmisc",
> "fsl,imx6q-usbmisc";
>
> But looking at the PHY register definition and reset values in the NXP
> i.MX93 Reference Manual,
>
> the registers are comparable to the i.MX95 [3] ones.
>
> Could you please clarify which source is correct (Mainline DTS vs Reference
> Manual)?
The Reference Manual is correct.
>
> Looking deeper at chipidea/usbmisc_imx shows the usage of the following
> register bits
>
> #define MX7D_USB_OTG_PHY_CFG2_CHRG_CHRGSEL BIT(0)
>
> #define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATDETENB0 BIT(1)
>
> #define MX7D_USB_OTG_PHY_CFG2_CHRG_VDATSRCENB0 BIT(2)
>
> #define MX7D_USB_OTG_PHY_CFG2_CHRG_DCDENB BIT(3)
>
> #define MX7D_USB_OTG_PHY_STATUS_LINE_STATE0 BIT(0)
>
> #define MX7D_USB_OTG_PHY_STATUS_LINE_STATE1 BIT(1)
>
> #define MX7D_USB_OTG_PHY_STATUS_CHRGDET BIT(29)
>
> According to NXP i.MX93 & i.MX95 Reference Manual, these are bits reserved.
>
> Is it correct that the chipidea/usbmisc_imx use these bits on i.MX93?
i.MX93 & i.MX95 no longer claims to support Battery charger detection. So these
bits are reserved. However, at the IP level, accessing these bits will not produce
errors. We will remove .charger_detection hook for the i.MX9 series in the future.
Do you want to use Battery charger detection on i.MX93?
Thanks,
Xu Yang
>
> Best regards
>
> [1] - https://www.nxp.com/docs/en/reference-manual/IMX93RM.pdf
> <https://www.nxp.com/docs/en/reference-manual/IMX93RM.pdf>
>
> [2] - https://www.nxp.com/docs/en/reference-manual/IMX8MMRM.pdf
> <https://www.nxp.com/docs/en/reference-manual/IMX8MMRM.pdf>
>
> [3] - https://www.nxp.com/docs/en/reference-manual/IMX95RM.pdf
> <https://www.nxp.com/docs/en/reference-manual/IMX95RM.pdf>
>
^ permalink raw reply
* [PATCH] usb: core: devio: validate device and interface before buffer allocation
From: André Moreira @ 2026-06-24 2:35 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-usb, linux-kernel, André Moreira
The proc_ioctl() function currently allocates a buffer using kmalloc()
before checking the USB device state and resolving the interface number.
If either validation fails, the function must free the buffer and return
an error.
Move these checks to the top of the function to fail early. This avoids
unnecessary memory allocation and deallocation on error paths, removes
the nested 'else' structure, and eliminates redundant kfree() calls,
making the code cleaner and easier to maintain.
Signed-off-by: André Moreira <andrem.33333@gmail.com>
---
drivers/usb/core/devio.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index e191934623c73..8329d1c7d1b27 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -2329,6 +2329,13 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
if (!connected(ps))
return -ENODEV;
+ if (ps->dev->state != USB_STATE_CONFIGURED)
+ return -EHOSTUNREACH;
+
+ intf = usb_ifnum_to_if(ps->dev, ctl->ifno);
+ if (!intf)
+ return -EINVAL;
+
/* alloc buffer */
size = _IOC_SIZE(ctl->ioctl_code);
if (size > 0) {
@@ -2345,11 +2352,7 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
- if (ps->dev->state != USB_STATE_CONFIGURED)
- retval = -EHOSTUNREACH;
- else if (!(intf = usb_ifnum_to_if(ps->dev, ctl->ifno)))
- retval = -EINVAL;
- else switch (ctl->ioctl_code) {
+ switch (ctl->ioctl_code) {
/* disconnect kernel driver from interface */
case USBDEVFS_DISCONNECT:
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Alan Stern @ 2026-06-24 1:35 UTC (permalink / raw)
To: Nikhil Solanke
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <CAFgddhJk0EYG71fnKdio=RHC-cH+JmL-EZ7-oVD-LdHoa2TBSA@mail.gmail.com>
On Wed, Jun 24, 2026 at 02:44:07AM +0530, Nikhil Solanke wrote:
> > Moving this delay up here changes the behavior when the quirk flag isn't
> > set. While it agrees with the intention of the USB_QUIRK_DELAY_INIT
> > flag, such a change should be mentioned in the patch description.
>
> How should I mention it then? Nothing comes to mind besides the
> obvious: "Also move the USB_QUIRK_DELAY_INIT sleep to before the
> initial descriptor read, so the delay applies consistently regardless
> of whether USB_QUIRK_CONFIG_SIZE is set.". Or should i revert it back
> to original position?
Actually, the best approach here would be to put this single change into
a separate patch that comes before the current one. That removes issues
of making more than one functional change in one patch and improves
bisectability.
But to answer your question: In general, a patch's description should
explain the reasons for the changes that the patch makes. Especially
when a particular change doesn't appear, at first glance, to be related
to the patch's primary purpose. (On the other hand, it doesn't need to
explain in detail what the patch does; we can see that for ourselves
just by reading the patch's contents.)
> > > + /*
> > > + * Grab just the first descriptor so we know how long the whole
> > > + * configuration is. In case of quirky firmware, try to grab the
> > > + * whole thing in one go by asking for a 255-bytes sized buffer
> > > + * mirroring Windows behavior.
> > > + */
> >
> > This needs to be rewritten, as it is self-contradictory. When the quirk
> > flag is set we issue a 255-byte request to mimic the Windows behavior,
> > and only when the flag isn't set do we grab just the first descriptor.
>
> I am sorry I didn't understand how it is self contradictory. The
> comment does say, "in case of quirky firmware..."? Am i missing
> something?
Literally, what the comment says is: Grab just the first descriptor,
and if the quirk flag is set, get all the descriptors. That's a
contradiction -- you can get just the first, or you can get all of
them, but you can't do both at the same time!
> > > result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> > > - desc, USB_DT_CONFIG_SIZE);
> > > + desc, usb_config_req_size);
> >
> > Don't make extraneous changes to the existing indentation (or whitespace
> > in general), here and below.
>
> Well the linux coding style guidelines mention that those descendants
> should preferably be aligned with the function open parenthesis. Since
> i did "touch" that line/part of code I though might as well indent it
> a bit accordingly. Should i revert the indent then (in this and the
> other place)?
The style used in this file is to indent continuation lines by 4 spaces,
because some of the continued statements are extremely long. If you
want to align new continuation lines with an open paren, you can -- but
you didn't even do that in the example above; you aligned it with the
space following the first comma.
And while you did change some nearby code, you did not change the code
in this line. So reformatting it is not justified.
> > > if (result != -EPIPE)
> > > goto err;
> > > dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
> > > @@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
> > > break;
> > > } else if (result < 4) {
> > > dev_err(ddev, "config index %d descriptor too short "
> > > - "(expected %i, got %i)\n", cfgno,
> > > - USB_DT_CONFIG_SIZE, result);
> > > + "(asked for %zu, got %i, expected at least %i)\n",
> > > + cfgno, usb_config_req_size, result, 4);
> > > result = -EINVAL;
> > > goto err;
> > > }
> > > +
> > > length = max_t(int, le16_to_cpu(desc->wTotalLength),
> > > - USB_DT_CONFIG_SIZE);
> > > + USB_DT_CONFIG_SIZE);
> >
> > This is another example of a change that has nothing to do with the
> > purpose of the patch.
>
> Isn't that what you told me to change? So the logs are accurate? I
> made that change because you suggested it. :')
My comment referred to the two lines directly above it, and I did not
suggest leaving the code exactly the same except for indenting it
farther. Or inserting an extra blank line just before the assignment to
length.
Alan Stern
^ permalink raw reply
* [PATCH] thunderbolt: xdomain: notify peers after enumeration
From: Rqirus @ 2026-06-24 1:11 UTC (permalink / raw)
To: Mika Westerberg
Cc: Andreas Noever, Michael Jamet, Yehezkel Bernat, linux-usb,
linux-kernel, Rqirus
Service drivers may register local XDomain properties while discovery is
still in progress. This can cause the properties changed notification to be
sent before the peer is ready to act on it.
If the peer has already read the local property block before the service
was registered, it may keep using the old property generation and miss the
newly registered service. With ThunderboltIP this can leave the network
service half-discovered after a warm reboot and the login request
eventually times out.
Queue another properties changed notification after the XDomain reaches
ENUMERATED so the peer can re-read the final local properties.
Signed-off-by: Rqirus <cmh79479@gmail.com>
---
drivers/thunderbolt/xdomain.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/thunderbolt/xdomain.c b/drivers/thunderbolt/xdomain.c
index 86b2f7474..9c068d073 100644
--- a/drivers/thunderbolt/xdomain.c
+++ b/drivers/thunderbolt/xdomain.c
@@ -1811,6 +1811,7 @@ static void tb_xdomain_state_work(struct work_struct *work)
tb_xdomain_failed(xd);
} else {
xd->state = XDOMAIN_STATE_ENUMERATED;
+ tb_xdomain_queue_properties_changed(xd);
}
break;
base-commit: 502d801f0ab03e4f32f9a33d203154ce84887921
--
2.47.3
^ permalink raw reply related
* Re: [PATCH net v2] net: usb: lan78xx: restore VLAN and hash filters after link up
From: patchwork-bot+netdevbpf @ 2026-06-23 23:30 UTC (permalink / raw)
To: Nicolai Buchwitz
Cc: Thangaraj.S, Rengarajan.S, UNGLinuxDriver, Woojung.Huh,
andrew+netdev, davem, edumazet, kuba, pabeni, schuchmann, netdev,
linux-usb, linux-kernel
In-Reply-To: <20260622102911.484045-1-nb@tipi-net.de>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Mon, 22 Jun 2026 12:29:11 +0200 you wrote:
> Configured VLANs intermittently stop receiving traffic after a link
> down/up cycle, e.g. when the network cable is unplugged and plugged back
> in. VLAN filtering stays enabled but all VLAN-tagged frames are dropped
> until a VLAN is added or removed again.
>
> The LAN7801 datasheet (DS00002123E) states:
>
> [...]
Here is the summary with links:
- [net,v2] net: usb: lan78xx: restore VLAN and hash filters after link up
https://git.kernel.org/netdev/net/c/5c12248673c7
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Nikhil Solanke @ 2026-06-23 21:14 UTC (permalink / raw)
To: Alan Stern
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <567e8866-4308-4e5f-819c-fe778dbf74f8@rowland.harvard.edu>
> Moving this delay up here changes the behavior when the quirk flag isn't
> set. While it agrees with the intention of the USB_QUIRK_DELAY_INIT
> flag, such a change should be mentioned in the patch description.
How should I mention it then? Nothing comes to mind besides the
obvious: "Also move the USB_QUIRK_DELAY_INIT sleep to before the
initial descriptor read, so the delay applies consistently regardless
of whether USB_QUIRK_CONFIG_SIZE is set.". Or should i revert it back
to original position?
> > +
> > + /*
> > + * Grab just the first descriptor so we know how long the whole
> > + * configuration is. In case of quirky firmware, try to grab the
> > + * whole thing in one go by asking for a 255-bytes sized buffer
> > + * mirroring Windows behavior.
> > + */
>
> This needs to be rewritten, as it is self-contradictory. When the quirk
> flag is set we issue a 255-byte request to mimic the Windows behavior,
> and only when the flag isn't set do we grab just the first descriptor.
I am sorry I didn't understand how it is self contradictory. The
comment does say, "in case of quirky firmware..."? Am i missing
something?
> > result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> > - desc, USB_DT_CONFIG_SIZE);
> > + desc, usb_config_req_size);
>
> Don't make extraneous changes to the existing indentation (or whitespace
> in general), here and below.
Well the linux coding style guidelines mention that those descendants
should preferably be aligned with the function open parenthesis. Since
i did "touch" that line/part of code I though might as well indent it
a bit accordingly. Should i revert the indent then (in this and the
other place)?
> > if (result != -EPIPE)
> > goto err;
> > dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
> > @@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
> > break;
> > } else if (result < 4) {
> > dev_err(ddev, "config index %d descriptor too short "
> > - "(expected %i, got %i)\n", cfgno,
> > - USB_DT_CONFIG_SIZE, result);
> > + "(asked for %zu, got %i, expected at least %i)\n",
> > + cfgno, usb_config_req_size, result, 4);
> > result = -EINVAL;
> > goto err;
> > }
> > +
> > length = max_t(int, le16_to_cpu(desc->wTotalLength),
> > - USB_DT_CONFIG_SIZE);
> > + USB_DT_CONFIG_SIZE);
>
> This is another example of a change that has nothing to do with the
> purpose of the patch.
Isn't that what you told me to change? So the logs are accurate? I
made that change because you suggested it. :')
> > +
> > + /*
> > + * If the device returns the full length configuration
> > + * descriptor, skip the second read. Otherwise, send a second
>
> Strictly speaking, the configuration descriptor is only 9 bytes long.
> What you mean here is the entire configuration descriptor set.
Alright i'll reword it.
> > + * request asking for the full length.
> > + */
> > + if (result >= le16_to_cpu(desc->wTotalLength)) {
>
> Shouldn't this be: result >= length? No point in repeating the
> le16_to_cpu calculation.
Yess. initially the length assignment was happening afterwards in my
patch. then i decided to move it before the "if" statement since the
outcome of length was going to be similar in any case (within if and
after if). but then i forgot to modify the if too. Will fix it.
> Like above, this string should all be on one line.
Will fix all the strings as well
Nikhil Solanke
^ permalink raw reply
* Re: [PATCH v2 2/2] dt-bindings: Drop incorrect usage of double '::'
From: Andi Shyti @ 2026-06-23 20:26 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: linux-arm-msm, devicetree, linux-kernel, linux-arm-kernel,
linux-samsung-soc, linux-clk, dri-devel, freedreno, linux-i2c,
linux-pm, linux-leds, linux-media, linux-mmc, linux-phy,
linux-gpio, linux-renesas-soc, linux-serial, linux-sound,
linux-usb
In-Reply-To: <20260623054842.21831-4-krzysztof.kozlowski@oss.qualcomm.com>
Hi Krzysztof,
On Tue, Jun 23, 2026 at 07:48:44AM +0200, Krzysztof Kozlowski wrote:
> There is no use of double colon '::' in YAML. OTOH, the literal style
> block, e.g. using '|' treats all characters as content [1] therefore
> single use of ':' in descriptions is perfectly fine, whenever '|' is
> used.
>
> Cleanup existing code, so the confusing style won't be re-used in new
> contributions.
>
> Link: https://yaml.org/spec/1.2.2/#literal-style [1]
> Acked-by: Conor Dooley <conor.dooley@microchip.com>
> Acked-by: Alim Akhtar <alim.akhtar@samsung.com>
> Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
> Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> Acked-by: Mark Brown <broonie@kernel.org>
> Acked-by: Geert Uytterhoeven <geert+renesas@glider.be> # renesas
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Acked-by: Andi Shyti <andi.shyti@kernel.org>
Thanks,
Andi
^ permalink raw reply
* Re: [PATCH v2 1/2] dt-bindings: clock: Drop incorrect usage of double '::'
From: Andi Shyti @ 2026-06-23 20:26 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: linux-arm-msm, devicetree, linux-kernel, linux-arm-kernel,
linux-samsung-soc, linux-clk, dri-devel, freedreno, linux-i2c,
linux-pm, linux-leds, linux-media, linux-mmc, linux-phy,
linux-gpio, linux-renesas-soc, linux-serial, linux-sound,
linux-usb
In-Reply-To: <20260623054842.21831-3-krzysztof.kozlowski@oss.qualcomm.com>
Hi Krzysztof,
On Tue, Jun 23, 2026 at 07:48:43AM +0200, Krzysztof Kozlowski wrote:
> There is no use of double colon '::' in YAML. OTOH, the literal style
> block, e.g. using '|' treats all characters as content [1] therefore
> single use of ':' in descriptions is perfectly fine, whenever '|' is
> used.
>
> Cleanup existing code, so the confusing style won't be re-used in new
> contributions.
>
> Link: https://yaml.org/spec/1.2.2/#literal-style [1]
> Acked-by: Alim Akhtar <alim.akhtar@samsung.com>
> Acked-by: Conor Dooley <conor.dooley@microchip.com>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Acked-by: Andi Shyti <andi.shyti@kernel.org>
Thanks,
Andi
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Alan Stern @ 2026-06-23 20:24 UTC (permalink / raw)
To: Nikhil Solanke
Cc: linux-usb, gregkh, linux-kernel, michal.pecio, stable, corbet,
skhan, linux-doc
In-Reply-To: <20260623161035.5792-1-nikhilsolanke5@gmail.com>
This is looking better. A few more things to mention below, but
otherwise okay.
On Tue, Jun 23, 2026 at 09:40:35PM +0530, Nikhil Solanke wrote:
> Certain third-party USB game controllers exposing (or spoofing) an Xbox
> 360-compatible interface (VID:PID 045e:028e) fail to enumerate under Linux.
> The device disconnects from the bus without responding to the initial
> GET_DESCRIPTOR(CONFIGURATION) request, and the kernel logs 'unable to read
> config index 0 descriptor/start: -71'.
>
> The device then falls back to a secondary Android HID mode (with a
> different VID:PID), losing XInput functionality including rumble support.
> The failure reproduces across multiple machines, host controller types, and
> kernel versions including current mainline and LTS. The device enumerates
> correctly and remains in XInput mode under Windows. Notably, the device
> enumerates correctly in Android mode when the same 9-byte request
> is issued for that mode's configuration descriptor, confirming the firmware
> bug is specific to the XInput mode.
>
> usbmon traces from Linux and Wireshark/USBPcap traces from Windows are
> identical up to the point of failure, with no visible protocol-level
> difference explaining the divergence. The root cause was identified when
> Michal Pecio discovered via a QEMU bus-level capture that Windows does not
> use wLength=9 for the initial config descriptor request; it uses
> wLength=255. Alan Stern subsequently confirmed this with a bus
> analyzer on a different USB 2.0 device, and Michal verified the behavior
> goes back to Windows 95 OSR2.1.
>
> So, add a new quirk flag USB_QUIRK_CONFIG_SIZE which causes
> usb_get_configuration() to issue a 255 byte sized configuration request
> instead of USB_DT_CONFIG_SIZE (9) for the initial
> GET_DESCRIPTOR(CONFIGURATION) request, mimicking long-standing Windows
> behavior.
>
> Suggested-by: Alan Stern <stern@rowland.harvard.edu>
> Suggested-by: Michal Pecio <michal.pecio@gmail.com>
> Closes: https://lore.kernel.org/linux-usb/CAFgddh+JWdT4LLwMc5qjM8q_pBu-fRo2qADR5ovAKoGHWMQrRw@mail.gmail.com/
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
>
> Signed-off-by: Nikhil Solanke <nikhilsolanke5@gmail.com>
Normally people don't leave a blank line before their Signed-off-by:
(unless it's the first tag to appear). But I don't think it makes any
difference, especially if the checkpatch.pl script doesn't object.
> ---
> Changes in v2:
> - Add Documentation
> - Naming changes
> - Refactored to have a better flow with existing code.
>
> .../admin-guide/kernel-parameters.txt | 9 +++
> drivers/usb/core/config.c | 61 ++++++++++++++-----
> drivers/usb/core/hub.c | 6 +-
> drivers/usb/core/quirks.c | 4 ++
> include/linux/usb/quirks.h | 3 +
> 5 files changed, 67 insertions(+), 16 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 97007f4f69d4..af4bf0ef2c7b 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -8158,6 +8158,15 @@ Kernel parameters
> q = USB_QUIRK_FORCE_ONE_CONFIG (Device
> claims zero configurations,
> forcing to 1);
> + r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device
> + fails during initialization when asked for
> + 9-bytes configuration desciptor request. Ask
> + for 255-bytes request instead to mirror
> + Windows' behavior. This quirk is originally
> + meant to fix some quirky gamepads that refuse
> + to connect in their XInput mode. But it can also
> + potentially fix issues with other USB devices
> + that work on Windows but not on Linux)
> Example: quirks=0781:5580:bk,0a5c:5834:gij
As Randy said, use tabs instead of spaces. And this new entry should be
aligned with all the preceding entries, and it should end with a ';'
like they do.
I would leave out the two sentences of explanation, but that's more of a
personal choice. We'll see if Greg KH objects.
>
> usbhid.mousepoll=
> diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
> index 45e20c6d76c0..4fc3145404d6 100644
> --- a/drivers/usb/core/config.c
> +++ b/drivers/usb/core/config.c
> @@ -19,6 +19,9 @@
>
> #define USB_MAXCONFIG 8 /* Arbitrary limit */
>
> +/* config req size if USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE is set */
> +#define USB_CONFIG_WINDOWS_REQ_SIZE 255
> +
> static int find_next_descriptor(unsigned char *buffer, int size,
> int dt1, int dt2, int *num_skipped)
> {
> @@ -912,6 +915,13 @@ int usb_get_configuration(struct usb_device *dev)
> unsigned char *bigbuffer;
> struct usb_config_descriptor *desc;
> int result;
> + /*
> + * Devices with quirky firmware will stall or reset when asked only for
> + * the configuration header. This variable decides which size to use in
> + * that case, if the quirk for that device was set.
> + */
> + size_t usb_config_req_size = (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE)
> + ? USB_CONFIG_WINDOWS_REQ_SIZE : USB_DT_CONFIG_SIZE;
It's a little unusual to have a multiline comment in the middle of a
bunch of variable definitions. The alternative is to do the assignment
later on and move the comment there.
>
> if (ncfg > USB_MAXCONFIG) {
> dev_notice(ddev, "too many configurations: %d, "
> @@ -938,18 +948,27 @@ int usb_get_configuration(struct usb_device *dev)
> if (!dev->rawdescriptors)
> return -ENOMEM;
>
> - desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
> + desc = kmalloc(usb_config_req_size, GFP_KERNEL);
> +
> if (!desc)
> return -ENOMEM;
>
> for (cfgno = 0; cfgno < ncfg; cfgno++) {
> - /* We grab just the first descriptor so we know how long
> - * the whole configuration is */
> +
> + if (dev->quirks & USB_QUIRK_DELAY_INIT)
> + msleep(200);
Moving this delay up here changes the behavior when the quirk flag isn't
set. While it agrees with the intention of the USB_QUIRK_DELAY_INIT
flag, such a change should be mentioned in the patch description.
> +
> + /*
> + * Grab just the first descriptor so we know how long the whole
> + * configuration is. In case of quirky firmware, try to grab the
> + * whole thing in one go by asking for a 255-bytes sized buffer
> + * mirroring Windows behavior.
> + */
This needs to be rewritten, as it is self-contradictory. When the quirk
flag is set we issue a 255-byte request to mimic the Windows behavior,
and only when the flag isn't set do we grab just the first descriptor.
> result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> - desc, USB_DT_CONFIG_SIZE);
> + desc, usb_config_req_size);
Don't make extraneous changes to the existing indentation (or whitespace
in general), here and below.
> if (result < 0) {
> dev_err(ddev, "unable to read config index %d "
> - "descriptor/%s: %d\n", cfgno, "start", result);
> + "descriptor/%s: %d\n", cfgno, "start", result);
At the time this code was originally written, the policy for kernel code
was to break lines before 80 columns. Since then the policy has changed
to avoid splitting long literal strings into pieces, even when that
means exceeding 80 columns. So your new string here should all go on
one line.
> if (result != -EPIPE)
> goto err;
> dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
> @@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
> break;
> } else if (result < 4) {
> dev_err(ddev, "config index %d descriptor too short "
> - "(expected %i, got %i)\n", cfgno,
> - USB_DT_CONFIG_SIZE, result);
> + "(asked for %zu, got %i, expected at least %i)\n",
> + cfgno, usb_config_req_size, result, 4);
> result = -EINVAL;
> goto err;
> }
> +
> length = max_t(int, le16_to_cpu(desc->wTotalLength),
> - USB_DT_CONFIG_SIZE);
> + USB_DT_CONFIG_SIZE);
This is another example of a change that has nothing to do with the
purpose of the patch.
> +
> + /*
> + * If the device returns the full length configuration
> + * descriptor, skip the second read. Otherwise, send a second
Strictly speaking, the configuration descriptor is only 9 bytes long.
What you mean here is the entire configuration descriptor set.
> + * request asking for the full length.
> + */
> + if (result >= le16_to_cpu(desc->wTotalLength)) {
Shouldn't this be: result >= length? No point in repeating the
le16_to_cpu calculation.
> + bigbuffer = (unsigned char *) desc;
> + desc = NULL;
> + goto store_and_parse;
> + }
>
> /* Now that we know the length, get the whole thing */
> bigbuffer = kmalloc(length, GFP_KERNEL);
> @@ -972,23 +1003,25 @@ int usb_get_configuration(struct usb_device *dev)
> goto err;
> }
>
> - if (dev->quirks & USB_QUIRK_DELAY_INIT)
> - msleep(200);
> -
> result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
> - bigbuffer, length);
> + bigbuffer, length);
> +
> if (result < 0) {
> dev_err(ddev, "unable to read config index %d "
> - "descriptor/%s\n", cfgno, "all");
> + "descriptor/%s\n", cfgno, "all");
> kfree(bigbuffer);
> goto err;
> }
> +
More examples of unnecessary whitespace changes.
> if (result < length) {
> dev_notice(ddev, "config index %d descriptor too short "
> - "(expected %i, got %i)\n", cfgno, length, result);
> + "(asked for %i, got %i)\n",
> + cfgno, length, result);
> length = result;
> }
>
> +store_and_parse:
> + krealloc(bigbuffer, length, GFP_KERNEL);
> dev->rawdescriptors[cfgno] = bigbuffer;
>
> result = usb_parse_configuration(dev, cfgno,
> diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
> index 24960ba9caa9..9acd278666fc 100644
> --- a/drivers/usb/core/hub.c
> +++ b/drivers/usb/core/hub.c
> @@ -2527,8 +2527,10 @@ static int usb_enumerate_device(struct usb_device *udev)
> err = usb_get_configuration(udev);
> if (err < 0) {
> if (err != -ENODEV)
> - dev_err(&udev->dev, "can't read configurations, error %d\n",
> - err);
> + dev_err(&udev->dev, "can't read configurations, "
> + "for device %04x:%04x, error %d\n",
Like above, this string should all be on one line.
Alan Stern
> + le16_to_cpu(udev->descriptor.idVendor),
> + le16_to_cpu(udev->descriptor.idProduct), err);
> return err;
> }
> }
> diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
> index 87810eff974e..df670b0b66fe 100644
> --- a/drivers/usb/core/quirks.c
> +++ b/drivers/usb/core/quirks.c
> @@ -142,6 +142,10 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
> break;
> case 'q':
> flags |= USB_QUIRK_FORCE_ONE_CONFIG;
> + break;
> + case 'r':
> + flags |= USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE;
> + break;
> /* Ignore unrecognized flag characters */
> }
> }
> diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
> index b3cc7beab4a3..a4043b33c2c2 100644
> --- a/include/linux/usb/quirks.h
> +++ b/include/linux/usb/quirks.h
> @@ -81,4 +81,7 @@
> /* Device claims zero configurations, forcing to 1 */
> #define USB_QUIRK_FORCE_ONE_CONFIG BIT(18)
>
> +/* Use a 255 bytes config descriptor request mirroring windows behavior */
> +#define USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE BIT(19)
> +
> #endif /* __LINUX_USB_QUIRKS_H */
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Nikhil Solanke @ 2026-06-23 19:08 UTC (permalink / raw)
To: Randy Dunlap
Cc: linux-usb, gregkh, linux-kernel, stern, michal.pecio, stable,
corbet, skhan, linux-doc
In-Reply-To: <75822857-473d-4067-a378-aae2cdab4176@infradead.org>
> add ending '.'
>
> For all lines added here, use tabs instead of spaces for indentation.
Done! Waiting for any other changes before submitting v3
^ permalink raw reply
* Re: [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Randy Dunlap @ 2026-06-23 18:35 UTC (permalink / raw)
To: Nikhil Solanke, linux-usb
Cc: gregkh, linux-kernel, stern, michal.pecio, stable, corbet, skhan,
linux-doc
In-Reply-To: <20260623161035.5792-1-nikhilsolanke5@gmail.com>
On 6/23/26 9:10 AM, Nikhil Solanke wrote:
> Certain third-party USB game controllers exposing (or spoofing) an Xbox
> 360-compatible interface (VID:PID 045e:028e) fail to enumerate under Linux.
> The device disconnects from the bus without responding to the initial
> GET_DESCRIPTOR(CONFIGURATION) request, and the kernel logs 'unable to read
> config index 0 descriptor/start: -71'.
>
> The device then falls back to a secondary Android HID mode (with a
> different VID:PID), losing XInput functionality including rumble support.
> The failure reproduces across multiple machines, host controller types, and
> kernel versions including current mainline and LTS. The device enumerates
> correctly and remains in XInput mode under Windows. Notably, the device
> enumerates correctly in Android mode when the same 9-byte request
> is issued for that mode's configuration descriptor, confirming the firmware
> bug is specific to the XInput mode.
>
> usbmon traces from Linux and Wireshark/USBPcap traces from Windows are
> identical up to the point of failure, with no visible protocol-level
> difference explaining the divergence. The root cause was identified when
> Michal Pecio discovered via a QEMU bus-level capture that Windows does not
> use wLength=9 for the initial config descriptor request; it uses
> wLength=255. Alan Stern subsequently confirmed this with a bus
> analyzer on a different USB 2.0 device, and Michal verified the behavior
> goes back to Windows 95 OSR2.1.
>
> So, add a new quirk flag USB_QUIRK_CONFIG_SIZE which causes
> usb_get_configuration() to issue a 255 byte sized configuration request
> instead of USB_DT_CONFIG_SIZE (9) for the initial
> GET_DESCRIPTOR(CONFIGURATION) request, mimicking long-standing Windows
> behavior.
>
> Suggested-by: Alan Stern <stern@rowland.harvard.edu>
> Suggested-by: Michal Pecio <michal.pecio@gmail.com>
> Closes: https://lore.kernel.org/linux-usb/CAFgddh+JWdT4LLwMc5qjM8q_pBu-fRo2qADR5ovAKoGHWMQrRw@mail.gmail.com/
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
>
> Signed-off-by: Nikhil Solanke <nikhilsolanke5@gmail.com>
> ---
> Changes in v2:
> - Add Documentation
> - Naming changes
> - Refactored to have a better flow with existing code.
>
> .../admin-guide/kernel-parameters.txt | 9 +++
> drivers/usb/core/config.c | 61 ++++++++++++++-----
> drivers/usb/core/hub.c | 6 +-
> drivers/usb/core/quirks.c | 4 ++
> include/linux/usb/quirks.h | 3 +
> 5 files changed, 67 insertions(+), 16 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 97007f4f69d4..af4bf0ef2c7b 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -8158,6 +8158,15 @@ Kernel parameters
> q = USB_QUIRK_FORCE_ONE_CONFIG (Device
> claims zero configurations,
> forcing to 1);
> + r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device
> + fails during initialization when asked for
> + 9-bytes configuration desciptor request. Ask
descriptor
> + for 255-bytes request instead to mirror
> + Windows' behavior. This quirk is originally
> + meant to fix some quirky gamepads that refuse
> + to connect in their XInput mode. But it can also
> + potentially fix issues with other USB devices
> + that work on Windows but not on Linux)
add ending '.'
For all lines added here, use tabs instead of spaces for indentation.
> Example: quirks=0781:5580:bk,0a5c:5834:gij
>
> usbhid.mousepoll=
--
~Randy
^ permalink raw reply
* [PATCH v2] usbcore: Add quirk for 255-bytes initial config read
From: Nikhil Solanke @ 2026-06-23 16:10 UTC (permalink / raw)
To: linux-usb
Cc: gregkh, linux-kernel, stern, michal.pecio, stable, corbet, skhan,
linux-doc, Nikhil Solanke
Certain third-party USB game controllers exposing (or spoofing) an Xbox
360-compatible interface (VID:PID 045e:028e) fail to enumerate under Linux.
The device disconnects from the bus without responding to the initial
GET_DESCRIPTOR(CONFIGURATION) request, and the kernel logs 'unable to read
config index 0 descriptor/start: -71'.
The device then falls back to a secondary Android HID mode (with a
different VID:PID), losing XInput functionality including rumble support.
The failure reproduces across multiple machines, host controller types, and
kernel versions including current mainline and LTS. The device enumerates
correctly and remains in XInput mode under Windows. Notably, the device
enumerates correctly in Android mode when the same 9-byte request
is issued for that mode's configuration descriptor, confirming the firmware
bug is specific to the XInput mode.
usbmon traces from Linux and Wireshark/USBPcap traces from Windows are
identical up to the point of failure, with no visible protocol-level
difference explaining the divergence. The root cause was identified when
Michal Pecio discovered via a QEMU bus-level capture that Windows does not
use wLength=9 for the initial config descriptor request; it uses
wLength=255. Alan Stern subsequently confirmed this with a bus
analyzer on a different USB 2.0 device, and Michal verified the behavior
goes back to Windows 95 OSR2.1.
So, add a new quirk flag USB_QUIRK_CONFIG_SIZE which causes
usb_get_configuration() to issue a 255 byte sized configuration request
instead of USB_DT_CONFIG_SIZE (9) for the initial
GET_DESCRIPTOR(CONFIGURATION) request, mimicking long-standing Windows
behavior.
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Suggested-by: Michal Pecio <michal.pecio@gmail.com>
Closes: https://lore.kernel.org/linux-usb/CAFgddh+JWdT4LLwMc5qjM8q_pBu-fRo2qADR5ovAKoGHWMQrRw@mail.gmail.com/
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Nikhil Solanke <nikhilsolanke5@gmail.com>
---
Changes in v2:
- Add Documentation
- Naming changes
- Refactored to have a better flow with existing code.
.../admin-guide/kernel-parameters.txt | 9 +++
drivers/usb/core/config.c | 61 ++++++++++++++-----
drivers/usb/core/hub.c | 6 +-
drivers/usb/core/quirks.c | 4 ++
include/linux/usb/quirks.h | 3 +
5 files changed, 67 insertions(+), 16 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 97007f4f69d4..af4bf0ef2c7b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -8158,6 +8158,15 @@ Kernel parameters
q = USB_QUIRK_FORCE_ONE_CONFIG (Device
claims zero configurations,
forcing to 1);
+ r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device
+ fails during initialization when asked for
+ 9-bytes configuration desciptor request. Ask
+ for 255-bytes request instead to mirror
+ Windows' behavior. This quirk is originally
+ meant to fix some quirky gamepads that refuse
+ to connect in their XInput mode. But it can also
+ potentially fix issues with other USB devices
+ that work on Windows but not on Linux)
Example: quirks=0781:5580:bk,0a5c:5834:gij
usbhid.mousepoll=
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 45e20c6d76c0..4fc3145404d6 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -19,6 +19,9 @@
#define USB_MAXCONFIG 8 /* Arbitrary limit */
+/* config req size if USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE is set */
+#define USB_CONFIG_WINDOWS_REQ_SIZE 255
+
static int find_next_descriptor(unsigned char *buffer, int size,
int dt1, int dt2, int *num_skipped)
{
@@ -912,6 +915,13 @@ int usb_get_configuration(struct usb_device *dev)
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
int result;
+ /*
+ * Devices with quirky firmware will stall or reset when asked only for
+ * the configuration header. This variable decides which size to use in
+ * that case, if the quirk for that device was set.
+ */
+ size_t usb_config_req_size = (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE)
+ ? USB_CONFIG_WINDOWS_REQ_SIZE : USB_DT_CONFIG_SIZE;
if (ncfg > USB_MAXCONFIG) {
dev_notice(ddev, "too many configurations: %d, "
@@ -938,18 +948,27 @@ int usb_get_configuration(struct usb_device *dev)
if (!dev->rawdescriptors)
return -ENOMEM;
- desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
+ desc = kmalloc(usb_config_req_size, GFP_KERNEL);
+
if (!desc)
return -ENOMEM;
for (cfgno = 0; cfgno < ncfg; cfgno++) {
- /* We grab just the first descriptor so we know how long
- * the whole configuration is */
+
+ if (dev->quirks & USB_QUIRK_DELAY_INIT)
+ msleep(200);
+
+ /*
+ * Grab just the first descriptor so we know how long the whole
+ * configuration is. In case of quirky firmware, try to grab the
+ * whole thing in one go by asking for a 255-bytes sized buffer
+ * mirroring Windows behavior.
+ */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
- desc, USB_DT_CONFIG_SIZE);
+ desc, usb_config_req_size);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s: %d\n", cfgno, "start", result);
+ "descriptor/%s: %d\n", cfgno, "start", result);
if (result != -EPIPE)
goto err;
dev_notice(ddev, "chopping to %d config(s)\n", cfgno);
@@ -957,13 +976,25 @@ int usb_get_configuration(struct usb_device *dev)
break;
} else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short "
- "(expected %i, got %i)\n", cfgno,
- USB_DT_CONFIG_SIZE, result);
+ "(asked for %zu, got %i, expected at least %i)\n",
+ cfgno, usb_config_req_size, result, 4);
result = -EINVAL;
goto err;
}
+
length = max_t(int, le16_to_cpu(desc->wTotalLength),
- USB_DT_CONFIG_SIZE);
+ USB_DT_CONFIG_SIZE);
+
+ /*
+ * If the device returns the full length configuration
+ * descriptor, skip the second read. Otherwise, send a second
+ * request asking for the full length.
+ */
+ if (result >= le16_to_cpu(desc->wTotalLength)) {
+ bigbuffer = (unsigned char *) desc;
+ desc = NULL;
+ goto store_and_parse;
+ }
/* Now that we know the length, get the whole thing */
bigbuffer = kmalloc(length, GFP_KERNEL);
@@ -972,23 +1003,25 @@ int usb_get_configuration(struct usb_device *dev)
goto err;
}
- if (dev->quirks & USB_QUIRK_DELAY_INIT)
- msleep(200);
-
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
- bigbuffer, length);
+ bigbuffer, length);
+
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
- "descriptor/%s\n", cfgno, "all");
+ "descriptor/%s\n", cfgno, "all");
kfree(bigbuffer);
goto err;
}
+
if (result < length) {
dev_notice(ddev, "config index %d descriptor too short "
- "(expected %i, got %i)\n", cfgno, length, result);
+ "(asked for %i, got %i)\n",
+ cfgno, length, result);
length = result;
}
+store_and_parse:
+ krealloc(bigbuffer, length, GFP_KERNEL);
dev->rawdescriptors[cfgno] = bigbuffer;
result = usb_parse_configuration(dev, cfgno,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 24960ba9caa9..9acd278666fc 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2527,8 +2527,10 @@ static int usb_enumerate_device(struct usb_device *udev)
err = usb_get_configuration(udev);
if (err < 0) {
if (err != -ENODEV)
- dev_err(&udev->dev, "can't read configurations, error %d\n",
- err);
+ dev_err(&udev->dev, "can't read configurations, "
+ "for device %04x:%04x, error %d\n",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct), err);
return err;
}
}
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 87810eff974e..df670b0b66fe 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -142,6 +142,10 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
break;
case 'q':
flags |= USB_QUIRK_FORCE_ONE_CONFIG;
+ break;
+ case 'r':
+ flags |= USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE;
+ break;
/* Ignore unrecognized flag characters */
}
}
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index b3cc7beab4a3..a4043b33c2c2 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -81,4 +81,7 @@
/* Device claims zero configurations, forcing to 1 */
#define USB_QUIRK_FORCE_ONE_CONFIG BIT(18)
+/* Use a 255 bytes config descriptor request mirroring windows behavior */
+#define USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE BIT(19)
+
#endif /* __LINUX_USB_QUIRKS_H */
--
2.54.0
^ permalink raw reply related
* Re: [PATCH V2] thunderbolt: fix bandwidth group reservation indexing
From: Mika Westerberg @ 2026-06-23 15:40 UTC (permalink / raw)
To: raoxu; +Cc: andreas.noever, westeri, YehezkelShB, linux-usb, linux-kernel
In-Reply-To: <E53B82E8FA767BC5+20260623133759.3019094-1-raoxu@uniontech.com>
Hi,
On Tue, Jun 23, 2026 at 09:37:59PM +0800, raoxu wrote:
> From: Xu Rao <raoxu@uniontech.com>
>
> Group ID 0 is reserved, while valid bandwidth groups use IDs 1 through
> 7. MAX_GROUPS is used both for tb_cm::groups, which stores allocatable
> bandwidth groups, and for group_reserved[], which is indexed directly
> by Group ID.
>
> tb_init_bandwidth_groups() assigns i + 1 to each entry in
> tb_cm::groups. Keeping seven entries therefore creates exactly the valid
> Group IDs 1 through 7.
>
> However, group_reserved[MAX_GROUPS] currently also has seven entries,
> providing indices 0 through 6. When a tunnel belongs to Group ID 7,
> tb_consumed_dp_bandwidth() reads and may write one element past the end
> of the array. The reservation for that group is consequently not
> included in the consumed bandwidth total either.
>
> Define MAX_GROUPS as 7 + 1 so arrays indexed directly by Group ID cover
> the complete 0 through 7 range, including the reserved ID 0. Size
> tb_cm::groups as MAX_GROUPS - 1 so only seven bandwidth group objects
> are initialized and tb_init_bandwidth_groups() continues to assign IDs
> 1 through 7. tb_consumed_dp_bandwidth() can then retain the direct
> Group ID indexing, with Group ID 7 selecting the final valid array
> element instead of accessing beyond it.
>
> Fixes: 52a4490e89d7 ("thunderbolt: Reserve released DisplayPort bandwidth for a group for 10 seconds")
> Signed-off-by: Xu Rao <raoxu@uniontech.com>
> ---
> Changes in v2:
> - Drop the zero-based Group ID conversion used in v1 and keep
> group->index as the direct group_reserved[] index.
> - Include the reserved Group ID 0 in MAX_GROUPS so direct-indexed arrays
> cover the complete Group ID range 0 through 7.
> - Size tb_cm::groups as MAX_GROUPS - 1 so
> tb_init_bandwidth_groups() continues to create only the seven valid
> groups with IDs 1 through 7.
>
> drivers/thunderbolt/tb.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
> index 76323255439a..51f909db9383 100644
> --- a/drivers/thunderbolt/tb.c
> +++ b/drivers/thunderbolt/tb.c
> @@ -41,7 +41,7 @@
> */
> #define TB_ASYM_THRESHOLD 45000
>
> -#define MAX_GROUPS 7 /* max Group_ID is 7 */
> +#define MAX_GROUPS (7 + 1) /* Group ID 0 is reserved */
>
> static unsigned int asym_threshold = TB_ASYM_THRESHOLD;
> module_param_named(asym_threshold, asym_threshold, uint, 0444);
> @@ -66,7 +66,7 @@ struct tb_cm {
> struct list_head dp_resources;
> bool hotplug_active;
> struct delayed_work remove_work;
> - struct tb_bandwidth_group groups[MAX_GROUPS];
> + struct tb_bandwidth_group groups[MAX_GROUPS - 1];
Why this? We still need to be able to put there GroupIDs 1 to 7 (and keep
the 0 as is).
> };
>
> static inline struct tb *tcm_to_tb(struct tb_cm *tcm)
> --
> 2.50.1
^ permalink raw reply
* Re: [PATCH v2 1/3] usb: typec: Add helper to check cable altmode support
From: Andrei Kuchynski @ 2026-06-23 15:34 UTC (permalink / raw)
To: Heikki Krogerus
Cc: Benson Leung, Jameson Thies, Greg Kroah-Hartman, linux-usb,
linux-kernel
In-Reply-To: <ajpEG7ryQi8im7U-@kuha>
if you are not against it
On Tue, Jun 23, 2026 at 10:30 AM Heikki Krogerus
<heikki.krogerus@linux.intel.com> wrote:
>
> One day and I'm completely confused again :). I opened the code for
> myself (not compiled) to get the idea again. Please consider that, or
> something like it - the important part for me is the enum. The enum
> does not cost that many lines, but it does make the idea more clear,
> at least for me.
>
Thank you for such a detailed look.
The code not only compiles, but it actually works as expected)
> case IDH_PTYPE_PCABLE:
> if (speed == CABLE_USB2_ONLY)
> return CABLE_NOT_SUPPORTED;
> break;
With one change: `return CABLE_SUPPORTED;` instead of `break` here.
So, the enum and the wrapper are in V3.
If you don't mind, I'll add you to the "Co-Developers" list.
Thanks,
Andrei
^ permalink raw reply
* [PATCH 1/3] USB: serial: metro-usb: replace unnecessary atomic allocation
From: Johan Hovold @ 2026-06-23 15:21 UTC (permalink / raw)
To: linux-usb; +Cc: Greg Kroah-Hartman, linux-kernel, Johan Hovold
In-Reply-To: <20260623152148.316149-1-johan@kernel.org>
The unthrottle callback is allowed to sleep so pass the correct GFP flag
to usb_submit_urb() to avoid unnecessary atomic allocations.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/usb/serial/metro-usb.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
index 35473544f1c8..f42ad5dec35e 100644
--- a/drivers/usb/serial/metro-usb.c
+++ b/drivers/usb/serial/metro-usb.c
@@ -329,7 +329,7 @@ static void metrousb_unthrottle(struct tty_struct *tty)
spin_unlock_irqrestore(&metro_priv->lock, flags);
/* Submit the urb to read from the port. */
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"failed submitting interrupt in urb error code=%d\n",
--
2.53.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox