public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL
@ 2018-09-14 18:24 Kirkendall, Garrett
  2018-09-16 10:19 ` Laszlo Ersek
  0 siblings, 1 reply; 4+ messages in thread
From: Kirkendall, Garrett @ 2018-09-14 18:24 UTC (permalink / raw)
  To: edk2-devel@lists.01.org

Hopefully someone can help me understand.

I assume I should be able to access MMIO pointed to by a PCI devices Prefetchable Memory BAR.  I would think I would use EFI_PCI_IO_PROTOCOL.Mem.Read or Write.  This in turn will send the request up to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Mem.Read or Write.  

MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c: RootBridgeIoMemRead (Write) calls RootBridgeIoCheckParameter() to verify that the request falls within the confines of the PCI root bridge.  The below code verifies the address against non-prefetchable MMIO regions and skips the prefetchable memory regions.  Is this correct, and if so what is the method to read/write prefetchable memory regions?  If I force EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM, then I can access prefetchable memory regions because they are forced within Mem.* and MemAbove4G.*



EFI_STATUS
RootBridgeIoCheckParameter (
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
  IN OPERATION_TYPE                         OperationType,
  IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
  IN UINT64                                 Address,
  IN UINTN                                  Count,
  IN VOID                                   *Buffer
  )
{
...
  } else if (OperationType == MemOperation) {
    //
    // Allow Legacy MMIO access
    //
    if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {
      if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {
        return EFI_SUCCESS;
      }
    }
    //
    // By comparing the Address against Limit we know which range to be used
    // for checking
    //
    if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {
      Base = RootBridge->Mem.Base;
      Limit = RootBridge->Mem.Limit;
    } else {
      Base = RootBridge->MemAbove4G.Base;
      Limit = RootBridge->MemAbove4G.Limit;
    }
  } else {
...

GARRETT KIRKENDALL
SMTS Firmware Engineer | CTE
7171 Southwest Parkway, Austin, TX 78735 USA 
AMD   facebook  |  amd.com



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL
  2018-09-14 18:24 How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL Kirkendall, Garrett
@ 2018-09-16 10:19 ` Laszlo Ersek
  2018-09-19  1:53   ` Kirkendall, Garrett
  0 siblings, 1 reply; 4+ messages in thread
From: Laszlo Ersek @ 2018-09-16 10:19 UTC (permalink / raw)
  To: Kirkendall, Garrett; +Cc: edk2-devel@lists.01.org, Ruiyu Ni

Adding Ray, and a comment at the bottom:

On 09/14/18 20:24, Kirkendall, Garrett wrote:
> Hopefully someone can help me understand.
> 
> I assume I should be able to access MMIO pointed to by a PCI devices Prefetchable Memory BAR.  I would think I would use EFI_PCI_IO_PROTOCOL.Mem.Read or Write.  This in turn will send the request up to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Mem.Read or Write.  
> 
> MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c: RootBridgeIoMemRead (Write) calls RootBridgeIoCheckParameter() to verify that the request falls within the confines of the PCI root bridge.  The below code verifies the address against non-prefetchable MMIO regions and skips the prefetchable memory regions.  Is this correct, and if so what is the method to read/write prefetchable memory regions?  If I force EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM, then I can access prefetchable memory regions because they are forced within Mem.* and MemAbove4G.*
> 
> 
> 
> EFI_STATUS
> RootBridgeIoCheckParameter (
>   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
>   IN OPERATION_TYPE                         OperationType,
>   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
>   IN UINT64                                 Address,
>   IN UINTN                                  Count,
>   IN VOID                                   *Buffer
>   )
> {
> ...
>   } else if (OperationType == MemOperation) {
>     //
>     // Allow Legacy MMIO access
>     //
>     if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {
>       if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {
>         return EFI_SUCCESS;
>       }
>     }
>     //
>     // By comparing the Address against Limit we know which range to be used
>     // for checking
>     //
>     if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {
>       Base = RootBridge->Mem.Base;
>       Limit = RootBridge->Mem.Limit;
>     } else {
>       Base = RootBridge->MemAbove4G.Base;
>       Limit = RootBridge->MemAbove4G.Limit;
>     }
>   } else {
> ...
> 

I'm not a PCI expert, but I think you are right; the code should permit
access to the PMem / PMemAbove4G apertures as well. According to the PCI
spec (--> fair use citation below),

"A PCI Express Function requesting memory resources through a BAR must
set the BAR's Prefetchable bit unless the range contains locations with
read side effects or locations in which the Function does not tolerate
write merging."

IOW "prefetchable" means "there are no side effects to reading, and the
Function tolerates write merging".

I don't see why that's reason for RootBridgeIoCheckParameter() to reject
the access.

Ray, what's your take?

Thanks
Laszlo


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL
  2018-09-16 10:19 ` Laszlo Ersek
@ 2018-09-19  1:53   ` Kirkendall, Garrett
  2018-09-21  7:25     ` Ni, Ruiyu
  0 siblings, 1 reply; 4+ messages in thread
From: Kirkendall, Garrett @ 2018-09-19  1:53 UTC (permalink / raw)
  To: Laszlo Ersek; +Cc: edk2-devel@lists.01.org, Ruiyu Ni

Ray, did you get a chance to look at the code and see how Prefetchable Memory regions should be handled?

GARRETT KIRKENDALL
SMTS Firmware Engineer | CTE
7171 Southwest Parkway, Austin, TX 78735 USA 
AMD   facebook  |  amd.com

-----Original Message-----
From: Laszlo Ersek <lersek@redhat.com> 
Sent: Sunday, September 16, 2018 5:20 AM
To: Kirkendall, Garrett <Garrett.Kirkendall@amd.com>
Cc: edk2-devel@lists.01.org; Ruiyu Ni <ruiyu.ni@intel.com>
Subject: Re: [edk2] How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL

Adding Ray, and a comment at the bottom:

On 09/14/18 20:24, Kirkendall, Garrett wrote:
> Hopefully someone can help me understand.
> 
> I assume I should be able to access MMIO pointed to by a PCI devices Prefetchable Memory BAR.  I would think I would use EFI_PCI_IO_PROTOCOL.Mem.Read or Write.  This in turn will send the request up to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Mem.Read or Write.  
> 
> MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c: 
> RootBridgeIoMemRead (Write) calls RootBridgeIoCheckParameter() to 
> verify that the request falls within the confines of the PCI root 
> bridge.  The below code verifies the address against non-prefetchable 
> MMIO regions and skips the prefetchable memory regions.  Is this 
> correct, and if so what is the method to read/write prefetchable 
> memory regions?  If I force EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM, then 
> I can access prefetchable memory regions because they are forced 
> within Mem.* and MemAbove4G.*
> 
> 
> 
> EFI_STATUS
> RootBridgeIoCheckParameter (
>   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
>   IN OPERATION_TYPE                         OperationType,
>   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
>   IN UINT64                                 Address,
>   IN UINTN                                  Count,
>   IN VOID                                   *Buffer
>   )
> {
> ...
>   } else if (OperationType == MemOperation) {
>     //
>     // Allow Legacy MMIO access
>     //
>     if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {
>       if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {
>         return EFI_SUCCESS;
>       }
>     }
>     //
>     // By comparing the Address against Limit we know which range to be used
>     // for checking
>     //
>     if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {
>       Base = RootBridge->Mem.Base;
>       Limit = RootBridge->Mem.Limit;
>     } else {
>       Base = RootBridge->MemAbove4G.Base;
>       Limit = RootBridge->MemAbove4G.Limit;
>     }
>   } else {
> ...
> 

I'm not a PCI expert, but I think you are right; the code should permit access to the PMem / PMemAbove4G apertures as well. According to the PCI spec (--> fair use citation below),

"A PCI Express Function requesting memory resources through a BAR must set the BAR's Prefetchable bit unless the range contains locations with read side effects or locations in which the Function does not tolerate write merging."

IOW "prefetchable" means "there are no side effects to reading, and the Function tolerates write merging".

I don't see why that's reason for RootBridgeIoCheckParameter() to reject the access.

Ray, what's your take?

Thanks
Laszlo

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL
  2018-09-19  1:53   ` Kirkendall, Garrett
@ 2018-09-21  7:25     ` Ni, Ruiyu
  0 siblings, 0 replies; 4+ messages in thread
From: Ni, Ruiyu @ 2018-09-21  7:25 UTC (permalink / raw)
  To: Kirkendall, Garrett, Laszlo Ersek; +Cc: edk2-devel@lists.01.org

Garrett,
I think it's a real bug in the code. Thanks for reporting that.
I just submitted a Bz 1196 for this issue.
Patches are also sent out.

Thanks/Ray

> -----Original Message-----
> From: edk2-devel <edk2-devel-bounces@lists.01.org> On Behalf Of
> Kirkendall, Garrett
> Sent: Wednesday, September 19, 2018 9:53 AM
> To: Laszlo Ersek <lersek@redhat.com>
> Cc: Ni, Ruiyu <ruiyu.ni@intel.com>; edk2-devel@lists.01.org
> Subject: Re: [edk2] How do I access Prefetchable Memory region through
> EFI_PCI_IO_PROTOCOL
> 
> Ray, did you get a chance to look at the code and see how Prefetchable
> Memory regions should be handled?
> 
> GARRETT KIRKENDALL
> SMTS Firmware Engineer | CTE
> 7171 Southwest Parkway, Austin, TX 78735 USA AMD   facebook  |  amd.com
> 
> -----Original Message-----
> From: Laszlo Ersek <lersek@redhat.com>
> Sent: Sunday, September 16, 2018 5:20 AM
> To: Kirkendall, Garrett <Garrett.Kirkendall@amd.com>
> Cc: edk2-devel@lists.01.org; Ruiyu Ni <ruiyu.ni@intel.com>
> Subject: Re: [edk2] How do I access Prefetchable Memory region through
> EFI_PCI_IO_PROTOCOL
> 
> Adding Ray, and a comment at the bottom:
> 
> On 09/14/18 20:24, Kirkendall, Garrett wrote:
> > Hopefully someone can help me understand.
> >
> > I assume I should be able to access MMIO pointed to by a PCI devices
> Prefetchable Memory BAR.  I would think I would use
> EFI_PCI_IO_PROTOCOL.Mem.Read or Write.  This in turn will send the
> request up to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.Mem.Read or Write.
> >
> > MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c:
> > RootBridgeIoMemRead (Write) calls RootBridgeIoCheckParameter() to
> > verify that the request falls within the confines of the PCI root
> > bridge.  The below code verifies the address against non-prefetchable
> > MMIO regions and skips the prefetchable memory regions.  Is this
> > correct, and if so what is the method to read/write prefetchable
> > memory regions?  If I force
> EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM, then
> > I can access prefetchable memory regions because they are forced
> > within Mem.* and MemAbove4G.*
> >
> >
> >
> > EFI_STATUS
> > RootBridgeIoCheckParameter (
> >   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
> >   IN OPERATION_TYPE                         OperationType,
> >   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
> >   IN UINT64                                 Address,
> >   IN UINTN                                  Count,
> >   IN VOID                                   *Buffer
> >   )
> > {
> > ...
> >   } else if (OperationType == MemOperation) {
> >     //
> >     // Allow Legacy MMIO access
> >     //
> >     if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <=
> 0xC0000) {
> >       if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0)
> {
> >         return EFI_SUCCESS;
> >       }
> >     }
> >     //
> >     // By comparing the Address against Limit we know which range to be
> used
> >     // for checking
> >     //
> >     if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {
> >       Base = RootBridge->Mem.Base;
> >       Limit = RootBridge->Mem.Limit;
> >     } else {
> >       Base = RootBridge->MemAbove4G.Base;
> >       Limit = RootBridge->MemAbove4G.Limit;
> >     }
> >   } else {
> > ...
> >
> 
> I'm not a PCI expert, but I think you are right; the code should permit access
> to the PMem / PMemAbove4G apertures as well. According to the PCI spec
> (--> fair use citation below),
> 
> "A PCI Express Function requesting memory resources through a BAR must
> set the BAR's Prefetchable bit unless the range contains locations with read
> side effects or locations in which the Function does not tolerate write
> merging."
> 
> IOW "prefetchable" means "there are no side effects to reading, and the
> Function tolerates write merging".
> 
> I don't see why that's reason for RootBridgeIoCheckParameter() to reject the
> access.
> 
> Ray, what's your take?
> 
> Thanks
> Laszlo
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2018-09-21  7:25 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-09-14 18:24 How do I access Prefetchable Memory region through EFI_PCI_IO_PROTOCOL Kirkendall, Garrett
2018-09-16 10:19 ` Laszlo Ersek
2018-09-19  1:53   ` Kirkendall, Garrett
2018-09-21  7:25     ` Ni, Ruiyu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox