608 lines
20 KiB
C
608 lines
20 KiB
C
/*
|
|
* 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;
|
|
|
|
rt_bool_t pm_enabled;
|
|
|
|
struct rt_pci_bus_resource resource[RT_PCI_BAR_NR_MAX];
|
|
struct rt_pci_bus_resource rom;
|
|
|
|
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);
|
|
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;
|
|
|
|
#endif /* __PCI_H__ */
|