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

basic osfp support, combine the powers of reads/parse #305

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions decode/src/datapath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub enum ConnectorType {
Rj45,
Mpo2x12,
Mpo1x16,
NoSeparableConnector,
Other(u8),
Reserved(u8),
VendorSpecific(u8),
Expand All @@ -96,6 +97,7 @@ impl From<u8> for ConnectorType {
0x0c => Mpo1x12,
0x0d => Mpo2x16,
0x22 => Rj45,
0x23 => NoSeparableConnector,
0x27 => Mpo2x12,
0x28 => Mpo1x16,
0x0e..=0x1f | 0x29..=0x7f => Reserved(value),
Expand All @@ -116,6 +118,7 @@ impl fmt::Display for ConnectorType {
ConnectorType::Rj45 => write!(f, "RJ-45"),
ConnectorType::Mpo2x12 => write!(f, "MPO-2x12"),
ConnectorType::Mpo1x16 => write!(f, "MPO-1x16"),
ConnectorType::NoSeparableConnector => write!(f, "No separable connector"),
ConnectorType::Other(x) => write!(f, "Other ({x:02x})"),
ConnectorType::Reserved(x) => write!(f, "Reserved ({x:02x})"),
ConnectorType::VendorSpecific(x) => write!(f, "Vendor-specific ({x:02x})"),
Expand Down Expand Up @@ -183,7 +186,10 @@ impl ParseFromModule for Datapath {
MemoryRead::new(sff8636::Page::Upper(sff8636::UpperPage::new(0)?), 192, 1)?;
Ok(vec![tx_enable, los, cdr, compliance, extended_compliance])
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
bnaecker marked this conversation as resolved.
Show resolved Hide resolved
// As with most module data, CMIS is _far_ more complicated than
// SFF-8636. Lanes can be assigned to different datapaths,
// though only one at a time, and modules can have a large
Expand Down Expand Up @@ -401,7 +407,10 @@ impl ParseFromModule for Datapath {
lanes,
})
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// First, read the connector type and which lanes are
// _unsupported_.
let connector_type = reads.next().expect("No connector type read");
Expand Down
15 changes: 11 additions & 4 deletions decode/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,13 @@ crate::bitfield_enum! {
0x16, Cdfp3, "CDFP (Style 3)",
0x17, MicroQsfp, "MicroQSFP",
0x18, QsfpDD, "QSFP-DD Double Density 8X Pluggable Transceiver",
0x19, Qsfp8, "QSFP 8X Pluggable Transceiver",
0x19, Osfp8, "OSFP 8X Pluggable Transceiver",
0x1a, SfpDD, "SFP-DD 2X Double Density Pluggable Transceiver",
0x1b, Dsfp, "DSFP Dual Small Form Factor Pluggable Transceiver",
0x1c, X4MultiLink, "x4 MiniLink/OcuLink",
0x1d, X8MiniLink, "x8 MiniLink",
0x1e, QsfpPlusCmis, "QSFP+ or later with Common Management Interface Specification",
0x21, OsfpXd, "OSFP-XD with Common Management Interface Specification"
},
other_variants = {
Reserved : 0x21..=0x7f,
Expand All @@ -67,7 +68,7 @@ impl Identifier {
use Identifier::*;
match self {
QsfpPlusSff8636 | Qsfp28 => Ok(ManagementInterface::Sff8636),
QsfpPlusCmis | QsfpDD => Ok(ManagementInterface::Cmis),
QsfpPlusCmis | QsfpDD | Osfp8 | OsfpXd => Ok(ManagementInterface::Cmis),
_ => Err(Error::UnsupportedIdentifier(*self)),
}
}
Expand Down Expand Up @@ -189,7 +190,10 @@ impl ParseFromModule for VendorInfo {
const END: u8 = 220;
Ok(vec![MemoryRead::new(page, START, END - START)?])
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// See CMIS rev 5.0 Table 8-24.
//
// In contrast to SFF-8636, these bytes are all contiguous.
Expand Down Expand Up @@ -256,7 +260,10 @@ impl ParseFromModule for VendorInfo {
vendor,
})
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// The byte offsets in the `reads` data, offset by first byte.
const NAME: Range<usize> = 0..16; // 16 bytes
const OUI: Range<usize> = 16..19; // 3 bytes
Expand Down
10 changes: 10 additions & 0 deletions decode/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,14 @@ pub trait ParseFromModule: Sized {

/// Parse the result of the above reads into `Self`.
fn parse<'a>(id: Identifier, reads: impl Iterator<Item = &'a [u8]>) -> Result<Self, Error>;

/// Use `reads` and `parse` together to collect data from a buffer.
fn from_buf(id: Identifier, data: &[u8]) -> Result<Self, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

How is this being or going to be used? It looks like data needs to already have the entire memory map of the module in order for the offsets in the reads to correctly index it. Also, this doesn't take into account the page information in the reads, so I'm not sure how this would be used to parse that spans more than one page.

Copy link
Author

Choose a reason for hiding this comment

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

I'm currently using this to parse EEPROM data made available by a Linux kernel driver as a file in sysfs.

https://github.com/oxidecomputer/x2/blob/860a02811c57fcff8fa5e281c8baf788ae944838/x2-evb/src/lib.rs#L43-L53

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't know the details of the Linux implementation there, but I don't understand how that can work. The datapath information is spread across many different pages, for example. How does the driver expose the idea of a page?

let chunks = Self::reads(id)?.into_iter().map(|r| {
let begin = r.offset() as usize;
let end = (r.offset() + r.len()) as usize;
&data[begin..end]
});
Ok(Self::parse(id, chunks.into_iter())?)
}
}
10 changes: 8 additions & 2 deletions decode/src/monitors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,10 @@ impl ParseFromModule for Monitors {
reads.extend(per_lane);
Ok(reads)
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// TODO-completeness: There are two additional complexities
// here. First, this data is technically only available when the
// MemoryModel of the module indicates it is paged. Nearly all
Expand Down Expand Up @@ -487,7 +490,10 @@ impl ParseFromModule for Monitors {
aux_monitors: None,
})
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// First read of 2 bytes indicates support for module level
// monitors.
let support = reads.next().ok_or(Error::ParseFailed)?;
Expand Down
10 changes: 8 additions & 2 deletions decode/src/power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ impl ParseFromModule for PowerControl {
let power = MemoryRead::new(page, 93, 1).unwrap();
Ok(vec![power])
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// See CMIS 5.0 table 8-10.
//
// Byte 26, bit 6 contains the software override bit, and bit 4
Expand Down Expand Up @@ -73,7 +76,10 @@ impl ParseFromModule for PowerControl {
}
})
}
Identifier::QsfpPlusCmis | Identifier::QsfpDD => {
Identifier::QsfpPlusCmis
| Identifier::QsfpDD
| Identifier::Osfp8
| Identifier::OsfpXd => {
// Bit 6 -> override (but see above), bit 4 -> force low-power.
reads
.next()
Expand Down