Select correct max packet sizes during init.
This commit is contained in:
@@ -180,6 +180,7 @@ impl EndpDesc {
|
||||
}
|
||||
pub fn isoch_mult(&self, lec: bool) -> u8 {
|
||||
if !lec && self.is_isoch() {
|
||||
if self.is_superspeedplus() { return 0 }
|
||||
self.ssc
|
||||
.as_ref()
|
||||
.map(|ssc| ssc.attributes & 0x3)
|
||||
|
||||
@@ -114,13 +114,28 @@ impl ProtocolSpeed {
|
||||
Self { a: Mmio::from(raw) }
|
||||
}
|
||||
pub fn is_lowspeed(&self) -> bool {
|
||||
self.psim() == 1500 && self.psie() == Psie::Kbps
|
||||
self.psim() == 1500 && self.psie() == Psie::Kbps && !self.pfd()
|
||||
}
|
||||
pub fn is_fullspeed(&self) -> bool {
|
||||
self.psim() == 12 && self.psie() == Psie::Mbps
|
||||
self.psim() == 12 && self.psie() == Psie::Mbps && !self.pfd()
|
||||
}
|
||||
pub fn is_highspeed(&self) -> bool {
|
||||
self.psim() == 480 && self.psie() == Psie::Mbps
|
||||
self.psim() == 480 && self.psie() == Psie::Mbps && !self.pfd()
|
||||
}
|
||||
pub fn is_superspeed_gen1x1(&self) -> bool {
|
||||
self.psim() == 5 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeed
|
||||
}
|
||||
pub fn is_superspeedplus_gen2x1(&self) -> bool {
|
||||
self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus
|
||||
}
|
||||
pub fn is_superspeedplus_gen1x2(&self) -> bool {
|
||||
self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus
|
||||
}
|
||||
pub fn is_superspeedplus_gen2x2(&self) -> bool {
|
||||
self.psim() == 20 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus
|
||||
}
|
||||
pub fn is_superspeed_gen_x(&self) -> bool {
|
||||
self.is_superspeed_gen1x1() || self.is_superspeedplus_gen2x1() || self.is_superspeedplus_gen1x2() || self.is_superspeedplus_gen2x2()
|
||||
}
|
||||
/// Protocol speed ID value
|
||||
pub fn psiv(&self) -> u8 {
|
||||
|
||||
+140
-42
@@ -344,49 +344,8 @@ impl Xhci {
|
||||
|
||||
println!(" - Slot {}", slot);
|
||||
|
||||
// transfer ring?
|
||||
let mut ring = Ring::new(true)?;
|
||||
|
||||
let mut input = Dma::<InputContext>::zeroed()?;
|
||||
{
|
||||
input.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit).
|
||||
|
||||
input
|
||||
.device
|
||||
.slot
|
||||
.a
|
||||
.write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated.
|
||||
input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16);
|
||||
|
||||
// control endpoint?
|
||||
input.device.endpoints[0]
|
||||
.b
|
||||
.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count
|
||||
let tr = ring.register();
|
||||
input.device.endpoints[0].trh.write((tr >> 32) as u32);
|
||||
input.device.endpoints[0].trl.write(tr as u32);
|
||||
}
|
||||
|
||||
{
|
||||
let (cmd, cycle, event) = self.cmd.next();
|
||||
|
||||
cmd.address_device(slot, input.physical(), cycle);
|
||||
|
||||
self.dbs[0].write(0);
|
||||
|
||||
while event.data.read() == 0 {
|
||||
println!(" - Waiting for event");
|
||||
}
|
||||
|
||||
if event.completion_code() != TrbCompletionCode::Success as u8
|
||||
|| event.trb_type() != TrbType::CommandCompletion as u8
|
||||
{
|
||||
panic!("ADDRESS DEVICE FAILED");
|
||||
}
|
||||
|
||||
cmd.reserved(false);
|
||||
event.reserved(false);
|
||||
}
|
||||
let mut ring = self.address_device(&mut input, i, slot, speed)?;
|
||||
|
||||
let dev_desc = Self::get_dev_desc_raw(
|
||||
&mut self.ports,
|
||||
@@ -397,6 +356,9 @@ impl Xhci {
|
||||
slot,
|
||||
&mut ring,
|
||||
)?;
|
||||
|
||||
self.update_default_control_pipe(&mut input, slot, &dev_desc)?;
|
||||
|
||||
let mut port_state = PortState {
|
||||
slot,
|
||||
input_context: input,
|
||||
@@ -424,6 +386,142 @@ impl Xhci {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_default_control_pipe(&mut self, input_context: &mut Dma<InputContext>, slot_id: u8, dev_desc: &DevDesc) -> Result<()> {
|
||||
let new_max_packet_size = if dev_desc.major_version() == 2 {
|
||||
u32::from(dev_desc.packet_size)
|
||||
} else {
|
||||
1u32 << dev_desc.packet_size
|
||||
};
|
||||
let endp_ctx = &mut input_context.device.endpoints[0];
|
||||
let mut b = endp_ctx.b.read();
|
||||
b &= 0x0000_FFFF;
|
||||
b |= (new_max_packet_size) << 16;
|
||||
endp_ctx.b.write(b);
|
||||
|
||||
{
|
||||
let (cmd, cycle, event) = self.cmd.next();
|
||||
|
||||
cmd.evaluate_context(slot_id, input_context.physical(), false, cycle);
|
||||
|
||||
self.dbs[0].write(0);
|
||||
|
||||
while event.data.read() == 0 {
|
||||
println!(" - Waiting for event");
|
||||
}
|
||||
|
||||
if event.completion_code() != TrbCompletionCode::Success as u8
|
||||
|| event.trb_type() != TrbType::CommandCompletion as u8
|
||||
{
|
||||
panic!("EVALUATE_CONTEXT failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read());
|
||||
}
|
||||
|
||||
cmd.reserved(false);
|
||||
event.reserved(false);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn address_device(&mut self, input_context: &mut Dma<InputContext>, i: usize, slot: u8, speed: u8) -> Result<Ring> {
|
||||
let mut ring = Ring::new(true)?;
|
||||
|
||||
{
|
||||
input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit).
|
||||
|
||||
let slot_ctx = &mut input_context.device.slot;
|
||||
|
||||
let route_string = 0u32; // TODO
|
||||
let context_entries = 1u8;
|
||||
let mtt = false;
|
||||
let hub = false;
|
||||
|
||||
assert_eq!(route_string & 0x000F_FFFF, route_string);
|
||||
slot_ctx.a.write(
|
||||
route_string
|
||||
| (u32::from(mtt) << 25)
|
||||
| (u32::from(hub) << 26)
|
||||
| (u32::from(context_entries) << 27)
|
||||
);
|
||||
|
||||
let max_exit_latency = 0u16;
|
||||
let root_hub_port_num = (i + 1) as u8;
|
||||
let number_of_ports = 0u8;
|
||||
slot_ctx.b.write(
|
||||
u32::from(max_exit_latency)
|
||||
| (u32::from(root_hub_port_num) << 16)
|
||||
| (u32::from(number_of_ports) << 24)
|
||||
);
|
||||
|
||||
// TODO
|
||||
let parent_hud_slot_id = 0u8;
|
||||
let parent_port_num = 0u8;
|
||||
let ttt = 0u8;
|
||||
let interrupter = 0u8;
|
||||
|
||||
assert_eq!(ttt & 0b11, ttt);
|
||||
slot_ctx.c.write(
|
||||
u32::from(parent_hud_slot_id)
|
||||
| (u32::from(parent_port_num) << 8)
|
||||
| (u32::from(ttt) << 16)
|
||||
| (u32::from(interrupter) << 22)
|
||||
);
|
||||
|
||||
let endp_ctx = &mut input_context.device.endpoints[0];
|
||||
|
||||
let speed_id = self.lookup_psiv(root_hub_port_num, speed).expect("Failed to retrieve speed ID");
|
||||
|
||||
let max_error_count = 3u8; // recommended value according to the XHCI spec
|
||||
let ep_ty = 4u8; // control endpoint, bidirectional
|
||||
let max_packet_size: u32 = if speed_id.is_lowspeed() {
|
||||
8 // only valid value
|
||||
} else if speed_id.is_fullspeed() {
|
||||
64 // valid values are 8, 16, 32, 64
|
||||
} else if speed_id.is_highspeed() {
|
||||
64 // only valid value
|
||||
} else if speed_id.is_superspeed_gen_x() {
|
||||
512 // only valid value
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
let host_initiate_disable = false; // only applies to streams
|
||||
let max_burst_size = 0u8; // TODO
|
||||
|
||||
assert_eq!(max_error_count & 0b11, max_error_count);
|
||||
endp_ctx.b.write(
|
||||
(u32::from(max_error_count) << 1)
|
||||
| (u32::from(ep_ty) << 3)
|
||||
| (u32::from(host_initiate_disable) << 7)
|
||||
| (u32::from(max_burst_size) << 8)
|
||||
| (u32::from(max_packet_size) << 16)
|
||||
);
|
||||
|
||||
let tr = ring.register();
|
||||
endp_ctx.trh.write((tr >> 32) as u32);
|
||||
endp_ctx.trl.write(tr as u32);
|
||||
}
|
||||
|
||||
{
|
||||
let (cmd, cycle, event) = self.cmd.next();
|
||||
|
||||
cmd.address_device(slot, input_context.physical(), false, cycle);
|
||||
|
||||
self.dbs[0].write(0);
|
||||
|
||||
while event.data.read() == 0 {
|
||||
println!(" - Waiting for event");
|
||||
}
|
||||
|
||||
if event.completion_code() != TrbCompletionCode::Success as u8
|
||||
|| event.trb_type() != TrbType::CommandCompletion as u8
|
||||
{
|
||||
panic!("ADDRESS DEVICE FAILED");
|
||||
}
|
||||
|
||||
cmd.reserved(false);
|
||||
event.reserved(false);
|
||||
}
|
||||
Ok(ring)
|
||||
}
|
||||
|
||||
pub fn ring_command_doorbell(&mut self) {
|
||||
self.dbs[0].write(0);
|
||||
}
|
||||
|
||||
@@ -316,7 +316,7 @@ impl Xhci {
|
||||
}
|
||||
fn endp_ctx_max_packet_size(endp_desc: &EndpDesc) -> u16 {
|
||||
// TODO: Control endpoint? Encoding?
|
||||
endp_desc.max_packet_size & 0x03FF
|
||||
endp_desc.max_packet_size & 0x07FF
|
||||
}
|
||||
fn endp_ctx_max_esit_payload(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc, max_packet_size: u16, max_burst_size: u8) -> u32 {
|
||||
const KIB: u32 = 1024;
|
||||
|
||||
+21
-4
@@ -190,17 +190,22 @@ impl Trb {
|
||||
);
|
||||
}
|
||||
|
||||
pub fn address_device(&mut self, slot_id: u8, input: usize, cycle: bool) {
|
||||
pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) {
|
||||
assert_eq!(
|
||||
input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0,
|
||||
input_ctx_ptr,
|
||||
"unaligned input context ptr"
|
||||
);
|
||||
self.set(
|
||||
input as u64,
|
||||
input_ctx_ptr as u64,
|
||||
0,
|
||||
((slot_id as u32) << 24) | ((TrbType::AddressDevice as u32) << 10) | (cycle as u32),
|
||||
(u32::from(slot_id) << 24) | ((TrbType::AddressDevice as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle),
|
||||
);
|
||||
}
|
||||
// Synchronizes the input context endpoints with the device context endpoints, I think.
|
||||
pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) {
|
||||
assert_eq!(
|
||||
input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80,
|
||||
input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0,
|
||||
input_ctx_ptr,
|
||||
"unaligned input context ptr"
|
||||
);
|
||||
@@ -213,6 +218,18 @@ impl Trb {
|
||||
| u32::from(cycle),
|
||||
);
|
||||
}
|
||||
pub fn evaluate_context(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) {
|
||||
assert_eq!(
|
||||
input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0,
|
||||
input_ctx_ptr,
|
||||
"unaligned input context ptr"
|
||||
);
|
||||
self.set(
|
||||
input_ctx_ptr as u64,
|
||||
0,
|
||||
(u32::from(slot_id) << 24) | ((TrbType::EvaluateContext as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle),
|
||||
);
|
||||
}
|
||||
pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) {
|
||||
assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc);
|
||||
self.set(
|
||||
|
||||
Reference in New Issue
Block a user