feat: fast Intel BT firmware download (bulk-pipelined payload, no timeout burns)

Two fixes, verified on the AX211 (8087:0033), ibt-1040-0041.sfi, 720 KB:

1. TryHeader waited 1500+2000 ms for secure-send results after the CSS and
   key/signature sends, but on success this controller stays SILENT until
   the end of the whole download (traced) -- both timeouts always burned in
   full.  A rejection arrives within milliseconds, so 250 ms windows lose
   nothing and save ~3 s per cold boot.

2. The payload now goes over the bulk OUT endpoint with up to 7 fragments
   in flight (the btusb bootloader path for 0xFC09), replacing ~2900
   synchronous 3-stage EP0 control transfers.  Headers stay on EP0; the
   ACL TX DMA ring is reused (no ACL header, no NOCP credit accounting).
   DrainBulkTx() ensures all bytes reach the controller before waiting for
   the download-complete result.

Also in this branch since main: IRQ-safe BT-TRACE ring (KernelLogStream in
TransferCallback deadlocked on the terminal Mutex from MSI context), xHCI
interrupt-IN ZLP length fix, always-re-arm of the BT event pipe,
InPollContext same-core owner check, TLV version read retry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
danielandClaude Fable 5 committed 2026-07-07 11:52:21 +02:00
1 parent dc89495011
commit 72f6c4449c
4 files changed
+95 -5

No files matched your search

@@ -153,20 +153,25 @@ namespace Drivers::USB::Bluetooth {
uint8_t result = 0, status = 0;
// 1. CSS header init -- check the result before committing key/sig.
// A rejection event arrives within milliseconds; on SUCCESS the
// controller stays silent until the END of the whole download (traced
// on the AX211), so a long timeout here only burns boot time.
Hci::ClearSecureSendResult();
if (!Hci::IntelSecureSend(0x00, fw + cssOff, 128)) return false;
if (Hci::WaitSecureSendResult(1500, &result, &status) && (result || status)) {
if (Hci::WaitSecureSendResult(250, &result, &status) && (result || status)) {
KernelLogStream(WARNING, "BT-FW") << name << " CSS rejected (result="
<< base::hex << (uint64_t)result << " status=" << (uint64_t)status
<< base::dec << ")";
return false;
}
// 2. Public key + signature.
// 2. Public key + signature. Same rule: silence means accepted; a
// rejected header also fails the payload phase immediately, so the
// short window loses nothing.
Hci::ClearSecureSendResult();
if (!Hci::IntelSecureSend(0x03, fw + pkeyOff, pkeyLen)) return false;
if (!Hci::IntelSecureSend(0x02, fw + sigOff, sigLen)) return false;
if (Hci::WaitSecureSendResult(2000, &result, &status) && (result || status)) {
if (Hci::WaitSecureSendResult(250, &result, &status) && (result || status)) {
KernelLogStream(WARNING, "BT-FW") << name << " header rejected (result="
<< base::hex << (uint64_t)result << " status=" << (uint64_t)status
<< base::dec << ")";
@@ -203,7 +208,10 @@ namespace Drivers::USB::Bluetooth {
}
if ((fragLen % 4) == 0) {
if (!Hci::IntelSecureSend(0x01, fw + fwPtr, fragLen)) {
// Payload goes over the bulk endpoint, pipelined (the btusb
// bootloader path) -- EP0's synchronous 3-stage transfers made
// the 720 KB image the dominant boot cost.
if (!Hci::IntelSecureSendBulk(0x01, fw + fwPtr, fragLen)) {
KernelLogStream(ERROR, "BT-FW") << "Payload secure-send failed at offset "
<< fwPtr;
return false;
@@ -233,6 +241,14 @@ namespace Drivers::USB::Bluetooth {
}
}
}
// The bulk pipeline may still hold up to 7 in-flight fragments; make
// sure every byte reached the controller before the caller waits for
// the download-complete result.
if (!Hci::DrainBulkTx(3000)) {
KernelLogStream(ERROR, "BT-FW") << "Bulk TX drain timed out at end of payload";
return false;
}
return true;
}