blob: a37cbb36639621bab25ede9b4f93b910368829e4 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_DEVICES_USB_DRIVERS_XHCI_REWRITE_XHCI_TRANSFER_RING_H_
#define SRC_DEVICES_USB_DRIVERS_XHCI_REWRITE_XHCI_TRANSFER_RING_H_
#include <map>
#include <ddk/protocol/usb/request.h>
#include "registers.h"
#include "xhci-context.h"
#include "xhci-event-ring.h"
namespace usb_xhci {
class UsbXhci;
// Used for queueing transfers to the XHCI controller
class TransferRing {
public:
struct State {
TRB* trbs;
// Producer Cycle state
bool pcs;
};
TransferRing() : trb_context_allocator_(-1, true) {}
bool IsIsochronous() { return isochronous_; }
void SetIsochronous() { isochronous_ = true; }
size_t GetShortCount() { return short_count_; }
void ResetShortCount() { short_count_ = 0; }
void IncrementShortCount(size_t size) { short_count_ += size; }
zx_status_t AddTRB(const TRB& trb, std::unique_ptr<TRBContext> context);
zx_status_t AssignContext(TRB* trb, std::unique_ptr<TRBContext> context, TRB* first_trb);
// Handles a short packet. This will walk the TRB list up to and including short_trb
// and return the number of bytes transferred. Returns ZX_ERR_IO if the transfer was
// mis-aligned.
zx_status_t HandleShortPacket(TRB* short_trb, size_t* transferred, TRB** first_trb,
size_t short_length);
// Allocates a TRB but does not configure it.
// It is the caller's responsibility to fully configure the returned TRB.
// The caller may optionally rollback a transaction by calling Restore
// The Cycle bit will be passed via the status field of the TRB.
// The caller should store the Cycle bit locally and zero the status field
// prior to doing anything else with the TRB.
zx_status_t AllocateTRB(TRB** trb, State* state);
State SaveState();
State SaveStateLocked() __TA_REQUIRES(mutex_);
void CommitLocked() __TA_REQUIRES(mutex_);
// Commits the current page.
void Commit();
// Commits a multi-TRB transaction
void CommitTransaction(const State& start);
void Restore(const State& state);
void RestoreLocked(const State& state) __TA_REQUIRES(mutex_);
zx_status_t Init(size_t page_size, const zx::bti& bti, EventRing* ring, bool is_32bit,
ddk::MmioBuffer* mmio, const UsbXhci& hci);
// Assumption: This function must ONLY be called from the interrupt
// thread. Otherwise thread-safety assumptions are violated.
zx_status_t DeinitIfActive() __TA_NO_THREAD_SAFETY_ANALYSIS;
zx_status_t Deinit();
bool active() {
fbl::AutoLock l(&mutex_);
return trbs_;
}
// Only called during initialization when no other threads are running.
// Would be pointless to hold the mutex here.
CRCR phys(uint8_t cap_length);
zx_paddr_t VirtToPhys(TRB* trb);
zx_paddr_t VirtToPhysLocked(TRB* trb) __TA_REQUIRES(mutex_);
TRB* PhysToVirt(zx_paddr_t paddr);
TRB* PhysToVirtLocked(zx_paddr_t paddr) __TA_REQUIRES(mutex_);
zx_status_t CompleteTRB(TRB* trb, std::unique_ptr<TRBContext>* context);
fbl::DoublyLinkedList<std::unique_ptr<TRBContext>> TakePendingTRBs();
fbl::DoublyLinkedList<std::unique_ptr<TRBContext>> TakePendingTRBsUntil(TRB* end);
std::unique_ptr<TRBContext> AllocateContext() {
fbl::AutoLock _(&mutex_);
auto ctx = trb_context_allocator_.New();
ctx->token = token_;
return ctx;
}
TRBPromise AddressDeviceCommand(uint8_t slot_id, uint8_t port_id, std::optional<HubInfo> hub_info,
bool bsr);
zx_status_t InitializeSlotBuffer(uint8_t slot_id, uint8_t port_id,
const std::optional<HubInfo>& hub_info, ddk::IoBuffer* out);
zx_status_t InitializeEndpointContext(uint8_t slot_id, uint8_t port_id,
const std::optional<HubInfo>& hub_info,
const ddk::IoBuffer& slot_context_buffer);
zx_status_t InitializeOutputContextBuffer(uint8_t slot_id, uint8_t port_id,
const std::optional<HubInfo>& hub_info,
ddk::IoBuffer* out);
private:
bool AvailableSlots(size_t count) __TA_REQUIRES(mutex_);
zx_status_t AllocInternal(Control control) __TA_REQUIRES(mutex_);
fbl::DoublyLinkedList<std::unique_ptr<TRBContext>> pending_trbs_ __TA_GUARDED(mutex_);
// Allocates and initializes a buffer (transfer ring segment)
// and increases the size of the ERST if necessary.
// Each buffer can fit 1 page of TRBs
// The dma_buffer::Buffer is owned by this TransferRing.
zx_status_t AllocBuffer(dma_buffer::ContiguousBuffer** out) __TA_REQUIRES(mutex_);
// Advances the enqueue pointer after a new element has been added to the transfer ring
void AdvancePointer() __TA_REQUIRES(mutex_);
fbl::Mutex mutex_;
uint64_t token_ = 0;
AllocatorType trb_context_allocator_ __TA_GUARDED(mutex_);
fbl::DoublyLinkedList<std::unique_ptr<dma_buffer::ContiguousBuffer>> buffers_
__TA_GUARDED(mutex_);
std::map<zx_vaddr_t, dma_buffer::ContiguousBuffer*> virt_to_buffer_ __TA_GUARDED(mutex_);
std::map<zx_paddr_t, dma_buffer::ContiguousBuffer*> phys_to_buffer_ __TA_GUARDED(mutex_);
// Start of TRBs from perspective of enqueue pointer.
// This pointer is incremented along with the enqueue pointer.
TRB* trbs_ __TA_GUARDED(mutex_) = nullptr;
zx_paddr_t trb_start_phys_ = 0;
// Producer cycle bit (section 4.9.2)
bool pcs_ __TA_GUARDED(mutex_) = true;
TRB* dequeue_trb_ __TA_GUARDED(mutex_) = 0;
// Capacity (number of TRBs, including link TRBs in ring)
size_t capacity_ __TA_GUARDED(mutex_) = 0;
size_t page_size_ __TA_GUARDED(mutex_);
const zx::bti* bti_ __TA_GUARDED(mutex_);
EventRing* ring_ __TA_GUARDED(mutex_);
bool is_32_bit_ __TA_GUARDED(mutex_);
ddk::MmioBuffer* mmio_ __TA_GUARDED(mutex_);
// Not guarded by a mutex since this is synchronized by the event ring.
size_t short_count_ = 0;
bool isochronous_ = false;
const UsbXhci* hci_;
};
// The singleton xHCI command ring
class CommandRing : public TransferRing {
public:
zx_status_t Init(size_t page_size, zx::bti* bti, EventRing* ring, bool is_32bit,
ddk::MmioBuffer* mmio, UsbXhci* hci) {
return TransferRing::Init(page_size, *bti, ring, is_32bit, mmio, *hci);
}
// Generates a NOP command
TRB Nop() {
TRB retval;
Control::Get().FromValue(0).set_Type(Control::NopCommand).ToTrb(&retval);
return retval;
}
};
} // namespace usb_xhci
#endif // SRC_DEVICES_USB_DRIVERS_XHCI_REWRITE_XHCI_TRANSFER_RING_H_