Skip to content

Commit cec0f50

Browse files
committed
uefi: Implement polling for both IO and memory
1 parent eaee087 commit cec0f50

File tree

3 files changed

+80
-13
lines changed

3 files changed

+80
-13
lines changed

uefi/src/proto/pci/mod.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,11 @@ impl Ord for PciIoAddress {
9595

9696
/// Trait implemented by all data types that can natively be read from a PCI device.
9797
/// Note: Not all of them have to actually be supported by the hardware at hand.
98-
pub trait PciIoUnit: Sized + Default {}
98+
pub trait PciIoUnit: Sized + Default + Into<u64> {}
9999
impl PciIoUnit for u8 {}
100100
impl PciIoUnit for u16 {}
101101
impl PciIoUnit for u32 {}
102102
impl PciIoUnit for u64 {}
103-
impl PciIoUnit for i8 {}
104-
impl PciIoUnit for i16 {}
105-
impl PciIoUnit for i32 {}
106-
impl PciIoUnit for i64 {}
107103

108104
#[allow(dead_code)]
109105
enum PciIoMode {

uefi/src/proto/pci/resource.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,9 @@ pub trait QWordAddressSpaceDescriptorExt {
186186
/// Returns if this descriptor is currently 64 bit or 32 bit.
187187
///
188188
/// # Returns
189-
/// None: It's unspecified
190-
/// true: This descriptor is 64 bit
191-
/// false: This descriptor is 32 bit
189+
/// [`None`]: It's unspecified
190+
/// [`true`]: This descriptor is 64 bit
191+
/// [`false`]: This descriptor is 32 bit
192192
fn is_64bit(&self) -> Option<bool> {
193193
let granularity = self.descriptor().address_granularity;
194194
match granularity {

uefi/src/proto/pci/root_bridge.rs

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,14 @@ use core::mem::MaybeUninit;
1313
use core::num::NonZeroUsize;
1414
use core::ptr;
1515
use core::ptr::{NonNull, slice_from_raw_parts};
16+
use core::time::Duration;
1617
use log::debug;
1718
use uefi::proto::pci::PciIoMode;
1819
use uefi::proto::pci::root_bridge::io_access::IoAccessType;
1920
use uefi_macros::unsafe_protocol;
2021
use uefi_raw::protocol::pci::resource::QWordAddressSpaceDescriptor;
2122
use uefi_raw::Status;
22-
use uefi_raw::protocol::pci::root_bridge::{
23-
PciRootBridgeIoAccess, PciRootBridgeIoProtocol, PciRootBridgeIoProtocolAttribute,
24-
PciRootBridgeIoProtocolOperation,
25-
};
23+
use uefi_raw::protocol::pci::root_bridge::{PciRootBridgeIoAccess, PciRootBridgeIoProtocol, PciRootBridgeIoProtocolAttribute, PciRootBridgeIoProtocolOperation, PciRootBridgeIoProtocolWidth};
2624
use uefi_raw::table::boot::{AllocateType, MemoryType, PAGE_SIZE};
2725

2826
#[cfg(doc)]
@@ -280,7 +278,80 @@ impl PciRootBridgeIo {
280278
}
281279
}
282280

283-
// TODO: poll I/O
281+
/// Polls a same memory location until criteria is met.
282+
/// The criteria in question is met when value read from provided reference
283+
/// equals to provided value when masked:
284+
/// `(*to_poll) & mask == value`
285+
/// /// Refer to [`Self::poll_io`] for polling io port instead.
286+
///
287+
/// # Returns
288+
/// [`Ok`]: Criteria was met before timeout.
289+
/// [`Err`]: One of below error happened:
290+
/// * [`Status::TIMEOUT`]: Delay expired before a match occurred.
291+
/// * [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
292+
///
293+
/// # Panic
294+
/// Panics when delay is too large (longer than 58494 years).
295+
pub fn poll_mem<U: PciIoUnit>(&self, to_poll: &U, mask: U, value: U, delay: Duration) -> crate::Result<(), U> {
296+
let mut result = U::default();
297+
let delay = delay.as_nanos().div_ceil(100).try_into().unwrap();
298+
let status = unsafe {
299+
(self.0.poll_mem)(
300+
ptr::from_ref(&self.0).cast_mut(),
301+
encode_io_mode_and_unit::<U>(PciIoMode::Normal),
302+
ptr::from_ref(to_poll).addr() as u64,
303+
mask.into(),
304+
value,
305+
delay,
306+
&mut result
307+
)
308+
};
309+
310+
match status {
311+
Status::SUCCESS => {
312+
Ok(())
313+
}
314+
e => Err(e.into()),
315+
}
316+
}
317+
318+
/// Polls a same io port until criteria is met.
319+
/// The criteria in question is met when value read from provided reference
320+
/// equals to provided value when masked:
321+
/// `(*to_poll) & mask == value`
322+
/// Refer to [`Self::poll_mem`] for polling memory instead.
323+
///
324+
/// # Returns
325+
/// [`Ok`]: Criteria was met before timeout.
326+
/// [`Err`]: One of below error happened:
327+
/// * [`Status::TIMEOUT`]: Delay expired before a match occurred.
328+
/// * [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
329+
///
330+
/// # Panic
331+
/// Panics when delay is too large (longer than 58494 years).
332+
pub fn poll_io<U: PciIoUnit>(&self, to_poll: &U, mask: U, value: U, delay: Duration) -> crate::Result<(), U> {
333+
let mut result = U::default();
334+
let delay = delay.as_nanos().div_ceil(100).try_into().unwrap();
335+
let status = unsafe {
336+
(self.0.poll_io)(
337+
ptr::from_ref(&self.0).cast_mut(),
338+
encode_io_mode_and_unit::<U>(PciIoMode::Normal),
339+
ptr::from_ref(to_poll).addr() as u64,
340+
mask.into(),
341+
value,
342+
delay,
343+
&mut result
344+
)
345+
};
346+
347+
match status {
348+
Status::SUCCESS => {
349+
Ok(())
350+
}
351+
e => Err(e.into()),
352+
}
353+
}
354+
284355
// TODO: get/set attributes
285356
}
286357

0 commit comments

Comments
 (0)