Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transparent 'Raw TRB type' #169

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft

Conversation

paulsohn
Copy link
Contributor

@paulsohn paulsohn commented Dec 6, 2023

To implement this I rewrote virtually all macros to make them more general, accepting visibility and indexing base expression arguments.

Effectively, these changes are supposed to reflect what I expressed in the issue #161 . Changes includes:

  • Each of trb::{transfer|command|event} now has its own AllowedType enum and a transparent raw TRB type.
    • This means, instead of one big TRB type, we have three TRB types for each purposes.
      Event Ring Segment would be &[event::TRB] and Command Ring &mut [command::TRB], and so on.
    • Any concrete TRB type can be converted into raw TRB type; e.g. transfer::TRB implements From<transfer::Normal>. Conversely transfer::Normal implements TryFrom<transfer::TRB>, which performs type and RSVDZ checks.
    • A concrete type can be used to get/set appropriate fields except for the cycle bit.
      Cycle bits should be handled by ring buffer implementation or by xhc.
  • In a favor of AllowedTypes and the concrete types, trb::Type and trb::{transfer|command|event}::Allowed are removed.
    • A drawback of this is that, if one wants to match a TRB into a concrete type, then if let Some-ing TryFrom::<Concrete>::try_from(trb) is the only choice now. Hopefully we can also write a macro for this. Current state isn't that bad though, especially for the users (just like me) who don't match every possible TRB types, but check if the type matches with a few supported types and only process them.

Since this is a HUGE breaking change, many minor API changes are involved on refactoring. These includes (but not limited to):

  • Previously transfer::DataStage and transfer::StatusStage both had direction bit but their types were different. (One was Direction while the other was boolean.) This was fixed so that both types are boolean.
  • Some TRBs have fields which semantics depends on flags and other fields. For transfer::Isoch, the field representing Transfer Burst Count can be either 'TD Size/TBC' or 'TBC/TRBSts'. The latter is even RSVDZ in some situations. So I renamed transfer_burst_count into tbc_or_sts. (That's one reason why I'm against the RSVDZ checkings in .try_from().)

See here to compare previous implementation(ring::trb) and mine(ring::block) in parallel.
On last commits, I removed previous ring::trb and the name is taken by previous ring::block.

(Disclaimer: currently I haven't tested anything. Only rustc says it's fine and built docs looked nice.)

@toku-sa-n
Copy link
Member

Thanks for the PR. Can I postpone the review until I finish implementing the test os? It's not easy to review a large PR without any tests.

@toku-sa-n
Copy link
Member

Sorry for the long delay. I stopped writing a test program for this crate because I'm now in doubt if I really need it (See #159 (comment)). I'll review this PR it in a few days.

Copy link
Member

@toku-sa-n toku-sa-n left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR, and again, sorry for the long delay. Sorry, I haven't completely reviewed your code yet, and I understand this is still a draft PR, but I leave a few comments.

}
rw_zero_trailing!(
pub, self,
self.0; 4~; "64-byte aligned",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
self.0; 4~; "64-byte aligned",
self.0; 4~; "16-byte aligned",

@@ -3,7 +3,7 @@
use super::ExtendedCapability;
use accessor::single;
use accessor::Mapper;
use bit_field::BitField;
// use bit_field::BitField;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// use bit_field::BitField;

@@ -2,7 +2,7 @@

use accessor::single;
use accessor::Mapper;
use bit_field::BitField;
// use bit_field::BitField;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// use bit_field::BitField;

@@ -8,7 +8,7 @@ use accessor::marker::Readable;
use accessor::single;
use accessor::Mapper;
use core::convert::TryFrom;
use core::convert::TryInto;
// use core::convert::TryInto;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// use core::convert::TryInto;

/// # Panics
///
/// This method will panic if `len >= 4096`.
pub unsafe fn new(base: *const event::TRB, len: usize) -> Self {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd change the type of base to u64 because we need the physical address of a ring, not a virtual one.

Comment on lines +52 to +61
/// Returns the mutable slice that this entry is representing.
pub fn as_mut_slice(&mut self) -> &mut [event::TRB] {
unsafe {
let base = self.ring_segment_base_address() as usize as *mut _;
let len = self.len();

core::slice::from_raw_parts_mut(base, len)
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

}
}
}
impl EventRingSegmentTableEntry {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to separate impls?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be better to define only the EventRingSegmentTableEntry type with a correct alignment and necessary field getters/setters because an ERST entry contains physical, not virtual, addresses of rings and the size of the table is variable.

Also, could you split this change to another PR? It'd be easier to review.

);

/// Returns the value of the ring segment end address.
pub fn ring_segment_bound_address(&self) -> u64 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ring_segment_end_address might be better, but I'm not sure.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A trailing newline is preferred.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants