> On Aug 25, 2015, at 6:10 AM, Benjamin Herrenschmidt 
> <[email protected]> wrote:
> 
> Hi !
> 
> I have a situation where the mapping from the CPU address space to the
> PCI MMIO space isn't 1:1
> 
> To give an example, I have, let's say, a 2G MMIO window to PCI, which
> can generate PCI addresses 0x8000_0000..0xffff_ffff by accessing CPU
> address 0x100_8000_0000..0x100_ffff_ffff.
> 
> So far, I have done the translation inside my Pci Root IO protocol. IE,
> all the resources are in term of PCI addresses, and when doing Read()
> or Write(), my implementation will apply the appropriate offset to the
> actual MMIO access.
> 
> So far it works fine for everything ... except when confronted to a
> driver that uses GetBarAttributes() from the PCI IO protocol.
> 
> This is typically the case of GOP drivers which use this in order to
> get the framebuffer address.
> 
> In that case, the PciBusDxe returns a resource containing the PCI
> address, which isn't usable as a CPU address directly and thus things
> break horribly.
> 
> Sadly it doesn't seem like the UEFI spec caters well to that non-1:1
> mapping (which is quite common outside of the x86 world), and doesn't
> really sat what GetBarAttributes() is supposed to return. However,
> practically, for GOP drivers (and possibly others) to work, we need to
> return a CPU physical address, so we need to *translate* the BAR value.
> 

I think you have it backwards. The UEFI spec abstracts PCI properly, and 
drivers are implemented incorrectly, but they work due to x86 PC assumptions. 

GetBarAttributes() returns the BAR. That is the correct thing to do. If that 
Bar was accessed via 
EFI_PCI_IO_PROTOCOL.Mem.Read()/EFI_PCI_IO_PROTOCOL.Mem.Write()//EFI_PCI_IO_PROTOCOL.CopyMem()
  then it is being accessed relative to the BAR and everything should work. 
Casting a pointer to the value returned in GetBarAttributes() is not guaranteed 
to work. 

There have  also been lots of bugs in regards to DMA. Drivers don’t use 
Map()/Unmap()/AllocateBuffer() correctly, but since x86 makes DMA cache 
coherent it all seems to work. When we did the 1st port to ARM even the edk2 
USB stack had issues not doing DMA correctly (On ARM you end up doing DMA into 
non-cached buffers, so you need to follow the rules).

> Unfortunately, I haven't found any way for my root bridge to intercept
> this and perform the translation. The Root IO protocol is standard so
> cannot be easily modified to handle this. The resource allocation
> protocol is not, so could be extended, but by the time we get those
> GetBarAttributes() call, there is no remaining reference to that
> protocol around that I can find (but I may have missed something).
> Ideally, if it stuck around, it would be handy to have a hook in there
> to "adjust" the resource returned by GetBarAttribtues().
> 
> Another way would be to actually use the AddressTranslationOffset field
> of the ACPI resource descriptor. IE, the PciBusDxe resource allocation
> code could make use of that field to maintain an offset associated with
> the BAR value internally in the PCI_IO_DEVICE to be able to perform
> such adjustments.
> 
> Unfortunately, it appears that the current implementation already
> hijacks that field for user uses.
> 
> Note that just playing with the MMU to punch a hole at 8000_0000 in the
> CPU address space and route that to PCI won't fly very high unless I'm
> ready to limit the 32-bit space drastically. The machines I'm playing
> with can have 3 or 4 PCI Host Bridge per chip, each of them having a
> completely separate aperture.
> 
> Any recommendation on what is the best approach here ? I'd rather not
> completely duplicate & hack the PciBusDxe, so the less invasive change
> would be the best here…
> 

Adding hacks to work around broken drivers is just going to cause chaos. 

You are going to need to work with the driver writers to get their driver fixed.

http://tianocore.sourceforge.net/wiki/UEFI_Driver_Writer's_Guide 
<http://tianocore.sourceforge.net/wiki/UEFI_Driver_Writer's_Guide>
The PCI I/O Protocol provides services that allow a PCI driver to easily access 
the resources of the PCI controllers it is currently managing. These services 
hide platform- specific implementation details and prevent a PCI driver from 
inadvertently accessing resources of the motherboard or other PCI controllers. 
The PCI I/O Protocol has also been designed to simplify the implementation of 
PCI drivers. For example, a PCI driver should never read the BARs in the PCI 
configuration header. Instead, the PCI driver passes in a BarIndex and Offset 
into the PCI I/O Protocol services. The PCI bus driver is responsible for 
managing the PCI controller’s BARs.

Thanks,

Andrew Fish

> Cheers,
> Ben.
> _______________________________________________
> edk2-devel mailing list
> [email protected]
> https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.01.org_mailman_listinfo_edk2-2Ddevel&d=BQICAg&c=eEvniauFctOgLOKGJOplqw&r=1HnUuXD1wDvw67rut5_idw&m=QE9d1rL3ijH-gexHgoNe54QWnW-gCrncwCMR3WJMIDs&s=MyGORn2OZERedpoAMdvuxIcbai_x3TEDR9WZqoxJmJg&e=
>  

_______________________________________________
edk2-devel mailing list
[email protected]
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to