summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorGUI <[email protected]>2026-08-14 12:42:32 +0800
committerGitHub <[email protected]>2026-08-14 12:42:32 +0800
commit7bf01ae18d33fee5971c499466e178b6b262a46b (patch)
tree6b45db9187fca7e7b67c2ff1af17e7273c81eae6 /components
parentf2c05253d11f0b5746ade4bdb7d8d838bb7a5df1 (diff)
[DM/OFW][PCI] Fix address translation and PCI resource enumeration (#11677)
* [DM/OFW][PCI] Fix address translation and PCI resource enumeration Rework OFW address translation to walk nested bus ranges in the correct direction and cache "ranges" and "dma-ranges" independently. Handle PCI three-cell addresses without treating the PCI flags cell as part of the address, and fix CPU-to-DMA and DMA-to-CPU translation across nested buses. Fix PCI BAR sizing and assignment by disabling address decoding during probing, preserving BAR attribute bits, and programming 64-bit BARs correctly. Add device enable and disable helpers so resources and bus mastering are enabled before driver probe. Program bridge memory and prefetch windows while scanning downstream buses, correctly link child buses into the PCI bus hierarchy, and avoid unnecessary PCIe link retraining when the link is already active. Allow host bridges without a device-tree pci-domain property by allocating unique domains dynamically, while preserving explicit domain assignments. Fix MSI and MSI-X IRQ setup, rollback, vector addressing, and affinity selection. Add the Raspberry Pi PCI vendor ID for RP1 and other downstream devices. Signed-off-by: GuEe-GUI <[email protected]> * style: format code with clang-format * style: format complete changed files with clang-format * drivers: pci: address OFW review feedback * style: format PCI and OFW changes for current master --------- Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components')
-rwxr-xr-xcomponents/drivers/include/drivers/ofw_io.h36
-rw-r--r--components/drivers/include/drivers/pci.h188
-rwxr-xr-xcomponents/drivers/ofw/io.c257
-rwxr-xr-xcomponents/drivers/ofw/ofw_internal.h13
-rw-r--r--components/drivers/pci/msi/irq.c10
-rw-r--r--components/drivers/pci/msi/msi.c44
-rw-r--r--components/drivers/pci/ofw.c47
-rw-r--r--components/drivers/pci/pci.c185
-rw-r--r--components/drivers/pci/pci_ids.h1
-rw-r--r--components/drivers/pci/probe.c249
10 files changed, 682 insertions, 348 deletions
diff --git a/components/drivers/include/drivers/ofw_io.h b/components/drivers/include/drivers/ofw_io.h
index f458435d09..bbd9e0c57a 100755
--- a/components/drivers/include/drivers/ofw_io.h
+++ b/components/drivers/include/drivers/ofw_io.h
@@ -22,7 +22,7 @@ int rt_ofw_io_size_cells(struct rt_ofw_node *np);
int rt_ofw_get_address_count(struct rt_ofw_node *np);
rt_err_t rt_ofw_get_address(struct rt_ofw_node *np, int index, rt_uint64_t *out_address, rt_uint64_t *out_size);
rt_err_t rt_ofw_get_address_by_name(struct rt_ofw_node *np, const char *name,
- rt_uint64_t *out_address, rt_uint64_t *out_size);
+ rt_uint64_t *out_address, rt_uint64_t *out_size);
int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_regs);
rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address);
@@ -30,22 +30,44 @@ rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_typ
rt_inline rt_uint64_t rt_ofw_translate_dma2cpu(struct rt_ofw_node *np, rt_uint64_t address)
{
- rt_uint64_t bus_addr, cpu_addr;
+ rt_uint64_t cpu_addr;
- bus_addr = rt_ofw_reverse_address(np, "dma-ranges", address);
- cpu_addr = rt_ofw_translate_address(np, "ranges", bus_addr);
+ cpu_addr = rt_ofw_translate_address(np, "dma-ranges", address);
+ if (cpu_addr != ~0ULL && cpu_addr != address)
+ {
+ return cpu_addr;
+ }
- return cpu_addr != ~0ULL ? cpu_addr : address;
+ cpu_addr = rt_ofw_translate_address(np, "ranges", address);
+ if (cpu_addr != ~0ULL && cpu_addr != address)
+ {
+ return cpu_addr;
+ }
+
+ return address;
}
rt_inline rt_uint64_t rt_ofw_translate_cpu2dma(struct rt_ofw_node *np, rt_uint64_t address)
{
rt_uint64_t bus_addr, dma_addr;
+ dma_addr = rt_ofw_reverse_address(np, "dma-ranges", address);
+ if (dma_addr != ~0ULL && dma_addr != address)
+ {
+ return dma_addr;
+ }
+
bus_addr = rt_ofw_reverse_address(np, "ranges", address);
- dma_addr = rt_ofw_translate_address(np, "dma-ranges", bus_addr);
+ if (bus_addr != ~0ULL && bus_addr != address)
+ {
+ dma_addr = rt_ofw_reverse_address(np, "dma-ranges", bus_addr);
+ if (dma_addr != ~0ULL && dma_addr != address)
+ {
+ return dma_addr;
+ }
+ }
- return dma_addr != ~0ULL ? dma_addr : address;
+ return address;
}
void *rt_ofw_iomap(struct rt_ofw_node *np, int index);
diff --git a/components/drivers/include/drivers/pci.h b/components/drivers/include/drivers/pci.h
index 414a0abf1a..a341efe615 100644
--- a/components/drivers/include/drivers/pci.h
+++ b/components/drivers/include/drivers/pci.h
@@ -22,12 +22,12 @@
#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_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
+#define RT_PCI_FIND_CAP_TTL 48
/*
* The PCI interface treats multi-function devices as independent
@@ -37,25 +37,24 @@
* 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 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 \
-)
+#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
{
@@ -65,10 +64,10 @@ struct rt_pci_bus_region
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 */
+#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;
};
@@ -104,17 +103,17 @@ struct rt_pci_bus;
struct rt_pci_device_id
{
-#define PCI_ANY_ID (~0)
+#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, \
+#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 */
@@ -167,15 +166,15 @@ struct rt_pci_device
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 */
+ 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;
@@ -217,9 +216,9 @@ struct rt_pci_ops
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_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);
+ rt_uint32_t devfn, int reg, int width, rt_uint32_t value);
};
struct rt_pci_bus
@@ -278,9 +277,9 @@ enum rt_pci_power
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);
+ 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)
+ enum rt_pci_power state)
{
if (!pdev->pme_cap)
{
@@ -295,6 +294,8 @@ 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);
+rt_err_t rt_pci_enable_device(struct rt_pci_device *pdev);
+rt_err_t rt_pci_disable_device(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 *);
@@ -340,7 +341,7 @@ rt_inline rt_bool_t rt_pci_is_root_bus(struct rt_pci_bus *bus)
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;
+ pdev->hdr_type == PCIM_HDRTYPE_CARDBUS;
}
rt_inline rt_bool_t rt_pci_is_pcie(struct rt_pci_device *pdev)
@@ -349,78 +350,77 @@ rt_inline rt_bool_t rt_pci_is_pcie(struct rt_pci_device *pdev)
}
#define rt_pci_foreach_bridge(pdev, bus) \
- rt_list_for_each_entry(pdev, &bus->devices_nodes, list) \
- if (rt_pci_is_bridge(pdev))
+ 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_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_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_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_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_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_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_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_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_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_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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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)
+ 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_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);
+ 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);
+ 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);
@@ -428,7 +428,7 @@ 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)
+ struct rt_pci_host_bridge *host_bridge)
{
return RT_EOK;
}
@@ -449,12 +449,12 @@ 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)
+ 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)
+ struct rt_pci_host_bridge *host_bridge)
{
return -RT_ENOSYS;
}
@@ -481,30 +481,30 @@ 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)
+#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)));
+ 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)));
+ 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)));
+ 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)))
+ rt_uint32_t flags, RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
return -RT_ENOSYS;
}
@@ -525,7 +525,7 @@ rt_inline rt_err_t rt_pci_msi_disable(struct rt_pci_device *pdev)
}
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)))
+ int min, int max, RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
return -RT_ENOSYS;
}
@@ -541,15 +541,15 @@ rt_inline rt_err_t rt_pci_msix_disable(struct rt_pci_device *pdev)
}
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)))
+ 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)
+ rt_size_t nvectors)
{
for (int i = 0; i < nvectors; ++i)
{
@@ -558,7 +558,7 @@ rt_inline void rt_pci_msix_entry_index_linear(struct rt_pci_msix_entry *entries,
}
rt_inline rt_ssize_t rt_pci_msi_enable_range(struct rt_pci_device *pdev,
- int min, int max)
+ int min, int max)
{
return rt_pci_msi_enable_range_affinity(pdev, min, max, RT_NULL);
}
@@ -570,37 +570,37 @@ rt_inline rt_err_t rt_pci_msi_enable(struct rt_pci_device *pdev)
}
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)
+ 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)
+ 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);
+ 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);
+ 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);
+ 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 *id);
const struct rt_pci_device_id *rt_pci_match_ids(struct rt_pci_device *pdev,
- const struct rt_pci_device_id *ids);
+ 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);
-struct rt_pci_bus_resource *rt_pci_find_bar(struct rt_pci_device* pdev,rt_ubase_t flags,int index);
-#define RT_PCI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, pci, BUILIN)
+struct rt_pci_bus_resource *rt_pci_find_bar(struct rt_pci_device *pdev, rt_ubase_t flags, int index);
+#define RT_PCI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, pci, BUILIN)
extern struct rt_spinlock rt_pci_lock;
diff --git a/components/drivers/ofw/io.c b/components/drivers/ofw/io.c
index a84df210a6..ac8695aff1 100755
--- a/components/drivers/ofw/io.c
+++ b/components/drivers/ofw/io.c
@@ -154,7 +154,7 @@ rt_err_t rt_ofw_get_address(struct rt_ofw_node *np, int index, rt_uint64_t *out_
}
static rt_err_t ofw_get_address_by_name(struct rt_ofw_node *np, const char *name,
- rt_uint64_t *out_address, rt_uint64_t *out_size)
+ rt_uint64_t *out_address, rt_uint64_t *out_size)
{
int index = 0;
rt_err_t err = -RT_EEMPTY;
@@ -177,7 +177,7 @@ static rt_err_t ofw_get_address_by_name(struct rt_ofw_node *np, const char *name
}
rt_err_t rt_ofw_get_address_by_name(struct rt_ofw_node *np, const char *name,
- rt_uint64_t *out_address, rt_uint64_t *out_size)
+ rt_uint64_t *out_address, rt_uint64_t *out_size)
{
rt_err_t err;
@@ -228,7 +228,7 @@ int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_re
count = nr;
- while (nr --> 0)
+ while (nr-- > 0)
{
*out_regs = rt_fdt_next_cell(&cell, addr_cells);
*out_regs = rt_ofw_translate_address(np, RT_NULL, *out_regs);
@@ -246,6 +246,37 @@ int rt_ofw_get_address_array(struct rt_ofw_node *np, int nr, rt_uint64_t *out_re
return count;
}
+static rt_bool_t ofw_bus_is_pci(struct rt_ofw_node *bus)
+{
+ rt_ssize_t len;
+ struct rt_ofw_prop *prop;
+
+ if (!bus)
+ {
+ return RT_FALSE;
+ }
+
+ prop = rt_ofw_get_prop(bus, "device_type", &len);
+
+ return prop && prop->value && len >= 3 &&
+ !rt_strncmp(prop->value, "pci", 3);
+}
+
+static rt_uint64_t ofw_read_bus_address(const fdt32_t **cell, int addr_cells,
+ struct rt_ofw_node *bus)
+{
+ if (addr_cells == 3 && ofw_bus_is_pci(bus))
+ {
+ const fdt32_t *c = *cell;
+
+ *cell += 3;
+
+ return ((rt_uint64_t)fdt32_to_cpu(c[1]) << 32) | fdt32_to_cpu(c[2]);
+ }
+
+ return rt_fdt_next_cell(cell, addr_cells);
+}
+
static struct bus_ranges *ofw_bus_ranges(struct rt_ofw_node *np, struct rt_ofw_prop *prop)
{
int id;
@@ -285,7 +316,8 @@ static struct bus_ranges *ofw_bus_ranges(struct rt_ofw_node *np, struct rt_ofw_p
* bus-address = parent-bus-address + (reg-address - child-bus-address)
*/
- do {
+ do
+ {
child_address_cells = rt_ofw_bus_addr_cells(np);
child_size_cells = rt_ofw_bus_size_cells(np);
parent_address_cells = rt_ofw_io_addr_cells(np);
@@ -293,7 +325,7 @@ static struct bus_ranges *ofw_bus_ranges(struct rt_ofw_node *np, struct rt_ofw_p
if (child_address_cells < 0 || child_size_cells < 0 || parent_address_cells < 0)
{
LOG_D("%s read address/size cells fail: child[%d, %d] parent[%d]",
- np->full_name, child_address_cells, child_size_cells, parent_address_cells);
+ np->full_name, child_address_cells, child_size_cells, parent_address_cells);
break;
}
@@ -319,14 +351,15 @@ static struct bus_ranges *ofw_bus_ranges(struct rt_ofw_node *np, struct rt_ofw_p
parent_addr = ranges->parent_addr;
child_size = ranges->child_size;
- while (groups --> 0)
+ while (groups-- > 0)
{
- *child_addr++ = rt_fdt_next_cell(&cell, child_address_cells);
- *parent_addr++ = rt_fdt_next_cell(&cell, parent_address_cells);
+ *child_addr++ = ofw_read_bus_address(&cell, child_address_cells, np);
+ *parent_addr++ = ofw_read_bus_address(&cell, parent_address_cells, np->parent);
*child_size++ = rt_fdt_next_cell(&cell, child_size_cells);
}
ranges->np = np;
+ ranges->range_type = prop->name;
id = (int)rt_atomic_add(&_bus_ranges_idx, 1);
RT_ASSERT(id < RT_ARRAY_SIZE(_bus_ranges));
@@ -337,158 +370,176 @@ static struct bus_ranges *ofw_bus_ranges(struct rt_ofw_node *np, struct rt_ofw_p
return ranges;
}
-rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address)
+static struct bus_ranges *ofw_get_bus_ranges(struct rt_ofw_node *bus, const char *range_type)
{
- rt_uint64_t cpu_addr = address;
+ rt_ssize_t len;
+ struct rt_ofw_prop *prop;
+ struct bus_ranges *ranges = RT_NULL;
- if (!range_type)
+ prop = rt_ofw_get_prop(bus, range_type, &len);
+
+ if (!prop || !len)
{
- range_type = "ranges";
+ return RT_NULL;
}
- rt_ofw_foreach_parent_node(np)
+ for (int i = 0; i < RT_ARRAY_SIZE(_bus_ranges); ++i)
{
- rt_ssize_t len;
- struct rt_ofw_prop *prop;
- struct bus_ranges *ranges = RT_NULL;
-
- prop = rt_ofw_get_prop(np, range_type, &len);
-
- if (!prop || !len)
+ if (!_bus_ranges[i])
{
- continue;
+ break;
}
- for (int i = 0; i < RT_ARRAY_SIZE(_bus_ranges); ++i)
+ if (_bus_ranges[i]->np == bus &&
+ !rt_strcmp(_bus_ranges[i]->range_type, range_type))
{
- if (!_bus_ranges[i])
- {
- break;
- }
-
- if (_bus_ranges[i]->np == np)
- {
- ranges = _bus_ranges[i];
- break;
- }
+ ranges = _bus_ranges[i];
+ break;
}
+ }
- if (!ranges)
- {
- ranges = ofw_bus_ranges(np, prop);
- }
+ if (!ranges)
+ {
+ ranges = ofw_bus_ranges(bus, prop);
+ }
- if (ranges)
- {
- for (int i = 0; i < ranges->nr; ++i)
- {
- rt_uint64_t child_addr = ranges->child_addr[i];
- rt_uint64_t child_size = ranges->child_size[i];
+ return ranges;
+}
- if (address >= child_addr && address < child_addr + child_size)
- {
- cpu_addr = address + (ranges->parent_addr[i] - child_addr);
+static rt_uint64_t ofw_translate_at_bus(struct rt_ofw_node *bus, const char *range_type,
+ rt_uint64_t address)
+{
+ struct bus_ranges *ranges = ofw_get_bus_ranges(bus, range_type);
- break;
- }
- }
- }
- else
+ if (!ranges)
+ {
+ return ~0ULL;
+ }
+
+ for (int i = 0; i < ranges->nr; ++i)
+ {
+ rt_uint64_t child_addr = ranges->child_addr[i];
+ rt_uint64_t child_size = ranges->child_size[i];
+
+ if (address >= child_addr && address < child_addr + child_size)
{
- cpu_addr = ~0ULL;
+ return address + (ranges->parent_addr[i] - child_addr);
}
+ }
- rt_ofw_node_put(np);
+ return address;
+}
+
+static rt_uint64_t ofw_reverse_at_bus(struct rt_ofw_node *bus, const char *range_type,
+ rt_uint64_t address)
+{
+ struct bus_ranges *ranges = ofw_get_bus_ranges(bus, range_type);
- break;
+ if (!ranges)
+ {
+ return ~0ULL;
}
- return cpu_addr;
+ for (int i = 0; i < ranges->nr; ++i)
+ {
+ rt_uint64_t parent_addr = ranges->parent_addr[i];
+ rt_uint64_t child_size = ranges->child_size[i];
+
+ if (address >= parent_addr && address < parent_addr + child_size)
+ {
+ return ranges->child_addr[i] + (address - parent_addr);
+ }
+ }
+
+ return address;
}
-rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address)
+rt_uint64_t rt_ofw_translate_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address)
{
- rt_uint64_t bus_addr = address;
+ struct rt_ofw_node *bus;
if (!range_type)
{
range_type = "ranges";
}
- rt_ofw_foreach_parent_node(np)
+ for (bus = np ? np->parent : RT_NULL; bus; bus = bus->parent)
{
rt_ssize_t len;
- struct rt_ofw_prop *prop;
- struct bus_ranges *ranges = RT_NULL;
+ rt_uint64_t translated;
- prop = rt_ofw_get_prop(np, range_type, &len);
-
- if (!prop || !len)
+ if (!rt_ofw_get_prop(bus, range_type, &len) || !len)
{
continue;
}
- for (int i = 0; i < RT_ARRAY_SIZE(_bus_ranges); ++i)
+ translated = ofw_translate_at_bus(bus, range_type, address);
+ if (translated == ~0ULL)
{
- if (!_bus_ranges[i])
- {
- break;
- }
-
- if (_bus_ranges[i]->np == np)
- {
- ranges = _bus_ranges[i];
- break;
- }
+ return ~0ULL;
}
- if (!ranges)
+ address = translated;
+ }
+
+ return address;
+}
+
+rt_uint64_t rt_ofw_reverse_address(struct rt_ofw_node *np, const char *range_type, rt_uint64_t address)
+{
+ struct rt_ofw_node *bus;
+ struct rt_ofw_node *parents[OFW_NODE_MAX_DEPTH];
+ int count = 0;
+
+ if (!range_type)
+ {
+ range_type = "ranges";
+ }
+
+ for (bus = np ? np->parent : RT_NULL; bus; bus = bus->parent)
+ {
+ rt_ssize_t len;
+
+ if (!rt_ofw_get_prop(bus, range_type, &len) || !len)
{
- ranges = ofw_bus_ranges(np, prop);
+ continue;
}
- if (ranges)
+ if (count < (int)RT_ARRAY_SIZE(parents))
{
- for (int i = 0; i < ranges->nr; ++i)
- {
- rt_uint64_t parent_addr = ranges->parent_addr[i];
- rt_uint64_t child_size = ranges->child_size[i];
+ parents[count++] = bus;
+ }
+ }
- if (address >= parent_addr && address < parent_addr + child_size)
- {
- bus_addr = ranges->child_addr[i] + (address - parent_addr);
+ while (count-- > 0)
+ {
+ rt_uint64_t reversed = ofw_reverse_at_bus(parents[count], range_type, address);
- break;
- }
- }
- }
- else
+ if (reversed == ~0ULL)
{
- bus_addr = ~0ULL;
+ return ~0ULL;
}
- rt_ofw_node_put(np);
-
- break;
+ address = reversed;
}
- return bus_addr;
+ return address;
}
#ifdef ARCH_CPU_64BIT
#define ofw_address_cpu_cast(np, address) (void *)(address)
#else
#define ofw_address_cpu_cast(np, address) \
-({ \
- if (((address) >> 32)) \
- { \
- LOG_W("%s find 64 bits address = %x%x", \
- rt_ofw_node_full_name(np), \
- ofw_static_cast(rt_ubase_t, (address) >> 32), \
- ofw_static_cast(rt_ubase_t, (address))); \
- } \
- (void *)ofw_static_cast(rt_ubase_t, (address)); \
-})
+ ({ \
+ if (((address) >> 32)) \
+ { \
+ LOG_W("%s find 64 bits address = %x%x", \
+ rt_ofw_node_full_name(np), \
+ ofw_static_cast(rt_ubase_t, (address) >> 32), \
+ ofw_static_cast(rt_ubase_t, (address))); \
+ } \
+ (void *)ofw_static_cast(rt_ubase_t, (address)); \
+ })
#endif
void *rt_ofw_iomap(struct rt_ofw_node *np, int index)
diff --git a/components/drivers/ofw/ofw_internal.h b/components/drivers/ofw/ofw_internal.h
index 0a8c7c8b23..7778dbc4c5 100755
--- a/components/drivers/ofw/ofw_internal.h
+++ b/components/drivers/ofw/ofw_internal.h
@@ -15,14 +15,14 @@
#include <posix/string.h>
#include <drivers/ofw.h>
-#define OFW_PHANDLE_MIN 1
-#define OFW_PHANDLE_MAX FDT_MAX_PHANDLE
+#define OFW_PHANDLE_MIN 1
+#define OFW_PHANDLE_MAX FDT_MAX_PHANDLE
-#define OFW_NODE_MAX_DEPTH 64
-#define OFW_NODE_MIN_HASH 128
+#define OFW_NODE_MAX_DEPTH 64
+#define OFW_NODE_MIN_HASH 128
-#define OFW_ROOT_NODE_ADDR_CELLS_DEFAULT 1
-#define OFW_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+#define OFW_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+#define OFW_ROOT_NODE_SIZE_CELLS_DEFAULT 1
struct fdt_info
{
/* Always "/", because we save "ofw" information in root node. */
@@ -51,6 +51,7 @@ struct bus_ranges
{
rt_size_t nr;
struct rt_ofw_node *np;
+ const char *range_type;
rt_uint64_t *child_addr;
rt_uint64_t *parent_addr;
diff --git a/components/drivers/pci/msi/irq.c b/components/drivers/pci/msi/irq.c
index 8e3b7333e0..8659e11768 100644
--- a/components/drivers/pci/msi/irq.c
+++ b/components/drivers/pci/msi/irq.c
@@ -49,14 +49,14 @@ rt_err_t rt_pci_msi_setup_irqs(struct rt_pci_device *pdev, int nvec, int type)
{
err = irq;
- LOG_E("Setup %s[%d] IRQ error = %s", "MSI", i, rt_strerror(err));
+ LOG_E("Setup %s[%d] IRQ in %s error = %s", "MSI", i, msi_pic->ops->name, rt_strerror(err));
break;
}
if (last_irq >= 0 && last_irq + 1 != irq)
{
- for (int idx = 0; idx < i; ++i, --last_irq)
+ for (int idx = 0; idx < i; ++idx, --last_irq)
{
rt_bitmap_set_bit(msi_irq_map, last_irq);
}
@@ -88,7 +88,7 @@ rt_err_t rt_pci_msi_setup_irqs(struct rt_pci_device *pdev, int nvec, int type)
{
for (int idx = 0; idx < nvec; ++idx)
{
- pirq = rt_pic_find_pirq(msi_pic, irq + idx);
+ pirq = rt_pic_find_pirq(msi_pic, desc->irq + idx);
pirq->msi_desc = desc;
msi_pic->ops->irq_compose_msi_msg(pirq, &desc->msg);
@@ -105,8 +105,8 @@ rt_err_t rt_pci_msi_setup_irqs(struct rt_pci_device *pdev, int nvec, int type)
{
err = irq;
- LOG_E("Setup %s[%d] IRQ error = %s", "MSI-X",
- desc->msix.index, rt_strerror(err));
+ LOG_E("Setup %s[%d] IRQ in %s error = %s", "MSI-X",
+ desc->msix.index, msi_pic->ops->name, rt_strerror(err));
break;
}
diff --git a/components/drivers/pci/msi/msi.c b/components/drivers/pci/msi/msi.c
index 11ccdcb10c..5d20b52d40 100644
--- a/components/drivers/pci/msi/msi.c
+++ b/components/drivers/pci/msi/msi.c
@@ -39,7 +39,7 @@ rt_inline void *msix_vector_ctrl_base(struct rt_pci_msix_conf *msix)
}
rt_inline void msix_write_vector_ctrl(struct rt_pci_msix_conf *msix,
- rt_uint32_t ctrl)
+ rt_uint32_t ctrl)
{
void *vc_addr = msix_vector_ctrl_base(msix);
@@ -56,7 +56,7 @@ rt_inline void msix_mask(struct rt_pci_msix_conf *msix)
}
static void msix_update_ctrl(struct rt_pci_device *pdev,
- rt_uint16_t clear, rt_uint16_t set)
+ rt_uint16_t clear, rt_uint16_t set)
{
rt_uint16_t msgctl;
@@ -83,7 +83,7 @@ rt_inline rt_uint32_t msi_multi_mask(struct rt_pci_msi_conf *msi)
}
static void msi_write_mask(struct rt_pci_msi_conf *msi,
- rt_uint32_t clear, rt_uint32_t set, struct rt_pci_device *pdev)
+ rt_uint32_t clear, rt_uint32_t set, struct rt_pci_device *pdev)
{
if (msi->cap.is_masking)
{
@@ -98,13 +98,13 @@ static void msi_write_mask(struct rt_pci_msi_conf *msi,
}
rt_inline void msi_mask(struct rt_pci_msi_conf *msi,
- rt_uint32_t mask, struct rt_pci_device *pdev)
+ rt_uint32_t mask, struct rt_pci_device *pdev)
{
msi_write_mask(msi, 0, mask, pdev);
}
rt_inline void msi_unmask(struct rt_pci_msi_conf *msi,
- rt_uint32_t mask, struct rt_pci_device *pdev)
+ rt_uint32_t mask, struct rt_pci_device *pdev)
{
msi_write_mask(msi, mask, 0, pdev);
}
@@ -126,14 +126,14 @@ static void msi_write_enable(struct rt_pci_device *pdev, rt_bool_t enable)
}
static void msi_affinity_init(struct rt_pci_msi_desc *desc, int msi_index,
- rt_bitmap_t *cpumasks)
+ rt_bitmap_t *cpumasks)
{
int irq;
struct rt_pic_irq *pirq;
struct rt_pci_device *pdev = desc->pdev;
struct rt_pic *msi_pic = pdev->msi_pic;
- irq = desc->irq + desc->is_msix ? 0 : msi_index;
+ irq = desc->is_msix ? desc->irq : desc->irq + msi_index;
pirq = rt_pic_find_pirq(msi_pic, irq);
/* Save affinity */
@@ -365,7 +365,7 @@ void rt_pci_msi_unmask_irq(struct rt_pic_irq *pirq)
}
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)))
+ rt_uint32_t flags, RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
rt_ssize_t res = -RT_ENOSYS;
@@ -458,9 +458,9 @@ static rt_err_t msi_verify_entries(struct rt_pci_device *pdev)
if (desc->msg.address_hi)
{
LOG_D("%s: Arch assigned 64-bit MSI address %08x%08x"
- "but device only supports 32 bits",
- rt_dm_dev_get_name(&pdev->parent),
- desc->msg.address_hi, desc->msg.address_lo);
+ "but device only supports 32 bits",
+ rt_dm_dev_get_name(&pdev->parent),
+ desc->msg.address_hi, desc->msg.address_lo);
return -RT_EIO;
}
@@ -471,7 +471,7 @@ static rt_err_t msi_verify_entries(struct rt_pci_device *pdev)
}
static rt_err_t msi_insert_desc(struct rt_pci_device *pdev,
- struct rt_pci_msi_desc *init_desc)
+ struct rt_pci_msi_desc *init_desc)
{
rt_size_t msi_affinity_ptr_size = 0;
struct rt_pci_msi_desc *msi_desc;
@@ -591,7 +591,7 @@ static rt_err_t msi_setup_msi_desc(struct rt_pci_device *pdev, int nvec)
}
static rt_ssize_t msi_capability_init(struct rt_pci_device *pdev,
- int nvec, RT_IRQ_AFFINITY_DECLARE((*affinities)))
+ int nvec, RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
rt_err_t err;
struct rt_pci_msi_desc *desc;
@@ -624,7 +624,7 @@ static rt_ssize_t msi_capability_init(struct rt_pci_device *pdev,
rt_pci_msi_free_irqs(pdev);
LOG_E("%s: Setup %s interrupts(%d) error = %s",
- rt_dm_dev_get_name(&pdev->parent), "MSI", nvec, rt_strerror(err));
+ rt_dm_dev_get_name(&pdev->parent), "MSI", nvec, rt_strerror(err));
return err;
}
@@ -651,7 +651,7 @@ static rt_ssize_t msi_capability_init(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)))
+ int min, int max, RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
int nvec = max;
rt_size_t entries_nr;
@@ -756,7 +756,7 @@ static void *msix_table_remap(struct rt_pci_device *pdev, rt_size_t entries_nr)
}
static rt_err_t msix_setup_msi_descs(struct rt_pci_device *pdev,
- void *table_base, struct rt_pci_msix_entry *entries, int nvec)
+ void *table_base, struct rt_pci_msix_entry *entries, int nvec)
{
rt_err_t err;
struct rt_pci_msi_desc desc;
@@ -789,8 +789,8 @@ static rt_err_t msix_setup_msi_descs(struct rt_pci_device *pdev,
}
static rt_ssize_t msix_capability_init(struct rt_pci_device *pdev,
- struct rt_pci_msix_entry *entries, int nvec,
- RT_IRQ_AFFINITY_DECLARE((*affinities)))
+ struct rt_pci_msix_entry *entries, int nvec,
+ RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
rt_err_t err;
rt_uint16_t msgctl;
@@ -840,7 +840,7 @@ static rt_ssize_t msix_capability_init(struct rt_pci_device *pdev,
rt_pci_msi_free_irqs(pdev);
LOG_E("%s: Setup %s interrupts(%d) error = %s",
- rt_dm_dev_get_name(&pdev->parent), "MSI-X", nvec, rt_strerror(err));
+ rt_dm_dev_get_name(&pdev->parent), "MSI-X", nvec, rt_strerror(err));
goto _out_disbale_msix;
}
@@ -879,8 +879,8 @@ _out_disbale_msix:
}
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)))
+ struct rt_pci_msix_entry *entries, int min, int max,
+ RT_IRQ_AFFINITY_DECLARE((*affinities)))
{
int nvec = max;
rt_size_t entries_nr;
@@ -940,7 +940,7 @@ rt_ssize_t rt_pci_msix_enable_range_affinity(struct rt_pci_device *pdev,
if (target->index == entries[j].index)
{
LOG_E("%s: msix entry[%d].index = entry[%d].index",
- rt_dm_dev_get_name(&pdev->parent), i, j);
+ rt_dm_dev_get_name(&pdev->parent), i, j);
return -RT_EINVAL;
}
diff --git a/components/drivers/pci/ofw.c b/components/drivers/pci/ofw.c
index 450402d6bd..7d0a476d8b 100644
--- a/components/drivers/pci/ofw.c
+++ b/components/drivers/pci/ofw.c
@@ -115,21 +115,21 @@ _err:
if (err == -RT_EEMPTY)
{
LOG_W("PCI-Device<%s> no interrupt-map found, INTx interrupts not available",
- rt_dm_dev_get_name(&pdev->parent));
+ rt_dm_dev_get_name(&pdev->parent));
LOG_W("PCI-Device<%s> possibly some PCI slots don't have level triggered interrupts capability",
- rt_dm_dev_get_name(&pdev->parent));
+ rt_dm_dev_get_name(&pdev->parent));
}
else if (err && err != -RT_ENOSYS)
{
LOG_E("PCI-Device<%s> irq parse failed with err = %s",
- rt_dm_dev_get_name(&pdev->parent), rt_strerror(err));
+ rt_dm_dev_get_name(&pdev->parent), rt_strerror(err));
}
return err;
}
int rt_pci_ofw_irq_parse_and_map(struct rt_pci_device *pdev,
- rt_uint8_t slot, rt_uint8_t pin)
+ rt_uint8_t slot, rt_uint8_t pin)
{
int irq = -1;
rt_err_t status;
@@ -159,8 +159,8 @@ _end:
}
static rt_err_t pci_ofw_parse_ranges(struct rt_ofw_node *dev_np, const char *propname,
- int phy_addr_cells, int phy_size_cells, int cpu_addr_cells,
- struct rt_pci_bus_region **out_regions, rt_size_t *out_regions_nr)
+ int phy_addr_cells, int phy_size_cells, int cpu_addr_cells,
+ struct rt_pci_bus_region **out_regions, rt_size_t *out_regions_nr)
{
const fdt32_t *cell;
rt_ssize_t total_cells;
@@ -227,8 +227,7 @@ static rt_err_t pci_ofw_parse_ranges(struct rt_ofw_node *dev_np, const char *pro
if (space_code & 2)
{
- (*out_regions)[i].flags = phy_addr[0] & (1U << 30) ?
- PCI_BUS_REGION_F_PREFETCH : PCI_BUS_REGION_F_MEM;
+ (*out_regions)[i].flags = phy_addr[0] & (1U << 30) ? PCI_BUS_REGION_F_PREFETCH : PCI_BUS_REGION_F_MEM;
}
else if (space_code & 1)
{
@@ -246,7 +245,7 @@ static rt_err_t pci_ofw_parse_ranges(struct rt_ofw_node *dev_np, const char *pro
}
rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
- struct rt_pci_host_bridge *host_bridge)
+ struct rt_pci_host_bridge *host_bridge)
{
rt_err_t err;
int phy_addr_cells = -1, phy_size_cells = -1, cpu_addr_cells;
@@ -266,8 +265,8 @@ rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
}
if (pci_ofw_parse_ranges(dev_np, "ranges",
- phy_addr_cells, phy_size_cells, cpu_addr_cells,
- &host_bridge->bus_regions, &host_bridge->bus_regions_nr))
+ phy_addr_cells, phy_size_cells, cpu_addr_cells,
+ &host_bridge->bus_regions, &host_bridge->bus_regions_nr))
{
return -RT_EINVAL;
}
@@ -281,8 +280,8 @@ rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
}
err = pci_ofw_parse_ranges(dev_np, "dma-ranges",
- phy_addr_cells, phy_size_cells, cpu_addr_cells,
- &host_bridge->dma_regions, &host_bridge->dma_regions_nr);
+ phy_addr_cells, phy_size_cells, cpu_addr_cells,
+ &host_bridge->dma_regions, &host_bridge->dma_regions_nr);
if (err && err != -RT_EEMPTY)
{
@@ -290,7 +289,7 @@ rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
host_bridge->bus_regions_nr = 0;
LOG_E("%s: Read dma-ranges error = %s", rt_ofw_node_full_name(dev_np),
- rt_strerror(err));
+ rt_strerror(err));
return err;
}
@@ -299,7 +298,7 @@ rt_err_t rt_pci_ofw_parse_ranges(struct rt_ofw_node *dev_np,
}
rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np,
- struct rt_pci_host_bridge *host_bridge)
+ struct rt_pci_host_bridge *host_bridge)
{
rt_err_t err;
const char *propname;
@@ -317,11 +316,19 @@ rt_err_t rt_pci_ofw_host_bridge_init(struct rt_ofw_node *dev_np,
host_bridge->bus_range[0] = 0x00;
host_bridge->bus_range[1] = 0xff;
LOG_I("%s: No \"%s\" found, using [%#02x, %#02x]", rt_ofw_node_full_name(dev_np), "bus-range",
- host_bridge->bus_range[0], host_bridge->bus_range[1]);
+ host_bridge->bus_range[0], host_bridge->bus_range[1]);
}
propname = rt_ofw_get_prop_fuzzy_name(dev_np, ",pci-domain$");
- rt_ofw_prop_read_u32(dev_np, propname, &host_bridge->domain);
+
+ if (propname)
+ {
+ rt_ofw_prop_read_u32(dev_np, propname, &host_bridge->domain);
+ }
+ else
+ {
+ host_bridge->domain = RT_UINT32_MAX;
+ }
err = rt_pci_ofw_parse_ranges(dev_np, host_bridge);
@@ -505,21 +512,21 @@ static void ofw_msi_pic_init(struct rt_pci_device *pdev)
if (!pdev->msi_pic->ops->irq_compose_msi_msg)
{
LOG_E("%s: MSI pic MUST implemented %s",
- rt_ofw_node_full_name(msi_ic_np), "irq_compose_msi_msg");
+ rt_ofw_node_full_name(msi_ic_np), "irq_compose_msi_msg");
RT_ASSERT(0);
}
if (!pdev->msi_pic->ops->irq_alloc_msi)
{
LOG_E("%s: MSI pic MUST implemented %s",
- rt_ofw_node_full_name(msi_ic_np), "irq_alloc_msi");
+ rt_ofw_node_full_name(msi_ic_np), "irq_alloc_msi");
RT_ASSERT(0);
}
if (!pdev->msi_pic->ops->irq_free_msi)
{
LOG_E("%s: MSI pic MUST implemented %s",
- rt_ofw_node_full_name(msi_ic_np), "irq_free_msi");
+ rt_ofw_node_full_name(msi_ic_np), "irq_free_msi");
RT_ASSERT(0);
}
diff --git a/components/drivers/pci/pci.c b/components/drivers/pci/pci.c
index 3ba3967e7d..e2fa293956 100644
--- a/components/drivers/pci/pci.c
+++ b/components/drivers/pci/pci.c
@@ -47,7 +47,7 @@ rt_uint32_t rt_pci_domain(struct rt_pci_device *pdev)
}
static rt_uint8_t pci_find_next_cap_ttl(struct rt_pci_bus *bus,
- rt_uint32_t devfn, rt_uint8_t pos, int cap, int *ttl)
+ rt_uint32_t devfn, rt_uint8_t pos, int cap, int *ttl)
{
rt_uint8_t ret = 0, id;
rt_uint16_t ent;
@@ -81,7 +81,7 @@ static rt_uint8_t pci_find_next_cap_ttl(struct rt_pci_bus *bus,
}
static rt_uint8_t pci_find_next_cap(struct rt_pci_bus *bus,
- rt_uint32_t devfn, rt_uint8_t pos, int cap)
+ rt_uint32_t devfn, rt_uint8_t pos, int cap)
{
int ttl = RT_PCI_FIND_CAP_TTL;
@@ -89,7 +89,7 @@ static rt_uint8_t pci_find_next_cap(struct rt_pci_bus *bus,
}
static rt_uint8_t pci_bus_find_cap_start(struct rt_pci_bus *bus,
- rt_uint32_t devfn, rt_uint8_t hdr_type)
+ rt_uint32_t devfn, rt_uint8_t hdr_type)
{
rt_uint8_t res = 0;
rt_uint16_t status;
@@ -262,6 +262,83 @@ void rt_pci_clear_master(struct rt_pci_device *pdev)
}
}
+static rt_err_t pci_enable_resources(struct rt_pci_device *pdev)
+{
+ rt_uint16_t cmd, old_cmd, subclass;
+
+ rt_pci_read_config_u16(pdev, PCIR_COMMAND, &cmd);
+ old_cmd = cmd;
+
+ for (int i = 0; i < RT_PCI_BAR_NR_MAX; ++i)
+ {
+ struct rt_pci_bus_resource *res = &pdev->resource[i];
+
+ if (res->flags == PCI_BUS_REGION_F_NONE || res->size == 0)
+ {
+ continue;
+ }
+
+ if (res->flags & PCI_BUS_REGION_F_IO)
+ {
+ cmd |= PCIM_CMD_PORTEN;
+ }
+ else
+ {
+ cmd |= PCIM_CMD_MEMEN;
+ }
+ }
+
+ if (pdev->rom.size)
+ {
+ cmd |= PCIM_CMD_MEMEN;
+ }
+
+ rt_pci_read_config_u16(pdev, PCIR_SUBCLASS, &subclass);
+
+ if (subclass == PCIS_DISPLAY_VGA)
+ {
+ cmd |= PCIM_CMD_PORTEN;
+ }
+
+ if (cmd != old_cmd)
+ {
+ LOG_D("%s enabling device (%04x -> %04x)", rt_dm_dev_get_name(&pdev->parent), old_cmd, cmd);
+ rt_pci_write_config_u16(pdev, PCIR_COMMAND, cmd);
+ }
+
+ return RT_EOK;
+}
+
+rt_err_t rt_pci_enable_device(struct rt_pci_device *pdev)
+{
+ if (!pdev)
+ {
+ return -RT_EINVAL;
+ }
+
+ pci_enable_resources(pdev);
+ rt_pci_set_master(pdev);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_pci_disable_device(struct rt_pci_device *pdev)
+{
+ rt_uint16_t cmd;
+
+ if (!pdev)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_pci_read_config_u16(pdev, PCIR_COMMAND, &cmd);
+ cmd &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
+ rt_pci_write_config_u16(pdev, PCIR_COMMAND, cmd);
+ pdev->busmaster = RT_FALSE;
+
+ return RT_EOK;
+}
+
void rt_pci_intx(struct rt_pci_device *pdev, rt_bool_t enable)
{
rt_uint16_t pci_command, new;
@@ -460,9 +537,7 @@ rt_err_t rt_pci_region_setup(struct rt_pci_host_bridge *host_bridge)
region->bus_start = rt_max_t(rt_size_t, 0x1000, region->phy_addr);
LOG_I("Bus %s region(%d):",
- region->flags == PCI_BUS_REGION_F_MEM ? "Memory" :
- (region->flags == PCI_BUS_REGION_F_PREFETCH ? "Prefetchable Mem" :
- (region->flags == PCI_BUS_REGION_F_IO ? "I/O" : "Unknown")), i);
+ region->flags == PCI_BUS_REGION_F_MEM ? "Memory" : (region->flags == PCI_BUS_REGION_F_PREFETCH ? "Prefetchable Mem" : (region->flags == PCI_BUS_REGION_F_IO ? "I/O" : "Unknown")), i);
LOG_I(" cpu: [%p, %p]", region->cpu_addr, (region->cpu_addr + region->size - 1));
LOG_I(" physical: [%p, %p]", region->phy_addr, (region->phy_addr + region->size - 1));
}
@@ -471,7 +546,7 @@ 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)
+ void **out_addr, rt_size_t size, rt_ubase_t flags, rt_bool_t mem64)
{
struct rt_pci_bus_region *bus_region, *region = RT_NULL;
@@ -500,8 +575,9 @@ struct rt_pci_bus_region *rt_pci_region_alloc(struct rt_pci_host_bridge *host_br
continue;
}
}
- else if (addr64)
+ else if (addr64 && flags == PCI_BUS_REGION_F_MEM)
{
+ /* 32-bit MEM BAR needs a CPU address below 4G. */
region = RT_NULL;
/* Try again */
@@ -526,7 +602,7 @@ struct rt_pci_bus_region *rt_pci_region_alloc(struct rt_pci_host_bridge *host_br
}
rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
- struct rt_pci_device *pdev)
+ struct rt_pci_device *pdev)
{
rt_err_t err = RT_EOK;
rt_size_t size;
@@ -535,7 +611,7 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
rt_size_t bars_nr;
rt_uint8_t hdr_type;
rt_bool_t prefetch = RT_FALSE;
- rt_uint16_t class, command = 0;
+ rt_uint16_t orig_cmd, command = 0;
for (int i = 0; i < host_bridge->bus_regions_nr; ++i)
{
@@ -546,8 +622,13 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
}
}
- rt_pci_read_config_u16(pdev, PCIR_COMMAND, &command);
- command = (command & ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN)) | PCIM_CMD_BUSMASTEREN;
+ rt_pci_read_config_u16(pdev, PCIR_COMMAND, &orig_cmd);
+ if (orig_cmd & (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN))
+ {
+ rt_pci_write_config_u16(pdev, PCIR_COMMAND,
+ orig_cmd & ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN));
+ }
+
rt_pci_read_config_u8(pdev, PCIR_HDRTYPE, &hdr_type);
if (pdev->hdr_type != hdr_type)
@@ -579,6 +660,8 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
rt_ubase_t flags;
rt_ubase_t bar_base;
rt_bool_t mem64 = RT_FALSE;
+ rt_bool_t bar_is_64 = RT_FALSE;
+ rt_uint32_t bar_lo_mask = 0;
struct rt_pci_bus_region *region;
cfg = 0;
@@ -596,11 +679,11 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
rt_pci_write_config_u32(pdev, bar_base, 0UL);
continue;
}
-
- if (cfg & PCIM_BAR_SPACE)
+ else if (cfg & PCIM_BAR_SPACE)
{
mem64 = RT_FALSE;
flags = PCI_BUS_REGION_F_IO;
+ bar_lo_mask = cfg & ~PCIM_BAR_IO_MASK;
size = cfg & PCIM_BAR_IO_MASK;
size &= ~(size - 1);
@@ -608,6 +691,8 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
else
{
/* memory */
+ bar_lo_mask = cfg & ~PCIM_BAR_MEM_MASK;
+
if ((cfg & PCIM_BAR_MEM_TYPE_MASK) == PCIM_BAR_MEM_TYPE_64)
{
/* 64bits */
@@ -615,6 +700,7 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
rt_uint64_t bar64;
mem64 = RT_TRUE;
+ bar_is_64 = RT_TRUE;
rt_pci_write_config_u32(pdev, bar_base + sizeof(rt_uint32_t), RT_UINT32_MAX);
rt_pci_read_config_u32(pdev, bar_base + sizeof(rt_uint32_t), &cfg64);
@@ -644,27 +730,39 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
if (region)
{
- rt_pci_write_config_u32(pdev, bar_base, addr);
+ rt_uint32_t bar_val;
- if (mem64)
+ if (flags == PCI_BUS_REGION_F_IO)
{
- bar_base += sizeof(rt_uint32_t);
- #ifdef RT_PCI_SYS_64BIT
- rt_pci_write_config_u32(pdev, bar_base, (rt_uint32_t)(addr >> 32));
- #else
- /*
- * If we are a 64-bit decoder then increment to the upper 32 bits
- * of the bar and force it to locate in the lower 4GB of memory.
- */
- rt_pci_write_config_u32(pdev, bar_base, 0UL);
- #endif
+ bar_val = rt_lower_32_bits(addr) | bar_lo_mask;
+ rt_pci_write_config_u32(pdev, bar_base, bar_val);
+ }
+ else
+ {
+ rt_pci_write_config_u32(pdev, bar_base, 0);
+ if (bar_is_64)
+ {
+ rt_pci_write_config_u32(pdev, bar_base + sizeof(rt_uint32_t), 0);
+ }
+
+ bar_val = rt_lower_32_bits((rt_ubase_t)addr) | bar_lo_mask;
+ rt_pci_write_config_u32(pdev, bar_base, bar_val);
+
+ if (bar_is_64)
+ {
+#ifdef RT_PCI_SYS_64BIT
+ rt_pci_write_config_u32(pdev, bar_base + sizeof(rt_uint32_t), rt_upper_32_bits(addr));
+#else
+ rt_pci_write_config_u32(pdev, bar_base + sizeof(rt_uint32_t), 0UL);
+#endif
+ }
}
pdev->resource[i].size = size;
pdev->resource[i].base = region->cpu_addr + (addr - region->phy_addr);
pdev->resource[i].flags = flags;
- if (mem64)
+ if (bar_is_64)
{
++i;
pdev->resource[i].flags = PCI_BUS_REGION_F_NONE;
@@ -675,8 +773,6 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
err = -RT_ERROR;
LOG_W("%s alloc bar(%d) address fail", rt_dm_dev_get_name(&pdev->parent), i);
}
-
- command |= (cfg & PCIM_BAR_SPACE) ? PCIM_CMD_PORTEN : PCIM_CMD_MEMEN;
}
if (hdr_type == PCIM_HDRTYPE_NORMAL || hdr_type == PCIM_HDRTYPE_BRIDGE)
@@ -694,7 +790,6 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
{
rt_pci_write_config_u32(pdev, rom_addr, addr);
}
- command |= PCIM_CMD_MEMEN;
pdev->rom.base = addr;
pdev->rom.size = size;
@@ -702,21 +797,17 @@ rt_err_t rt_pci_device_alloc_resource(struct rt_pci_host_bridge *host_bridge,
}
}
- rt_pci_read_config_u16(pdev, PCIR_SUBCLASS, &class);
-
- if (class == PCIS_DISPLAY_VGA)
- {
- command |= PCIM_CMD_PORTEN;
- }
-
+ rt_pci_read_config_u16(pdev, PCIR_COMMAND, &command);
+ command &= ~(PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
rt_pci_write_config_u16(pdev, PCIR_COMMAND, command);
+ pdev->busmaster = RT_FALSE;
rt_pci_write_config_u8(pdev, PCIR_CACHELNSZ, RT_PCI_CACHE_LINE_SIZE);
rt_pci_write_config_u8(pdev, PCIR_LATTIMER, 0x80);
return err;
}
-struct rt_pci_bus_resource *rt_pci_find_bar(struct rt_pci_device* pdev,rt_ubase_t flags,int index)
+struct rt_pci_bus_resource *rt_pci_find_bar(struct rt_pci_device *pdev, rt_ubase_t flags, int index)
{
for (int i = 0; i < RT_PCI_BAR_NR_MAX; i++)
{
@@ -731,7 +822,7 @@ struct rt_pci_bus_resource *rt_pci_find_bar(struct rt_pci_device* pdev,rt_ubase_
}
void rt_pci_enum_device(struct rt_pci_bus *bus,
- rt_bool_t (callback(struct rt_pci_device *, void *)), void *data)
+ rt_bool_t(callback(struct rt_pci_device *, void *)), void *data)
{
rt_bool_t is_end = RT_FALSE;
struct rt_spinlock *lock;
@@ -859,7 +950,7 @@ void rt_pci_enum_device(struct rt_pci_bus *bus,
}
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 *id)
{
if ((id->vendor == PCI_ANY_ID || id->vendor == pdev->vendor) &&
(id->device == PCI_ANY_ID || id->device == pdev->device) &&
@@ -874,7 +965,7 @@ const struct rt_pci_device_id *rt_pci_match_id(struct rt_pci_device *pdev,
}
const struct rt_pci_device_id *rt_pci_match_ids(struct rt_pci_device *pdev,
- const struct rt_pci_device_id *ids)
+ const struct rt_pci_device_id *ids)
{
while (ids->vendor || ids->subsystem_vendor || ids->class_mask)
{
@@ -948,10 +1039,19 @@ static rt_err_t pci_probe(rt_device_t dev)
rt_pci_assign_irq(pdev);
rt_pci_enable_wake(pdev, RT_PCI_D0, RT_TRUE);
+ err = rt_pci_enable_device(pdev);
+
+ if (err)
+ {
+ rt_pci_enable_wake(pdev, RT_PCI_D0, RT_FALSE);
+ return err;
+ }
+
err = pdrv->probe(pdev);
if (err)
{
+ rt_pci_disable_device(pdev);
rt_pci_enable_wake(pdev, RT_PCI_D0, RT_FALSE);
}
@@ -1004,8 +1104,7 @@ static rt_err_t pci_shutdown(rt_device_t dev)
return RT_EOK;
}
-static struct rt_bus pci_bus =
-{
+static struct rt_bus pci_bus = {
.name = "pci",
.match = pci_match,
.probe = pci_probe,
diff --git a/components/drivers/pci/pci_ids.h b/components/drivers/pci/pci_ids.h
index 2dab735a0a..f7be3cb089 100644
--- a/components/drivers/pci/pci_ids.h
+++ b/components/drivers/pci/pci_ids.h
@@ -243,6 +243,7 @@
#define PCI_VENDOR_ID_FUNGIBLE 0x1dad
#define PCI_VENDOR_ID_HXT 0x1dbf
#define PCI_VENDOR_ID_TEKRAM 0x1de1
+#define PCI_VENDOR_ID_RPI 0x1de4
#define PCI_VENDOR_ID_TEHUTI 0x1fc9
#define PCI_VENDOR_ID_SUNIX 0x1fd4
#define PCI_VENDOR_ID_HINT 0x3388
diff --git a/components/drivers/pci/probe.c b/components/drivers/pci/probe.c
index 77cbb4185f..321d79c455 100644
--- a/components/drivers/pci/probe.c
+++ b/components/drivers/pci/probe.c
@@ -19,6 +19,8 @@
#include "procfs.h"
+static struct rt_dm_ida pci_domain_ida = RT_DM_IDA_INIT(CUSTOM);
+
rt_inline void spin_lock(struct rt_spinlock *spinlock)
{
rt_hw_spin_lock(&spinlock->lock);
@@ -65,6 +67,29 @@ rt_err_t rt_pci_host_bridge_init(struct rt_pci_host_bridge *host_bridge)
if (host_bridge->parent.ofw_node)
{
err = rt_pci_ofw_host_bridge_init(host_bridge->parent.ofw_node, host_bridge);
+
+ if (err)
+ {
+ return err;
+ }
+
+ if (host_bridge->domain == RT_UINT32_MAX)
+ {
+ host_bridge->domain = rt_dm_ida_alloc(&pci_domain_ida);
+
+ if ((int)(host_bridge->domain) < 0)
+ {
+ return -RT_EFULL;
+ }
+ }
+ else
+ {
+ if (!rt_dm_ida_take(&pci_domain_ida, host_bridge->domain))
+ {
+ LOG_E("Failed to take domain %u", host_bridge->domain);
+ return -RT_ERROR;
+ }
+ }
}
return err;
@@ -137,8 +162,8 @@ struct rt_pci_device *rt_pci_scan_single_device(struct rt_pci_bus *bus, rt_uint3
pdev->device = device;
rt_dm_dev_set_name(&pdev->parent, "%04x:%02x:%02x.%u",
- rt_pci_domain(pdev), pdev->bus->number,
- RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn));
+ rt_pci_domain(pdev), pdev->bus->number,
+ RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn));
if (rt_pci_setup_device(pdev))
{
@@ -340,7 +365,7 @@ rt_err_t rt_pci_setup_device(struct rt_pci_device *pdev)
}
rt_dm_dev_set_name(&pdev->parent, "%04x:%02x:%02x.%u", rt_pci_domain(pdev),
- pdev->bus->number, RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn));
+ pdev->bus->number, RT_PCI_SLOT(pdev->devfn), RT_PCI_FUNC(pdev->devfn));
class = pdev->class >> 8;
@@ -401,14 +426,14 @@ rt_err_t rt_pci_setup_device(struct rt_pci_device *pdev)
static struct rt_pci_bus *pci_alloc_bus(struct rt_pci_bus *parent);
static rt_err_t pci_child_bus_init(struct rt_pci_bus *bus, rt_uint32_t bus_no,
- struct rt_pci_host_bridge *host_bridge, struct rt_pci_device *pdev)
+ struct rt_pci_host_bridge *host_bridge, struct rt_pci_device *pdev)
{
rt_err_t err;
struct rt_pci_bus *parent_bus = bus->parent;
bus->sysdata = parent_bus->sysdata;
bus->self = pdev;
- bus->ops = host_bridge->child_ops ? : parent_bus->ops;
+ bus->ops = host_bridge->child_ops ?: parent_bus->ops;
bus->number = bus_no;
rt_sprintf(bus->name, "%04x:%02x", host_bridge->domain, bus_no);
@@ -422,7 +447,7 @@ static rt_err_t pci_child_bus_init(struct rt_pci_bus *bus, rt_uint32_t bus_no,
rt_pci_ofw_bus_free(bus);
LOG_E("PCI-Bus<%s> add bus failed with err = %s",
- bus->name, rt_strerror(err));
+ bus->name, rt_strerror(err));
return err;
}
@@ -432,7 +457,7 @@ static rt_err_t pci_child_bus_init(struct rt_pci_bus *bus, rt_uint32_t bus_no,
}
static rt_bool_t pci_ea_fixed_busnrs(struct rt_pci_device *pdev,
- rt_uint8_t *sec, rt_uint8_t *sub)
+ rt_uint8_t *sec, rt_uint8_t *sub)
{
int pos, offset;
rt_uint32_t dw;
@@ -448,7 +473,7 @@ static rt_bool_t pci_ea_fixed_busnrs(struct rt_pci_device *pdev,
rt_pci_read_config_u32(pdev, offset, &dw);
ea_sec = PCIM_EA_SEC_NR(dw);
ea_sub = PCIM_EA_SUB_NR(dw);
- if (ea_sec == 0 || ea_sub < ea_sec)
+ if (ea_sec == 0 || ea_sub < ea_sec)
{
return RT_FALSE;
}
@@ -459,31 +484,50 @@ static rt_bool_t pci_ea_fixed_busnrs(struct rt_pci_device *pdev,
return RT_TRUE;
}
+static rt_bool_t pci_is_pcie_port(struct rt_pci_device *pdev)
+{
+ rt_uint16_t exp_type;
+
+ if (!pdev || !rt_pci_is_pcie(pdev))
+ {
+ return RT_FALSE;
+ }
+
+ exp_type = pdev->exp_flags & PCIEM_FLAGS_TYPE;
+
+ return exp_type == PCIEM_TYPE_ROOT_PORT ||
+ exp_type == PCIEM_TYPE_DOWNSTREAM_PORT ||
+ exp_type == PCIEM_TYPE_PCIE_BRIDGE;
+}
+
static void pcie_fixup_link(struct rt_pci_device *pdev)
{
int pos = pdev->pcie_cap;
rt_uint16_t exp_lnkctl, exp_lnkctl2, exp_lnksta;
- rt_uint16_t exp_type = pdev->exp_flags & PCIEM_FLAGS_TYPE;
if ((pdev->exp_flags & PCIEM_FLAGS_VERSION) < 2)
{
return;
}
- if (exp_type != PCIEM_TYPE_ROOT_PORT &&
- exp_type != PCIEM_TYPE_DOWNSTREAM_PORT &&
- exp_type != PCIEM_TYPE_PCIE_BRIDGE)
+ if (!pci_is_pcie_port(pdev))
{
return;
}
rt_pci_read_config_u16(pdev, pos + PCIER_LINK_CTL, &exp_lnkctl);
rt_pci_read_config_u16(pdev, pos + PCIER_LINK_CTL2, &exp_lnkctl2);
+ rt_pci_read_config_u16(pdev, pos + PCIER_LINK_STA, &exp_lnksta);
+
+ if (exp_lnksta & PCIEM_LINK_STA_DL_ACTIVE)
+ {
+ return;
+ }
rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL2,
- (exp_lnkctl2 & ~PCIEM_LNKCTL2_TLS) | PCIEM_LNKCTL2_TLS_2_5GT);
+ (exp_lnkctl2 & ~PCIEM_LNKCTL2_TLS) | PCIEM_LNKCTL2_TLS_2_5GT);
rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL,
- exp_lnkctl | PCIEM_LINK_CTL_RETRAIN_LINK);
+ exp_lnkctl | PCIEM_LINK_CTL_RETRAIN_LINK);
for (int i = 0; i < 20; ++i)
{
@@ -500,15 +544,128 @@ static void pcie_fixup_link(struct rt_pci_device *pdev)
/* Fail, restore */
rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL2, exp_lnkctl2);
rt_pci_write_config_u16(pdev, pos + PCIER_LINK_CTL,
- exp_lnkctl | PCIEM_LINK_CTL_RETRAIN_LINK);
+ exp_lnkctl | PCIEM_LINK_CTL_RETRAIN_LINK);
_status_sync:
/* Wait a while for success or failure */
rt_thread_mdelay(100);
}
+static rt_bool_t pci_needs_bridge_window(struct rt_pci_device *pdev)
+{
+ if (!pdev)
+ {
+ return RT_FALSE;
+ }
+
+ if (pdev->hdr_type == PCIM_HDRTYPE_BRIDGE)
+ {
+ return RT_TRUE;
+ }
+
+ return pci_is_pcie_port(pdev);
+}
+
+static void pci_program_bridge_windows(struct rt_pci_device *bridge,
+ rt_uint64_t mem_start, rt_uint64_t mem_end,
+ rt_uint64_t pref_start, rt_uint64_t pref_end)
+{
+ rt_uint32_t l;
+ rt_uint16_t cmd;
+
+ if (!bridge || !pci_needs_bridge_window(bridge))
+ {
+ return;
+ }
+
+ if (mem_start <= mem_end)
+ {
+ l = ((rt_uint32_t)(mem_start >> 16) & 0xfff0) | (rt_uint32_t)(mem_end & 0xfff00000);
+ rt_pci_write_config_u32(bridge, PCIR_MEMBASE_1, l);
+ }
+ else
+ {
+ rt_pci_write_config_u32(bridge, PCIR_MEMBASE_1, 0x0000fff0);
+ }
+
+ if (pref_start <= pref_end)
+ {
+ rt_uint32_t bu = 0, lu = 0;
+
+ rt_pci_write_config_u32(bridge, PCIR_PMLIMITH_1, 0);
+
+ l = ((rt_uint32_t)(pref_start >> 16) & 0xfff0) | (rt_uint32_t)(pref_end & 0xfff00000);
+
+ if (pref_end > 0xffffffffULL || pref_start > 0xffffffffULL)
+ {
+ bu = rt_upper_32_bits(pref_start);
+ lu = rt_upper_32_bits(pref_end);
+ }
+
+ rt_pci_write_config_u32(bridge, PCIR_PMBASEL_1, l);
+ rt_pci_write_config_u32(bridge, PCIR_PMBASEH_1, bu);
+ rt_pci_write_config_u32(bridge, PCIR_PMLIMITH_1, lu);
+ }
+ else
+ {
+ rt_pci_write_config_u32(bridge, PCIR_PMBASEL_1, 0x0000fff0);
+ rt_pci_write_config_u32(bridge, PCIR_PMBASEH_1, 0);
+ rt_pci_write_config_u32(bridge, PCIR_PMLIMITH_1, 0);
+ }
+
+ rt_pci_read_config_u16(bridge, PCIR_COMMAND, &cmd);
+ cmd |= PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN;
+ rt_pci_write_config_u16(bridge, PCIR_COMMAND, cmd);
+}
+
+static void pci_bridge_program_host_windows(struct rt_pci_device *bridge,
+ struct rt_pci_host_bridge *host_bridge)
+{
+ rt_uint64_t mem_start = ~0ULL, mem_end = 0;
+ rt_uint64_t pref_start = ~0ULL, pref_end = 0;
+
+ if (!bridge || !host_bridge)
+ {
+ return;
+ }
+
+ for (int i = 0; i < host_bridge->bus_regions_nr; ++i)
+ {
+ rt_uint64_t start, end;
+ struct rt_pci_bus_region *region = &host_bridge->bus_regions[i];
+
+ start = region->phy_addr;
+ end = region->phy_addr + region->size - 1;
+
+ if (region->flags == PCI_BUS_REGION_F_PREFETCH)
+ {
+ if (start < pref_start)
+ {
+ pref_start = start;
+ }
+ if (end > pref_end)
+ {
+ pref_end = end;
+ }
+ }
+ else if (region->flags == PCI_BUS_REGION_F_MEM)
+ {
+ if (start < mem_start)
+ {
+ mem_start = start;
+ }
+ if (end > mem_end)
+ {
+ mem_end = end;
+ }
+ }
+ }
+
+ pci_program_bridge_windows(bridge, mem_start, mem_end, pref_start, pref_end);
+}
+
static rt_uint32_t pci_scan_bridge_extend(struct rt_pci_bus *bus, struct rt_pci_device *pdev,
- rt_uint32_t bus_no_start, rt_uint32_t buses, rt_bool_t reconfigured)
+ rt_uint32_t bus_no_start, rt_uint32_t buses, rt_bool_t reconfigured)
{
rt_bool_t fixed_buses;
rt_uint8_t fixed_sub, fixed_sec;
@@ -538,7 +695,7 @@ static rt_uint32_t pci_scan_bridge_extend(struct rt_pci_bus *bus, struct rt_pci_
}
LOG_I("Bridge configuration: primary(%02x) secondary(%02x) subordinate(%02x)",
- primary, secondary, subordinate);
+ primary, secondary, subordinate);
}
if (pdev->pcie_cap)
@@ -566,23 +723,30 @@ static rt_uint32_t pci_scan_bridge_extend(struct rt_pci_bus *bus, struct rt_pci_
/* Clear bus info */
rt_pci_write_config_u32(pdev, PCIR_PRIBUS_1, value & ~0xffffff);
- if (!(next_bus = pci_alloc_bus(bus)))
- {
- LOG_E("Alloc bus(%02x) fail", bus_no);
- goto _end;
- }
-
if (pci_child_bus_init(next_bus, bus_no, host_bridge, pdev))
{
goto _end;
}
+ spin_lock(&bus->lock);
+ rt_list_insert_before(&bus->children_nodes, &next_bus->list);
+ spin_unlock(&bus->lock);
+
/* Fill primary, secondary */
value = (buses & 0xff000000) | (bus->number << 0) | (next_bus->number << 8);
rt_pci_write_config_u32(pdev, PCIR_PRIBUS_1, value);
+ /*
+ * Open bridge MEM/prefetch windows to host ranges before downstream
+ * scan (BAR sizing/assign touches MMIO), then again after scan in
+ * case config writes disturbed the aperture.
+ */
+ pci_bridge_program_host_windows(pdev, host_bridge);
+
bus_no = rt_pci_scan_child_buses(next_bus, buses);
+ pci_bridge_program_host_windows(pdev, host_bridge);
+
/* Fill subordinate */
value |= next_bus->number + rt_list_len(&next_bus->children_nodes);
rt_pci_write_config_u32(pdev, PCIR_PRIBUS_1, value);
@@ -598,7 +762,7 @@ _end:
}
rt_uint32_t rt_pci_scan_bridge(struct rt_pci_bus *bus, struct rt_pci_device *pdev,
- rt_uint32_t bus_no_start, rt_bool_t reconfigured)
+ rt_uint32_t bus_no_start, rt_bool_t reconfigured)
{
if (!bus || !pdev)
{
@@ -610,28 +774,12 @@ rt_uint32_t rt_pci_scan_bridge(struct rt_pci_bus *bus, struct rt_pci_device *pde
rt_inline rt_bool_t only_one_child(struct rt_pci_bus *bus)
{
- struct rt_pci_device *pdev;
-
if (rt_pci_is_root_bus(bus))
{
return RT_FALSE;
}
- pdev = bus->self;
-
- if (rt_pci_is_pcie(pdev))
- {
- rt_uint16_t exp_type = pdev->exp_flags & PCIEM_FLAGS_TYPE;
-
- if (exp_type == PCIEM_TYPE_ROOT_PORT ||
- exp_type == PCIEM_TYPE_DOWNSTREAM_PORT ||
- exp_type == PCIEM_TYPE_PCIE_BRIDGE)
- {
- return RT_TRUE;
- }
- }
-
- return RT_FALSE;
+ return pci_is_pcie_port(bus->self);
}
static int next_fn(struct rt_pci_bus *bus, struct rt_pci_device *pdev, int fn)
@@ -729,8 +877,8 @@ rt_uint32_t rt_pci_scan_child_buses(struct rt_pci_bus *bus, rt_size_t buses)
bus_no = bus->number;
for (rt_uint32_t devfn = 0;
- devfn < RT_PCI_DEVFN(RT_PCI_DEVICE_MAX - 1, RT_PCI_FUNCTION_MAX - 1);
- devfn += RT_PCI_FUNCTION_MAX)
+ devfn < RT_PCI_DEVFN(RT_PCI_DEVICE_MAX - 1, RT_PCI_FUNCTION_MAX - 1);
+ devfn += RT_PCI_FUNCTION_MAX)
{
rt_pci_scan_slot(bus, devfn);
}
@@ -846,19 +994,24 @@ static rt_bool_t pci_remove_bus_device(struct rt_pci_device *pdev, void *data)
rt_err_t rt_pci_host_bridge_remove(struct rt_pci_host_bridge *host_bridge)
{
- rt_err_t err = RT_EOK;
+ if (!host_bridge)
+ {
+ return -RT_EINVAL;
+ }
- if (host_bridge && host_bridge->root_bus)
+ if (host_bridge->root_bus)
{
rt_pci_enum_device(host_bridge->root_bus, pci_remove_bus_device, RT_NULL);
host_bridge->root_bus = RT_NULL;
}
- else
+
+ if (host_bridge->domain != RT_UINT32_MAX)
{
- err = -RT_EINVAL;
+ rt_dm_ida_free(&pci_domain_ida, host_bridge->domain);
+ host_bridge->domain = RT_UINT32_MAX;
}
- return err;
+ return RT_EOK;
}
rt_err_t rt_pci_bus_remove(struct rt_pci_bus *bus)