Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion ASFWDriver/ASFWDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include "Protocols/AVC/AVCDiscovery.hpp"
#include "Protocols/AVC/CMP/CMPClient.hpp"
#include "Protocols/AVC/FCPResponseRouter.hpp"
#include "Protocols/SBP2/Session/DriverKitSessionScheduler.hpp"
#include "Scheduling/Scheduler.hpp"
#include "Service/DriverContext.hpp"
#include "Service/LocalRequestWiring.hpp"
Expand Down Expand Up @@ -306,7 +307,11 @@ kern_return_t IMPL(ASFWDriver, Start) {

// Construct the SBP-2 manager dependency, then assemble the single inbound
// request dispatch (CSR / FCP / DICE / SBP-2) in one place.
DriverWiring::EnsureSbp2Deps(ctx);
kr = DriverWiring::EnsureSbp2Deps(*this, ctx);
if (kr != kIOReturnSuccess) {
DriverWiring::CleanupStartFailure(ctx);
return kr;
}
ASFW::Service::WireLocalRequestDispatch(ctx);
EnsureRomScanner(ctx);

Expand Down Expand Up @@ -593,6 +598,21 @@ void ASFWDriver::AsyncWatchdogTimerFired_Impl(ASFWDriver_AsyncWatchdogTimerFired
ScheduleAsyncWatchdog(kAsyncWatchdogPeriodUsec);
}

void ASFWDriver::SBP2SessionTimerFired_Impl(ASFWDriver_SBP2SessionTimerFired_Args) {
(void)action;
(void)time;

if (!ivars || !ivars->context) {
return;
}
auto& ctx = *ivars->context;
if (ctx.stopping.load(std::memory_order_acquire) || !ctx.deps.sbp2SessionScheduler) {
return;
}

ctx.deps.sbp2SessionScheduler->HandleTimerFired();
}

void ASFWDriver::ProviderNotificationReady_Impl(ASFWDriver_ProviderNotificationReady_Args) {
(void)action;

Expand Down
4 changes: 4 additions & 0 deletions ASFWDriver/ASFWDriver.iig
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public:
uint64_t time)
TYPE(IOTimerDispatchSource::TimerOccurred);

virtual void SBP2SessionTimerFired(OSAction* action,
uint64_t time)
TYPE(IOTimerDispatchSource::TimerOccurred);

virtual void ProviderNotificationReady(OSAction* action)
TYPE(IOServiceNotificationDispatchSource::ServiceNotificationReady);

Expand Down
7 changes: 7 additions & 0 deletions ASFWDriver/Controller/ControllerCore.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ class FCPResponseRouter;

namespace ASFW::Protocols::SBP2 {
class AddressSpaceManager;
class DriverKitSessionScheduler;
class SessionRegistry;
}

namespace ASFW::IRM {
Expand Down Expand Up @@ -143,6 +145,8 @@ class ControllerCore final : private Role::IPhyConfigReset,
std::shared_ptr<ASFW::Protocols::AVC::AVCDiscovery> avcDiscovery;
std::shared_ptr<ASFW::Protocols::AVC::FCPResponseRouter> fcpResponseRouter;
std::shared_ptr<ASFW::Protocols::SBP2::AddressSpaceManager> sbp2AddressSpaceManager;
std::shared_ptr<ASFW::Protocols::SBP2::DriverKitSessionScheduler> sbp2SessionScheduler;
std::shared_ptr<ASFW::Protocols::SBP2::SessionRegistry> sbp2SessionRegistry;

// FW-19: local software CSR responder (STATE_SET/CLEAR, BROADCAST_CHANNEL,
// TOPOLOGY_MAP) plus its hardware adapters for root status / cycle master.
Expand Down Expand Up @@ -212,6 +216,9 @@ class ControllerCore final : private Role::IPhyConfigReset,
Protocols::SBP2::AddressSpaceManager* GetSbp2AddressSpaceManager() const;
void SetSbp2AddressSpaceManager(
std::shared_ptr<Protocols::SBP2::AddressSpaceManager> sbp2AddressSpaceManager);
Protocols::SBP2::SessionRegistry* GetSbp2SessionRegistry() const;
void SetSbp2SessionRegistry(
std::shared_ptr<Protocols::SBP2::SessionRegistry> sbp2SessionRegistry);

IRM::IRMClient* GetIRMClient() const;
void SetIRMClient(std::shared_ptr<IRM::IRMClient> client);
Expand Down
5 changes: 5 additions & 0 deletions ASFWDriver/Controller/ControllerCoreDiscovery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "../Hardware/RegisterMap.hpp"
#include "../Bus/IRM/IRMClient.hpp"
#include "../Protocols/AVC/AVCDiscovery.hpp"
#include "../Protocols/SBP2/Session/SessionRegistry.hpp"
#include "../Protocols/AVC/CMP/CMPClient.hpp"
#include "../Audio/Protocols/DeviceProtocolFactory.hpp"
#include "../Scheduling/Scheduler.hpp"
Expand Down Expand Up @@ -626,6 +627,10 @@ void ControllerCore::OnDiscoveryScanComplete(Discovery::Generation gen,
gen.value);
}

if (deps_.sbp2SessionRegistry) {
deps_.sbp2SessionRegistry->RefreshTargets(gen);
}

ASFW_LOG(Discovery, "Discovery complete: %zu devices processed in gen=%u", roms.size(),
gen.value);
ASFW_LOG(Discovery, "═══════════════════════════════════════════════════════");
Expand Down
10 changes: 10 additions & 0 deletions ASFWDriver/Controller/ControllerCoreFacades.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "../Bus/IRM/IRMClient.hpp"
#include "../Protocols/AVC/AVCDiscovery.hpp"
#include "../Protocols/AVC/CMP/CMPClient.hpp"
#include "../Protocols/SBP2/Session/SessionRegistry.hpp"
#include "../Audio/Protocols/DeviceProtocolFactory.hpp"
#include "../Scheduling/Scheduler.hpp"
#include "../Version/DriverVersion.hpp"
Expand Down Expand Up @@ -105,6 +106,15 @@ void ControllerCore::SetSbp2AddressSpaceManager(
deps_.sbp2AddressSpaceManager = std::move(sbp2AddressSpaceManager);
}

Protocols::SBP2::SessionRegistry* ControllerCore::GetSbp2SessionRegistry() const {
return deps_.sbp2SessionRegistry.get();
}

void ControllerCore::SetSbp2SessionRegistry(
std::shared_ptr<Protocols::SBP2::SessionRegistry> sbp2SessionRegistry) {
deps_.sbp2SessionRegistry = std::move(sbp2SessionRegistry);
}

IRM::IRMClient* ControllerCore::GetIRMClient() const { return deps_.irmClient.get(); }

void ControllerCore::SetIRMClient(std::shared_ptr<IRM::IRMClient> client) {
Expand Down
4 changes: 4 additions & 0 deletions ASFWDriver/Controller/ControllerCoreInterrupts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "../Hardware/RegisterMap.hpp"
#include "../Bus/IRM/IRMClient.hpp"
#include "../Protocols/AVC/AVCDiscovery.hpp"
#include "../Protocols/SBP2/Session/SessionRegistry.hpp"
#include "../Protocols/AVC/CMP/CMPClient.hpp"
#include "../Audio/Protocols/DeviceProtocolFactory.hpp"
#include "../Scheduling/Scheduler.hpp"
Expand Down Expand Up @@ -82,6 +83,9 @@ void ControllerCore::HandleInterrupt(const InterruptSnapshot& snapshot) {
if (powerLinkPolicy_) {
powerLinkPolicy_->OnBusResetStarted(generation);
}
if (deps_.sbp2SessionRegistry) {
deps_.sbp2SessionRegistry->OnBusReset(static_cast<uint16_t>(generation));
}
}
DispatchAsyncInterrupts(events);
LogBusResetCompletionEvents(events, snapshot.timestamp);
Expand Down
35 changes: 33 additions & 2 deletions ASFWDriver/Protocols/SBP2/AddressSpaceManager.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#pragma once

#include <algorithm>
#include <array>
#include <atomic>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <optional>
Expand Down Expand Up @@ -392,6 +392,21 @@ class AddressSpaceManager {
IOLockUnlock(lock_);
}

// Attach a human-readable label to a range for diagnostic logging only.
// No-op if the handle is unknown. Truncated to fit the fixed buffer.
void SetDebugLabel(uint64_t handle, const char* label) {
if (!lock_ || handle == 0) {
return;
}

IOLockLock(lock_);
auto it = ranges_.find(handle);
if (it != ranges_.end()) {
CopyDebugLabel(it->second, label);
}
IOLockUnlock(lock_);
}

void ClearAll() {
if (!lock_) {
return;
Expand All @@ -411,11 +426,14 @@ class AddressSpaceManager {
static constexpr uint32_t kAutoAddressWindowEndLo = 0x0FFF'FFFFu;
static constexpr uint64_t kAutoAddressAlignment = 8ULL;

static constexpr std::size_t kDebugLabelCapacity = 32;

struct AddressRange {
AddressRangeMeta meta{};
void* owner{nullptr};
std::vector<uint8_t> buffer;
RemoteWriteCallback onRemoteWrite;
std::array<char, kDebugLabelCapacity> debugLabel{};

OSSharedPtr<IOBufferMemoryDescriptor> descriptor{};
OSSharedPtr<IODMACommand> dmaCommand{};
Expand All @@ -425,6 +443,18 @@ class AddressSpaceManager {
bool hasBacking{false};
};

static void CopyDebugLabel(AddressRange& range, const char* label) {
range.debugLabel.fill('\0');
if (!label) {
return;
}
std::strncpy(range.debugLabel.data(), label, range.debugLabel.size() - 1);
}

[[maybe_unused]] static const char* DebugLabelCString(const AddressRange& range) {
return range.debugLabel[0] != '\0' ? range.debugLabel.data() : "unlabeled";
}

static uint64_t ComposeAddress(uint16_t hi, uint32_t lo) {
return (static_cast<uint64_t>(hi) << 32) | static_cast<uint64_t>(lo);
}
Expand Down Expand Up @@ -485,8 +515,9 @@ class AddressSpaceManager {
for (const auto& entry : ranges_) {
const auto& range = entry.second;
ASFW_ADDRSPACE_LOG(
"AddressSpaceManager[%p] range handle=0x%llx owner=%p addr=0x%012llx len=%u backing=%u dma=0x%08x",
"AddressSpaceManager[%p] range label=%s handle=0x%llx owner=%p addr=0x%012llx len=%u backing=%u dma=0x%08x",
this,
DebugLabelCString(range),
static_cast<unsigned long long>(range.meta.handle),
range.owner,
static_cast<unsigned long long>(range.meta.address),
Expand Down
41 changes: 29 additions & 12 deletions ASFWDriver/Protocols/SBP2/SBP2CommandORB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,15 @@ void SBP2CommandORB::DeallocateResources() noexcept {
// Command block (CDB)
// ---------------------------------------------------------------------------

void SBP2CommandORB::SetCommandBlock(std::span<const uint8_t> cdb) noexcept {
const uint32_t copyLen = static_cast<uint32_t>(
std::min(cdb.size(), static_cast<size_t>(maxCommandBlockSize_)));
bool SBP2CommandORB::SetCommandBlock(std::span<const uint8_t> cdb) noexcept {
// Reject (do not silently truncate) a CDB that won't fit the command block.
if (cdb.size() > static_cast<size_t>(maxCommandBlockSize_)) {
ASFW_LOG(Async, "SBP2CommandORB: CDB size %zu exceeds max command block %u",
cdb.size(), maxCommandBlockSize_);
return false;
}

const uint32_t copyLen = static_cast<uint32_t>(cdb.size());
if (copyLen > 0) {
std::memcpy(orbStorage_.data() + Wire::NormalORB::kHeaderSize,
cdb.data(), copyLen);
Expand All @@ -78,15 +83,20 @@ void SBP2CommandORB::SetCommandBlock(std::span<const uint8_t> cdb) noexcept {
std::memset(orbStorage_.data() + Wire::NormalORB::kHeaderSize + copyLen,
0, maxCommandBlockSize_ - copyLen);
}
return true;
}

// ---------------------------------------------------------------------------
// Prepare for execution (fills in dynamic fields)
// ---------------------------------------------------------------------------

void SBP2CommandORB::PrepareForExecution(uint16_t localNodeID,
FW::FwSpeed speed,
uint16_t maxPayloadLog) noexcept {
kern_return_t SBP2CommandORB::PrepareForExecution(uint16_t localNodeID,
FW::FwSpeed speed,
uint16_t maxPayloadLog) noexcept {
if (!IsValid()) {
return kIOReturnNotReady;
}

auto* orb = reinterpret_cast<Wire::NormalORB*>(orbStorage_.data());
const uint16_t busNodeID = Wire::NormalizeBusNodeID(localNodeID);

Expand Down Expand Up @@ -152,20 +162,21 @@ void SBP2CommandORB::PrepareForExecution(uint16_t localNodeID,
orb->dataSize = dataDescriptor_.dataSize;

// Flush ORB to address space
WriteORBToAddressSpace();
return WriteORBToAddressSpace();
}

// ---------------------------------------------------------------------------
// Write ORB buffer to DMA-backed address space
// ---------------------------------------------------------------------------

void SBP2CommandORB::WriteORBToAddressSpace() noexcept {
kern_return_t SBP2CommandORB::WriteORBToAddressSpace() noexcept {
const auto span = std::span<const uint8_t>(orbStorage_.data(), orbStorage_.size());
const kern_return_t kr = addrMgr_.WriteLocalData(
owner_, orbHandle_, 0, span);
if (kr != kIOReturnSuccess) {
ASFW_LOG(Async, "SBP2CommandORB: failed to write ORB to address space: 0x%08x", kr);
}
return kr;
}

// ---------------------------------------------------------------------------
Expand All @@ -180,20 +191,26 @@ Async::FWAddress SBP2CommandORB::GetORBAddress() const noexcept {
return Async::FWAddress(parts);
}

void SBP2CommandORB::SetNextORBAddress(uint32_t hi, uint32_t lo) noexcept {
kern_return_t SBP2CommandORB::SetNextORBAddress(uint32_t hi, uint32_t lo) noexcept {
if (!IsValid()) {
return kIOReturnNotReady;
}
auto* orb = reinterpret_cast<Wire::NormalORB*>(orbStorage_.data());
orb->nextORBAddressHi = hi;
orb->nextORBAddressLo = lo;
WriteORBToAddressSpace();
return WriteORBToAddressSpace();
}

void SBP2CommandORB::SetToDummy() noexcept {
kern_return_t SBP2CommandORB::SetToDummy() noexcept {
if (!IsValid()) {
return kIOReturnNotReady;
}
// Set rq_fmt=3 (bits [13:12] = 11) to make device skip this ORB
auto* orb = reinterpret_cast<Wire::NormalORB*>(orbStorage_.data());
uint16_t hostOptions = OSSwapBigToHostInt16(orb->options);
hostOptions = (hostOptions & ~0x3000u) | 0x6000u;
orb->options = OSSwapHostToBigInt16(hostOptions);
WriteORBToAddressSpace();
return WriteORBToAddressSpace();
}

// ---------------------------------------------------------------------------
Expand Down
23 changes: 15 additions & 8 deletions ASFWDriver/Protocols/SBP2/SBP2CommandORB.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,35 +49,42 @@ class SBP2CommandORB {
SBP2CommandORB& operator=(const SBP2CommandORB&) = delete;

// Configuration (call before submit)
void SetCommandBlock(std::span<const uint8_t> cdb) noexcept;
// Returns false if the CDB exceeds maxCommandBlockSize_ (rejected, not truncated).
[[nodiscard]] bool SetCommandBlock(std::span<const uint8_t> cdb) noexcept;
void SetFlags(uint32_t flags) noexcept { flags_ = flags; }
void SetMaxPayloadSize(uint16_t bytes) noexcept { maxPayloadSize_ = bytes; }
void SetTimeout(uint32_t ms) noexcept { timeoutDuration_ = ms; }
[[nodiscard]] uint32_t GetTimeout() const noexcept { return timeoutDuration_; }
void SetCompletionCallback(CompletionCallback cb) noexcept { completionCallback_ = std::move(cb); }

// Bind page table result from SBP2PageTable::Build.
void SetDataDescriptor(const SBP2PageTable::Result& ptResult) noexcept {
dataDescriptor_ = ptResult;
}

// Internal: called by the session layer before submission.
void PrepareForExecution(uint16_t localNodeID, FW::FwSpeed speed,
uint16_t maxPayloadLog) noexcept;
// Internal: called by the session layer before submission. Flushes the ORB to
// address space; returns the write status (kIOReturnNotReady if not allocated).
[[nodiscard]] kern_return_t PrepareForExecution(uint16_t localNodeID, FW::FwSpeed speed,
uint16_t maxPayloadLog) noexcept;

// Internal: ORB address for fetch agent / chaining.
[[nodiscard]] Async::FWAddress GetORBAddress() const noexcept;

// Internal: set the next ORB pointer (big-endian values).
void SetNextORBAddress(uint32_t hi, uint32_t lo) noexcept;
// Internal: set the next ORB pointer (big-endian values). Re-flushes the ORB.
[[nodiscard]] kern_return_t SetNextORBAddress(uint32_t hi, uint32_t lo) noexcept;

// Set rq_fmt=3 (NOP dummy) so device skips this ORB if already fetched.
void SetToDummy() noexcept;
[[nodiscard]] kern_return_t SetToDummy() noexcept;

// Internal: timer management.
void StartTimer(IODispatchQueue* queue) noexcept;
void CancelTimer() noexcept;

// State tracking.
// True once the ORB's address-space backing was allocated successfully.
// The constructor swallows an allocation failure, so callers must check this
// before submitting a freshly-constructed ORB.
[[nodiscard]] bool IsValid() const noexcept { return orbHandle_ != 0; }
[[nodiscard]] bool IsAppended() const noexcept { return isAppended_; }
void SetAppended(bool state) noexcept { isAppended_ = state; }

Expand All @@ -90,7 +97,7 @@ class SBP2CommandORB {
private:
bool AllocateResources() noexcept;
void DeallocateResources() noexcept;
void WriteORBToAddressSpace() noexcept;
[[nodiscard]] kern_return_t WriteORBToAddressSpace() noexcept;

AddressSpaceManager& addrMgr_;
void* owner_;
Expand Down
Loading
Loading