pci: better capability handling (todo: split/merge into master
separately)
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
use core::time::Duration;
|
||||
|
||||
use libk::{error::Error, task::runtime::psleep};
|
||||
use tock_registers::{fields::FieldValue, register_bitfields, LocalRegisterCopy};
|
||||
|
||||
use crate::{PciCapability, PciCapabilityId, PciConfigurationSpace};
|
||||
|
||||
// bitflags! {
|
||||
// pub struct PcieLinkControl: u16 {
|
||||
// const ASPM_DISABLE = 0 << 0;
|
||||
// // Active state power management control
|
||||
// const ASPM_MASK = 0x3 << 0;
|
||||
// // Enable clock power management
|
||||
// const ECPM = 1 << 8;
|
||||
// }
|
||||
// }
|
||||
|
||||
register_bitfields! {
|
||||
u32,
|
||||
pub DeviceCapabilities [
|
||||
MAX_PAYLOAD_SIZE OFFSET(0) NUMBITS(3) [],
|
||||
PHANTOM_FUNCTIONS OFFSET(3) NUMBITS(2) [],
|
||||
L0S_ACCEPTABLE_LATENCY OFFSET(6) NUMBITS(3) [],
|
||||
L1_ACCEPTABLE_LATENCY OFFSET(9) NUMBITS(3) [],
|
||||
ROLE_ERROR_REPORTING OFFSET(15) NUMBITS(1) [],
|
||||
CAPTURED_SLOT_POWER_LIMIT OFFSET(18) NUMBITS(8) [],
|
||||
CAPTURED_SLOT_POWER_SCALE OFFSET(26) NUMBITS(3) [],
|
||||
FUNCTION_LEVEL_RESET OFFSET(28) NUMBITS(1) [],
|
||||
],
|
||||
pub LinkCapabilities [
|
||||
MAX_LINK_SPEED OFFSET(0) NUMBITS(4) [],
|
||||
MAX_LINK_WIDTH OFFSET(4) NUMBITS(6) [],
|
||||
ASPM OFFSET(10) NUMBITS(2) [],
|
||||
L0S_EXIT_LATENCY OFFSET(12) NUMBITS(3) [],
|
||||
L1_EXIT_LATENCY OFFSET(15) NUMBITS(3) [],
|
||||
CLOCK_PM OFFSET(18) NUMBITS(1) [],
|
||||
SURPRISE_DOWN_ERROR OFFSET(19) NUMBITS(1) [],
|
||||
DATA_LINK_ACTIVE_REPORTING OFFSET(20) NUMBITS(1) [],
|
||||
LINK_BANDWIDTH_NOTIFICATION OFFSET(21) NUMBITS(1) [],
|
||||
ASPM_COMPLIANCE OFFSET(22) NUMBITS(1) [],
|
||||
PORT_NUMBER OFFSET(24) NUMBITS(8) [],
|
||||
],
|
||||
}
|
||||
|
||||
register_bitfields! {
|
||||
u16,
|
||||
pub DeviceControl [
|
||||
CORRECTABLE_ERROR_REPORTING OFFSET(0) NUMBITS(1) [],
|
||||
NONFATAL_ERROR_REPORTING OFFSET(1) NUMBITS(1) [],
|
||||
FATAL_ERROR_REPORTING OFFSET(2) NUMBITS(1) [],
|
||||
UNSUPPORTED_REQ_REPORTING OFFSET(3) NUMBITS(1) [],
|
||||
RELAXED_ORDERING OFFSET(4) NUMBITS(1) [],
|
||||
MAX_PAYLOAD_SIZE OFFSET(5) NUMBITS(3) [],
|
||||
EXTENDED_TAG_FIELD OFFSET(8) NUMBITS(1) [],
|
||||
PHANTOM_FUNCTIONS OFFSET(9) NUMBITS(1) [],
|
||||
AUX_POWER_PM_ENABLE OFFSET(10) NUMBITS(1) [],
|
||||
NO_SNOOP OFFSET(11) NUMBITS(1) [],
|
||||
MAX_READ_REQ_SIZE OFFSET(12) NUMBITS(3) [],
|
||||
FUNCTION_LEVEL_RESET OFFSET(15) NUMBITS(1) [],
|
||||
],
|
||||
pub LinkControl [
|
||||
ASPM OFFSET(0) NUMBITS(2) [
|
||||
Disabled = 0,
|
||||
L0sEntryEnabled = 1,
|
||||
L1EntryEnabled = 2,
|
||||
L0sL1EntryEnabled = 3,
|
||||
],
|
||||
READ_COMPLETION_BOUNDARY OFFSET(3) NUMBITS(1) [],
|
||||
LINK_DISABLE OFFSET(4) NUMBITS(1) [],
|
||||
RETRAIN_LINK OFFSET(5) NUMBITS(1) [],
|
||||
COMMON_CLOCK_CONFIG OFFSET(6) NUMBITS(1) [],
|
||||
EXTENDED_SYNCH OFFSET(7) NUMBITS(1) [],
|
||||
CLOCK_PM OFFSET(8) NUMBITS(1) [],
|
||||
HARDWARE_ABW_DISABLE OFFSET(9) NUMBITS(1) [],
|
||||
LINK_BW_MANAGEMENT_IRQ OFFSET(10) NUMBITS(1) [],
|
||||
LINK_ABW_IRQ OFFSET(11) NUMBITS(1) [],
|
||||
],
|
||||
}
|
||||
|
||||
/// PCIe capability
|
||||
pub struct PciExpressCapability;
|
||||
|
||||
/// PCI Express capability data structure
|
||||
pub struct PciExpressData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl PciCapability for PciExpressCapability {
|
||||
const ID: PciCapabilityId = PciCapabilityId::PciExpress;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = PciExpressData<'a, S>;
|
||||
|
||||
fn data<'s, S: PciConfigurationSpace + ?Sized + 's>(
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
_len: usize,
|
||||
) -> Self::CapabilityData<'s, S> {
|
||||
PciExpressData { space, offset }
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! reg_read {
|
||||
($self:expr, $offset:literal, u32) => {
|
||||
$self.space.read_u32($self.offset + $offset)
|
||||
};
|
||||
($self:expr, $offset:literal, u16) => {
|
||||
$self.space.read_u16($self.offset + $offset)
|
||||
};
|
||||
}
|
||||
macro_rules! reg_write {
|
||||
($self:expr, $offset:literal, u32, $value:expr) => {
|
||||
$self.space.write_u32($self.offset + $offset, $value)
|
||||
};
|
||||
($self:expr, $offset:literal, u16, $value:expr) => {
|
||||
$self.space.write_u16($self.offset + $offset, $value)
|
||||
};
|
||||
}
|
||||
macro_rules! make_register {
|
||||
(
|
||||
$reg:ident : $ty:ident @ $offset:literal {
|
||||
$get:ident
|
||||
$(, $set:ident, $modify:ident)?
|
||||
$(,)?
|
||||
}
|
||||
) => {
|
||||
pub fn $get(&self) -> LocalRegisterCopy<$ty, $reg::Register> {
|
||||
LocalRegisterCopy::new(reg_read!(self, $offset, $ty))
|
||||
}
|
||||
|
||||
$(
|
||||
pub fn $set(&mut self, value: $ty) {
|
||||
reg_write!(self, $offset, $ty, value)
|
||||
}
|
||||
|
||||
pub fn $modify(&mut self, field: FieldValue<$ty, $reg::Register>) {
|
||||
let mut value = self.$get();
|
||||
value.modify(field);
|
||||
self.$set(value.get());
|
||||
}
|
||||
)?
|
||||
};
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> PciExpressData<'s, S> {
|
||||
make_register!(DeviceCapabilities : u32 @ 0x04 { device_capabilities });
|
||||
make_register!(DeviceControl : u16 @ 0x08 {
|
||||
device_control,
|
||||
set_device_control,
|
||||
modify_device_control,
|
||||
});
|
||||
make_register!(LinkCapabilities : u32 @ 0x0C { link_capabilities });
|
||||
make_register!(LinkControl : u16 @ 0x10 {
|
||||
link_control,
|
||||
set_link_control,
|
||||
modify_link_control,
|
||||
});
|
||||
|
||||
pub fn function_level_reset(&mut self) -> Result<(), Error> {
|
||||
if self
|
||||
.device_capabilities()
|
||||
.matches_all(DeviceCapabilities::FUNCTION_LEVEL_RESET::SET)
|
||||
{
|
||||
self.modify_device_control(DeviceControl::FUNCTION_LEVEL_RESET::SET);
|
||||
psleep(Duration::from_millis(10));
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hot_link_reset(&mut self) {
|
||||
self.modify_link_control(LinkControl::LINK_DISABLE::SET);
|
||||
psleep(Duration::from_millis(10));
|
||||
self.modify_link_control(LinkControl::LINK_DISABLE::CLEAR);
|
||||
psleep(Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//! PCI capability structures and queries
|
||||
|
||||
pub mod express;
|
||||
pub mod msi;
|
||||
pub mod power;
|
||||
pub mod virtio;
|
||||
|
||||
pub use express::PciExpressCapability;
|
||||
pub use msi::{MsiCapability, MsiXCapability};
|
||||
pub use power::PowerManagementCapability;
|
||||
pub use virtio::{
|
||||
VirtioCapability, VirtioCommonConfigCapability, VirtioDeviceConfigCapability,
|
||||
VirtioInterruptStatusCapability, VirtioNotifyConfigCapability,
|
||||
};
|
||||
+7
-306
@@ -1,91 +1,21 @@
|
||||
//! PCI capability structures and queries
|
||||
|
||||
use alloc::{sync::Arc, vec, vec::Vec};
|
||||
use bitflags::bitflags;
|
||||
|
||||
use device_api::interrupt::{
|
||||
InterruptAffinity, InterruptHandler, MessageInterruptController, MsiInfo,
|
||||
};
|
||||
use libk::error::Error;
|
||||
use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIoMut};
|
||||
use tock_registers::{
|
||||
interfaces::{Readable, Writeable},
|
||||
registers::{ReadWrite, WriteOnly},
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::PciBaseAddress;
|
||||
|
||||
use super::{PciCapability, PciCapabilityId, PciConfigurationSpace};
|
||||
|
||||
bitflags! {
|
||||
pub struct PcieLinkControl: u16 {
|
||||
const ASPM_DISABLE = 0 << 0;
|
||||
// Active state power management control
|
||||
const ASPM_MASK = 0x3 << 0;
|
||||
// Enable clock power management
|
||||
const ECPM = 1 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
|
||||
use core::mem::offset_of;
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64", rust_analyzer))]
|
||||
use kernel_arch_x86::intrinsics;
|
||||
|
||||
pub trait VirtioCapabilityData<'s, S: PciConfigurationSpace + ?Sized + 's>: Sized {
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self;
|
||||
|
||||
fn space(&self) -> &'s S;
|
||||
fn offset(&self) -> usize;
|
||||
|
||||
fn bar_index(&self) -> Option<usize> {
|
||||
let value = self.space().read_u8(self.offset() + 4);
|
||||
(value <= 0x5).then_some(value as _)
|
||||
}
|
||||
|
||||
fn bar_offset(&self) -> usize {
|
||||
let value = self.space().read_u32(self.offset() + 8);
|
||||
value as _
|
||||
}
|
||||
|
||||
fn length(&self) -> usize {
|
||||
let value = self.space().read_u32(self.offset() + 12);
|
||||
value as _
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VirtioCapability {
|
||||
const CFG_TYPE: u8;
|
||||
const MIN_LEN: usize = 0;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a>: VirtioCapabilityData<'a, S>;
|
||||
}
|
||||
|
||||
/// Power management capability entry
|
||||
pub struct PowerManagementCapability;
|
||||
/// MSI-X capability query
|
||||
pub struct MsiXCapability;
|
||||
/// MSI capability query
|
||||
pub struct MsiCapability;
|
||||
/// PCIe capability
|
||||
pub struct PciExpressCapability;
|
||||
|
||||
// VirtIO-over-PCI capabilities
|
||||
/// VirtIO PCI configuration access
|
||||
pub struct VirtioDeviceConfigCapability;
|
||||
/// VirtIO common configuration
|
||||
pub struct VirtioCommonConfigCapability;
|
||||
/// VirtIO notify configuration
|
||||
pub struct VirtioNotifyConfigCapability;
|
||||
/// VirtIO interrupt status
|
||||
pub struct VirtioInterruptStatusCapability;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DevicePowerState {
|
||||
D0,
|
||||
D1,
|
||||
D2,
|
||||
D3Cold,
|
||||
D3Hot,
|
||||
}
|
||||
use crate::{PciBaseAddress, PciCapability, PciCapabilityId, PciConfigurationSpace};
|
||||
|
||||
/// Represents an entry in MSI-X vector table
|
||||
#[repr(C)]
|
||||
@@ -109,11 +39,10 @@ pub struct MsiXVectorTable<'a> {
|
||||
len: usize,
|
||||
}
|
||||
|
||||
/// PCI Power Management capability data structure
|
||||
pub struct PowerManagementData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
/// MSI-X capability query
|
||||
pub struct MsiXCapability;
|
||||
/// MSI capability query
|
||||
pub struct MsiCapability;
|
||||
|
||||
/// MSI-X capability data structure
|
||||
pub struct MsiXData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
@@ -127,63 +56,6 @@ pub struct MsiData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
/// PCI Express capability data structure
|
||||
pub struct PcieData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioDeviceConfigData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioCommonConfigData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioNotifyConfigData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioInterruptStatusData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<T: VirtioCapability> PciCapability for T {
|
||||
const ID: PciCapabilityId = PciCapabilityId::VendorSpecific;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = T::Output<'a, S>;
|
||||
|
||||
fn check<S: PciConfigurationSpace + ?Sized>(space: &S, offset: usize, len: usize) -> bool {
|
||||
let cfg_type = space.read_u8(offset + 3);
|
||||
cfg_type == T::CFG_TYPE && len >= T::MIN_LEN
|
||||
}
|
||||
|
||||
fn data<'s, S: PciConfigurationSpace + ?Sized + 's>(
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
_len: usize,
|
||||
) -> Self::CapabilityData<'s, S> {
|
||||
T::Output::from_space_offset(space, offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl PciCapability for PowerManagementCapability {
|
||||
const ID: PciCapabilityId = PciCapabilityId::PowerManagement;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = PowerManagementData<'a, S>;
|
||||
|
||||
fn data<'s, S: PciConfigurationSpace + ?Sized + 's>(
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
_len: usize,
|
||||
) -> Self::CapabilityData<'s, S> {
|
||||
PowerManagementData { space, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl PciCapability for MsiXCapability {
|
||||
const ID: PciCapabilityId = PciCapabilityId::MsiX;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = MsiXData<'a, S>;
|
||||
@@ -210,167 +82,6 @@ impl PciCapability for MsiCapability {
|
||||
}
|
||||
}
|
||||
|
||||
impl PciCapability for PciExpressCapability {
|
||||
const ID: PciCapabilityId = PciCapabilityId::PciExpress;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = PcieData<'a, S>;
|
||||
|
||||
fn data<'s, S: PciConfigurationSpace + ?Sized + 's>(
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
_len: usize,
|
||||
) -> Self::CapabilityData<'s, S> {
|
||||
PcieData { space, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioDeviceConfigCapability {
|
||||
const CFG_TYPE: u8 = 0x04;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioDeviceConfigData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioDeviceConfigData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioCommonConfigCapability {
|
||||
const CFG_TYPE: u8 = 0x01;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioCommonConfigData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioCommonConfigData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioNotifyConfigCapability {
|
||||
const CFG_TYPE: u8 = 0x02;
|
||||
const MIN_LEN: usize = 0x14;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioNotifyConfigData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioNotifyConfigData<'s, S> {
|
||||
pub fn offset_multiplier(&self) -> usize {
|
||||
self.space.read_u32(self.offset + 16) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioNotifyConfigData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioInterruptStatusCapability {
|
||||
const CFG_TYPE: u8 = 0x03;
|
||||
const MIN_LEN: usize = 1;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioInterruptStatusData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioInterruptStatusData<'s, S> {
|
||||
pub fn read_status(&self) -> (bool, bool) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioInterruptStatusData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> PowerManagementData<'s, S> {
|
||||
pub fn set_device_power_state(&self, state: DevicePowerState) {
|
||||
let pmcsr = self.space.read_u16(self.offset + 4) & !0x3;
|
||||
let current = self.get_device_power_state();
|
||||
|
||||
if state == current {
|
||||
return;
|
||||
}
|
||||
|
||||
log::info!("Set device power state: {state:?}");
|
||||
|
||||
match state {
|
||||
DevicePowerState::D0 => {
|
||||
// power = 0b00 | PME_EN
|
||||
self.space.write_u16(self.offset + 4, pmcsr);
|
||||
}
|
||||
_ => {
|
||||
log::warn!("TODO: {state:?} power state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pme_en(&self, state: bool) {
|
||||
let pmcsr = self.space.read_u16(self.offset + 4);
|
||||
let new = if state {
|
||||
pmcsr | (1 << 8)
|
||||
} else {
|
||||
pmcsr & !(1 << 8)
|
||||
};
|
||||
if pmcsr == new {
|
||||
return;
|
||||
}
|
||||
|
||||
log::info!("Set PMCSR.PME_En = {state}");
|
||||
|
||||
self.space.write_u16(self.offset + 4, new);
|
||||
}
|
||||
|
||||
pub fn get_device_power_state(&self) -> DevicePowerState {
|
||||
let pmcsr = self.space.read_u16(self.offset + 4);
|
||||
match pmcsr & 0x3 {
|
||||
0b00 => DevicePowerState::D0,
|
||||
0b01 => DevicePowerState::D1,
|
||||
0b10 => DevicePowerState::D2,
|
||||
0b11 => DevicePowerState::D3Hot,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiXData<'s, S> {
|
||||
// TODO use pending bits as well
|
||||
/// Maps and returns the vector table associated with the device's MSI-X capability
|
||||
@@ -601,13 +312,3 @@ impl<'s, S: PciConfigurationSpace + ?Sized + 's> MsiData<'s, S> {
|
||||
Ok(info)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> PcieData<'s, S> {
|
||||
pub fn link_control(&self) -> PcieLinkControl {
|
||||
PcieLinkControl::from_bits_retain(self.space.read_u16(self.offset + 0x10))
|
||||
}
|
||||
|
||||
pub fn set_link_control(&mut self, value: PcieLinkControl) {
|
||||
self.space.write_u16(self.offset + 0x10, value.bits());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
use crate::{PciCapability, PciCapabilityId, PciConfigurationSpace};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DevicePowerState {
|
||||
D0,
|
||||
D1,
|
||||
D2,
|
||||
D3Cold,
|
||||
D3Hot,
|
||||
}
|
||||
|
||||
/// Power management capability entry
|
||||
pub struct PowerManagementCapability;
|
||||
|
||||
/// PCI Power Management capability data structure
|
||||
pub struct PowerManagementData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl PciCapability for PowerManagementCapability {
|
||||
const ID: PciCapabilityId = PciCapabilityId::PowerManagement;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = PowerManagementData<'a, S>;
|
||||
|
||||
fn data<'s, S: PciConfigurationSpace + ?Sized + 's>(
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
_len: usize,
|
||||
) -> Self::CapabilityData<'s, S> {
|
||||
PowerManagementData { space, offset }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> PowerManagementData<'s, S> {
|
||||
pub fn set_device_power_state(&self, state: DevicePowerState) {
|
||||
let pmcsr = self.space.read_u16(self.offset + 4) & !0x3;
|
||||
let current = self.get_device_power_state();
|
||||
|
||||
if state == current {
|
||||
return;
|
||||
}
|
||||
|
||||
log::info!("Set device power state: {state:?}");
|
||||
|
||||
match state {
|
||||
DevicePowerState::D0 => {
|
||||
// power = 0b00 | PME_EN
|
||||
self.space.write_u16(self.offset + 4, pmcsr);
|
||||
}
|
||||
_ => {
|
||||
log::warn!("TODO: {state:?} power state");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_pme_en(&self, state: bool) {
|
||||
let pmcsr = self.space.read_u16(self.offset + 4);
|
||||
let new = if state {
|
||||
pmcsr | (1 << 8)
|
||||
} else {
|
||||
pmcsr & !(1 << 8)
|
||||
};
|
||||
if pmcsr == new {
|
||||
return;
|
||||
}
|
||||
|
||||
log::info!("Set PMCSR.PME_En = {state}");
|
||||
|
||||
self.space.write_u16(self.offset + 4, new);
|
||||
}
|
||||
|
||||
pub fn get_device_power_state(&self) -> DevicePowerState {
|
||||
let pmcsr = self.space.read_u16(self.offset + 4);
|
||||
match pmcsr & 0x3 {
|
||||
0b00 => DevicePowerState::D0,
|
||||
0b01 => DevicePowerState::D1,
|
||||
0b10 => DevicePowerState::D2,
|
||||
0b11 => DevicePowerState::D3Hot,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
use crate::{PciCapability, PciCapabilityId, PciConfigurationSpace};
|
||||
|
||||
pub trait VirtioCapabilityData<'s, S: PciConfigurationSpace + ?Sized + 's>: Sized {
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self;
|
||||
|
||||
fn space(&self) -> &'s S;
|
||||
fn offset(&self) -> usize;
|
||||
|
||||
fn bar_index(&self) -> Option<usize> {
|
||||
let value = self.space().read_u8(self.offset() + 4);
|
||||
(value <= 0x5).then_some(value as _)
|
||||
}
|
||||
|
||||
fn bar_offset(&self) -> usize {
|
||||
let value = self.space().read_u32(self.offset() + 8);
|
||||
value as _
|
||||
}
|
||||
|
||||
fn length(&self) -> usize {
|
||||
let value = self.space().read_u32(self.offset() + 12);
|
||||
value as _
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VirtioCapability {
|
||||
const CFG_TYPE: u8;
|
||||
const MIN_LEN: usize = 0;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a>: VirtioCapabilityData<'a, S>;
|
||||
}
|
||||
|
||||
// VirtIO-over-PCI capabilities
|
||||
/// VirtIO PCI configuration access
|
||||
pub struct VirtioDeviceConfigCapability;
|
||||
/// VirtIO common configuration
|
||||
pub struct VirtioCommonConfigCapability;
|
||||
/// VirtIO notify configuration
|
||||
pub struct VirtioNotifyConfigCapability;
|
||||
/// VirtIO interrupt status
|
||||
pub struct VirtioInterruptStatusCapability;
|
||||
|
||||
pub struct VirtioDeviceConfigData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioCommonConfigData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioNotifyConfigData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct VirtioInterruptStatusData<'s, S: PciConfigurationSpace + ?Sized + 's> {
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<T: VirtioCapability> PciCapability for T {
|
||||
const ID: PciCapabilityId = PciCapabilityId::VendorSpecific;
|
||||
type CapabilityData<'a, S: PciConfigurationSpace + ?Sized + 'a> = T::Output<'a, S>;
|
||||
|
||||
fn check<S: PciConfigurationSpace + ?Sized>(space: &S, offset: usize, len: usize) -> bool {
|
||||
let cfg_type = space.read_u8(offset + 3);
|
||||
cfg_type == T::CFG_TYPE && len >= T::MIN_LEN
|
||||
}
|
||||
|
||||
fn data<'s, S: PciConfigurationSpace + ?Sized + 's>(
|
||||
space: &'s S,
|
||||
offset: usize,
|
||||
_len: usize,
|
||||
) -> Self::CapabilityData<'s, S> {
|
||||
T::Output::from_space_offset(space, offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioDeviceConfigCapability {
|
||||
const CFG_TYPE: u8 = 0x04;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioDeviceConfigData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioDeviceConfigData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioCommonConfigCapability {
|
||||
const CFG_TYPE: u8 = 0x01;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioCommonConfigData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioCommonConfigData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioNotifyConfigCapability {
|
||||
const CFG_TYPE: u8 = 0x02;
|
||||
const MIN_LEN: usize = 0x14;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioNotifyConfigData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioNotifyConfigData<'s, S> {
|
||||
pub fn offset_multiplier(&self) -> usize {
|
||||
self.space.read_u32(self.offset + 16) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioNotifyConfigData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtioCapability for VirtioInterruptStatusCapability {
|
||||
const CFG_TYPE: u8 = 0x03;
|
||||
const MIN_LEN: usize = 1;
|
||||
type Output<'a, S: PciConfigurationSpace + ?Sized + 'a> = VirtioInterruptStatusData<'a, S>;
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioInterruptStatusData<'s, S> {
|
||||
pub fn read_status(&self) -> (bool, bool) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, S: PciConfigurationSpace + ?Sized + 's> VirtioCapabilityData<'s, S>
|
||||
for VirtioInterruptStatusData<'s, S>
|
||||
{
|
||||
fn from_space_offset(space: &'s S, offset: usize) -> Self {
|
||||
Self { space, offset }
|
||||
}
|
||||
|
||||
fn space(&self) -> &'s S {
|
||||
self.space
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
self.offset
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ use libk_util::{sync::spin_rwlock::IrqSafeRwLock, OneTimeInit};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::{
|
||||
capability::{MsiCapability, MsiXCapability, MsiXVectorTable},
|
||||
capability::{msi::MsiXVectorTable, MsiCapability, MsiXCapability, PciExpressCapability},
|
||||
driver::PciDriver,
|
||||
PciAddress, PciCommandRegister, PciConfigSpace, PciConfigurationSpace, PciSegmentInfo,
|
||||
};
|
||||
@@ -142,6 +142,23 @@ impl PciDeviceInfo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn function_level_reset(&self) -> Result<(), Error> {
|
||||
if let Some(mut pcie) = self.config_space.capability::<PciExpressCapability>() {
|
||||
pcie.function_level_reset()
|
||||
} else {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn hot_link_reset(&self) -> Result<(), Error> {
|
||||
if let Some(mut pcie) = self.config_space.capability::<PciExpressCapability>() {
|
||||
pcie.hot_link_reset();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_interrupts(&self, preferred_mode: PreferredInterruptMode) -> Result<(), Error> {
|
||||
self.interrupt_config
|
||||
.try_init_with(|| {
|
||||
|
||||
@@ -7,7 +7,8 @@ use rtl8139::Rtl8139;
|
||||
use rtl8168::Rtl8168;
|
||||
use ygg_driver_pci::{
|
||||
capability::{
|
||||
DevicePowerState, PciExpressCapability, PcieLinkControl, PowerManagementCapability,
|
||||
express::LinkControl, power::DevicePowerState, PciExpressCapability,
|
||||
PowerManagementCapability,
|
||||
},
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
@@ -30,9 +31,7 @@ pci_driver! {
|
||||
info.init_interrupts(PreferredInterruptMode::Msi(false))?;
|
||||
|
||||
if let Some(mut pcie) = info.config_space.capability::<PciExpressCapability>() {
|
||||
let mut lcr = pcie.link_control();
|
||||
lcr.remove(PcieLinkControl::ASPM_MASK | PcieLinkControl::ECPM);
|
||||
pcie.set_link_control(lcr);
|
||||
pcie.modify_link_control(LinkControl::ASPM::CLEAR + LinkControl::CLOCK_PM::CLEAR);
|
||||
}
|
||||
|
||||
// Enable MMIO + interrupts + bus mastering
|
||||
@@ -76,9 +75,7 @@ pci_driver! {
|
||||
}
|
||||
|
||||
if let Some(mut pcie) = info.config_space.capability::<PciExpressCapability>() {
|
||||
let mut lcr = pcie.link_control();
|
||||
lcr.remove(PcieLinkControl::ASPM_MASK | PcieLinkControl::ECPM);
|
||||
pcie.set_link_control(lcr);
|
||||
pcie.modify_link_control(LinkControl::ASPM::CLEAR + LinkControl::CLOCK_PM::CLEAR);
|
||||
}
|
||||
|
||||
let device = Rtl8168::new(dma.clone(), base, info.clone())?;
|
||||
|
||||
@@ -37,10 +37,13 @@ pub struct PinComplexWidget {
|
||||
default_config: PinDefaultConfig,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct MixerWidget {}
|
||||
#[derive(Debug)]
|
||||
pub enum AudioWidget {
|
||||
AudioOutput(AudioOutputWidget),
|
||||
AudioInput(AudioInputWidget),
|
||||
PinComplex(PinComplexWidget),
|
||||
Mixer(MixerWidget),
|
||||
Other,
|
||||
}
|
||||
|
||||
@@ -198,9 +201,13 @@ impl Node {
|
||||
pub async fn set_unsolicited_response(
|
||||
&self,
|
||||
hda: &HdAudio,
|
||||
enabled: bool,
|
||||
tag: Option<u8>,
|
||||
) -> Result<(), Error> {
|
||||
self.perform_command(hda, Verb::SetUnsolicitedResponse, enabled as u32)
|
||||
let value = match tag {
|
||||
Some(tag) => (tag as u32) | (1 << 7),
|
||||
None => 0,
|
||||
};
|
||||
self.perform_command(hda, Verb::SetUnsolicitedResponse, value)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -290,6 +297,9 @@ impl AudioWidgetNode {
|
||||
let default_config = node.get_pin_default_config(hda).await?;
|
||||
AudioWidget::PinComplex(PinComplexWidget { default_config })
|
||||
}
|
||||
Some(AudioWidgetCapabilities::TYPE::Value::AudioMixer) => {
|
||||
AudioWidget::Mixer(MixerWidget {})
|
||||
}
|
||||
v => {
|
||||
log::warn!("hda: unknown audio widget: {v:?}");
|
||||
AudioWidget::Other
|
||||
@@ -469,15 +479,24 @@ impl Codec {
|
||||
AudioWidget::PinComplex(_) => {
|
||||
log::info!(" Configure pin @ {wid:?}");
|
||||
wid.set_power_state(&*self.hda, true).await?;
|
||||
wid.set_unsolicited_response(&*self.hda, false).await?;
|
||||
wid.modify_pin_control(&*self.hda, PinControl::OutEnable::SET)
|
||||
// TODO only set for jacks
|
||||
wid.set_unsolicited_response(&*self.hda, Some(wid.nid))
|
||||
.await?;
|
||||
wid.modify_pin_control(
|
||||
&*self.hda,
|
||||
PinControl::OutEnable::SET + PinControl::HPhnEnable::SET,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
AudioWidget::AudioOutput(out) => {
|
||||
log::info!(" Configure audio output @ {wid:?}");
|
||||
audio_widget = Some(widget.node);
|
||||
wid.set_power_state(&*self.hda, true).await?;
|
||||
wid.set_unsolicited_response(&*self.hda, false).await?;
|
||||
wid.set_unsolicited_response(&*self.hda, None).await?;
|
||||
}
|
||||
AudioWidget::Mixer(_) => {
|
||||
log::info!(" Configure mixer @ {wid:?}");
|
||||
wid.set_power_state(&*self.hda, true).await?;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ register_bitfields! {
|
||||
Power = 0x5,
|
||||
VolumeKnob = 0x6,
|
||||
BeepGenerator = 0x7,
|
||||
VendorDefined = 0xF,
|
||||
],
|
||||
],
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ use futures_util::task::AtomicWaker;
|
||||
use libk::{
|
||||
dma::DmaBuffer,
|
||||
error::Error,
|
||||
task::runtime::{self, with_timeout},
|
||||
task::runtime::{self, psleep, with_timeout},
|
||||
time::monotonic_time,
|
||||
};
|
||||
use libk_mm::device::DeviceMemoryIo;
|
||||
@@ -33,6 +33,7 @@ use sink::HdAudioSink;
|
||||
use stream::{BufferDescriptorList, OutputStream};
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
|
||||
use ygg_driver_pci::{
|
||||
capability::{power::DevicePowerState, PowerManagementCapability},
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciBaseAddress, PciConfigurationSpace,
|
||||
@@ -163,6 +164,7 @@ impl HdAudio {
|
||||
match with_timeout(self.softirq_event.wait(), Duration::from_millis(100)).await {
|
||||
// IRQs happened
|
||||
Ok(events) => {
|
||||
log::info!("softirq()");
|
||||
for sink_index in
|
||||
self.input_stream_count..self.input_stream_count + self.output_stream_count
|
||||
{
|
||||
@@ -233,6 +235,8 @@ impl InterruptHandler for HdAudio {
|
||||
|
||||
impl Device for HdAudio {
|
||||
unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
|
||||
// FLR if capable
|
||||
self.pci.function_level_reset().ok();
|
||||
self.pci
|
||||
.map_interrupt(InterruptAffinity::Any, self.clone())?;
|
||||
|
||||
@@ -250,7 +254,10 @@ impl Device for HdAudio {
|
||||
self.bidi_stream_count
|
||||
);
|
||||
|
||||
regs.reset(Duration::from_millis(100))?;
|
||||
regs.reset(
|
||||
Duration::from_millis(100),
|
||||
self.input_stream_count + self.output_stream_count + self.bidi_stream_count,
|
||||
)?;
|
||||
|
||||
regs.disable_interrupts();
|
||||
regs.disable_control();
|
||||
|
||||
@@ -94,6 +94,10 @@ register_bitfields! {
|
||||
/// 64-bit addresses supported
|
||||
OK64 OFFSET(0) NUMBITS(1) [],
|
||||
],
|
||||
pub GSTS [
|
||||
/// Flush status bit
|
||||
FSTS OFFSET(1) NUMBITS(1) [],
|
||||
],
|
||||
pub CORBRP [
|
||||
/// CORB read pointer reset
|
||||
CORBRPRST OFFSET(15) NUMBITS(1) [],
|
||||
@@ -159,7 +163,7 @@ register_structs! {
|
||||
(0x0008 => pub GCTL: ReadWrite<u32, GCTL::Register>),
|
||||
(0x000C => pub WAKEEN: ReadWrite<u16>),
|
||||
(0x000E => pub WAKESTS: ReadWrite<u16>),
|
||||
(0x0010 => pub GSTS: ReadOnly<u16>),
|
||||
(0x0010 => pub GSTS: ReadWrite<u16, GSTS::Register>),
|
||||
(0x0012 => _0),
|
||||
(0x0018 => pub OUTSTRMPAY: ReadOnly<u16>),
|
||||
(0x001A => pub INSTRMPAY: ReadOnly<u16>),
|
||||
@@ -235,17 +239,39 @@ register_structs! {
|
||||
}
|
||||
|
||||
impl Regs {
|
||||
pub fn reset(&self, timeout: Duration) -> Result<(), Error> {
|
||||
pub fn reset(&self, timeout: Duration, stream_count: usize) -> Result<(), Error> {
|
||||
// Go through all the streams, disable their DMA
|
||||
for i in 0..stream_count {
|
||||
let stream = &self.STREAMS[i];
|
||||
stream
|
||||
.SDxCTL0
|
||||
.write(SDxCTL0::RUN::CLEAR + SDxCTL0::SRST::SET);
|
||||
}
|
||||
|
||||
self.CORBCTL.write(CORBCTL::CORBRUN::CLEAR);
|
||||
self.RIRBCTL.write(RIRBCTL::RIRBDMAEN::CLEAR);
|
||||
|
||||
// Flush the FIFO
|
||||
self.GCTL.modify(GCTL::FCNTRL::SET);
|
||||
psleep(Duration::from_millis(10));
|
||||
pwait(timeout, Duration::from_millis(10), || {
|
||||
self.GSTS.matches_all(GSTS::FSTS::SET)
|
||||
})?;
|
||||
self.GCTL.modify(GCTL::FCNTRL::CLEAR);
|
||||
self.GSTS.write(GSTS::FSTS::SET);
|
||||
|
||||
// TODO does FIFO need to be flushed here as well?
|
||||
// Begin controller reset
|
||||
self.GCTL.write(GCTL::CRST::CLEAR);
|
||||
psleep(Duration::from_millis(100));
|
||||
psleep(Duration::from_millis(10));
|
||||
// End controller reset
|
||||
self.GCTL.write(GCTL::CRST::SET);
|
||||
psleep(Duration::from_millis(100));
|
||||
psleep(Duration::from_millis(10));
|
||||
pwait(timeout, Duration::from_millis(10), || {
|
||||
self.GCTL.matches_all(GCTL::CRST::SET)
|
||||
})
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disable_interrupts(&self) {
|
||||
@@ -253,6 +279,8 @@ impl Regs {
|
||||
}
|
||||
|
||||
pub fn enable_interrupts(&self) {
|
||||
// Also accept unsolicited responses from codecs
|
||||
self.GCTL.modify(GCTL::UNSOL::SET);
|
||||
self.INTCTL.write(INTCTL::GIE::SET + INTCTL::CIE::SET);
|
||||
}
|
||||
|
||||
@@ -325,6 +353,8 @@ impl Regs {
|
||||
// Reset write/read pointers
|
||||
self.CORBWP.set(0);
|
||||
self.CORBRP.write(CORBRP::CORBRPRST::SET);
|
||||
self.RIRBSTS
|
||||
.write(RIRBSTS::RIRBOIS::SET + RIRBSTS::RINTFL::SET);
|
||||
self.RINTCNT.set(255);
|
||||
|
||||
// Ensure CORBRP is reset properly
|
||||
|
||||
@@ -262,7 +262,9 @@ impl CommandRing {
|
||||
pub(super) fn process_completions(&self, corb_tail: u8, rirb_head: u8) -> usize {
|
||||
let mut inner = self.inner.lock();
|
||||
inner.process_responses(
|
||||
|_, _| (),
|
||||
|codec, message| {
|
||||
log::info!("Unsolicited message: {message:#x} from codec {codec:#x}");
|
||||
},
|
||||
|codec| self.codec_notify[codec as usize].wake(),
|
||||
corb_tail as u32,
|
||||
rirb_head as u32,
|
||||
|
||||
@@ -9,7 +9,7 @@ use controller::Xhci;
|
||||
use device_api::{device::Device, dma::DmaAllocator, interrupt::InterruptAffinity};
|
||||
use regs::Regs;
|
||||
use ygg_driver_pci::{
|
||||
capability::{DevicePowerState, PowerManagementCapability},
|
||||
capability::{power::DevicePowerState, PowerManagementCapability},
|
||||
device::{PciDeviceInfo, PreferredInterruptMode},
|
||||
macros::pci_driver,
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
|
||||
@@ -5,7 +5,7 @@ use tock_registers::{
|
||||
};
|
||||
use ygg_driver_pci::{
|
||||
capability::{
|
||||
VirtioCapabilityData, VirtioCommonConfigCapability, VirtioDeviceConfigCapability,
|
||||
virtio::VirtioCapabilityData, VirtioCommonConfigCapability, VirtioDeviceConfigCapability,
|
||||
VirtioInterruptStatusCapability, VirtioNotifyConfigCapability,
|
||||
},
|
||||
PciCommandRegister, PciConfigurationSpace,
|
||||
|
||||
Reference in New Issue
Block a user