blob: 8174ce88f086baadf98a44f51fed20628a5aba49 [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::*;
use std;
// TODO(jkwang) move these to bitfield crate.
type B0 = BitField0;
type B1 = BitField1;
type B2 = BitField2;
type B3 = BitField3;
type B4 = BitField4;
type B5 = BitField5;
type B6 = BitField6;
type B7 = BitField7;
type B8 = BitField8;
type B9 = BitField9;
type B10 = BitField10;
type B11 = BitField11;
type B12 = BitField12;
type B13 = BitField13;
type B14 = BitField14;
type B15 = BitField15;
type B16 = BitField16;
type B17 = BitField17;
type B18 = BitField18;
type B19 = BitField19;
type B20 = BitField20;
type B21 = BitField21;
type B22 = BitField22;
type B23 = BitField23;
type B24 = BitField24;
type B25 = BitField25;
type B26 = BitField26;
type B27 = BitField27;
type B28 = BitField28;
type B29 = BitField29;
type B30 = BitField30;
type B31 = BitField31;
type B32 = BitField32;
type B33 = BitField33;
type B34 = BitField34;
type B35 = BitField35;
type B36 = BitField36;
type B37 = BitField37;
type B38 = BitField38;
type B39 = BitField39;
type B40 = BitField40;
type B41 = BitField41;
type B42 = BitField42;
type B43 = BitField43;
type B44 = BitField44;
type B45 = BitField45;
type B46 = BitField46;
type B47 = BitField47;
type B48 = BitField48;
type B49 = BitField49;
type B50 = BitField50;
type B51 = BitField51;
type B52 = BitField52;
type B53 = BitField53;
type B54 = BitField54;
type B55 = BitField55;
type B56 = BitField56;
type B57 = BitField57;
type B58 = BitField58;
type B59 = BitField59;
type B60 = BitField60;
type B61 = BitField61;
type B62 = BitField62;
type B63 = BitField63;
type B64 = BitField64;
// Fixed size of all TRB types.
const TRB_SIZE: usize = 16;
// Size of segment table.
const SEGMENT_TABLE_SIZE: usize = 16;
// Generic TRB struct containing only fields common to all types.
#[bitfield]
#[derive(Clone, Copy, PartialEq)]
pub struct Trb {
parameter: B64,
status: B32,
cycle: B1,
flags: B9,
trb_type: B6,
control: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct NormalTrb {
data_buffer: B64,
trb_transfer_length: B17,
td_size: B5,
interrupter_target: B10,
cycle: B1,
evaluate_next_trb: B1,
interrupt_on_short_packet: B1,
no_snoop: B1,
chain: B1,
interrupt_on_completion: B1,
immediate_data: B1,
reserved: B2,
block_event_interrupt: B1,
trb_type: B6,
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: B1,
reserved1: B4,
interrupt_on_completion: B1,
immediate_data: B1,
reserved2: B3,
trb_type: B6,
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: B1,
evaluate_next_trb: B1,
interrupt_on_short_packet: B1,
no_snoop: B1,
chain: B1,
interrupt_on_completion: B1,
immediate_data: B1,
reserved0: B3,
trb_type: B6,
direction: B1,
reserved1: B15,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct StatusStageTrb {
reserved0: B64,
reserved1: B22,
interrupter_target: B10,
cycle: B1,
evaluate_next_trb: B1,
reserved2: B2,
chain: B1,
interrupt_on_completion: B1,
reserved3: B4,
trb_type: B6,
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: B1,
evaulate_nex_trb: B1,
interrupt_on_short_packet: B1,
no_snoop: B1,
chain: B1,
interrupt_on_completion: B1,
immediate_data: B1,
transfer_burst_count: B2,
block_event_interrupt: B1,
trb_type: B6,
tlbpc: B4,
frame_id: B11,
sia: B1,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct LinkTrb {
ring_segment_pointer: B64,
reserved0: B22,
interrupter_target: B10,
cycle: B1,
toggle_cycle: B1,
reserved1: B2,
chain: B1,
interrupt_on_completion: B1,
reserved2: B4,
trb_type: B6,
reserved3: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EventDataTrb {
event_data: B64,
reserved0: B22,
interrupter_target: B10,
cycle: B1,
evaluate_next_trb: B1,
reserved1: B2,
chain: B1,
interrupt_on_completion: B1,
reserved2: B3,
block_event_interrupt: B1,
trb_type: B6,
reserved3: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct NoopTrb {
reserved0: B64,
reserved1: B22,
interrupter_target: B10,
cycle: B1,
evaluate_next_trb: B1,
reserved2: B2,
chain: B1,
interrupt_on_completion: B1,
reserved3: B4,
trb_type: B6,
reserved4: B16,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct DisableSlotCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: B1,
reserved3: B9,
trb_type: B6,
reserved4: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct AddressDeviceCommandTrb {
input_context_pointer: B64,
reserved: B32,
cycle: B1,
reserved2: B8,
block_set_address_request: B1,
trb_type: B6,
reserved3: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct ConfigureEndpointCommandTrb {
input_context_pointer: B64,
reserved0: B32,
cycle: B1,
reserved1: B8,
deconfigure: B1,
trb_type: B6,
reserved2: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EvaluateContextCommandTrb {
input_context_pointer: B64,
reserved0: B32,
cycle: B1,
reserved1: B9,
trb_type: B6,
reserved2: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct ResetEndpointCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: B1,
reserved3: B8,
transfer_state_preserve: B1,
trb_type: B6,
endpoint_id: B5,
reserved4: B3,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct StopEndpointCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: B1,
reserved3: B9,
trb_type: B6,
endpoint_id: B5,
reserved4: B2,
suspend: B1,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct SetTRDequeuePointerCommandTrb {
dequeue_cycle_state: B1,
stream_context_type: B3,
dequeue_ptr: B60,
reserved0: B16,
stream_id: B16,
cycle: B1,
reserved1: B9,
trb_type: B6,
endpoint_id: B5,
reserved3: B2,
suspend: B1,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct ResetDeviceCommandTrb {
reserved0: B32,
reserved1: B32,
reserved2: B32,
cycle: B1,
reserved3: B9,
trb_type: B6,
reserved4: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct TransferEventTrb {
trb_pointer: B64,
trb_transfer_length: B24,
completion_code: B8,
cycle: B1,
reserved0: B1,
event_data: B1,
reserved1: B7,
trb_type: B6,
endpoint_id: B5,
reserved2: B3,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct CommandCompletionEventTrb {
trb_pointer: B64,
command_completion_parameter: B24,
completion_code: B8,
cycle: B1,
reserved: B9,
trb_type: B6,
vf_id: B8,
slot_id: B8,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct PortStatusChangeEventTrb {
reserved0: B24,
port_id: B8,
reserved1: B32,
reserved2: B24,
completion_code: B8,
cycle: B1,
reserved3: B9,
trb_type: B6,
reserved4: B16,
}
#[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,
}
// 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: B5,
reserved4: B32,
reserved5: B32,
reserved6: B32,
reserved7: B32,
}
#[bitfield]
#[derive(Clone, Copy)]
pub struct EndpointContext {
endpoint_state: B3,
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: B1,
reserved4: B3,
tr_dequeue_pointer: B60,
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)]
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
);
}
}