From nobody Fri Sep 25 20:07:40 2026 Received: from mail-wr2-f12.google.com (mail-wr2-f12.google.com [74.125.225.76]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AB7683B47EF for ; Tue, 8 Sep 2026 23:43:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.76 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788911018; cv=none; b=fY1cmyExK0PMjmShDruQbiNUZXpq6Plk7MZCCT8Ulz1lwVdHAR0i2XeNnIblc9LK6EoxeeHzgKICOf6u84cbBLcgJkOtLW1Bgun4gGvRlUvvfdR51lEGQ4gpZVUZyEty3otRLpnVLzOCGPVHo8RYDEpMyLd3J2qWEfzihgUYezo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788911018; c=relaxed/simple; bh=uwYgOWB6T85giMBSAkiXo5AXxkPNnz+4KKs0hupdbKk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TzIa+z1Nv4nOlqiV3YF2QqlmiYi53jtdgCv1aD3sczrzJ+LR/J+hsakIesbYnhs+AtN201lRy/XD4ElgUwl+L3wsNkk5XT9usuYDOK6CaGwcnKE6dqshIQGFtlh8jx0GKa5L4VwiTfRERdQk5ZB+vET1xlpK/wAUixO1gfEitfs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=fireburn.co.uk; spf=none smtp.mailfrom=fireburn.co.uk; dkim=pass (2048-bit key) header.d=fireburn-co-uk.20251104.gappssmtp.com header.i=@fireburn-co-uk.20251104.gappssmtp.com header.b=0ICz5k5K; arc=none smtp.client-ip=74.125.225.76 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=fireburn.co.uk Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=fireburn.co.uk Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=fireburn-co-uk.20251104.gappssmtp.com header.i=@fireburn-co-uk.20251104.gappssmtp.com header.b="0ICz5k5K" Received: by mail-wr2-f12.google.com with SMTP id ffacd0b85a97d-482f6356256so730345f8f.1 for ; Tue, 08 Sep 2026 16:43:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=fireburn-co-uk.20251104.gappssmtp.com; s=20251104; t=1788911015; x=1789515815; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Z21b6fsoY2E6Vzr2RDS21MTgNdKIrr6ZxRGvarq9zjQ=; b=0ICz5k5KkX7+Cgy32968AY4YtYGJQLMvrLXdkeXr+ZRALB8GqR66KuKGcHGdD7sFCd 03qaoZzRGCZV+qvZ6ADriIZdWrRDhaOVNp5ak98iNOvafAZvCcqqPOaNGVFoq8S10ZPp ElbPIF2cMrIWLBxRSBpgZKAgWKW9uBUh8LcF2VWRRElckOCBv9isbKiOp+WoQOE9uAH2 Az8JxYaPxc40aCcssDqgtQx4Xcsl5IuxCdpvu4NnUpd/1ccCgBaj0OFQ5DksTSzt0v/7 bT9ziL7QYGfRghcVKp4EqLFR7mHggJaaWVDPX94Qef5wFo7bKC8z8rZ9BauGJvqPcDHq t48w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788911015; x=1789515815; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Z21b6fsoY2E6Vzr2RDS21MTgNdKIrr6ZxRGvarq9zjQ=; b=gmjJhBFY0gOByPNgu2mH3pfP/HPmaieXgwi0bLwKlHmgLTccPvfaEPbekp674NWG0H XUFAXJ/KrfbFqUwFeeirleu9MAg9XfpyYj4cir94ZwfkYVXuj7yQnd1cR/HlZevyTSvk CSCkfFktfPz/LKaH18UTKGFv0zhIsAX4ZDicxN4guFWAxVYuahnRvloUUOFk9X5daSs4 gfrUyKIR1Xjy/pVi0guvSGmTlnYzkTyDiXB/qprFYaMlTMzERXFrzKrhtrybwlzG6OPo n50zdWGO7a9kN7q/2MY3ITCgtNDRTLUisjrUtSDKVLoJSO71Zrdxq2Su5yDVnXD6wTtK 5Png== X-Forwarded-Encrypted: i=1; AKwUvBxoAX6ioOgqvkPVCdUDz/nGgB3p7fNDdenrUtlQim61hauYK/V6juP6wFn/rDk6f+cE5zE+zSJCkipJXf4=@vger.kernel.org X-Gm-Message-State: AFuF++knf40QUFKWENBLfIoaOgSae3P3PK+hdVe3+uLzVythMlnhIpwE AOg9S4v9cjz1yvYAlGMx40MjzT/ti/sXs/WYCBo11N2NlmpTHkMTCrV9rEFTLND1sw== X-Gm-Gg: AYBFou12aLal4jw5wOjCOEZyfe40ezUCMM8hY2HUxrOojEfvh0PWd8ZIBEieRaGlRTA lOiiuEYrKbwgqU9qkzC+n1VCsbQmFxt1dfEPOAy9FOMOoIZGm2ORLeBI7UmZxMGTMe92PJ2jSZa CZrXXpk9tznJrRKHU8kMc5j6qesXLLEssYW8fQg3wkEQMTmmrOUc03weLbtF7RckKNeJzqWjU1S iwHZkX22m+1mX3sXkBNCFr7oPxJRj4gE8cc3XnyqcFjpBlrddfIiRwlan4uozDg1NoZjPpwx5HZ vwQ3sGSaz7hH+VTfUA50IqeAsdH4bn321e6HO0MlhA55eWMOwkx14Jrbntl/nkQG1x6QHUZyIKL mwQA/HMKvRsVNHorF36b0zctctQ95a7AAij5hx4IfsTfE07AAyfjII2dR39CjDwk8lFkIsmTkyQ bCyq92rMH+veXBSyG1fGO+WSC8C1CWSekVB4KYYSSV+kt3rRyfWDUOXFkqEFDjqrk+vHDd771/2 N+z7Nvz6Bgmo5YNIdaZaQ8ZNlwT3rkgpie8 X-Received: by 2002:a05:600c:4455:b0:493:f783:c46a with SMTP id 5b1f17b1804b1-49d1754fdf6mr107220985e9.6.1788911014994; Tue, 08 Sep 2026 16:43:34 -0700 (PDT) Received: from axion.fireburn.co.uk ([2a01:4b00:d309:1c00:caf1:6b20:8531:818c]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-49cfbe5b252sm376047695e9.3.2026.09.08.16.43.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 08 Sep 2026 16:43:34 -0700 (PDT) From: Mike Lothian To: "Daniel J . Ogorchock" Cc: Jiri Kosina , Benjamin Tissoires , Silvan Jegen , Dmitry Torokhov , linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, Mike Lothian Subject: [PATCH v2] HID: nintendo: relax subcommand limiter until cadence is proven Date: Wed, 9 Sep 2026 00:43:15 +0100 Message-ID: <20260908234315.117903-1-mike@fireburn.co.uk> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260908224532.114357-1-mike@fireburn.co.uk> References: <20260908224532.114357-1-mike@fireburn.co.uk> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" joycon_config_rumble() queues a zero-rumble packet during probe. The rumble worker sends it once ctlr_state becomes READ, and joycon_handle_rumble_report() retries it a few more times. This is the first subcommand sent on every connection and it goes out before any input report has been seen, so consecutive_valid_report_deltas is still 0. joycon_enforce_subcmd_rate_strict() needs 3 consecutive reports in the 8-17ms window before it releases a subcommand, so the send exhausts all 25 attempts and warns on every connection. Add a subcmd_rate_unproven flag, set until the cadence has been observed, and use the legacy flat-delay throttle while it is set. joycon_parse_report() clears it after JC_SUBCMD_VALID_DELTA_REQ consecutive reports at a valid cadence. USB is excluded, as its consecutive_valid_report_deltas is forced to the requirement anyway. The flag is separate from subcmd_rate_relaxed so that the exhaustion fallback added by commit 781f8e020a78 ("HID: nintendo: fix rumble starved by the input report cadence gate") keeps its semantics. subcmd_rate_relaxed is written from the subcommand worker under output_mutex, subcmd_rate_unproven only from joycon_parse_report(). Found with btmon over Bluetooth on a MediaTek mt7921e: the three JC_SUBCMD_RATE_MAX_ATTEMPTS warnings on connect match three JC_OUTPUT_RUMBLE_ONLY (0x10) frames from the rumble worker's zero-countdown retries. Tested on a Pro Controller, which now connects reliably, where before it dropped within the first ~70 seconds of a fresh connection about half the time. Fixes: d750d1480362 ("HID: nintendo: fix rumble rate limiter") Signed-off-by: Mike Lothian Assisted-by: Claude:Opus-5 [Claude Code] --- v2: - Use a separate subcmd_rate_unproven flag rather than reusing subcmd_rate_relaxed. In v1 joycon_parse_report() cleared subcmd_rate_relaxed from softirq under ctlr->lock, while joycon_enforce_subcmd_rate_strict() sets it from the subcommand worker under output_mutex. Clearing it after the exhaustion counter had passed JC_SUBCMD_RATE_MAX_FAILURES would stop the ++subcmd_rate_exhaustions =3D=3D JC_SUBCMD_RATE_MAX_FAILURES test from ever matching again, permanently disabling the fallback added by 781f8e020a78. - Start USB controllers proven. consecutive_valid_report_deltas is forced to JC_SUBCMD_VALID_DELTA_REQ for USB at the end of joycon_parse_report(), so the v1 promotion could never run and USB would have been left on the legacy throttle. - v1 was assisted by Claude Sonnet 5, v2 by Claude Opus 5. Both issues in v1 were spotted by the Sashiko AI review: https://lore.kernel.org/linux-input/20260908225815.952CE1F00A3A@smtp.kernel= .org/ That review also flagged a pre-existing issue: that the probe error path does not set ctlr_state to JOYCON_CTLR_STATE_REMOVED, so a queued rumble worker could run against stopped hardware during destroy_workqueue(). As far as I can tell that is not reachable. The worker can only be queued from joycon_handle_rumble_report(), which runs via joycon_ctlr_read_handler() and is gated on ctlr_state =3D=3D JOYCON_CTLR_STATE_READ, and from joycon_play_effect(), which needs the input device registered. input_register_device() is the last call in joycon_input_create() that can fail, and ctlr_state is set to READ immediately after it returns, so there is no window in which the worker is queued and probe can still fail. v1: https://lore.kernel.org/linux-input/20260908224532.114357-1-mike@firebu= rn.co.uk/ drivers/hid/hid-nintendo.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-nintendo.c b/drivers/hid/hid-nintendo.c index 43e0f2aaea3b..5b3d97c0ad39 100644 --- a/drivers/hid/hid-nintendo.c +++ b/drivers/hid/hid-nintendo.c @@ -611,6 +611,7 @@ struct joycon_ctlr { unsigned int consecutive_valid_report_deltas; unsigned int subcmd_rate_exhaustions; bool subcmd_rate_relaxed; + bool subcmd_rate_unproven; =20 /* factory calibration data */ struct joycon_stick_cal left_stick_cal_x; @@ -917,7 +918,7 @@ static void joycon_enforce_subcmd_rate_legacy(struct jo= ycon_ctlr *ctlr) =20 static void joycon_enforce_subcmd_rate(struct joycon_ctlr *ctlr) { - if (ctlr->subcmd_rate_relaxed) + if (ctlr->subcmd_rate_relaxed || READ_ONCE(ctlr->subcmd_rate_unproven)) joycon_enforce_subcmd_rate_legacy(ctlr); else joycon_enforce_subcmd_rate_strict(ctlr); @@ -1797,8 +1798,11 @@ static void joycon_parse_report(struct joycon_ctlr *= ctlr, */ if (report_delta_ms >=3D JC_INPUT_REPORT_MIN_DELTA && report_delta_ms <=3D JC_INPUT_REPORT_MAX_DELTA) { - if (ctlr->consecutive_valid_report_deltas < JC_SUBCMD_VALID_DELTA_REQ) + if (ctlr->consecutive_valid_report_deltas < JC_SUBCMD_VALID_DELTA_REQ) { ctlr->consecutive_valid_report_deltas++; + if (ctlr->consecutive_valid_report_deltas =3D=3D JC_SUBCMD_VALID_DELTA_= REQ) + WRITE_ONCE(ctlr->subcmd_rate_unproven, false); + } } else { ctlr->consecutive_valid_report_deltas =3D 0; } @@ -2730,6 +2734,7 @@ static int nintendo_hid_probe(struct hid_device *hdev, =20 ctlr->hdev =3D hdev; ctlr->ctlr_state =3D JOYCON_CTLR_STATE_INIT; + ctlr->subcmd_rate_unproven =3D hdev->bus !=3D BUS_USB; ctlr->rumble_queue_head =3D 0; ctlr->rumble_queue_tail =3D 0; hid_set_drvdata(hdev, ctlr); --=20 2.55.0