10000 Allow updating single fields of InterrupterRegisterSet (#142) · rust-osdev/xhci@3af7a25 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3af7a25

Browse files
authored
Allow updating single fields of InterrupterRegisterSet (#142)
It is necessary to be able to update ERDP without confusing the controller (in QEMU, at least). The description of ERSTBA which is on page 428 of xHCI specification 1.2 says: > Writing this register sets the Event Ring State Machine:EREP Advancement to the Start state. Thus, writing to any register in an interrupter register set in the old API made an event ring reset.
1 parent 25df963 commit 3af7a25

File tree

2 files changed

+91
-36
lines changed

2 files changed

+91
-36
lines changed

src/registers/mod.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use accessor::Mapper;
55

66
pub use capability::Capability;
77
pub use operational::{Operational, PortRegisterSet};
8-
#[allow(deprecated)]
9-
pub use runtime::InterruptRegisterSet;
108
pub use runtime::InterrupterRegisterSet;
119
pub use runtime::Runtime;
1210

@@ -32,8 +30,7 @@ where
3230
/// Runtime Registers
3331
pub runtime: Runtime<M>,
3432
/// Interrupter Register Set Array
35-
// TODO rename to interrupter_register_set
36-
pub interrupt_register_set: array::ReadWrite<InterrupterRegisterSet, M>,
33+
pub interrupter_register_set: InterrupterRegisterSet<M>,
3734
}
3835
impl<M> Registers<M>
3936
where
@@ -83,7 +80,7 @@ where
8380
Operational::new(mmio_base, capability.caplength.read_volatile(), &mapper);
8481
let port_register_set = PortRegisterSet::new(mmio_base, &capability, mapper.clone());
8582
let runtime = Runtime::new(mmio_base, capability.rtsoff.read_volatile(), mapper.clone());
86-
let interrupt_register_set =
83+
let interrupter_register_set =
8784
InterrupterRegisterSet::new(mmio_base, capability.rtsoff.read_volatile(), mapper);
8885

8986
Self {
@@ -92,7 +89,7 @@ where
9289
operational,
9390
port_register_set,
9491
runtime,
95-
interrupt_register_set,
92+
interrupter_register_set,
9693
}
9794
}
9895
}

src/registers/runtime.rs

Lines changed: 88 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
//! Host Controller Runtime Registers.
22
33
use super::capability::RuntimeRegisterSpaceOffset;
4-
use accessor::array;
4+
use accessor::marker::AccessorTypeSpecifier;
5+
use accessor::marker::ReadOnly;
6+
use accessor::marker::ReadWrite;
7+
use accessor::marker::Readable;
58
use accessor::single;
69
use accessor::Mapper;
710
use core::convert::TryFrom;
811
use core::convert::TryInto;
12+
use core::marker::PhantomData;
913

