@@ -12,15 +12,18 @@ use core::marker::PhantomData;
1212use core:: mem:: MaybeUninit ;
1313use core:: num:: NonZeroUsize ;
1414use core:: ptr;
15- use core:: ptr:: { NonNull , slice_from_raw_parts } ;
15+ use core:: ptr:: NonNull ;
1616use core:: time:: Duration ;
1717use log:: debug;
1818use uefi:: proto:: pci:: PciIoMode ;
1919use uefi:: proto:: pci:: root_bridge:: io_access:: IoAccessType ;
2020use uefi_macros:: unsafe_protocol;
21- use uefi_raw:: protocol:: pci:: resource:: QWordAddressSpaceDescriptor ;
2221use uefi_raw:: Status ;
23- use uefi_raw:: protocol:: pci:: root_bridge:: { PciRootBridgeIoAccess , PciRootBridgeIoProtocol , PciRootBridgeIoProtocolAttribute , PciRootBridgeIoProtocolOperation , PciRootBridgeIoProtocolWidth } ;
22+ use uefi_raw:: protocol:: pci:: resource:: QWordAddressSpaceDescriptor ;
23+ use uefi_raw:: protocol:: pci:: root_bridge:: {
24+ PciRootBridgeIoAccess , PciRootBridgeIoProtocol , PciRootBridgeIoProtocolAttribute ,
25+ PciRootBridgeIoProtocolOperation ,
26+ } ;
2427use uefi_raw:: table:: boot:: { AllocateType , MemoryType , PAGE_SIZE } ;
2528
2629#[ cfg( doc) ]
@@ -191,9 +194,10 @@ impl PciRootBridgeIo {
191194 ///
192195 /// # Returns
193196 /// [`Ok`] on successful copy.
197+ ///
194198 /// [`Err`] otherwise.
195- /// * [`Status::INVALID_PARAMETER`]: Width is invalid for this PCI root bridge.
196- /// * [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
199+ /// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
200+ /// - [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
197201 /// # Question
198202 /// Should this support other types than just primitives?
199203 #[ cfg( feature = "alloc" ) ]
@@ -219,15 +223,16 @@ impl PciRootBridgeIo {
219223 ///
220224 /// # Returns
221225 /// [`Ok`] when it successfully retrieved current configuration.
226+ ///
222227 /// [`Err`] when it failed to retrieve current configuration.
223- /// * Status value will be [`Status::UNSUPPORTED`]
228+ /// - Its Status value will be [`Status::UNSUPPORTED`]
224229 ///
225230 /// # Panic
226231 /// It may panic if pci devices or drivers for those provided by boot service misbehave.
227232 /// There are multiple verifications put in place, and they will panic if invariants
228233 /// are broken, such as when invalid enum variant value was received
229234 /// or reserved bits are not 0
230- pub fn configuration ( & self ) -> crate :: Result < & ' static [ QWordAddressSpaceDescriptor ] > {
235+ pub fn configuration ( & self ) -> crate :: Result < & [ QWordAddressSpaceDescriptor ] > {
231236 let mut configuration_address = 0u64 ;
232237 let configuration_status = unsafe {
233238 ( self . 0 . configuration ) (
@@ -249,8 +254,10 @@ impl PciRootBridgeIo {
249254 cursor_ref. verify ( ) ;
250255 count += 1 ;
251256 if count >= 1024 {
252- panic ! ( "Timed out while fetching configurations:\
253- There are more than 1024 configuration spaces") ;
257+ panic ! (
258+ "Timed out while fetching configurations:\
259+ There are more than 1024 configuration spaces"
260+ ) ;
254261 }
255262 }
256263 0x79 => {
@@ -271,7 +278,7 @@ impl PciRootBridgeIo {
271278 }
272279 } ;
273280 let list: & [ QWordAddressSpaceDescriptor ] =
274- unsafe { slice_from_raw_parts ( head, count) . as_ref ( ) . unwrap ( ) } ;
281+ unsafe { ptr :: slice_from_raw_parts ( head, count) . as_ref ( ) . unwrap ( ) } ;
275282 Ok ( list)
276283 }
277284 e => Err ( e. into ( ) ) ,
@@ -282,77 +289,170 @@ impl PciRootBridgeIo {
282289 /// The criteria in question is met when value read from provided reference
283290 /// equals to provided value when masked:
284291 /// `(*to_poll) & mask == value`
285- /// /// Refer to [`Self::poll_io`] for polling io port instead.
292+ ///
293+ /// Refer to [`Self::poll_io`] for polling io port instead.
286294 ///
287295 /// # Returns
288296 /// [`Ok`]: Criteria was met before timeout.
297+ ///
289298 /// [`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.
299+ /// - [`Status::TIMEOUT`]: Delay expired before a match occurred.
300+ /// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
301+ /// - [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
292302 ///
293303 /// # Panic
294304 /// 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 ( ) ;
305+ pub fn poll_mem < U : PciIoUnit > (
306+ & self ,
307+ to_poll : & U ,
308+ mask : U ,
309+ value : U ,
310+ delay : Duration ,
311+ ) -> crate :: Result < ( ) , u64 > {
312+ let mut result = 0u64 ;
297313 let delay = delay. as_nanos ( ) . div_ceil ( 100 ) . try_into ( ) . unwrap ( ) ;
298314 let status = unsafe {
299315 ( self . 0 . poll_mem ) (
300316 ptr:: from_ref ( & self . 0 ) . cast_mut ( ) ,
301317 encode_io_mode_and_unit :: < U > ( PciIoMode :: Normal ) ,
302318 ptr:: from_ref ( to_poll) . addr ( ) as u64 ,
303319 mask. into ( ) ,
304- value,
320+ value. into ( ) ,
305321 delay,
306- & mut result
322+ & mut result,
307323 )
308324 } ;
309325
310- match status {
311- Status :: SUCCESS => {
312- Ok ( ( ) )
313- }
314- e => Err ( e. into ( ) ) ,
315- }
326+ status. to_result_with_err ( |_| result)
316327 }
317328
318329 /// Polls a same io port until criteria is met.
319330 /// The criteria in question is met when value read from provided reference
320331 /// equals to provided value when masked:
321332 /// `(*to_poll) & mask == value`
333+ ///
322334 /// Refer to [`Self::poll_mem`] for polling memory instead.
323335 ///
324336 /// # Returns
325337 /// [`Ok`]: Criteria was met before timeout.
338+ ///
326339 /// [`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.
340+ /// - [`Status::TIMEOUT`]: Delay expired before a match occurred.
341+ /// - [`Status::INVALID_PARAMETER`] The requested width is invalid for this PCI root bridge.
342+ /// - [`Status::OUT_OF_RESOURCES`]: The request could not be completed due to a lack of resources.
329343 ///
330344 /// # Panic
331345 /// 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 ( ) ;
346+ pub fn poll_io < U : PciIoUnit > (
347+ & self ,
348+ to_poll : & U ,
349+ mask : U ,
350+ value : U ,
351+ delay : Duration ,
352+ ) -> crate :: Result < ( ) , u64 > {
353+ let mut result = 0u64 ;
334354 let delay = delay. as_nanos ( ) . div_ceil ( 100 ) . try_into ( ) . unwrap ( ) ;
335355 let status = unsafe {
336356 ( self . 0 . poll_io ) (
337357 ptr:: from_ref ( & self . 0 ) . cast_mut ( ) ,
338358 encode_io_mode_and_unit :: < U > ( PciIoMode :: Normal ) ,
339359 ptr:: from_ref ( to_poll) . addr ( ) as u64 ,
340360 mask. into ( ) ,
341- value,
361+ value. into ( ) ,
342362 delay,
343- & mut result
363+ & mut result,
364+ )
365+ } ;
366+
367+ status. to_result_with_err ( |_| result)
368+ }
369+
370+ /// Returns available and used attributes of this root bridge.
371+ ///
372+ /// # Returns
373+ /// Both supported and used attribute will be returned in struct [`AttributeReport`]
374+ pub fn get_attributes ( & self ) -> AttributeReport {
375+ let mut supports = PciRootBridgeIoProtocolAttribute :: empty ( ) ;
376+ let mut attributes = PciRootBridgeIoProtocolAttribute :: empty ( ) ;
377+ let status = unsafe {
378+ ( self . 0 . get_attributes ) (
379+ & self . 0 ,
380+ ptr:: from_mut ( & mut supports) . cast ( ) ,
381+ ptr:: from_mut ( & mut attributes) . cast ( ) ,
382+ )
383+ } ;
384+
385+ match status {
386+ Status :: SUCCESS => AttributeReport {
387+ supported : supports,
388+ used : attributes,
389+ } ,
390+ Status :: INVALID_PARAMETER => unreachable ! ( ) ,
391+ e => panic ! ( "Unexpected error occurred: {:?}" , e) ,
392+ }
393+ }
394+
395+ /// Sets attributes to use for this root bridge.
396+ /// Specified attributes must be supported. Otherwise, it will return error.
397+ /// Supported attributes can be requested with [`Self::get_attributes`]
398+ ///
399+ /// # Returns
400+ /// [`Ok`]: Optional resource range. It will only be available when resource
401+ /// parameter is Some and one of:
402+ /// - [`PciRootBridgeIoProtocolAttribute::MEMORY_WRITE_COMBINE`]
403+ /// - [`PciRootBridgeIoProtocolAttribute::MEMORY_CACHED`]
404+ /// - [`PciRootBridgeIoProtocolAttribute::MEMORY_DISABLE`]
405+ /// is set.
406+ ///
407+ /// [`Err`]: Possible error cases:
408+ /// - [`Status::UNSUPPORTED`]: A bit is set in Attributes that is not supported by the PCI Root Bridge.
409+ /// The supported attribute bits are reported by [`Self::get_attributes`]
410+ /// - [`Status::INVALID_PARAMETER`]: More than one attribute bit is set in Attributes that requires a resource parameter.
411+ /// - [`Status::OUT_OF_RESOURCES`]: There are not enough resources to set the attributes on the resource range specified by resource parameter.
412+ pub fn set_attributes < ' a , ' p > (
413+ & ' p self ,
414+ attributes : PciRootBridgeIoProtocolAttribute ,
415+ resource : Option < & ' a [ u64 ] > ,
416+ ) -> crate :: Result < Option < & ' a [ u64 ] > >
417+ where
418+ ' p : ' a ,
419+ {
420+ let ( mut base, mut length) = match resource {
421+ Some ( v) => {
422+ let ptr: * const [ u64 ] = v;
423+ let base = ptr. addr ( ) as u64 ;
424+ let length = ptr. len ( ) as u64 ;
425+ ( base, length)
426+ }
427+ None => ( 0 , 0 ) ,
428+ } ;
429+ let status = unsafe {
430+ ( self . 0 . set_attributes ) (
431+ ptr:: from_ref ( & self . 0 ) . cast_mut ( ) ,
432+ attributes. bits ( ) ,
433+ & mut base,
434+ & mut length,
344435 )
345436 } ;
346437
347438 match status {
348439 Status :: SUCCESS => {
349- Ok ( ( ) )
440+ let to_return = if length != 0 {
441+ unsafe {
442+ Some (
443+ ptr:: slice_from_raw_parts ( base as * const u64 , length as usize )
444+ . as_ref ( )
445+ . unwrap ( ) ,
446+ )
447+ }
448+ } else {
449+ None
450+ } ;
451+ Ok ( to_return)
350452 }
351453 e => Err ( e. into ( ) ) ,
352454 }
353455 }
354-
355- // TODO: get/set attributes
356456}
357457
358458/// Struct for performing PCI I/O operations on a root bridge.
@@ -575,3 +675,15 @@ impl<T: IoAccessType> PciIoAccessPci<'_, T> {
575675 }
576676 }
577677}
678+
679+ /// Struct containing return value for [`PciRootBridgeIo::get_attributes`]
680+ /// This is to minimize confusion by giving both of them names.
681+ #[ derive( Debug ) ]
682+ pub struct AttributeReport {
683+ /// Attributes supported by this bridge.
684+ /// Only attributes in this set can be used as parameter for [`PciRootBridgeIo::set_attributes`]
685+ pub supported : PciRootBridgeIoProtocolAttribute ,
686+
687+ /// Attributes currently being used.
688+ pub used : PciRootBridgeIoProtocolAttribute ,
689+ }
0 commit comments