Re: [PATCH 8/9] pci: add EFI PCI root bridge IO protocol driver

2019-12-09 Thread Ahmad Fatoum
On 12/4/19 1:56 PM, Ahmad Fatoum wrote:
> UEFI 2.1D specifies two protocols for abstracting both the PCI host bus
> controller and for PCI devices. The protocol for PCI devices provides
> function pointers for accessing IO Port, Memory and PCI configuration
> space, among others. The protocol for bus controllers provides the
> ability to read the root bridge's PCI configuration space and to query
> resources.
> 
> In barebox, we would want to reuse existing PCI drivers unmodified, so
> we utilize the root bridge protocol, unlike most other EFI payloads.

Please dismiss this patch for now. While it works on QEMU,
it doesn't handle address space descriptors of zero size (easily fixable)
and the PCI bridges on my laptop (not so easily fixable).

I'll resend when I had time to figure it out.

Cheers
Ahmad

-- 
Pengutronix e.K.   | |
Steuerwalder Str. 21   | http://www.pengutronix.de/  |
31137 Hildesheim, Germany  | Phone: +49-5121-206917-0|
Amtsgericht Hildesheim, HRA 2686   | Fax:   +49-5121-206917- |

___
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox


[PATCH 8/9] pci: add EFI PCI root bridge IO protocol driver

2019-12-04 Thread Ahmad Fatoum
UEFI 2.1D specifies two protocols for abstracting both the PCI host bus
controller and for PCI devices. The protocol for PCI devices provides
function pointers for accessing IO Port, Memory and PCI configuration
space, among others. The protocol for bus controllers provides the
ability to read the root bridge's PCI configuration space and to query
resources.

In barebox, we would want to reuse existing PCI drivers unmodified, so
we utilize the root bridge protocol, unlike most other EFI payloads.

We still utilize the PCI (device) IO protocol, but not for core
functionality: EFI has already enumerated the bus for us and allocated
the EFI handles. It thus makes sense to have the new pci device have the
EFI handle as parent and the controller as grand parent instead of
being sibling with the EFI handles. This is done with an early PCI fixup
that patches the device's parent pointer after consulting the PCI IO
GetLocation.

Signed-off-by: Ahmad Fatoum 
---
 drivers/efi/Kconfig   |   1 +
 drivers/pci/Kconfig   |   5 +
 drivers/pci/Makefile  |   1 +
 drivers/pci/pci-efi.c | 311 +++
 drivers/pci/pci-efi.h | 331 ++
 5 files changed, 649 insertions(+)
 create mode 100644 drivers/pci/pci-efi.c
 create mode 100644 drivers/pci/pci-efi.h

diff --git a/drivers/efi/Kconfig b/drivers/efi/Kconfig
index cca1a2e1d632..80d9e6f0c5eb 100644
--- a/drivers/efi/Kconfig
+++ b/drivers/efi/Kconfig
@@ -2,3 +2,4 @@ config EFI_BOOTUP
bool
select BLOCK
select PARTITION_DISK
+   select HW_HAS_PCI
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 025c418f2bcf..32153cda1809 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -54,6 +54,11 @@ config PCI_LAYERSCAPE
select OF_PCI
select PCI
 
+config PCI_EFI
+   bool "EFI PCI protocol"
+   depends on EFI_BOOTUP
+   select PCI
+
 endmenu
 
 endif
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 3ca6708657be..5843957b1925 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -12,3 +12,4 @@ obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
 obj-$(CONFIG_PCIE_DW) += pcie-designware.o pcie-designware-host.o
 obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
 obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
+obj-$(CONFIG_PCI_EFI) += pci-efi.o
diff --git a/drivers/pci/pci-efi.c b/drivers/pci/pci-efi.c
new file mode 100644
index ..80d13d906fe9
--- /dev/null
+++ b/drivers/pci/pci-efi.c
@@ -0,0 +1,311 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum 
+ */
+#define pr_fmt(fmt) "pci-efi: " fmt
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "pci-efi.h"
+
+struct efi_pci_priv {
+   struct efi_pci_root_bridge_io_protocol *protocol;
+   struct device_d *dev;
+   struct pci_controller pci;
+   struct resource mem;
+   struct resource io;
+   struct list_head children;
+};
+
+struct pci_child_id {
+   size_t segmentno;
+   size_t busno;
+   size_t devno;
+   size_t funcno;
+};
+
+struct pci_child {
+   struct efi_pci_io_protocol *protocol;
+   struct device_d *dev;
+   struct list_head list;
+   struct pci_child_id id;
+};
+
+static inline bool pci_child_id_equal(struct pci_child_id *a, struct 
pci_child_id *b)
+{
+   return a->segmentno == b->segmentno
+   && a->busno == b->busno
+   && a->devno == b->devno
+   && a->funcno == b->funcno;
+}
+
+#define host_to_efi_pci(host) container_of(host, struct efi_pci_priv, pci)
+
+static inline u64 efi_pci_addr(struct pci_bus *bus, u32 devfn, int where)
+{
+   return EFI_PCI_ADDRESS(bus->number,
+  PCI_SLOT(devfn), PCI_FUNC(devfn),
+  where);
+}
+
+static int efi_pci_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+  int size, u32 *val)
+{
+   struct efi_pci_priv *priv = host_to_efi_pci(bus->host);
+   efi_status_t efiret;
+   u32 value;
+   enum efi_pci_protocol_width width;
+
+   switch (size) {
+   case 4:
+   width = EFI_PCI_WIDTH_U32;
+   break;
+   case 2:
+   width = EFI_PCI_WIDTH_U16;
+   break;
+   case 1:
+   width = EFI_PCI_WIDTH_U8;
+   break;
+   default:
+   return PCIBIOS_BAD_REGISTER_NUMBER;
+   }
+
+   efiret = priv->protocol->pci.read(priv->protocol, width,
+   efi_pci_addr(bus, devfn, where),
+   1, &value);
+
+   *val = 0x;
+
+   if (EFI_ERROR(efiret))
+   return PCIBIOS_BAD_REGISTER_NUMBER;
+
+   *val = value;
+
+   return PCIBIOS_SUCCESSFUL;
+}
+
+static int efi_pci_wr_conf(struct pci_bus *bus, u32 devfn, int where,
+  int size, u32 val)
+{
+   struct efi_pci_priv *priv = host_to_efi_pci(bus->host);
+   efi_s