1014
/// Runtime Registers
1115
///
@@ -57,21 +61,19 @@ impl_debug_from_methods! {
5761

5862
/// Interrupter Register Set
5963
#[repr(C)]
60-
#[derive(Copy, Clone, Debug)]
61-
pub struct InterrupterRegisterSet {
62-
/// Interrupter Management Register
63-
pub iman: InterrupterManagementRegister,
64-
/// Interrupter Moderation Register
65-
pub imod: InterrupterModerationRegister,
66-
/// Event Ring Segment Table Size Register
67-
pub erstsz: EventRingSegmentTableSizeRegister,
68-
_rsvd: u32,
69-
/// Event Ring Segment Table Base Address Register
70-
pub erstba: EventRingSegmentTableBaseAddressRegister,
71-
/// Event Ring Dequeue Pointer Register
72-
pub erdp: EventRingDequeuePointerRegister,
64+
#[derive(Debug)]
65+
pub struct InterrupterRegisterSet<M>
66+
where
67+
M: Mapper + Clone,
68+
{
69+
base: usize,
70+
mapper: M,
7371
}
74-
impl InterrupterRegisterSet {
72+
73+
impl<M> InterrupterRegisterSet<M>
74+
where
75+
M: Mapper + Clone,
76+
{
7577
/// Creates an accessor to the Interrupter Register Set.
7678
///
7779
/// # Safety
@@ -83,19 +85,79 @@ impl InterrupterRegisterSet {
8385
///
8486
/// This method panics if the base address of the Interrupter Register Sets is not aligned
8587
/// correctly.
86-
pub unsafe fn new<M>(
87-
mmio_base: usize,
88-
rtoff: RuntimeRegisterSpaceOffset,
89-
mapper: M,
90-
) -> array::ReadWrite<Self, M>
91-
where
92-
M: Mapper,
93-
{
94-
const NUM_INTERRUPT_REGISTER_SET: usize = 1024;
95-
88+
pub unsafe fn new(mmio_base: usize, rtoff: RuntimeRegisterSpaceOffset, mapper: M) -> Self {
9689
let base = mmio_base + usize::try_from(rtoff.get()).unwrap() + 0x20;
90+
assert!(base % 0x20 == 0, "base is not aligned");
91+
92+
Self { base, mapper }
93+
}
94+
95+
/// Returns a handler for an interrupter.
96+
///
97+
/// # Panics
98+
///
99+
/// This method panics if `index > 1023`.
100+
pub fn interrupter(&self, index: usize) -> Interrupter<'_, M, ReadOnly> {
101+
unsafe { Interrupter::new(self.base, index, self.mapper.clone()) }
102+
}
103+
104+
/// Returns a mutable handler for an interrupter.
105+
///
106+
/// # Panics
107+
///
108+
/// This method panics if `index > 1023`.
109+
pub fn interrupter_mut(&mut self, index: usize) -> Interrupter<'_, M, ReadWrite> {
110+
unsafe { Interrupter::new(self.base, index, self.mapper.clone()) }
111+
}
112+
}
113+
114+
/// Interrupter
115+
#[derive(Debug)]
116+
pub struct Interrupter<'a, M, A>
117+
where
118+
M: Mapper + Clone,
119+
A: AccessorTypeSpecifier + Readable,
120+
{
121+
/// Interrupter Management Register
122+
pub iman: single::Generic<InterrupterManagementRegister, M, A>,
123+
/// Interrupter Moderation Register
124+
pub imod: single::Generic<InterrupterModerationRegister, M, A>,
125+
/// Event Ring Segment Table Size Register
126+
pub erstsz: single::Generic<EventRingSegmentTableSizeRegister, M, A>,
127+
/// Event Ring Segment Table Base Address Register
128+
pub erstba: single::Generic<EventRingSegmentTableBaseAddressRegister, M, A>,
129+
/// Event Ring Dequeue Pointer Register
130+
pub erdp: single::Generic<EventRingDequeuePointerRegister, M, A>,
131+
// Tie the lifetime of this Interrupter to the parent InterrupterRegisterSet.
132+
// This prevents multiple mutable handlers from being created.
133+
_marker: PhantomData<&'a InterrupterRegisterSet<M>>,
134+
}
97135

98-
array::ReadWrite::new(base, NUM_INTERRUPT_REGISTER_SET, mapper)
136+
impl<M, A> Interrupter<'_, M, A>
137+
where
138+
M: Mapper + Clone,
139+
A: AccessorTypeSpecifier + Readable,
140+
{
141+
/// Creates an accessor to an interrupter.
142+
///
143+
/// # Safety
144+
///
145+
/// Any mutable handlers to this Interrupter must be unique.
146+
///
147+
/// # Panics
148+
///
149+
/// This method panics if `index > 1023`.
150+
unsafe fn new(interrupter_register_set_base: usize, index: usize, mapper: M) -> Self {
151+
assert!(index < 1024, "index out of range");
152+
let base = interrupter_register_set_base + index * 0x20;
153+
Self {
154+
iman: single::Generic::new(base, mapper.clone()),
155+
imod: single::Generic::new(base + 0x4, mapper.clone()),
156+
erstsz: single::Generic::new(base + 0x8, mapper.clone()),
157+
erstba: single::Generic::new(base + 0x10, mapper.clone()),
158+
erdp: single::Generic::new(base + 0x18, mapper),
159+
_marker: PhantomData,
160+
}
99161
}
100162
}
101163

@@ -220,7 +282,3 @@ impl_debug_from_methods! {
220282
event_ring_dequeue_pointer
221283
}
222284
}
223-
224-
/// Alias for [`InterrupterRegisterSet`].
225-
#[deprecated(note = "use InterrupterRegisterSet instead (note 'er')")]
226-
pub type InterruptRegisterSet = InterrupterRegisterSet;

0 commit comments

Comments
 (0)
0