summaryrefslogtreecommitdiff
path: root/components/drivers/include
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2024-05-30 17:47:56 +0800
committerMeco Man <[email protected]>2024-09-06 17:45:03 -0400
commit2168ed8e7d408aeada3427ebbb90bb8996885668 (patch)
tree62c168458c8e0edcc0981ca66113f79694567580 /components/drivers/include
parent802a6ed2caff69a4f881f109462931de4f4f2d40 (diff)
[DM/Feature] Basic PCI/PCIe (Peripheral Component Interconnect Express) bus
PCI/PCIe have better performance and more devices support, such as NVMe, GPU, Powerful NIC (Like RDMA). PCI/PCIe can access control by IOMMU that the virtualiztion and userspace driver will more safety. PCI/PCIe device could hot plugging, no design modifications SoC required, PCI/PCIe on Embedded SoC is popular now. We make a simple framework to support them. Feature Lists: 1.PCI INTx: the INT[A-D] pin IRQ for legacy PCI, work with platform PIC. 2.MSI/MSI-X: the message write IRQ for PCIe, work with platform's PIC. 3.PME: we only support the D0, D1, D2, D3HOT, D3COLD init by framework. 4.Endpoint: a simple EP framework for PCI FPGA or NTB function. 5.OFW: we only support work on OFW SoC, ACPI support in the future maybe. Host controller: 1. Common PCI host controller on ECAM. 2. Generic PCI host controller on ECAM. Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers/include')
-rw-r--r--components/drivers/include/drivers/pci.h604
-rw-r--r--components/drivers/include/drivers/pci_endpoint.h179
-rw-r--r--components/drivers/include/drivers/pci_msi.h189
3 files changed, 972 insertions, 0 deletions
diff --git a/components/drivers/include/drivers/pci.h b/components/drivers/include/drivers/pci.h
new file mode 100644
index 0000000000..a44e1bbdcc
--- /dev/null
+++ b/components/drivers/include/drivers/pci.h
@@ -0,0 +1,604 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-08-25 GuEe-GUI first version
+ */
+
+#ifndef __PCI_H__
+#define __PCI_H__
+
+#include <rtdef.h>
+#include <bitmap.h>
+#include <ioremap.h>
+#include <drivers/ofw.h>
+#include <drivers/pic.h>
+#include <drivers/core/dm.h>
+#include <drivers/core/driver.h>
+
+#include "../../pci/pci_ids.h"
+#include "../../pci/pci_regs.h"
+
+#define RT_PCI_INTX_PIN_MAX 4
+#define RT_PCI_BAR_NR_MAX 6
+#define RT_PCI_DEVICE_MAX 32
+#define RT_PCI_FUNCTION_MAX 8
+
+#define RT_PCI_FIND_CAP_TTL 48
+
+/*
+ * The PCI interface treats multi-function devices as independent
+ * devices. The slot/function address of each device is encoded
+ * in a single byte as follows:
+ *
+ * 7:3 = slot
+ * 2:0 = function
+ */
+#define RT_PCI_DEVID(bus, devfn) ((((rt_uint16_t)(bus)) << 8) | (devfn))
+#define RT_PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+#define RT_PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f)
+#define RT_PCI_FUNC(devfn) ((devfn) & 0x07)
+
+#define PCIE_LINK_STATE_L0S RT_BIT(0)
+#define PCIE_LINK_STATE_L1 RT_BIT(1)
+#define PCIE_LINK_STATE_CLKPM RT_BIT(2)
+#define PCIE_LINK_STATE_L1_1 RT_BIT(3)
+#define PCIE_LINK_STATE_L1_2 RT_BIT(4)
+#define PCIE_LINK_STATE_L1_1_PCIPM RT_BIT(5)
+#define PCIE_LINK_STATE_L1_2_PCIPM RT_BIT(6)
+#define PCIE_LINK_STATE_ALL \
+( \
+ PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | \
+ PCIE_LINK_STATE_CLKPM | \
+ PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2 | \
+ PCIE_LINK_STATE_L1_1_PCIPM | PCIE_LINK_STATE_L1_2_PCIPM \
+)
+
+struct rt_pci_bus_region
+{
+ rt_uint64_t phy_addr;
+ rt_uint64_t cpu_addr;
+ rt_uint64_t size;
+
+ rt_uint64_t bus_start;
+
+#define PCI_BUS_REGION_F_NONE 0xffffffff /* PCI no memory */
+#define PCI_BUS_REGION_F_MEM 0x00000000 /* PCI memory space */
+#define PCI_BUS_REGION_F_IO 0x00000001 /* PCI IO space */
+#define PCI_BUS_REGION_F_PREFETCH 0x00000008 /* Prefetchable PCI memory */
+ rt_ubase_t flags;
+};
+
+struct rt_pci_bus_resource
+{
+ rt_ubase_t base;
+ rt_size_t size;
+
+ rt_ubase_t flags;
+};
+
+/*
+ * PCI topology:
+ *
+ * +-----+-----+ +-------------+ PCI Bus 0 +------------+ PCI Bus 1
+ * | RAM | CPU |---------| Host Bridge |--------+-----| PCI Bridge |-----+
+ * +-----+-----+ +-------------+ | +------------+ | +-------------+
+ * | +----| End Point 2 |
+ * +-------------+ +-------------+ | +-------------+ | +-------------+
+ * | End Point 5 |----+ | End Point 0 |-------+ | End Point 3 |----+
+ * +-------------+ | +-------------+ | +-------------+ |
+ * | | |
+ * +-------------+ | +-------------+ | +-------------+ | +-------------+
+ * | End Point 6 |----+----| ISA Bridge |-------+-----| End Point 1 | +----| End Point 4 |
+ * +-------------+ +-------------+ | +-------------+ +-------------+
+ * |
+ * +------+ +----------------+ |
+ * | Port |---------| CardBus Bridge |----+
+ * +------+ +----------------+
+ */
+
+struct rt_pci_bus;
+
+struct rt_pci_device_id
+{
+#define PCI_ANY_ID (~0)
+#define RT_PCI_DEVICE_ID(vend, dev) \
+ .vendor = (vend), \
+ .device = (dev), \
+ .subsystem_vendor = PCI_ANY_ID, \
+ .subsystem_device = PCI_ANY_ID
+
+#define RT_PCI_DEVICE_CLASS(dev_class, dev_class_mask) \
+ .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+ .subsystem_vendor = PCI_ANY_ID, \
+ .subsystem_device = PCI_ANY_ID, \
+ .class = (dev_class), .class_mask = (dev_class_mask),
+
+ rt_uint32_t vendor, device; /* Vendor and device ID or PCI_ANY_ID */
+ rt_uint32_t subsystem_vendor; /* Subsystem ID's or PCI_ANY_ID */
+ rt_uint32_t subsystem_device; /* Subsystem ID's or PCI_ANY_ID */
+ rt_uint32_t class, class_mask; /* (class, subclass, prog-if) triplet */
+
+ const void *data;
+};
+
+struct rt_pci_device
+{
+ struct rt_device parent;
+ const char *name;
+
+ rt_list_t list;
+ struct rt_pci_bus *bus;
+ struct rt_pci_bus *subbus; /* In PCI-to-PCI bridge, 'End Point' or 'Port' is NULL */
+
+ const struct rt_pci_device_id *id;
+
+ rt_uint32_t devfn; /* Encoded device & function index */
+ rt_uint16_t vendor;
+ rt_uint16_t device;
+ rt_uint16_t subsystem_vendor;
+ rt_uint16_t subsystem_device;
+ rt_uint32_t class; /* 3 bytes: (base, sub, prog-if) */
+ rt_uint8_t revision;
+ rt_uint8_t hdr_type;
+ rt_uint8_t max_latency;
+ rt_uint8_t min_grantl;
+ rt_uint8_t int_pin;
+ rt_uint8_t int_line;
+ rt_uint16_t exp_flags;
+ rt_uint32_t cfg_size;
+
+ void *sysdata;
+
+ int irq;
+ rt_uint8_t pin;
+ struct rt_pic *intx_pic;
+
+ struct rt_pci_bus_resource resource[RT_PCI_BAR_NR_MAX];
+
+ rt_uint8_t pme_cap;
+ rt_uint8_t msi_cap;
+ rt_uint8_t msix_cap;
+ rt_uint8_t pcie_cap;
+
+ rt_uint8_t busmaster:1; /* Is the bus master */
+ rt_uint8_t multi_function:1; /* Multi-function device */
+ rt_uint8_t ari_enabled:1; /* Alternative Routing-ID Interpretation */
+ rt_uint8_t no_msi:1; /* May not use MSI */
+ rt_uint8_t no_64bit_msi:1; /* May only use 32-bit MSIs */
+ rt_uint8_t msi_enabled:1; /* MSI enable */
+ rt_uint8_t msix_enabled:1; /* MSIx enable */
+ rt_uint8_t broken_intx_masking:1; /* INTx masking can't be used */
+ rt_uint8_t pme_support:5; /* Bitmask of states from which PME# can be generated */
+
+#ifdef RT_PCI_MSI
+ void *msix_base;
+ struct rt_pic *msi_pic;
+ rt_list_t msi_desc_nodes;
+ struct rt_spinlock msi_lock;
+#endif
+};
+
+struct rt_pci_host_bridge
+{
+ struct rt_device parent;
+
+ rt_uint32_t domain;
+
+ struct rt_pci_bus *root_bus;
+ const struct rt_pci_ops *ops;
+ const struct rt_pci_ops *child_ops;
+
+ rt_uint32_t bus_range[2];
+ rt_size_t bus_regions_nr;
+ struct rt_pci_bus_region *bus_regions;
+ rt_size_t dma_regions_nr;
+ struct rt_pci_bus_region *dma_regions;
+
+ rt_uint8_t (*irq_slot)(struct rt_pci_device *pdev, rt_uint8_t *pinp);
+ int (*irq_map)(struct rt_pci_device *pdev, rt_uint8_t slot, rt_uint8_t pin);
+
+ void *sysdata;
+ rt_uint8_t priv[0];
+};
+#define rt_device_to_pci_host_bridge(dev) rt_container_of(dev, struct rt_pci_host_bridge, parent)
+
+struct rt_pci_ops
+{
+ rt_err_t (*add)(struct rt_pci_bus *bus);
+ rt_err_t (*remove)(struct rt_pci_bus *bus);
+
+ void *(*map)(struct rt_pci_bus *bus, rt_uint32_t devfn, int reg);
+
+ rt_err_t (*read)(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t *value);
+ rt_err_t (*write)(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t value);
+};
+
+struct rt_pci_bus
+{
+ rt_list_t list;
+ rt_list_t children_nodes;
+ rt_list_t devices_nodes;
+ struct rt_pci_bus *parent;
+
+ union
+ {
+ /* In PCI-to-PCI bridge, parent is not NULL */
+ struct rt_pci_device *self;
+ /* In Host bridge, this is Root bus ('PCI Bus 0') */
+ struct rt_pci_host_bridge *host_bridge;
+ };
+
+ const struct rt_pci_ops *ops;
+
+ char name[48];
+ char number;
+ struct rt_spinlock lock;
+
+ void *sysdata;
+};
+
+struct rt_pci_driver
+{
+ struct rt_driver parent;
+
+ const char *name;
+ const struct rt_pci_device_id *ids;
+
+ rt_err_t (*probe)(struct rt_pci_device *pdev);
+ rt_err_t (*remove)(struct rt_pci_device *pdev);
+ rt_err_t (*shutdown)(struct rt_pci_device *pdev);
+};
+
+struct rt_pci_msix_entry
+{
+ int irq;
+ int index;
+};
+
+enum rt_pci_power
+{
+ RT_PCI_D0,
+ RT_PCI_D1,
+ RT_PCI_D2,
+ RT_PCI_D3HOT,
+ RT_PCI_D3COLD,
+
+ RT_PCI_PME_MAX,
+};
+
+void rt_pci_pme_init(struct rt_pci_device *pdev);
+void rt_pci_pme_active(struct rt_pci_device *pdev, rt_bool_t enable);
+rt_err_t rt_pci_enable_wake(struct rt_pci_device *pci_dev,
+ enum rt_pci_power state, rt_bool_t enable);
+rt_inline rt_bool_t rt_pci_pme_capable(struct rt_pci_device *pdev,
+ enum rt_pci_power state)
+{
+ if (!pdev->pme_cap)
+ {
+ return RT_FALSE;
+ }
+
+ return !!(pdev->pme_support & (1 << state));
+}
+
+void rt_pci_msi_init(struct rt_pci_device *pdev);
+void rt_pci_msix_init(struct rt_pci_device *pdev);
+
+void rt_pci_set_master(struct rt_pci_device *pdev);
+void rt_pci_clear_master(struct rt_pci_device *pdev);
+
+struct rt_pci_host_bridge *rt_pci_host_bridge_alloc(rt_size_t priv_size);
+rt_err_t rt_pci_host_bridge_free(struct rt_pci_host_bridge *);
+rt_err_t rt_pci_host_bridge_init(struct rt_pci_host_bridge *host_bridge);
+rt_err_t rt_pci_host_bridge_probe(struct rt_pci_host_bridge *host_bridge);
+
+struct rt_pci_device *rt_pci_alloc_device(struct rt_pci_bus *bus);
+struct rt_pci_device *rt_pci_scan_single_device(struct rt_pci_bus *bus, rt_uint32_t devfn);
+rt_err_t rt_pci_setup_device(struct rt_pci_device *pdev);
+rt_size_t rt_pci_scan_slot(struct rt_pci_bus *bus, rt_uint32_t devfn);
+rt_uint32_t rt_pci_scan_child_buses(struct rt_pci_bus *bus, rt_size_t buses);
+rt_uint32_t rt_pci_scan_child_bus(struct rt_pci_bus *bus);
+
+rt_err_t rt_pci_host_bridge_register(struct rt_pci_host_bridge *host_bridge);
+rt_err_t rt_pci_scan_root_bus_bridge(struct rt_pci_host_bridge *host_bridge);
+
+rt_err_t rt_pci_host_bridge_remove(struct rt_pci_host_bridge *host_bridge);
+rt_err_t rt_pci_bus_remove(struct rt_pci_bus *bus);
+rt_err_t rt_pci_device_remove(struct rt_pci_device *pdev);
+
+rt_uint32_t rt_pci_domain(struct rt_pci_device *pdev);
+
+rt_uint8_t rt_pci_bus_find_capability(struct rt_pci_bus *bus, rt_uint32_t devfn, int cap);
+rt_uint8_t rt_pci_find_capability(struct rt_pci_device *pdev, int cap);
+rt_uint8_t rt_pci_find_next_capability(struct rt_pci_device *pdev, rt_uint8_t pos, int cap);
+
+rt_uint16_t rt_pci_find_ext_capability(struct rt_pci_device *pdev, int cap);
+rt_uint16_t rt_pci_find_ext_next_capability(struct rt_pci_device *pdev, rt_uint16_t pos, int cap);
+
+struct rt_pci_bus *rt_pci_find_root_bus(struct rt_pci_bus *bus);
+struct rt_pci_host_bridge *rt_pci_find_host_bridge(struct rt_pci_bus *bus);
+
+rt_inline rt_uint16_t rt_pci_dev_id(struct rt_pci_device *pdev)
+{
+ return RT_PCI_DEVID(pdev->bus->number, pdev->devfn);
+}
+
+rt_inline rt_bool_t rt_pci_is_root_bus(struct rt_pci_bus *bus)
+{
+ return bus->parent ? RT_FALSE : RT_TRUE;
+}
+
+rt_inline rt_bool_t rt_pci_is_bridge(struct rt_pci_device *pdev)
+{
+ return pdev->hdr_type == PCIM_HDRTYPE_BRIDGE ||
+ pdev->hdr_type == PCIM_HDRTYPE_CARDBUS;
+}
+
+rt_inline rt_bool_t rt_pci_is_pcie(struct rt_pci_device *pdev)
+{
+ return !!pdev->pcie_cap;
+}
+
+#define rt_pci_foreach_bridge(pdev, bus) \
+ rt_list_for_each_entry(pdev, &bus->devices_nodes, list) \
+ if (rt_pci_is_bridge(pdev))
+
+rt_err_t rt_pci_bus_read_config_u8(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int pos, rt_uint8_t *value);
+rt_err_t rt_pci_bus_read_config_u16(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int pos, rt_uint16_t *value);
+rt_err_t rt_pci_bus_read_config_u32(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int pos, rt_uint32_t *value);
+
+rt_err_t rt_pci_bus_write_config_u8(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, rt_uint8_t value);
+rt_err_t rt_pci_bus_write_config_u16(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, rt_uint16_t value);
+rt_err_t rt_pci_bus_write_config_u32(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, rt_uint32_t value);
+
+rt_err_t rt_pci_bus_read_config_uxx(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t *value);
+rt_err_t rt_pci_bus_write_config_uxx(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t value);
+
+rt_err_t rt_pci_bus_read_config_generic_u32(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t *value);
+rt_err_t rt_pci_bus_write_config_generic_u32(struct rt_pci_bus *bus,
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t value);
+
+rt_inline rt_err_t rt_pci_read_config_u8(const struct rt_pci_device *pdev,
+ int reg, rt_uint8_t *value)
+{
+ return rt_pci_bus_read_config_u8(pdev->bus, pdev->devfn, reg, value);
+}
+
+rt_inline rt_err_t rt_pci_read_config_u16(const struct rt_pci_device *pdev,
+ int reg, rt_uint16_t *value)
+{
+ return rt_pci_bus_read_config_u16(pdev->bus, pdev->devfn, reg, value);
+}
+
+rt_inline rt_err_t rt_pci_read_config_u32(const struct rt_pci_device *pdev,
+ int reg, rt_uint32_t *value)
+{
+ return rt_pci_bus_read_config_u32(pdev->bus, pdev->devfn, reg, value);
+}
+
+rt_inline rt_err_t rt_pci_write_config_u8(const struct rt_pci_device *pdev,
+ int reg, rt_uint8_t value)
+{
+ return rt_pci_bus_write_config_u8(pdev->bus, pdev->devfn, reg, value);
+}
+
+rt_inline rt_err_t rt_pci_write_config_u16(const struct rt_pci_device *pdev,
+ int reg, rt_uint16_t value)
+{
+ return rt_pci_bus_write_config_u16(pdev->bus, pdev->devfn, reg, value);
+}
+
+rt_inline rt_err_t rt_pci_write_config_u32(const struct rt_pci_device *pdev,
+ int reg, rt_uint32_t value)
+{
+ return rt_pci_bus_write_config_u32(pdev->bus, pdev->devfn, reg, value);
+}
+
+#ifdef RT_USING_OFW
+int rt_pci_ofw_irq_parse_and_map(struct rt_pci_device *pdev,
+ rt_uint8_t slot, rt_uint8_t pin);
+
+rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
+ struct rt_pci_host_bridge *host_bridge);
+
+rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np,
+ struct rt_pci_host_bridge *host_bridge);
+
+rt_err_t rt_pci_ofw_bus_init(struct rt_pci_bus *bus);
+rt_err_t rt_pci_ofw_bus_free(struct rt_pci_bus *bus);
+rt_err_t rt_pci_ofw_device_init(struct rt_pci_device *pdev);
+rt_err_t rt_pci_ofw_device_free(struct rt_pci_device *pdev);
+#else
+rt_inline rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np,
+ struct rt_pci_host_bridge *host_bridge)
+{
+ return RT_EOK;
+}
+rt_inline rt_err_t rt_pci_ofw_bus_init(struct rt_pci_bus *bus)
+{
+ return RT_EOK;
+}
+rt_inline rt_err_t rt_pci_ofw_bus_free(struct rt_pci_bus *bus)
+{
+ return RT_EOK;
+}
+rt_inline rt_err_t rt_pci_ofw_device_init(struct rt_pci_device *pdev)
+{
+ return RT_EOK;
+}
+rt_inline rt_err_t rt_pci_ofw_device_free(struct rt_pci_device *pdev)
+{
+ return RT_EOK;
+}
+rt_inline int rt_pci_ofw_irq_parse_and_map(struct rt_pci_device *pdev,
+ rt_uint8_t slot, rt_uint8_t pin)
+{
+ return -1;
+}
+rt_inline rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
+ struct rt_pci_host_bridge *host_bridge)
+{
+ return -RT_ENOSYS;
+}
+#endif /* RT_USING_OFW */
+
+rt_inline void *rt_pci_iomap(struct rt_pci_device *pdev, int bar_idx)
+{
+ struct rt_pci_bus_resource *res = &pdev->resource[bar_idx];
+
+ RT_ASSERT(bar_idx < RT_ARRAY_SIZE(pdev->resource));
+
+ return rt_ioremap((void *)res->base, res->size);
+}
+
+rt_uint8_t rt_pci_irq_intx(struct rt_pci_device *pdev, rt_uint8_t pin);
+rt_uint8_t rt_pci_irq_slot(struct rt_pci_device *pdev, rt_uint8_t *pinp);
+
+void rt_pci_assign_irq(struct rt_pci_device *pdev);
+
+void rt_pci_intx(struct rt_pci_device *pdev, rt_bool_t enable);
+rt_bool_t rt_pci_check_and_mask_intx(struct rt_pci_device *pdev);
+rt_bool_t rt_pci_check_and_unmask_intx(struct rt_pci_device *pdev);
+
+void rt_pci_irq_mask(struct rt_pci_device *pdev);
+void rt_pci_irq_unmask(struct rt_pci_device *pdev);
+
+#define RT_PCI_IRQ_F_LEGACY RT_BIT(0) /* Allow legacy interrupts */
+#define RT_PCI_IRQ_F_MSI RT_BIT(1) /* Allow MSI interrupts */
+#define RT_PCI_IRQ_F_MSIX RT_BIT(2) /* Allow MSI-X interrupts */
+#define RT_PCI_IRQ_F_AFFINITY RT_BIT(3) /* Auto-assign affinity */
+#define RT_PCI_IRQ_F_ALL_TYPES (RT_PCI_IRQ_F_LEGACY | RT_PCI_IRQ_F_MSI | RT_PCI_IRQ_F_MSIX)
+
+#ifdef RT_PCI_MSI
+rt_ssize_t rt_pci_alloc_vector(struct rt_pci_device *pdev, int min, int max,
+ rt_uint32_t flags, RT_IRQ_AFFINITY_DECLARE((*affinities)));
+void rt_pci_free_vector(struct rt_pci_device *pdev);
+
+rt_ssize_t rt_pci_msi_vector_count(struct rt_pci_device *pdev);
+rt_err_t rt_pci_msi_disable(struct rt_pci_device *pdev);
+rt_ssize_t rt_pci_msi_enable_range_affinity(struct rt_pci_device *pdev,
+ int min, int max, RT_IRQ_AFFINITY_DECLARE((*affinities)));
+
+rt_ssize_t rt_pci_msix_vector_count(struct rt_pci_device *pdev);
+rt_err_t rt_pci_msix_disable(struct rt_pci_device *pdev);
+rt_ssize_t rt_pci_msix_enable_range_affinity(struct rt_pci_device *pdev,
+ struct rt_pci_msix_entry *entries, int min, int max,
+ RT_IRQ_AFFINITY_DECLARE((*affinities)));
+#else
+rt_inline rt_ssize_t rt_pci_alloc_vector(struct rt_pci_device *pdev, int min, int max,
+ rt_uint32_t flags, RT_IRQ_AFFINITY_DECLARE((*affinities)))
+{
+ return -RT_ENOSYS;
+}
+
+rt_inline void rt_pci_free_vector(struct rt_pci_device *pdev)
+{
+ return;
+}
+
+rt_inline rt_ssize_t rt_pci_msi_vector_count(struct rt_pci_device *pdev)
+{
+ return 0;
+}
+
+rt_inline rt_err_t rt_pci_msi_disable(struct rt_pci_device *pdev)
+{
+ return RT_EOK;
+}
+
+rt_inline rt_ssize_t rt_pci_msi_enable_range_affinity(struct rt_pci_device *pdev,
+ int min, int max, RT_IRQ_AFFINITY_DECLARE((*affinities)))
+{
+ return -RT_ENOSYS;
+}
+
+rt_inline rt_ssize_t rt_pci_msix_vector_count(struct rt_pci_device *pdev)
+{
+ return 0;
+}
+
+rt_inline rt_err_t rt_pci_msix_disable(struct rt_pci_device *pdev)
+{
+ return RT_EOK;
+}
+
+rt_inline rt_ssize_t rt_pci_msix_enable_range_affinity(struct rt_pci_device *pdev,
+ struct rt_pci_msix_entry *entries, int min, int max,
+ RT_IRQ_AFFINITY_DECLARE((*affinities)))
+{
+ return -RT_ENOSYS;
+}
+#endif /* RT_PCI_MSI */
+
+rt_inline void rt_pci_msix_entry_index_linear(struct rt_pci_msix_entry *entries,
+ rt_size_t nvectors)
+{
+ for (int i = 0; i < nvectors; ++i)
+ {
+ entries[i].index = i;
+ }
+}
+
+rt_inline rt_ssize_t rt_pci_msi_enable_range(struct rt_pci_device *pdev,
+ int min, int max)
+{
+ return rt_pci_msi_enable_range_affinity(pdev, min, max, RT_NULL);
+}
+
+rt_inline rt_err_t rt_pci_msi_enable(struct rt_pci_device *pdev)
+{
+ rt_ssize_t res = rt_pci_msi_enable_range(pdev, 1, 1);
+ return res == 1 ? res : RT_EOK;
+}
+
+rt_inline rt_ssize_t rt_pci_msix_enable_range(struct rt_pci_device *pdev,
+ struct rt_pci_msix_entry *entries, int min, int max)
+{
+ return rt_pci_msix_enable_range_affinity(pdev, entries, min, max, RT_NULL);
+}
+
+rt_inline rt_ssize_t rt_pci_msix_enable(struct rt_pci_device *pdev,
+ struct rt_pci_msix_entry *entries, int count)
+{
+ return rt_pci_msix_enable_range(pdev, entries, count, count);
+}
+
+rt_err_t rt_pci_region_setup(struct rt_pci_host_bridge *host_bridge);
+struct rt_pci_bus_region *rt_pci_region_alloc(struct rt_pci_host_bridge *host_bridge,
+ void **out_addr, rt_size_t size, rt_ubase_t flags, rt_bool_t mem64);
+
+rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
+ struct rt_pci_device *pdev);
+
+void rt_pci_enum_device(struct rt_pci_bus *bus,
+ rt_bool_t (callback(struct rt_pci_device *, void *)), void *data);
+
+const struct rt_pci_device_id *rt_pci_match_id(struct rt_pci_device *pdev,
+ const struct rt_pci_device_id *id);
+
+const struct rt_pci_device_id *rt_pci_match_ids(struct rt_pci_device *pdev,
+ const struct rt_pci_device_id *ids);
+
+rt_err_t rt_pci_driver_register(struct rt_pci_driver *pdrv);
+rt_err_t rt_pci_device_register(struct rt_pci_device *pdev);
+
+#define RT_PCI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, pci, BUILIN)
+
+extern struct rt_spinlock rt_pci_lock;
+
+#endif /* __PCI_H__ */
diff --git a/components/drivers/include/drivers/pci_endpoint.h b/components/drivers/include/drivers/pci_endpoint.h
new file mode 100644
index 0000000000..3e6fd7c918
--- /dev/null
+++ b/components/drivers/include/drivers/pci_endpoint.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-08-25 GuEe-GUI first version
+ */
+
+#ifndef __PCI_ENDPOINT_H__
+#define __PCI_ENDPOINT_H__
+
+#include <drivers/pci.h>
+
+enum rt_pci_ep_pin
+{
+ RT_PCI_EP_PIN_UNKNOWN,
+ RT_PCI_EP_PIN_INTA,
+ RT_PCI_EP_PIN_INTB,
+ RT_PCI_EP_PIN_INTC,
+ RT_PCI_EP_PIN_INTD,
+};
+
+enum rt_pci_ep_irq
+{
+ RT_PCI_EP_IRQ_UNKNOWN,
+ RT_PCI_EP_IRQ_LEGACY,
+ RT_PCI_EP_IRQ_MSI,
+ RT_PCI_EP_IRQ_MSIX,
+};
+
+struct rt_pci_ep_header
+{
+ rt_uint16_t vendor;
+ rt_uint16_t device;
+ rt_uint8_t revision;
+ rt_uint8_t progif;
+ rt_uint8_t subclass;
+ rt_uint8_t class_code;
+ rt_uint8_t cache_line_size;
+ rt_uint16_t subsystem_vendor;
+ rt_uint16_t subsystem_device;
+
+ enum rt_pci_ep_pin intx;
+};
+
+struct rt_pci_ep_bar
+{
+ /* To PCI Bus */
+ struct rt_pci_bus_resource bus;
+ /* To CPU */
+ rt_ubase_t cpu_addr;
+};
+
+/*
+ * Type of MSI-X table, For more format detail,
+ * please read `components/drivers/include/drivers/pci_msi.h`
+ */
+struct rt_pci_ep_msix_tbl
+{
+ union
+ {
+ rt_uint64_t msg_addr;
+ struct
+ {
+ rt_uint32_t msg_addr_upper;
+ rt_uint32_t msg_addr_lower;
+ };
+ };
+ rt_uint32_t msg_data;
+ rt_uint32_t vector_ctrl;
+};
+
+struct rt_pci_ep_ops;
+
+struct rt_pci_ep
+{
+ rt_list_t list;
+ const char *name;
+
+ struct rt_ref ref;
+
+ const struct rt_device *rc_dev;
+ const struct rt_pci_ep_ops *ops;
+
+ rt_uint8_t max_functions;
+ RT_BITMAP_DECLARE(functions_map, 8);
+ rt_list_t epf_nodes;
+ struct rt_mutex lock;
+
+ void *priv;
+};
+
+struct rt_pci_epf
+{
+ rt_list_t list;
+ const char *name;
+
+ struct rt_pci_ep_header *header;
+ struct rt_pci_ep_bar bar[PCI_STD_NUM_BARS];
+
+ rt_uint8_t msi_interrupts;
+ rt_uint16_t msix_interrupts;
+ rt_uint8_t func_no;
+
+ struct rt_pci_ep *ep;
+};
+
+struct rt_pci_ep_ops
+{
+ rt_err_t (*write_header)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ struct rt_pci_ep_header *hdr);
+
+ rt_err_t (*set_bar)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ struct rt_pci_ep_bar *bar, int bar_idx);
+ rt_err_t (*clear_bar)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ struct rt_pci_ep_bar *bar, int bar_idx);
+
+ rt_err_t (*map_addr)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ rt_ubase_t addr, rt_uint64_t pci_addr, rt_size_t size);
+ rt_err_t (*unmap_addr)(struct rt_pci_ep *ep, rt_uint8_t func_no, rt_ubase_t addr);
+
+ rt_err_t (*set_msi)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned irq_nr);
+ rt_err_t (*get_msi)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned *out_irq_nr);
+
+ rt_err_t (*set_msix)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned irq_nr, int bar_idx, rt_off_t offset);
+ rt_err_t (*get_msix)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned *out_irq_nr);
+
+ rt_err_t (*raise_irq)(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ enum rt_pci_ep_irq type, unsigned irq);
+
+ rt_err_t (*start)(struct rt_pci_ep *ep);
+ rt_err_t (*stop)(struct rt_pci_ep *ep);
+};
+
+rt_err_t rt_pci_ep_write_header(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ struct rt_pci_ep_header *hdr);
+
+rt_err_t rt_pci_ep_set_bar(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ struct rt_pci_ep_bar *bar, int bar_idx);
+rt_err_t rt_pci_ep_clear_bar(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ struct rt_pci_ep_bar *bar, int bar_idx);
+
+rt_err_t rt_pci_ep_map_addr(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ rt_ubase_t addr, rt_uint64_t pci_addr, rt_size_t size);
+rt_err_t rt_pci_ep_unmap_addr(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ rt_ubase_t addr);
+
+rt_err_t rt_pci_ep_set_msi(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned irq_nr);
+rt_err_t rt_pci_ep_get_msi(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned *out_irq_nr);
+
+rt_err_t rt_pci_ep_set_msix(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned irq_nr, int bar_idx, rt_off_t offset);
+rt_err_t rt_pci_ep_get_msix(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ unsigned *out_irq_nr);
+
+rt_err_t rt_pci_ep_raise_irq(struct rt_pci_ep *ep, rt_uint8_t func_no,
+ enum rt_pci_ep_irq type, unsigned irq);
+
+rt_err_t rt_pci_ep_start(struct rt_pci_ep *ep);
+rt_err_t rt_pci_ep_stop(struct rt_pci_ep *ep);
+
+rt_err_t rt_pci_ep_register(struct rt_pci_ep *ep);
+rt_err_t rt_pci_ep_unregister(struct rt_pci_ep *ep);
+
+rt_err_t rt_pci_ep_add_epf(struct rt_pci_ep *ep, struct rt_pci_epf *epf);
+rt_err_t rt_pci_ep_remove_epf(struct rt_pci_ep *ep, struct rt_pci_epf *epf);
+
+struct rt_pci_ep *rt_pci_ep_get(const char *name);
+void rt_pci_ep_put(struct rt_pci_ep *ep);
+
+#endif /* __PCI_ENDPOINT_H__ */
diff --git a/components/drivers/include/drivers/pci_msi.h b/components/drivers/include/drivers/pci_msi.h
new file mode 100644
index 0000000000..b8238e6470
--- /dev/null
+++ b/components/drivers/include/drivers/pci_msi.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-08-25 GuEe-GUI first version
+ */
+
+#ifndef __PCI_MSI_H__
+#define __PCI_MSI_H__
+
+#include <drivers/pci.h>
+
+/*
+ * MSI Format:
+ * T0: 32-bit Address
+ * T1: 64-bit Address
+ * T2: 32-bit Address with Per-Vector Masking
+ * T3: 64-bit Address with Per-Vector Masking
+ *
+ * 31 16 15 8 7 0
+ * +---------------------------+-----------------+---------------+
+ * | Message Control | Next Capability | Capability ID | DW0
+ * | | Pointer | (05h) |
+ * +---------------------------+-----------------+---------------+
+ * | Message Address [31:0] | DW1
+ * +-------------------------------------------------------------+
+ * | Message Address [63:32] | DW2 (T1: only 64-bit)
+ * +---------------------------+---------------------------------+
+ * | Reserved | Message Data | DW3
+ * +---------------------------+---------------------------------+
+ * | Mask Bits | DW4 (T2/T3: only with Per-Vector Masking)
+ * +-------------------------------------------------------------+
+ * | Pending Bits | DW5 (T2/T3: only with Per-Vector Masking)
+ * +-------------------------------------------------------------+
+ *
+ * MSI Message Control:
+ *
+ * 15 9 8 7 6 4 3 1 0
+ * +----------------------+---+---+---------------+----------+---+
+ * | Reserved | | | | | |
+ * +----------------------+---+---+---------------+----------+---+
+ * ^ ^ ^ ^ ^
+ * | | | | |
+ * | | | | +---- MSI Enable (RW)
+ * | | | +----------- Multiple Message Capable (RO, log2n, [n <= 5])
+ * | | +------------------------- Multiple Message Enable (RW, log2n, [n <= 5])
+ * | +----------------------------------- 64-bit Address Capable
+ * +--------------------------------------- Per-Vector Masking Capable
+ */
+
+struct rt_pci_msi_conf
+{
+ rt_uint32_t mask;
+ rt_uint8_t mask_pos;
+ int default_irq;
+
+ struct
+ {
+ rt_uint8_t is_masking:1;
+ rt_uint8_t is_64bit:1;
+ rt_uint8_t multi_msg_max:3; /* log2 num of messages allocated */
+ rt_uint8_t multi_msg_use:3; /* log2 num of messages supported */
+ } cap;
+};
+
+/*
+ * MSI-X Format:
+ *
+ * 31 16 15 8 7 0
+ * +---------------------------+-----------------+---------------+
+ * | Message Control | Next Capability | Capability ID | DW0
+ * | | Pointer | (11h) |
+ * +---------------------------+-----------------+---+-----------+
+ * | MSI-X Table Offset | Table BIR | DW1 (BIR: BAR Index Register)
+ * +-------------------------------------------------+-----------+ |
+ * | Pending Bit Array (PBA) Offset | PBA BIR | DW2 --------+ |
+ * +-------------------------------------------------+-----------+ | |
+ * | |
+ * MSI-X Message Control: | |
+ * | |
+ * 15 14 13 11 10 0 | |
+ * +---+---+----------+------------------------------------------+ | |
+ * | | | Reserved | Table Size in N-1 (RO) | | |
+ * +---+---+----------+------------------------------------------+ | |
+ * ^ ^ | |
+ * | | | |
+ * | +---- Function Mask (RW) | |
+ * +-------- MSI-X Enable (RW) | |
+ * | |
+ * MSI-X Table (BAR[Table BIR] + MSI-X Table Offset): | |
+ * | |
+ * DW3 DW2 DW1 DW0 | |
+ * +----------------+--------------+---------------+---------------+ <---------|-+
+ * | Vector Control | Message Data | Upper Address | Lower Address | Entry 0 |
+ * +----------------+--------------+---------------+---------------+ |
+ * | Vector Control | Message Data | Upper Address | Lower Address | Entry 1 |
+ * +----------------+--------------+---------------+---------------+ |
+ * | ...... | ...... | ...... | ...... | |
+ * +----------------+--------------+---------------+---------------+ |
+ * | Vector Control | Message Data | Upper Address | Lower Address | Entry N-1 |
+ * +----------------+--------------+---------------+---------------+ |
+ * ^ |
+ * | |
+ * +---- Bit 0 is vector Mask Bit (R/W) |
+ * |
+ * MSI-X Pending Bit Array (BAR[PBA BIR] + Pending Bit Array Offset): |
+ * |
+ * DW1 DW0 |
+ * +-------------------------------+ <-----------------------------------------+
+ * | Pending Bits 0 - 63 | QW 0
+ * +-------------------------------+
+ * | Pending Bits 64 - 127 | QW 1
+ * +-------------------------------+
+ * | ...... |
+ * +-------------------------------+
+ * | Pending Bits | QW (N-1)/64
+ * +-------------------------------+
+ */
+
+struct rt_pci_msix_conf
+{
+ int index;
+
+ rt_uint32_t msg_ctrl;
+ void *table_base;
+};
+
+struct rt_pci_msi_msg
+{
+ rt_uint32_t address_lo;
+ rt_uint32_t address_hi;
+ rt_uint32_t data;
+};
+
+struct rt_pci_msi_desc
+{
+ rt_list_t list;
+
+ int irq;
+ rt_size_t vector_used;
+ rt_size_t vector_count;
+
+ union
+ {
+ /* For MSI-X */
+ rt_bitmap_t *affinity;
+ /* For MSI */
+ rt_bitmap_t **affinities;
+ };
+
+ struct rt_pci_device *pdev;
+ struct rt_pci_msi_msg msg;
+
+ void *write_msi_msg_data;
+ void (*write_msi_msg)(struct rt_pci_msi_desc *, void *);
+
+ rt_bool_t is_msix;
+ union
+ {
+ struct rt_pci_msi_conf msi;
+ struct rt_pci_msix_conf msix;
+ };
+
+ void *priv;
+};
+
+#define rt_pci_msi_first_desc(pdev) \
+ (rt_list_isempty(&(pdev)->msi_desc_nodes) ? RT_NULL : \
+ rt_list_first_entry(&(pdev)->msi_desc_nodes, struct rt_pci_msi_desc, list))
+
+#define rt_pci_msi_for_each_desc(pdev, desc) \
+ rt_list_for_each_entry(desc, &(pdev)->msi_desc_nodes, list)
+
+#define rt_pci_msix_table_size(flags) ((flags & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
+
+rt_err_t rt_pci_msi_setup_irqs(struct rt_pci_device *pdev, int nvec, int type);
+
+void rt_pci_msi_shutdown(struct rt_pci_device *pdev);
+void rt_pci_msix_shutdown(struct rt_pci_device *pdev);
+void rt_pci_msi_free_irqs(struct rt_pci_device *pdev);
+void rt_pci_msi_write_msg(struct rt_pci_msi_desc *desc, struct rt_pci_msi_msg *msg);
+
+void rt_pci_msi_mask_irq(struct rt_pic_irq *pirq);
+void rt_pci_msi_unmask_irq(struct rt_pic_irq *pirq);
+
+#endif /* __PCI_MSI_H__ */