Allow every settable MSI field to be set.
This commit is contained in:
@@ -40,7 +40,9 @@ pub struct PciFunction {
|
||||
/// BAR sizes
|
||||
pub bar_sizes: [u32; 6],
|
||||
|
||||
/// Legacy IRQ line
|
||||
/// Legacy IRQ line: It's the responsibility of pcid to make sure that it be mapped in either
|
||||
/// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly.
|
||||
/// The vector to map is always this field, plus 32.
|
||||
pub legacy_interrupt_line: u8,
|
||||
|
||||
/// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all.
|
||||
@@ -114,6 +116,48 @@ pub enum PcidClientHandleError {
|
||||
}
|
||||
pub type Result<T, E = PcidClientHandleError> = std::result::Result<T, E>;
|
||||
|
||||
// TODO: Remove these "features" and just go strait to the actual thing.
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct MsiSetFeatureInfo {
|
||||
/// The Multi Message Enable field of the Message Control in the MSI Capability Structure,
|
||||
/// is the log2 of the interrupt vectors, minus one. Can only be 0b000..=0b101.
|
||||
pub multi_message_enable: Option<u8>,
|
||||
|
||||
/// The system-specific message address, must be DWORD aligned.
|
||||
///
|
||||
/// The message address contains things like the CPU that will be targeted, at least on
|
||||
/// x86_64.
|
||||
pub message_address: Option<u32>,
|
||||
|
||||
/// The upper 32 bits of the 64-bit message address. Not guaranteed to exist, and is
|
||||
/// reserved on x86_64 (currently).
|
||||
pub message_upper_address: Option<u32>,
|
||||
|
||||
/// The message data, containing the actual interrupt vector (lower 8 bits), etc.
|
||||
///
|
||||
/// The spec mentions that the lower N bits can be modified, where N is the multi message
|
||||
/// enable, which means that the vector set here has to be aligned to that number, and that
|
||||
/// all vectors in that range have to be allocated.
|
||||
pub message_data: Option<u16>,
|
||||
|
||||
/// A bitmap of the vectors that are masked. This field is not guaranteed (and not likely,
|
||||
/// at least according to the feature flags I got from QEMU), to exist.
|
||||
pub mask_bits: Option<u32>,
|
||||
}
|
||||
|
||||
/// Some flags that might be set simultaneously, but separately.
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum SetFeatureInfo {
|
||||
Msi(MsiSetFeatureInfo),
|
||||
|
||||
MsiX {
|
||||
/// Masks the entire function, and all of its vectors.
|
||||
function_mask: Option<bool>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum PcidClientRequest {
|
||||
@@ -122,12 +166,14 @@ pub enum PcidClientRequest {
|
||||
EnableFeature(PciFeature),
|
||||
FeatureStatus(PciFeature),
|
||||
FeatureInfo(PciFeature),
|
||||
SetFeatureInfo(SetFeatureInfo),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[non_exhaustive]
|
||||
pub enum PcidServerResponseError {
|
||||
NonexistentFeature(PciFeature),
|
||||
InvalidBitPattern,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -139,6 +185,7 @@ pub enum PcidClientResponse {
|
||||
FeatureStatus(PciFeature, FeatureStatus),
|
||||
Error(PcidServerResponseError),
|
||||
FeatureInfo(PciFeature, PciFeatureInfo),
|
||||
SetFeatureInfo(PciFeature),
|
||||
}
|
||||
|
||||
// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over
|
||||
|
||||
+54
-4
@@ -29,7 +29,7 @@ pub struct DriverHandler {
|
||||
|
||||
state: Arc<State>,
|
||||
}
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &Pci, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T {
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &dyn CfgAccess, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T {
|
||||
let bus = PciBus {
|
||||
pci,
|
||||
num: bus_num,
|
||||
@@ -46,7 +46,7 @@ fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(pci: &Pci, bus_num: u8, dev_nu
|
||||
}
|
||||
impl DriverHandler {
|
||||
fn with_pci_func_raw<T, F: FnOnce(&PciFunc) -> T>(&self, function: F) -> T {
|
||||
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, function)
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, function)
|
||||
}
|
||||
fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse {
|
||||
use driver_interface::*;
|
||||
@@ -70,7 +70,7 @@ impl DriverHandler {
|
||||
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
|
||||
};
|
||||
unsafe {
|
||||
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
capability.set_enabled(true);
|
||||
capability.write_message_control(func, offset);
|
||||
});
|
||||
@@ -83,7 +83,7 @@ impl DriverHandler {
|
||||
None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)),
|
||||
};
|
||||
unsafe {
|
||||
with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
capability.set_msix_enabled(true);
|
||||
capability.write_a(func, offset);
|
||||
});
|
||||
@@ -115,6 +115,56 @@ impl DriverHandler {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
|
||||
}
|
||||
}),
|
||||
PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set {
|
||||
SetFeatureInfo::Msi(info_to_set) => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) {
|
||||
if let Some(mme) = info_to_set.multi_message_enable {
|
||||
if info.multi_message_capable() < mme || mme > 0b101 {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern);
|
||||
}
|
||||
info.set_multi_message_enable(mme);
|
||||
|
||||
}
|
||||
if let Some(message_addr) = info_to_set.message_address {
|
||||
if message_addr & 0b11 != 0 {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern);
|
||||
}
|
||||
info.set_message_address(message_addr);
|
||||
}
|
||||
if let Some(message_addr_upper) = info_to_set.message_upper_address {
|
||||
info.set_message_upper_address(message_addr_upper);
|
||||
}
|
||||
if let Some(message_data) = info_to_set.message_data {
|
||||
if message_data & ((1 << info.multi_message_enable()) - 1) != 0 {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern);
|
||||
}
|
||||
info.set_message_data(message_data);
|
||||
}
|
||||
if let Some(mask_bits) = info_to_set.mask_bits {
|
||||
info.set_mask_bits(mask_bits);
|
||||
}
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
info.write_all(func, offset);
|
||||
});
|
||||
}
|
||||
PcidClientResponse::SetFeatureInfo(PciFeature::Msi)
|
||||
} else {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::Msi));
|
||||
}
|
||||
SetFeatureInfo::MsiX { function_mask } => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) {
|
||||
if let Some(mask) = function_mask {
|
||||
info.set_function_mask(mask);
|
||||
unsafe {
|
||||
with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| {
|
||||
info.write_a(func, offset);
|
||||
});
|
||||
}
|
||||
}
|
||||
PcidClientResponse::SetFeatureInfo(PciFeature::MsiX)
|
||||
} else {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::MsiX));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn handle_spawn(mut self, pcid_to_client_write: Option<usize>, pcid_from_client_read: Option<usize>, args: driver_interface::SubdriverArguments) {
|
||||
|
||||
+2
-2
@@ -48,13 +48,13 @@ pub enum MsiCapability {
|
||||
_32BitAddress {
|
||||
message_control: u32,
|
||||
message_address: u32,
|
||||
message_data: u32,
|
||||
message_data: u16,
|
||||
},
|
||||
_64BitAddress {
|
||||
message_control: u32,
|
||||
message_address_lo: u32,
|
||||
message_address_hi: u32,
|
||||
message_data: u32,
|
||||
message_data: u16,
|
||||
},
|
||||
_32BitAddressWithPvm {
|
||||
message_control: u32,
|
||||
|
||||
+97
-5
@@ -48,13 +48,13 @@ impl MsiCapability {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(u16::from(offset + 4)),
|
||||
message_address_hi: reader.read_u32(u16::from(offset + 8)),
|
||||
message_data: reader.read_u32(u16::from(offset + 12)),
|
||||
message_data: reader.read_u32(u16::from(offset + 12)) as u16,
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddress {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(u16::from(offset + 4)),
|
||||
message_data: reader.read_u32(u16::from(offset + 8)),
|
||||
message_data: reader.read_u32(u16::from(offset + 8)) as u16,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ impl MsiCapability {
|
||||
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
|
||||
}
|
||||
}
|
||||
pub unsafe fn write_message_control<W: ConfigWriter>(&mut self, writer: &W, offset: u8) {
|
||||
pub unsafe fn write_message_control<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(u16::from(offset), self.message_control_raw());
|
||||
}
|
||||
pub fn is_pvt_capable(&self) -> bool {
|
||||
@@ -100,14 +100,106 @@ impl MsiCapability {
|
||||
pub fn multi_message_capable(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8
|
||||
}
|
||||
pub fn multi_message_enabled(&self) -> u8 {
|
||||
pub fn multi_message_enable(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8
|
||||
}
|
||||
pub fn set_multi_message_enabled(&mut self, log_mme: u8) {
|
||||
pub fn set_multi_message_enable(&mut self, log_mme: u8) {
|
||||
let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK);
|
||||
new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT);
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
|
||||
pub fn message_address(&self) -> u32 {
|
||||
match self {
|
||||
&Self::_32BitAddress { message_address, .. } | &Self::_32BitAddressWithPvm { message_address, .. } => message_address,
|
||||
&Self::_64BitAddress { message_address_lo, .. } | &Self::_64BitAddressWithPvm { message_address_lo, .. } => message_address_lo,
|
||||
}
|
||||
}
|
||||
pub fn message_upper_address(&self) -> Option<u32> {
|
||||
match self {
|
||||
&Self::_64BitAddress { message_address_hi, .. } | &Self::_64BitAddressWithPvm { message_address_hi, .. } => Some(message_address_hi),
|
||||
&Self::_32BitAddress { .. } | &Self::_32BitAddressWithPvm { .. } => None,
|
||||
}
|
||||
}
|
||||
pub fn message_data(&self) -> u16 {
|
||||
match self {
|
||||
&Self::_32BitAddress { message_data, .. } | &Self::_64BitAddress { message_data, .. } => message_data,
|
||||
&Self::_32BitAddressWithPvm { message_data, .. } | &Self::_64BitAddressWithPvm { message_data, .. } => message_data as u16,
|
||||
}
|
||||
}
|
||||
pub fn mask_bits(&self) -> Option<u32> {
|
||||
match self {
|
||||
&Self::_32BitAddressWithPvm { mask_bits, .. } | &Self::_64BitAddressWithPvm { mask_bits, .. } => Some(mask_bits),
|
||||
&Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => None,
|
||||
}
|
||||
}
|
||||
pub fn pending_bits(&self) -> Option<u32> {
|
||||
match self {
|
||||
&Self::_32BitAddressWithPvm { pending_bits, .. } | &Self::_64BitAddressWithPvm { pending_bits, .. } => Some(pending_bits),
|
||||
&Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => None,
|
||||
}
|
||||
}
|
||||
pub fn set_message_address(&mut self, message_address: u32) {
|
||||
assert_eq!(message_address & 0xFFFF_FFFC, message_address, "unaligned message address (this should already be validated)");
|
||||
match self {
|
||||
&mut Self::_32BitAddress { message_address: ref mut addr, .. } | &mut Self::_32BitAddressWithPvm { message_address: ref mut addr, .. } => *addr = message_address,
|
||||
&mut Self::_64BitAddress { message_address_lo: ref mut addr, .. } | &mut Self::_64BitAddressWithPvm { message_address_lo: ref mut addr, .. } => *addr = message_address,
|
||||
}
|
||||
}
|
||||
pub fn set_message_upper_address(&mut self, message_upper_address: u32) -> Option<()> {
|
||||
match self {
|
||||
&mut Self::_64BitAddress { ref mut message_address_hi, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_address_hi, .. } => *message_address_hi = message_upper_address,
|
||||
&mut Self::_32BitAddress { .. } | &mut Self::_32BitAddressWithPvm { .. } => return None,
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
pub fn set_message_data(&mut self, value: u16) {
|
||||
match self {
|
||||
&mut Self::_32BitAddress { ref mut message_data, .. } | &mut Self::_64BitAddress { ref mut message_data, .. } => *message_data = value,
|
||||
&mut Self::_32BitAddressWithPvm { ref mut message_data, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_data, .. } => {
|
||||
*message_data &= 0xFFFF_0000;
|
||||
*message_data |= u32::from(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn set_mask_bits(&mut self, mask_bits: u32) -> Option<()> {
|
||||
match self {
|
||||
&mut Self::_32BitAddressWithPvm { mask_bits: ref mut bits, .. } | &mut Self::_64BitAddressWithPvm { mask_bits: ref mut bits, .. } => *bits = mask_bits,
|
||||
&mut Self::_32BitAddress { .. } | &mut Self::_64BitAddress { .. } => return None,
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
pub unsafe fn write_message_address<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(u16::from(offset) + 4, self.message_address())
|
||||
}
|
||||
pub unsafe fn write_message_upper_address<W: ConfigWriter>(&self, writer: &W, offset: u8) -> Option<()> {
|
||||
let value = self.message_upper_address()?;
|
||||
writer.write_u32(u16::from(offset + 8), value);
|
||||
Some(())
|
||||
}
|
||||
pub unsafe fn write_message_data<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
match self {
|
||||
&Self::_32BitAddress { message_data, .. } => writer.write_u32(u16::from(offset + 8), message_data.into()),
|
||||
&Self::_32BitAddressWithPvm { message_data, .. } => writer.write_u32(u16::from(offset + 8), message_data),
|
||||
&Self::_64BitAddress { message_data, .. } => writer.write_u32(u16::from(offset + 12), message_data.into()),
|
||||
&Self::_64BitAddressWithPvm { message_data, .. } => writer.write_u32(u16::from(offset + 12), message_data),
|
||||
}
|
||||
}
|
||||
pub unsafe fn write_mask_bits<W: ConfigWriter>(&self, writer: &W, offset: u8) -> Option<()> {
|
||||
match self {
|
||||
&Self::_32BitAddressWithPvm { mask_bits, .. } => writer.write_u32(u16::from(offset + 12), mask_bits),
|
||||
&Self::_64BitAddressWithPvm { mask_bits, .. } => writer.write_u32(u16::from(offset + 16), mask_bits),
|
||||
&Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None,
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
pub unsafe fn write_all<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
self.write_message_control(writer, offset);
|
||||
self.write_message_address(writer, offset);
|
||||
self.write_message_upper_address(writer, offset);
|
||||
self.write_message_data(writer, offset);
|
||||
self.write_mask_bits(writer, offset);
|
||||
}
|
||||
}
|
||||
|
||||
impl MsixCapability {
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ fn main() {
|
||||
PciFeatureInfo::MsiX(_) => panic!(),
|
||||
};
|
||||
// use one vector
|
||||
capability.set_multi_message_enabled(0);
|
||||
capability.set_multi_message_enable(0);
|
||||
|
||||
todo!("msi (msix is implemented though)")
|
||||
} else if msix_enabled {
|
||||
|
||||
Reference in New Issue
Block a user