Using the generic host PCIe driver

Bjorn Helgaas helgaas at kernel.org
Mon Feb 27 08:44:30 PST 2017


On Mon, Feb 27, 2017 at 05:14:15PM +0100, Mason wrote:
> On 17/02/2017, Bjorn Helgaas wrote:
> 
> > I don't know anything about your hardware or environment, but I highly
> > encourage you to use [...] generic DT (drivers/pci/host/pci-host-generic.c)
> > instead of writing a custom host controller driver.
> > 
> > The native drivers in drivers/pci/host are a huge maintenance hassle
> > for no real benefit.
> >
> > You're right that the programming model of the host bridge itself is
> > not specified by PCI specs, so it's impossible to have a generic
> > driver that can manage it completely by itself.
> > 
> > If you have firmware that initializes the bridge and tells the OS what
> > the windows are (bus numbers, memory space, I/O space) and where the
> > PCIe-specified ECAM space is, a generic driver can take it from there.
> 
> I am currently trying the approach suggested by Bjorn.
> 
> This is what my DT node currently looks like:
> 
> 		pcie at 50000000 {
> 			compatible = "pci-host-ecam-generic";
> 			reg = <0x50000000 0x200000>;
> 			device_type = "pci";
> 			bus-range = <0>, <1>;
> 			#size-cells = <2>;
> 			#address-cells = <3>;
> 			#interrupt-cells = <1>;
> 			/* BUS_ADDRESS(3)  CPU_PHYSICAL(1)  SIZE(2) */
> 			ranges = <0x02000000 0x0 0xa0000000  0xa0000000  0x0 0x00100000>;
> 		};
> 
> (I am aware that interrupt specs are missing, but I hope this
> is not a problem at an early stage.)
> 
> I.e. the configuration space is at 0x5000_0000
> (so bus_0 at 0x5000_0000, and bus_1 at 0x5010_0000)
> 
> And I defined a 32-bit non-prefetchable memory space at 0xa0000000
> 
> Question 1:
> Is there any reason to map CPU address 0xa0000000 anywhere else than
> PCI bus address 0xa0000000?

Not really.  Large systems with multiple host bridges might map things
differently so they can use the same 32-bit bus addresses on several
root buses.  But if you only have one host bridge, that's not
necessary.

> Now, this host controller is revision 1, and as such contains several
> "interesting" bugs. How can I work around them in software?
> 
> 
> Bug #1
> 
> The controller reports an incorrect class. It is a bridge, but it
> reports class = 0x048000
> 
> AFAICT, tegra had a similar problem, and the solution seems to be
> to define a DECLARE_PCI_FIXUP_EARLY hook:
> 
> /* Root complex reports incorrect device class */
> static void tango_pcie_fixup_class(struct pci_dev *dev)
> {
> 	dev->class = PCI_CLASS_BRIDGE_PCI << 8;
> }
> DECLARE_PCI_FIXUP_EARLY(0x1105, 0x8758, tango_pcie_fixup_class);
> 
> Is that the correct way to work around bug #1

That seems fine, at least for now.

> Bug #2
> 
> Bus 0 cannot be enumerated, because it reports garbage data for
> devices and functions other than 0, i.e. only 0/0/0 works.
> 
> How do I work around that issue?

There are several drivers that provide their own "ECAM-like" config
accessors.  Look at "struct pci_ecam_ops" structures, e.g.,
hisi_pcie_ops, pci_thunder_ecam_ops, xgene_v1_pcie_ecam_ops, etc.

You can also work around Bug #1 in a custom accessor instead of a
quirk.

Bjorn



More information about the linux-arm-kernel mailing list