summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAhmad Fatoum <ahmad@a3f.at>2021-04-16 08:24:35 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2021-05-03 14:06:30 +0200
commitffdb6a435e7ed5576f37d6cea14157d6ce51e16b (patch)
treed53a4d9175c919fca307f45190b9d17e960f9f3f
parentc3a53742f3ae16443ee80dfe3c525a863c577e40 (diff)
downloadbarebox-ffdb6a435e7ed5576f37d6cea14157d6ce51e16b.tar.gz
barebox-ffdb6a435e7ed5576f37d6cea14157d6ce51e16b.tar.xz
pci: add EFI PCI root bridge IO protocol driver
UEFI 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. Driver is written from scratch and hasn't seen heavy usage yet, so it should be used with care. It was written while consulting the UEFI 2.1D specification. Signed-off-by: Ahmad Fatoum <ahmad@a3f.at> Link: https://lore.barebox.org/20210416062436.332665-4-ahmad@a3f.at Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--arch/x86/configs/efi_defconfig1
-rw-r--r--arch/x86/include/asm/pci.h7
-rw-r--r--drivers/efi/Kconfig1
-rw-r--r--drivers/pci/Kconfig5
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/pci-efi.c342
-rw-r--r--drivers/pci/pci-efi.h343
7 files changed, 700 insertions, 0 deletions
diff --git a/arch/x86/configs/efi_defconfig b/arch/x86/configs/efi_defconfig
index 761ffbe261..e007bf8a01 100644
--- a/arch/x86/configs/efi_defconfig
+++ b/arch/x86/configs/efi_defconfig
@@ -88,6 +88,7 @@ CONFIG_WATCHDOG=y
CONFIG_WATCHDOG_EFI=y
CONFIG_F71808E_WDT=y
# CONFIG_PINCTRL is not set
+CONFIG_PCI_EFI=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
new file mode 100644
index 0000000000..ca1c0f912d
--- /dev/null
+++ b/arch/x86/include/asm/pci.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PCI_H
+#define __ASM_PCI_H
+
+#define pcibios_assign_all_busses() 0
+
+#endif
diff --git a/drivers/efi/Kconfig b/drivers/efi/Kconfig
index cca1a2e1d6..80d9e6f0c5 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 0585460976..71d05055d4 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 d227619ed4..6fc4eaf6b2 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -10,3 +10,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 0000000000..e1fe11d070
--- /dev/null
+++ b/drivers/pci/pci-efi.c
@@ -0,0 +1,342 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2019 Ahmad Fatoum <a.fatoum@pengutronix.de>
+ */
+#define pr_fmt(fmt) "pci-efi: " fmt
+
+#include <common.h>
+#include <driver.h>
+#include <init.h>
+#include <xfuncs.h>
+#include <efi.h>
+#include <efi/efi.h>
+#include <efi/efi-device.h>
+#include <linux/pci.h>
+
+#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 mem_pref;
+ 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 = 0xFFFFFFFF;
+
+ 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_status_t efiret;
+ 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.write(priv->protocol, width,
+ efi_pci_addr(bus, devfn, where),
+ 1, &val);
+ if (EFI_ERROR(efiret))
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static inline struct resource build_resource(const char *name,
+ resource_size_t start,
+ resource_size_t len,
+ unsigned long flags)
+{
+ struct resource res;
+
+ res.name = name;
+ res.start = start;
+ res.end = start + len - 1;
+ res.flags = flags;
+ res.parent = NULL;
+ INIT_LIST_HEAD(&res.children);
+ INIT_LIST_HEAD(&res.sibling);
+
+ return res;
+}
+
+static const struct pci_ops efi_pci_ops = {
+ .read = efi_pci_rd_conf,
+ .write = efi_pci_wr_conf,
+};
+
+static u8 *acpi_parse_resource(u8 *next, struct resource *out)
+{
+ struct efi_acpi_resource *res;
+ const char *name = NULL;
+ unsigned long flags = 0;
+
+ do {
+ if (*next == ACPI_RESOURCE_END_TAG)
+ return NULL;
+
+ if (*next != ACPI_RESOURCE_DESC_TAG)
+ return ERR_PTR(-EIO);
+
+ res = container_of(next, struct efi_acpi_resource, asd);
+
+ next = (u8 *)&res[1];
+ } while (res->addr_len == 0);
+
+ switch (res->restype) {
+ case ACPI_RESOURCE_TYPE_MEM:
+ if ((res->typflags & ACPI_RESOURCE_TYPFLAG_MTP_MASK)
+ != ACPI_RESOURCE_TYPFLAG_MTP_MEM)
+ break;
+
+ name = "NP-MEM";
+ flags = IORESOURCE_MEM;
+
+ switch (res->typflags & ACPI_RESOURCE_TYPFLAG_MEM_MASK) {
+ case ACPI_RESOURCE_TYPFLAG_MEM_PREF:
+ name = "P-MEM";
+ flags |= IORESOURCE_PREFETCH;
+ /* fallthrough */
+ case ACPI_RESOURCE_TYPFLAG_MEM_WC:
+ case ACPI_RESOURCE_TYPFLAG_MEM_CACHEABLE:
+ flags |= IORESOURCE_CACHEABLE;
+ }
+
+ if (res->typflags & ACPI_RESOURCE_TYPFLAG_RW_MASK)
+ flags |= IORESOURCE_MEM_WRITEABLE;
+
+ break;
+ case ACPI_RESOURCE_TYPE_IO:
+ name = "IO";
+ flags = IORESOURCE_IO;
+ break;
+ case ACPI_RESOURCE_TYPE_BUSNO:
+ name = "BUS";
+ flags = IORESOURCE_BUS;
+ break;
+ default:
+ return ERR_PTR(-ENXIO);
+ }
+
+ *out = build_resource(name, res->addr_min, res->addr_len, flags);
+
+ pr_debug("%s: %llx-%llx (len=%llx, gr=%lld, xlate_off=%llx, resflags=%08lx)\n",
+ out->name,
+ res->addr_min, res->addr_max, res->addr_len,
+ res->addr_granularity, res->addr_xlate_off,
+ flags);
+
+ return next;
+}
+
+/* EFI already enumerated the bus for us, match our new pci devices with the efi
+ * handles
+ */
+static void efi_pci_fixup_dev_parent(struct pci_dev *dev)
+{
+ struct efi_pci_priv *priv = host_to_efi_pci(dev->bus->host);
+ struct pci_child *child;
+ struct pci_child_id id;
+
+ id.segmentno = priv->protocol->segmentno;
+ id.busno = dev->bus->number;
+ id.devno = PCI_SLOT(dev->devfn);
+ id.funcno = PCI_FUNC(dev->devfn);
+
+ list_for_each_entry(child, &priv->children, list) {
+ if (IS_ERR(child->protocol))
+ continue;
+
+ if (!child->protocol) {
+ struct efi_device *efichild = to_efi_device(child->dev);
+ efi_status_t efiret;
+
+ BS->handle_protocol(efichild->handle, &EFI_PCI_IO_PROTOCOL_GUID,
+ (void **)&child->protocol);
+ if (!child->protocol) {
+ child->protocol = ERR_PTR(-ENODEV);
+ continue;
+ }
+
+ efiret = child->protocol->get_location(child->protocol,
+ &child->id.segmentno,
+ &child->id.busno,
+ &child->id.devno,
+ &child->id.funcno);
+
+ if (EFI_ERROR(efiret)) {
+ child->protocol = ERR_PTR(-efi_errno(efiret));
+ continue;
+ }
+ }
+
+ if (pci_child_id_equal(&child->id, &id)) {
+ dev->dev.priv = child->protocol;
+ dev->dev.parent = child->dev;
+ return;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, efi_pci_fixup_dev_parent);
+
+static int efi_pci_probe(struct efi_device *efidev)
+{
+ struct device_d *child;
+ struct efi_pci_priv *priv;
+ efi_status_t efiret;
+ void *resources;
+ struct resource resource;
+ u8 *res;
+
+ priv = xzalloc(sizeof(*priv));
+
+ BS->handle_protocol(efidev->handle, &EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID,
+ (void **)&priv->protocol);
+ if (!priv->protocol)
+ return -ENODEV;
+
+ efiret = priv->protocol->configuration(priv->protocol, &resources);
+ if (EFI_ERROR(efiret))
+ return -efi_errno(efiret);
+
+ res = resources;
+
+ while (1) {
+ res = acpi_parse_resource(res, &resource);
+
+ if (IS_ERR(res))
+ return PTR_ERR(res);
+
+ if (!res)
+ break;
+
+ if ((resource.flags & (IORESOURCE_MEM | IORESOURCE_PREFETCH))
+ == (IORESOURCE_MEM | IORESOURCE_PREFETCH)) {
+ priv->pci.mem_pref_resource = &priv->mem_pref;
+ priv->mem_pref = resource;
+ } else if (resource.flags & IORESOURCE_MEM) {
+ priv->pci.mem_resource = &priv->mem;
+ priv->mem = resource;
+ } else if (resource.flags & IORESOURCE_IO) {
+ priv->pci.io_resource = &priv->io;
+ priv->io = resource;
+ }
+ }
+
+ priv->pci.parent = &efidev->dev;
+ priv->pci.pci_ops = &efi_pci_ops;
+
+ INIT_LIST_HEAD(&priv->children);
+
+ device_for_each_child(&efidev->dev, child) {
+ struct pci_child *pci_child;
+ struct efi_device *efichild = to_efi_device(child);
+
+ if (!efi_device_has_guid(efichild, EFI_PCI_IO_PROTOCOL_GUID))
+ continue;
+
+ pci_child = xzalloc(sizeof(*pci_child));
+
+ pci_child->dev = &efichild->dev;
+
+ /*
+ * regiser_pci_controller can reconfigure bridge bus numbers,
+ * thus we only collect the child node handles here, but
+ * don't yet call GetLocation on them
+ */
+ list_add_tail(&pci_child->list, &priv->children);
+ };
+
+ register_pci_controller(&priv->pci);
+
+ return 0;
+}
+
+static struct efi_driver efi_pci_driver = {
+ .driver = {
+ .name = "efi-pci",
+ },
+ .probe = efi_pci_probe,
+ .guid = EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_GUID,
+};
+device_efi_driver(efi_pci_driver);
diff --git a/drivers/pci/pci-efi.h b/drivers/pci/pci-efi.h
new file mode 100644
index 0000000000..1943461cdf
--- /dev/null
+++ b/drivers/pci/pci-efi.h
@@ -0,0 +1,343 @@
+// SPDX-License-Identifier: GPL-2.0
+#ifndef __PCI_EFI_H_
+#define __PCI_EFI_H_
+
+#include <efi.h>
+
+struct efi_pci_root_bridge_io_protocol;
+struct efi_pci_io_protocol;
+
+enum efi_pci_protocol_width {
+ EFI_PCI_WIDTH_U8,
+ EFI_PCI_WIDTH_U16,
+ EFI_PCI_WIDTH_U32,
+ EFI_PCI_WIDTH_U64,
+ EFI_PCI_WIDTH_FIFO_U8,
+ EFI_PCI_WIDTH_FIFO_U16,
+ EFI_PCI_WIDTH_FIFO_U32,
+ EFI_PCI_WIDTH_FIFO_U64,
+ EFI_PCI_WIDTH_FILL_U8,
+ EFI_PCI_WIDTH_FILL_U16,
+ EFI_PCI_WIDTH_FILL_U32,
+ EFI_PCI_WIDTH_FILL_U64,
+ EFI_PCI_WIDTH_MAX
+};
+
+#define EFI_PCI_IO_PASS_THROUGH_BAR 0xff
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_io_mem) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u64 addr,
+ size_t count,
+ void *buf
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_io_mem) (
+ struct efi_pci_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u8 bar,
+ u64 offset,
+ size_t count,
+ void *buf
+);
+
+struct efi_pci_root_bridge_io_protocol_access {
+ efi_pci_root_bridge_io_protocol_io_mem read;
+ efi_pci_root_bridge_io_protocol_io_mem write;
+};
+
+struct efi_pci_io_protocol_access {
+ efi_pci_io_protocol_io_mem read;
+ efi_pci_io_protocol_io_mem write;
+};
+
+#define EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001
+#define EFI_PCI_ATTRIBUTE_ISA_IO 0x0002
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO 0x0004
+#define EFI_PCI_ATTRIBUTE_VGA_MEMORY 0x0008
+#define EFI_PCI_ATTRIBUTE_VGA_IO 0x0010
+#define EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO 0x0020
+#define EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO 0x0040
+#define EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080
+#define EFI_PCI_ATTRIBUTE_IO 0x0100
+#define EFI_PCI_ATTRIBUTE_MEMORY 0x0200
+#define EFI_PCI_ATTRIBUTE_BUS_MASTER 0x0400
+#define EFI_PCI_ATTRIBUTE_MEMORY_CACHED 0x0800
+#define EFI_PCI_ATTRIBUTE_MEMORY_DISABLE 0x1000
+#define EFI_PCI_ATTRIBUTE_EMBEDDED_DEVICE 0x2000
+#define EFI_PCI_ATTRIBUTE_EMBEDDED_ROM 0x4000
+#define EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000
+#define EFI_PCI_ATTRIBUTE_ISA_IO_16 0x10000
+#define EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000
+#define EFI_PCI_ATTRIBUTE_VGA_IO_16 0x40000
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_poll_io_mem) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u64 address,
+ u64 mask,
+ u64 value,
+ u64 delay,
+ u64 *result
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_poll_io_mem) (
+ struct efi_pci_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u8 bar,
+ u64 offset,
+ u64 mask,
+ u64 value,
+ u64 delay,
+ u64 *result
+);
+
+enum efi_pci_root_bridge_io_protocol_operation {
+ EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_READ,
+ EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_WRITE,
+ EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_COMMON_BUFFER,
+ EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_READ64,
+ EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_WRITE64,
+ EFI_PCI_ROOT_BRIGE_IO_OP_BUS_MASTER_COMMON_BUFFER64,
+ EFI_PCI_ROOT_BRIGE_IO_OP_MAX
+};
+
+enum efi_pci_io_protocol_operation {
+ EFI_PCI_IO_OP_BUS_MASTER_READ,
+ EFI_PCI_IO_OP_BUS_MASTER_WRITE,
+ EFI_PCI_IO_OP_BUS_MASTER_COMMON_BUFFER,
+ EFI_PCI_IO_OP_MAX
+};
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_copy_mem) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u64 dst,
+ u64 src,
+ size_t count
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_copy_mem) (
+ struct efi_pci_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u8 dst_bar,
+ u64 dst_offset,
+ u8 src_bar,
+ u64 src_offset,
+ size_t count
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_map) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ enum efi_pci_root_bridge_io_protocol_operation operation,
+ void *hostaddr,
+ size_t *nbytes,
+ efi_physical_addr_t *devaddr,
+ void **mapping
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_map) (
+ struct efi_pci_io_protocol *this,
+ enum efi_pci_io_protocol_operation operation,
+ void *hostaddr,
+ size_t *nbytes,
+ efi_physical_addr_t *devaddr,
+ void **mapping
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_unmap) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ void *mapping
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_unmap) (
+ struct efi_pci_io_protocol *this,
+ void *mapping
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_allocate_buffer) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ enum efi_allocate_type alloctype,
+ enum efi_memory_type memtype,
+ size_t npages,
+ void **hostaddr,
+ u64 attrs
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_allocate_buffer) (
+ struct efi_pci_io_protocol *this,
+ enum efi_allocate_type alloctype,
+ enum efi_memory_type memtype,
+ size_t npages,
+ void **hostaddr,
+ u64 attrs
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_free_buffer) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ size_t npages,
+ void *hostaddr
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_free_buffer) (
+ struct efi_pci_io_protocol *this,
+ size_t npages,
+ void *hostaddr
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_flush) (
+ struct efi_pci_root_bridge_io_protocol *this
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_flush) (
+ struct efi_pci_io_protocol *this
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_get_location) (
+ struct efi_pci_io_protocol *this,
+ size_t *segmentno,
+ size_t *busno,
+ size_t *deveno,
+ size_t *funcno
+);
+
+enum efi_io_protocol_attribute_operation {
+ PCI_IO_ATTR_OP_GET,
+ PCI_IO_ATTR_OP_SET,
+ PCI_IO_ATTR_OP_ENABLE,
+ PCI_IO_ATTR_OP_DISABLE,
+ PCI_IO_ATTR_OP_SUPPORTED,
+ PCI_IO_ATTR_OP_MAX,
+};
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_attributes) (
+ struct efi_pci_io_protocol *this,
+ enum efi_io_protocol_attribute_operation operation,
+ u64 attrs,
+ u64 *result
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_get_attributes) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ u64 *supports,
+ u64 *attrs
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_get_bar_attributes) (
+ struct efi_pci_io_protocol *this,
+ u8 bar,
+ u64 *supports,
+ void **resources
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_set_attributes) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ u64 attrs,
+ u64 *resource_base,
+ u64 *resource_len
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_set_bar_attributes) (
+ struct efi_pci_io_protocol *this,
+ u64 attrs,
+ u8 bar,
+ u64 *offset,
+ u64 *len
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_root_bridge_io_protocol_configuration) (
+ struct efi_pci_root_bridge_io_protocol *this,
+ void **resources
+);
+
+typedef efi_status_t (EFIAPI *efi_pci_io_protocol_config) (
+ struct efi_pci_io_protocol *this,
+ enum efi_pci_protocol_width width,
+ u32 offset,
+ size_t count,
+ void *buffer
+);
+
+struct efi_pci_io_protocol_config_access {
+ efi_pci_io_protocol_config read;
+ efi_pci_io_protocol_config write;
+};
+
+struct __packed efi_acpi_resource {
+#define ACPI_RESOURCE_DESC_TAG 0x8A
+#define ACPI_RESOURCE_END_TAG 0x79
+ u8 asd; /* 0x8A */
+ u16 len; /* 0x2B */
+#define ACPI_RESOURCE_TYPE_MEM 0
+#define ACPI_RESOURCE_TYPE_IO 1
+#define ACPI_RESOURCE_TYPE_BUSNO 2
+ u8 restype;
+ u8 genflags;
+#define ACPI_RESOURCE_TYPFLAG_TTP_MASK 0b00100000
+#define ACPI_RESOURCE_TYPFLAG_MTP_MASK 0b00011000
+#define ACPI_RESOURCE_TYPFLAG_MTP_MEM 0
+#define ACPI_RESOURCE_TYPFLAG_MTP_RESERVED 1
+#define ACPI_RESOURCE_TYPFLAG_MTP_ACPI 2
+#define ACPI_RESOURCE_TYPFLAG_MTP_NVS 3
+#define ACPI_RESOURCE_TYPFLAG_MEM_MASK 0b00000110
+#define ACPI_RESOURCE_TYPFLAG_MEM_NONCACHEABLE 0
+#define ACPI_RESOURCE_TYPFLAG_MEM_CACHEABLE 1
+#define ACPI_RESOURCE_TYPFLAG_MEM_WC 2
+#define ACPI_RESOURCE_TYPFLAG_MEM_PREF 3
+#define ACPI_RESOURCE_TYPFLAG_RW_MASK 0b00000001
+ u8 typflags;
+ u64 addr_granularity;
+ u64 addr_min;
+ u64 addr_max;
+ u64 addr_xlate_off;
+ u64 addr_len;
+};
+
+struct efi_pci_root_bridge_io_protocol {
+ efi_handle_t parent_handle;
+ efi_pci_root_bridge_io_protocol_poll_io_mem poll_mem;
+ efi_pci_root_bridge_io_protocol_poll_io_mem poll_io;
+ struct efi_pci_root_bridge_io_protocol_access mem;
+ struct efi_pci_root_bridge_io_protocol_access io;
+ struct efi_pci_root_bridge_io_protocol_access pci;
+ efi_pci_root_bridge_io_protocol_copy_mem copy_mem;
+ efi_pci_root_bridge_io_protocol_map map;
+ efi_pci_root_bridge_io_protocol_unmap unmap;
+ efi_pci_root_bridge_io_protocol_allocate_buffer allocate_buffer;
+ efi_pci_root_bridge_io_protocol_free_buffer free_buffer;
+ efi_pci_root_bridge_io_protocol_flush flush;
+ efi_pci_root_bridge_io_protocol_get_attributes get_attributes;
+ efi_pci_root_bridge_io_protocol_set_attributes set_attributes;
+ efi_pci_root_bridge_io_protocol_configuration configuration;
+ u32 segmentno;
+};
+
+struct efi_pci_io_protocol {
+ efi_pci_io_protocol_poll_io_mem poll_mem;
+ efi_pci_io_protocol_poll_io_mem poll_io;
+ struct efi_pci_io_protocol_access mem;
+ struct efi_pci_io_protocol_access io;
+ struct efi_pci_io_protocol_access pci;
+ efi_pci_io_protocol_copy_mem copy_mem;
+ efi_pci_io_protocol_map map;
+ efi_pci_io_protocol_unmap unmap;
+ efi_pci_io_protocol_allocate_buffer allocate_buffer;
+ efi_pci_io_protocol_free_buffer free_buffer;
+ efi_pci_io_protocol_flush flush;
+ efi_pci_io_protocol_get_location get_location;
+ efi_pci_io_protocol_attributes attributes;
+ efi_pci_io_protocol_get_bar_attributes get_bar_attributes;
+ efi_pci_io_protocol_set_bar_attributes set_bar_attributes;
+ u64 rom_size;
+ void *rom_image;
+};
+
+#define EFI_PCI_ADDRESS(bus, dev, func, reg) \
+ (u64) ( \
+ (((size_t) bus) << 24) | \
+ (((size_t) dev) << 16) | \
+ (((size_t) func) << 8) | \
+ (((size_t) (reg)) < 256 ? ((size_t) (reg)) : ((u64)(reg)) << 32))
+
+#endif