wip: async BT firmware download attempt — DO NOT MERGE, breaks AX211 bring-up
Deferring the Intel BT firmware download off the boot path made the AX211 bootloader stop answering after the first FC05; even the final synchronous revert freezes boot, so one of the 'neutral' fixes kept in this diff breaks the bring-up on its own (candidates: BT-TRACE logging inside TransferCallback, unconditional interrupt-IN re-queue after error completions on a halted EP, xHCI interrupt-IN ZLP len fix interacting with HID, InPollContext owner check). Full history + next experiments in memory notes, 2026-07-05/06. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
@@ -15,6 +15,8 @@
|
||||
#include <CppLib/Stream.hpp>
|
||||
#include <Libraries/Memory.hpp>
|
||||
#include <Timekeeping/ApicTimer.hpp>
|
||||
#include <Hal/SmpBoot.hpp>
|
||||
#include <atomic>
|
||||
|
||||
using namespace Kt;
|
||||
|
||||
@@ -31,8 +33,10 @@ namespace Drivers::USB::Bluetooth {
|
||||
// True when the USB transport is up but the firmware-dependent HCI init is
|
||||
// still waiting for the ramdisk (drive 0) to be mounted. Set when an
|
||||
// adapter enumerates during the boot port scan, which runs before the boot
|
||||
// filesystems are mounted; cleared by ServiceDeferredInit() once VFS is up.
|
||||
static bool g_initPending = false;
|
||||
// filesystems are mounted; claimed (atomically -- the pickup runs from the
|
||||
// idle loop, concurrently with the rest of the system) by
|
||||
// ServiceDeferredInit() once VFS is up.
|
||||
static std::atomic<bool> g_initPending{false};
|
||||
|
||||
// Forward declaration: firmware-dependent HCI bring-up, run once VFS is up.
|
||||
static void CompleteInit();
|
||||
@@ -236,15 +240,19 @@ namespace Drivers::USB::Bluetooth {
|
||||
|
||||
// Start the event pipe BEFORE sending any HCI commands.
|
||||
// HCI command responses arrive as events on the interrupt IN endpoint,
|
||||
// so it must be queued to receive them.
|
||||
// so it must be queued to receive them. Deliberately done HERE, at
|
||||
// enumeration time, not in the deferred bring-up: this preserves the
|
||||
// exact transport timing of the original synchronous boot path.
|
||||
Hci::StartEventPipe();
|
||||
|
||||
// The firmware download path reads the .sfi/.ddc images from the
|
||||
// ramdisk (drive 0). Adapters present at boot enumerate during the
|
||||
// xHCI port scan, which runs before the boot filesystems are mounted,
|
||||
// so defer the firmware-dependent bring-up until VFS is available.
|
||||
// The idle loop (ServiceDeferredInit) picks it up after boot, keeping
|
||||
// the multi-second firmware download off the boot-critical path.
|
||||
if (!Fs::Vfs::IsDriveRegistered(0)) {
|
||||
g_initPending = true;
|
||||
g_initPending.store(true, std::memory_order_release);
|
||||
KernelLogStream(INFO, "BT") << "Transport up; deferring init until ramdisk is mounted";
|
||||
return;
|
||||
}
|
||||
@@ -362,12 +370,33 @@ namespace Drivers::USB::Bluetooth {
|
||||
// =========================================================================
|
||||
|
||||
void ServiceDeferredInit() {
|
||||
if (!g_initPending || g_initialized) return;
|
||||
if (!g_initPending.load(std::memory_order_relaxed) || g_initialized) return;
|
||||
if (!Fs::Vfs::IsDriveRegistered(0)) return; // ramdisk still not mounted
|
||||
if (Xhci::InPollContext()) return; // never nest under PollEvents
|
||||
|
||||
g_initPending = false;
|
||||
KernelLogStream(INFO, "BT") << "Ramdisk mounted; completing Bluetooth init";
|
||||
// Claim the pending init (this runs from the idle loop; make sure only
|
||||
// one pass performs the bring-up). The firmware download inside takes
|
||||
// seconds -- running it here instead of on the boot path is what keeps
|
||||
// boot fast.
|
||||
bool expected = true;
|
||||
if (!g_initPending.compare_exchange_strong(expected, false,
|
||||
std::memory_order_acquire)) return;
|
||||
|
||||
KernelLogStream(INFO, "BT") << "Completing deferred Bluetooth init in background";
|
||||
|
||||
// Reserve this CPU for the duration. The bring-up overlaps desktop
|
||||
// startup, and if the scheduler tick pulls this idle context away
|
||||
// whenever a process is ready, the HCI waits' wall-clock timeouts
|
||||
// expire with almost no polling done. Reserved, the bring-up runs
|
||||
// uninterrupted here while processes use other CPUs; on a single-CPU
|
||||
// system this briefly pauses userspace, matching the old synchronous
|
||||
// behavior minus the boot-path stall.
|
||||
auto* cpu = Smp::GetCurrentCpuData();
|
||||
if (cpu) cpu->reservedForKernelWork = true;
|
||||
Hci::SetFwTrace(true); // bounded per-completion event-pipe trace
|
||||
CompleteInit();
|
||||
Hci::SetFwTrace(false);
|
||||
if (cpu) cpu->reservedForKernelWork = false;
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
Reference in New Issue
Block a user