blob: 5a8748eafced8fb933e6edfe004953e4ddfb141e [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use bit_field::Error as BitFieldError;
use bit_field::*;
use data_model::DataInit;
use std::fmt::{self, Display};
use sys_util::GuestAddress;
use std;
#[derive(Debug)]
pub enum Error {
UnknownTrbType(BitFieldError),
CannotCastTrb,
}
type Result<T> = std::result::Result<T, Error>;
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
match self {
UnknownTrbType(e) => write!(f, "we got an unknown trb type value: {}", e),
CannotCastTrb => write!(f, "cannot cast trb from raw memory"),
}
}
}
// Fixed size of all TRB types.
const TRB_SIZE: usize = 16;
// Size of segment table.
const SEGMENT_TABLE_SIZE: usize = 16;
/// All kinds of trb.
#[bitfield]
#[bits = 6]
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum TrbType {
Reserved = 0,
Normal = 1,
SetupStage = 2,
DataStage = 3,
StatusStage = 4,
Isoch = 5,
Link = 6,
EventData = 7,
Noop = 8,
EnableSlotCommand = 9,
DisableSlotCommand = 10,
AddressDeviceCommand = 11,
ConfigureEndpointCommand = 12,
EvaluateContextCommand = 13,
ResetEndpointCommand = 14,
StopEndpointCommand = 15,
SetTRDequeuePointerCommand = 16,
ResetDeviceCommand = 17,
NoopCommand = 23,
TransferEvent = 32,
CommandCompletionEvent = 33,
PortStatusChangeEvent = 34,
}
/// Completion code of trb types.
#[bitfield]
#[bits = 8]
#[derive(PartialEq, Debug)]
pub enum TrbCompletionCode {
Success = 1,
TransactionError = 4,
TrbError = 5,
NoSlotsAvailableError = 9,
SlotNotEnabledError = 11,
ShortPacket = 13,
ContextStateError = 19,
}
/// State of device slot.
#[bitfield]
#[bits = 5]
#[derive(PartialEq, Debug)]
pub enum DeviceSlotState {
// The same value (0) is used for both the enabled and disabled states. See
// xhci spec table 60.
DisabledOrEnabled = 0,
Default = 1,
Addressed = 2,
Configured = 3,
}
/// State of endpoint.
#[bitfield]
#[bits = 3]
#[derive(PartialEq, Debug)]
pub enum EndpointState {
Disabled = 0,
Running = 1,
}
#[bitfield]
#[bits = 60]
#[derive(PartialEq, Debug)]
pub struct DequeuePtr(u64);
impl DequeuePtr {
pub fn new(addr: GuestAddress) -> Self {
DequeuePtr(addr.0 >> 4)
}
// Get the guest physical address.
pub fn get_gpa(&self) -> GuestAddress {
GuestAddress(self.0 << 4)
}
}
// Generic TRB struct containing only fields common to all types.
#[bitfield]
#[derive(Clone, Copy, PartialEq)]
pub struct Trb {
parameter: B64,
status: B32,
cycle: bool,
flags: B9,
trb_type: TrbType,
control: B16,
}
impl Trb {
fn fmt_helper(&self, f: &mut fmt::Formatter) -> Result<fmt::Result> {
match self.get_trb_type().map_err(Error::UnknownTrbType)? {
TrbType::Reserved => Ok(write!(f, "reserved trb type")),
TrbType::Normal => {
let t = self.cast::<NormalTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::SetupStage => {
let t = self.cast::<SetupStageTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::DataStage => {
let t = self.cast::<DataStageTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::StatusStage => {
let t = self.cast::<StatusStageTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::Isoch => {
let t = self.cast::<IsochTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::Link => {
let t = self.cast::<LinkTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::EventData => {
let t = self.cast::<EventDataTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::Noop => {
let t = self.cast::<NoopTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::EnableSlotCommand => Ok(write!(f, "trb: enable slot command {:?}", self)),
TrbType::DisableSlotCommand => {
let t = self.cast::<DisableSlotCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::AddressDeviceCommand => {
let t = self.cast::<AddressDeviceCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::ConfigureEndpointCommand => {
let t = self.cast::<ConfigureEndpointCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::EvaluateContextCommand => {
let t = self.cast::<EvaluateContextCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::ResetEndpointCommand => {
let t = self.cast::<ResetEndpointCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::StopEndpointCommand => {
let t = self.cast::<StopEndpointCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::SetTRDequeuePointerCommand => {
let t = self.cast::<SetTRDequeuePointerCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::ResetDeviceCommand => {
let t = self.cast::<ResetDeviceCommandTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::NoopCommand => Ok(write!(f, "trb: noop command {:?}", self)),
TrbType::TransferEvent => {
let t = self.cast::<TransferEventTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::CommandCompletionEvent => {
let t = self.cast::<CommandCompletionEventTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
TrbType::PortStatusChangeEvent => {
let t = self.cast::<PortStatusChangeEventTrb>()?;
Ok(write!(f, "trb: {:?}", t))
}
}
}
}
impl Display for Trb {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.fmt_helper(f) {
Ok(f) => f,
Err(e) => write!(f, "fail to format trb {}", e),
}
}
}
impl Trb {
/// Get chain bit.
pub fn get_chain_bit(&self) -> Result<bool> {
Ok(match self.get_trb_type() {
Ok(TrbType::Normal) => self.cast::<NormalTrb>()?.get_chain(),
Ok(TrbType::DataStage) => self.cast::<DataStageTrb>()?.get_chain(),
Ok(TrbType::StatusStage) => self.cast::<StatusStageTrb>()?.get_chain(),
Ok(TrbType::Isoch) => self.cast::<IsochTrb>()?.get_chain(),
Ok(TrbType::Noop) => self.cast::<NoopTrb>()?.get_chain(),
Ok(TrbType::Link) => self.cast::<LinkTrb>()?.get_chain(),
Ok(TrbType::EventData) => self.cast::<EventDataTrb>()?.get_chain(),
_ => false,
})
}
/// Get interrupt target.
pub fn interrupter_target(&self) -> u8 {
const STATUS_INTERRUPTER_TARGET_OFFSET: u8 = 22;
(self.get_status() >> STATUS_INTERRUPTER_TARGET_OFFSET) as u8
}
/// Only some of trb types could appear in transfer ring.
pub fn can_be_in_transfer_ring(&self) -> Result<bool> {
match self.get_trb_type().map_err(Error::UnknownTrbType)? {
TrbType::Normal
| TrbType::SetupStage
| TrbType::DataStage
| TrbType::StatusStage
| TrbType::Isoch
| TrbType::Link
| TrbType::EventData
| TrbType::Noop => Ok(true),
_ => Ok(false),
}
}
/// Length of this transfer.
pub fn transfer_length(&self) -> Result<u32> {
const STATUS_TRANSFER_LENGTH_MASK: u32 = 0x1ffff;
match self.get_trb_type().map_err(Error::UnknownTrbType)? {
TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => {
Ok(self.get_status() & STATUS_TRANSFER_LENGTH_MASK)
}
_ => Ok(0),
}
}
/// Returns true if interrupt is required on completion.
pub fn interrupt_on_completion(&self) -> bool {
const FLAGS_INTERRUPT_ON_COMPLETION_MASK: u16 = 0x10;
(self.get_flags() & FLAGS_INTERRUPT_ON_COMPLETION_MASK) > 0
}
/// Returns true if interrupt is required on transfer of short packet.
pub fn interrupt_on_short_packet(&self) -> bool {
const FLAGS_INTERRUPT_ON_SHORT_PACKET: u16 = 0x2;
(self.get_flags() & FLAGS_INTERRUPT_ON_SHORT_PACKET) > 0
}
/// Returns true if this trb is immediate data.
pub fn immediate_data(&self) -> Result<bool> {
const FLAGS_IMMEDIATE_DATA_MASK: u16 = 0x20;
match self.get_trb_type().map_err(Error::UnknownTrbType)? {
TrbType::Normal | TrbType::SetupStage | TrbType::DataStage | TrbType::Isoch => {
Ok((self.get_flags() & FLAGS_IMMEDIATE_DATA_MASK) != 0)
}
_ => Ok(false),
}
}
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct NormalTrb {
data_buffer: B64,
trb_transfer_length: B17,
td_size: B5,
interrupter_target: B10,
cycle: bool,
evaluate_next_trb: B1,
interrupt_on_short_packet: B1,
no_snoop: B1,
chain: bool,
interrupt_on_completion: B1,
immediate_data: B1,
reserved: B2,
block_event_interrupt: B1,
trb_type: TrbType,
reserved1: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct SetupStageTrb {
request_type: B8,
request: B8,
value: B16,
index: B16,
length: B16,
trb_transfer_length: B17,
reserved0: B5,
interrupter_target: B10,
cycle: bool,
reserved1: B4,
interrupt_on_completion: B1,
immediate_data: B1,
reserved2: B3,
trb_type: TrbType,
transfer_type: B2,
reserved3: B14,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct DataStageTrb {
data_buffer_pointer: B64,
trb_transfer_length: B17,
td_size: B5,
interrupter_target: B10,
cycle: bool,
evaluate_next_trb: B1,
interrupt_on_short_packet: B1,
no_snoop: B1,
chain: bool,
interrupt_on_completion: B1,
immediate_data: B1,
reserved0: B3,
trb_type: TrbType,
direction: B1,
reserved1: B15,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct StatusStageTrb {
reserved0: B64,
reserved1: B22,
interrupter_target: B10,
cycle: bool,
evaluate_next_trb: B1,
reserved2: B2,
chain: bool,
interrupt_on_completion: B1,
reserved3: B4,
trb_type: TrbType,
direction: B1,
reserved4: B15,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct IsochTrb {
data_buffer_pointer: B64,
trb_transfer_length: B17,
td_size: B5,
interrupter_target: B10,
cycle: bool,
evaulate_nex_trb: B1,
interrupt_on_short_packet: B1,
no_snoop: B1,
chain: bool,
interrupt_on_completion: B1,
immediate_data: B1,
transfer_burst_count: B2,
block_event_interrupt: B1,
trb_type: TrbType,
tlbpc: B4,
frame_id: B11,
sia: B1,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct LinkTrb {
ring_segment_pointer: B64,
reserved0: B22,
interrupter_target: B10,
cycle: bool,
toggle_cycle: bool,
reserved1: B2,
chain: bool,
interrupt_on_completion: bool,
reserved2: B4,
trb_type: TrbType,
reserved3: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EventDataTrb {
event_data: B64,
reserved0: B22,
interrupter_target: B10,
cycle: bool,
evaluate_next_trb: B1,
reserved1: B2,
chain: bool,
interrupt_on_completion: B1,
reserved2: B3,
block_event_interrupt: B1,
trb_type: TrbType,
reserved3: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct NoopTrb {
reserved0: B64,
reserved1: B22,
interrupter_target: B10,
cycle: bool,
evaluate_next_trb: B1,
reserved2: B2,
chain: bool,
interrupt_on_completion: B1,
reserved3: B4,
trb_type: TrbType,
reserved4: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct DisableSlotCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: bool,
reserved3: B9,
trb_type: TrbType,
reserved4: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct AddressDeviceCommandTrb {
input_context_pointer: B64,
reserved: B32,
cycle: bool,
reserved2: B8,
block_set_address_request: bool,
trb_type: TrbType,
reserved3: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct ConfigureEndpointCommandTrb {
input_context_pointer: B64,
reserved0: B32,
cycle: bool,
reserved1: B8,
deconfigure: bool,
trb_type: TrbType,
reserved2: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EvaluateContextCommandTrb {
input_context_pointer: B64,
reserved0: B32,
cycle: bool,
reserved1: B9,
trb_type: TrbType,
reserved2: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct ResetEndpointCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: bool,
reserved3: B8,
transfer_state_preserve: B1,
trb_type: TrbType,
endpoint_id: B5,
reserved4: B3,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct StopEndpointCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: bool,
reserved3: B9,
trb_type: TrbType,
endpoint_id: B5,
reserved4: B2,
suspend: B1,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct SetTRDequeuePointerCommandTrb {
dequeue_cycle_state: bool,
stream_context_type: B3,
dequeue_ptr: DequeuePtr,
reserved0: B16,
stream_id: B16,
cycle: bool,
reserved1: B9,
trb_type: TrbType,
endpoint_id: B5,
reserved3: B2,
suspend: B1,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct ResetDeviceCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: bool,
reserved3: B9,
trb_type: TrbType,
reserved4: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct TransferEventTrb {
trb_pointer: B64,
trb_transfer_length: B24,
completion_code: TrbCompletionCode,
cycle: bool,
reserved0: B1,
event_data: B1,
reserved1: B7,
trb_type: TrbType,
endpoint_id: B5,
reserved2: B3,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct CommandCompletionEventTrb {
trb_pointer: B64,
command_completion_parameter: B24,
completion_code: TrbCompletionCode,
cycle: bool,
reserved: B9,
trb_type: TrbType,
vf_id: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct PortStatusChangeEventTrb {
reserved0: B24,
port_id: B8,
reserved1: B32,
reserved2: B24,
completion_code: TrbCompletionCode,
cycle: bool,
reserved3: B9,
trb_type: TrbType,
reserved4: B16,
}
/// Associate real type of trb.
pub trait TypedTrb {
const TY: TrbType;
}
impl TypedTrb for Trb {
const TY: TrbType = TrbType::Reserved;
}
impl TypedTrb for NormalTrb {
const TY: TrbType = TrbType::Normal;
}
impl TypedTrb for SetupStageTrb {
const TY: TrbType = TrbType::SetupStage;
}
impl TypedTrb for DataStageTrb {
const TY: TrbType = TrbType::DataStage;
}
impl TypedTrb for StatusStageTrb {
const TY: TrbType = TrbType::StatusStage;
}
impl TypedTrb for IsochTrb {
const TY: TrbType = TrbType::Isoch;
}
impl TypedTrb for LinkTrb {
const TY: TrbType = TrbType::Link;
}
impl TypedTrb for EventDataTrb {
const TY: TrbType = TrbType::EventData;
}
impl TypedTrb for NoopTrb {
const TY: TrbType = TrbType::Noop;
}
impl TypedTrb for DisableSlotCommandTrb {
const TY: TrbType = TrbType::DisableSlotCommand;
}
impl TypedTrb for AddressDeviceCommandTrb {
const TY: TrbType = TrbType::AddressDeviceCommand;
}
impl TypedTrb for ConfigureEndpointCommandTrb {
const TY: TrbType = TrbType::ConfigureEndpointCommand;
}
impl TypedTrb for EvaluateContextCommandTrb {
const TY: TrbType = TrbType::EvaluateContextCommand;
}
impl TypedTrb for ResetEndpointCommandTrb {
const TY: TrbType = TrbType::ResetEndpointCommand;
}
impl TypedTrb for StopEndpointCommandTrb {
const TY: TrbType = TrbType::StopEndpointCommand;
}
impl TypedTrb for SetTRDequeuePointerCommandTrb {
const TY: TrbType = TrbType::SetTRDequeuePointerCommand;
}
impl TypedTrb for ResetDeviceCommandTrb {
const TY: TrbType = TrbType::ResetDeviceCommand;
}
impl TypedTrb for TransferEventTrb {
const TY: TrbType = TrbType::TransferEvent;
}
impl TypedTrb for CommandCompletionEventTrb {
const TY: TrbType = TrbType::CommandCompletionEvent;
}
impl TypedTrb for PortStatusChangeEventTrb {
const TY: TrbType = TrbType::PortStatusChangeEvent;
}
/// All trb structs have the same size. One trb could be safely casted to another, though the
/// values might be invalid.
pub unsafe trait TrbCast: DataInit + TypedTrb {
fn cast<T: TrbCast>(&self) -> Result<&T> {
T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
}
fn cast_mut<T: TrbCast>(&mut self) -> Result<&mut T> {
T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
}
fn checked_cast<T: TrbCast>(&self) -> Result<&T> {
if Trb::from_slice(self.as_slice())
.ok_or(Error::CannotCastTrb)?
.get_trb_type()
.map_err(Error::UnknownTrbType)?
!= T::TY
{
return Err(Error::CannotCastTrb);
}
T::from_slice(self.as_slice()).ok_or(Error::CannotCastTrb)
}
fn checked_mut_cast<T: TrbCast>(&mut self) -> Result<&mut T> {
if Trb::from_slice(self.as_slice())
.ok_or(Error::CannotCastTrb)?
.get_trb_type()
.map_err(Error::UnknownTrbType)?
!= T::TY
{
return Err(Error::CannotCastTrb);
}
T::from_mut_slice(self.as_mut_slice()).ok_or(Error::CannotCastTrb)
}
}
unsafe impl DataInit for Trb {}
unsafe impl DataInit for NormalTrb {}
unsafe impl DataInit for SetupStageTrb {}
unsafe impl DataInit for DataStageTrb {}
unsafe impl DataInit for StatusStageTrb {}
unsafe impl DataInit for IsochTrb {}
unsafe impl DataInit for LinkTrb {}
unsafe impl DataInit for EventDataTrb {}
unsafe impl DataInit for NoopTrb {}
unsafe impl DataInit for DisableSlotCommandTrb {}
unsafe impl DataInit for AddressDeviceCommandTrb {}
unsafe impl DataInit for ConfigureEndpointCommandTrb {}
unsafe impl DataInit for EvaluateContextCommandTrb {}
unsafe impl DataInit for ResetEndpointCommandTrb {}
unsafe impl DataInit for StopEndpointCommandTrb {}
unsafe impl DataInit for SetTRDequeuePointerCommandTrb {}
unsafe impl DataInit for ResetDeviceCommandTrb {}
unsafe impl DataInit for TransferEventTrb {}
unsafe impl DataInit for CommandCompletionEventTrb {}
unsafe impl DataInit for PortStatusChangeEventTrb {}
unsafe impl DataInit for EventRingSegmentTableEntry {}
unsafe impl DataInit for InputControlContext {}
unsafe impl DataInit for SlotContext {}
unsafe impl DataInit for EndpointContext {}
unsafe impl DataInit for DeviceContext {}
unsafe impl DataInit for AddressedTrb {}
unsafe impl TrbCast for Trb {}
unsafe impl TrbCast for NormalTrb {}
unsafe impl TrbCast for SetupStageTrb {}
unsafe impl TrbCast for DataStageTrb {}
unsafe impl TrbCast for StatusStageTrb {}
unsafe impl TrbCast for IsochTrb {}
unsafe impl TrbCast for LinkTrb {}
unsafe impl TrbCast for EventDataTrb {}
unsafe impl TrbCast for NoopTrb {}
unsafe impl TrbCast for DisableSlotCommandTrb {}
unsafe impl TrbCast for AddressDeviceCommandTrb {}
unsafe impl TrbCast for ConfigureEndpointCommandTrb {}
unsafe impl TrbCast for EvaluateContextCommandTrb {}
unsafe impl TrbCast for ResetEndpointCommandTrb {}
unsafe impl TrbCast for StopEndpointCommandTrb {}
unsafe impl TrbCast for SetTRDequeuePointerCommandTrb {}
unsafe impl TrbCast for ResetDeviceCommandTrb {}
unsafe impl TrbCast for TransferEventTrb {}
unsafe impl TrbCast for CommandCompletionEventTrb {}
unsafe impl TrbCast for PortStatusChangeEventTrb {}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EventRingSegmentTableEntry {
ring_segment_base_address: B64,
ring_segment_size: B16,
reserved2: B48,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct InputControlContext {
// Xhci spec 6.2.5.1.
drop_context_flags: B32,
add_context_flags: B32,
reserved0: B32,
reserved1: B32,
reserved2: B32,
reserved3: B32,
reserved4: B32,
configuration_value: B8,
interface_number: B8,
alternate_setting: B8,
reserved5: B8,
}
impl InputControlContext {
/// Get drop context flag.
pub fn drop_context_flag(&self, idx: u8) -> bool {
(self.get_drop_context_flags() & (1 << idx)) != 0
}
/// Get add context flag.
pub fn add_context_flag(&self, idx: u8) -> bool {
(self.get_add_context_flags() & (1 << idx)) != 0
}
}
// Size of device context entries (SlotContext and EndpointContext).
pub const DEVICE_CONTEXT_ENTRY_SIZE: usize = 32usize;
#[bitfield]
#[derive(Clone, Copy)]
pub struct SlotContext {
route_string: B20,
speed: B4,
reserved1: B1,
mtt: B1,
hub: B1,
context_entries: B5,
max_exit_latency: B16,
root_hub_port_number: B8,
num_ports: B8,
tt_hub_slot_id: B8,
tt_port_number: B8,
tt_think_time: B2,
reserved2: B4,
interrupter_target: B10,
usb_device_address: B8,
reserved3: B19,
slot_state: DeviceSlotState,
reserved4: B32,
reserved5: B32,
reserved6: B32,
reserved7: B32,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EndpointContext {
endpoint_state: EndpointState,
reserved1: B5,
mult: B2,
max_primary_streams: B5,
linear_stream_array: B1,
interval: B8,
max_esit_payload_hi: B8,
reserved2: B1,
error_count: B2,
endpoint_type: B3,
reserved3: B1,
host_initiate_disable: B1,
max_burst_size: B8,
max_packet_size: B16,
dequeue_cycle_state: bool,
reserved4: B3,
tr_dequeue_pointer: DequeuePtr,
average_trb_length: B16,
max_esit_payload_lo: B16,
reserved5: B32,
reserved6: B32,
reserved7: B32,
}
/// Device context.
#[derive(Clone, Copy, Debug)]
pub struct DeviceContext {
pub slot_context: SlotContext,
pub endpoint_context: [EndpointContext; 31],
}
/// POD struct associates a TRB with its address in guest memory. This is
/// useful because transfer and command completion event TRBs must contain
/// pointers to the original TRB that generated the event.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct AddressedTrb {
pub trb: Trb,
pub gpa: u64,
}
pub type TransferDescriptor = Vec<AddressedTrb>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_struct_sizes() {
assert_eq!(std::mem::size_of::<Trb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<NormalTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<SetupStageTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<DataStageTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<StatusStageTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<IsochTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<LinkTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<EventDataTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<NoopTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<DisableSlotCommandTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<AddressDeviceCommandTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<ConfigureEndpointCommandTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<EvaluateContextCommandTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<ResetEndpointCommandTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<StopEndpointCommandTrb>(), TRB_SIZE);
assert_eq!(
std::mem::size_of::<SetTRDequeuePointerCommandTrb>(),
TRB_SIZE
);
assert_eq!(std::mem::size_of::<ResetDeviceCommandTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<TransferEventTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<CommandCompletionEventTrb>(), TRB_SIZE);
assert_eq!(std::mem::size_of::<PortStatusChangeEventTrb>(), TRB_SIZE);
assert_eq!(
std::mem::size_of::<EventRingSegmentTableEntry>(),
SEGMENT_TABLE_SIZE
);
assert_eq!(std::mem::size_of::<InputControlContext>(), 32);
assert_eq!(
std::mem::size_of::<SlotContext>(),
DEVICE_CONTEXT_ENTRY_SIZE
);
assert_eq!(
std::mem::size_of::<EndpointContext>(),
DEVICE_CONTEXT_ENTRY_SIZE
);
assert_eq!(
std::mem::size_of::<DeviceContext>(),
32 * DEVICE_CONTEXT_ENTRY_SIZE
);
}
}