From 37f5ff892c1239fa1367fd9dccb1e919bc182a3d Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Tue, 7 Jul 2026 11:52:21 +0200 Subject: [PATCH] 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 --- kernel/src/Api/BuildNo.hpp | 2 +- kernel/src/Drivers/USB/Bluetooth/Hci.cpp | 67 +++++++++++++++++++ kernel/src/Drivers/USB/Bluetooth/Hci.hpp | 7 ++ .../Drivers/USB/Bluetooth/IntelFirmware.cpp | 24 +++++-- 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 8b446bd..39cdee0 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 23 +#define MONTAUK_BUILD_NUMBER 25 diff --git a/kernel/src/Drivers/USB/Bluetooth/Hci.cpp b/kernel/src/Drivers/USB/Bluetooth/Hci.cpp index 41f20ea..cb1762f 100644 --- a/kernel/src/Drivers/USB/Bluetooth/Hci.cpp +++ b/kernel/src/Drivers/USB/Bluetooth/Hci.cpp @@ -1248,6 +1248,73 @@ namespace Drivers::USB::Bluetooth::Hci { return true; } + // Bulk-OUT variant of IntelSecureSend, for the firmware PAYLOAD phase. + // In bootloader mode the Intel controller accepts 0xFC09 command packets + // on the bulk OUT endpoint (the btusb bootloader path); unlike EP0's + // 3-stage synchronous transfers this lets several fragments be in flight + // at once, which is where Linux's ~1.3s download speed comes from. + // Reuses the ACL TX DMA ring (no ACL traffic can exist yet -- the ACL + // header is deliberately absent, and the NOCP credit counter is NOT + // touched: these are commands, not ACL data). + bool IntelSecureSendBulk(uint8_t fragmentType, const uint8_t* data, uint32_t len) { + if (!g_initialized || !g_aclTxRing[0]) return false; + + uint32_t off = 0; + while (len > 0) { + uint8_t frag = (len > 252) ? 252 : (uint8_t)len; + + // Throttle on TX ring slots (leave one of headroom), reaping + // completions while full. A wall-clock bound keeps a wedged + // controller from freezing the boot path. + uint64_t start = Timekeeping::GetMilliseconds(); + while (AclTxInFlight() >= (uint32_t)(ACL_TX_SLOTS - 1)) { + Xhci::PollEvents(); + if (Timekeeping::GetMilliseconds() - start > 2000) { + KernelLogStream(ERROR, "BT-HCI") + << "Bulk secure-send stalled at frag #" << (uint64_t)g_ssFragsSent + << " byte " << g_ssBytesSent; + return false; + } + asm volatile("pause" ::: "memory"); + } + + g_aclTxLock.Acquire(); + uint8_t* txBuf = g_aclTxRing[g_aclTxSlot]; + uint64_t txPhys = g_aclTxRingPhys[g_aclTxSlot]; + g_aclTxSlot = (uint8_t)((g_aclTxSlot + 1) % ACL_TX_SLOTS); + + // Raw HCI command packet, bulk-framed: opcode + plen + [type + data]. + txBuf[0] = (uint8_t)(OP_INTEL_SECURE_SEND & 0xFF); + txBuf[1] = (uint8_t)(OP_INTEL_SECURE_SEND >> 8); + txBuf[2] = (uint8_t)(frag + 1); + txBuf[3] = fragmentType; + memcpy(&txBuf[4], data + off, frag); + + g_aclTxCount.fetch_add(1, std::memory_order_relaxed); + Xhci::QueueBulkOutTransfer(g_slotId, txBuf, txPhys, (uint32_t)frag + 4); + g_aclTxLock.Release(); + + g_ssBytesSent += frag; + g_ssFragsSent++; + len -= frag; + off += frag; + } + return true; + } + + // Wait until every queued bulk OUT transfer has completed (all payload + // bytes handed to the controller). Call before waiting for the final + // secure-send result. + bool DrainBulkTx(uint32_t timeoutMs) { + uint64_t start = Timekeeping::GetMilliseconds(); + while (AclTxInFlight() > 0) { + Xhci::PollEvents(); + if (Timekeeping::GetMilliseconds() - start > timeoutMs) return false; + asm volatile("pause" ::: "memory"); + } + return true; + } + bool IntelBootFirmware(uint32_t bootAddr, uint32_t timeoutMs) { g_intelBootup = false; diff --git a/kernel/src/Drivers/USB/Bluetooth/Hci.hpp b/kernel/src/Drivers/USB/Bluetooth/Hci.hpp index 51452b2..6b41bfc 100644 --- a/kernel/src/Drivers/USB/Bluetooth/Hci.hpp +++ b/kernel/src/Drivers/USB/Bluetooth/Hci.hpp @@ -244,6 +244,13 @@ namespace Drivers::USB::Bluetooth::Hci { // 0xFF/0x06 secure-send result event (see WaitSecureSendResult). bool IntelSecureSend(uint8_t fragmentType, const uint8_t* data, uint32_t len); + // Pipelined bulk-OUT variant for the firmware payload (btusb bootloader + // path: 0xFC09 packets on the bulk endpoint, several in flight). Call + // DrainBulkTx() after the last fragment to ensure everything reached the + // controller before waiting for the download-complete result. + bool IntelSecureSendBulk(uint8_t fragmentType, const uint8_t* data, uint32_t len); + bool DrainBulkTx(uint32_t timeoutMs); + // Reset / await the Intel "secure send result" vendor event (0xFF/0x06). // Call ClearSecureSendResult() before a download phase, then // WaitSecureSendResult() to read the outcome (result/status, 0 = success). diff --git a/kernel/src/Drivers/USB/Bluetooth/IntelFirmware.cpp b/kernel/src/Drivers/USB/Bluetooth/IntelFirmware.cpp index aa0c44f..8fa3cf5 100644 --- a/kernel/src/Drivers/USB/Bluetooth/IntelFirmware.cpp +++ b/kernel/src/Drivers/USB/Bluetooth/IntelFirmware.cpp @@ -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; }