Skip to content

Commit

Permalink
pcie: ecam: implement MSI/MSI-X interrupts setup
Browse files Browse the repository at this point in the history
This implements the msi_device_setup() callback for ECAM controllers
used with an ARM GIC ITS MSI message translater.

Signed-off-by: Neil Armstrong <[email protected]>
  • Loading branch information
superna9999 authored and carlescufi committed Mar 25, 2022
1 parent acd38cb commit d89efe0
Showing 1 changed file with 70 additions and 0 deletions.
70 changes: 70 additions & 0 deletions drivers/pcie/host/pcie_ecam.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ LOG_MODULE_REGISTER(pcie_ecam, LOG_LEVEL_ERR);
#include <device.h>
#include <drivers/pcie/pcie.h>
#include <drivers/pcie/controller.h>
#ifdef CONFIG_GIC_V3_ITS
#include <drivers/interrupt_controller/gicv3_its.h>
#endif

#define DT_DRV_COMPAT pci_host_ecam_generic

Expand Down Expand Up @@ -306,17 +309,84 @@ static bool pcie_ecam_region_translate(const struct device *dev, pcie_bdf_t bdf,
return true;
}

#if CONFIG_PCIE_MSI
static uint8_t pcie_ecam_msi_device_setup(const struct device *dev, unsigned int priority,
msi_vector_t *vectors, uint8_t n_vector)
{
#ifdef CONFIG_GIC_V3_ITS
const struct pcie_ctrl_config *cfg = (const struct pcie_ctrl_config *)dev->config;
unsigned int device_id;
pcie_bdf_t bdf;
int ret, i;

if (!n_vector) {
return 0;
}

bdf = vectors[0].bdf;

/* We do not support allocating vectors for multiple BDFs for now,
* This would need tracking vectors already allocated for a BDF and
* re-allocating a proper table in ITS for each BDF since we can't be
* sure more vectors for each BDF will be allocated later.
* Simply bail-out if it's the case here.
*/
for (i = 1; i < n_vector; i++) {
if (vectors[i].bdf != bdf) {
LOG_ERR("Multiple BDFs in a single MSI vector allocation isn't supported");
return 0;
}
}

device_id = PCI_BDF_TO_DEVID(bdf);

ret = its_setup_deviceid(cfg->msi_parent, device_id, n_vector);
if (ret) {
return 0;
}

for (i = 0; i < n_vector; i++) {
vectors[i].arch.irq = its_alloc_intid(cfg->msi_parent);
vectors[i].arch.address = its_get_msi_addr(cfg->msi_parent);
vectors[i].arch.eventid = i;
vectors[i].arch.priority = priority;

ret = its_map_intid(cfg->msi_parent, device_id,
vectors[i].arch.eventid, vectors[i].arch.irq);
if (ret) {
break;
}
}

return i;
#else
return 0;
#endif
}
#endif

static const struct pcie_ctrl_driver_api pcie_ecam_api = {
.conf_read = pcie_ecam_ctrl_conf_read,
.conf_write = pcie_ecam_ctrl_conf_write,
.region_allocate = pcie_ecam_region_allocate,
.region_get_allocate_base = pcie_ecam_region_get_allocate_base,
.region_translate = pcie_ecam_region_translate,
#if CONFIG_PCIE_MSI
.msi_device_setup = pcie_ecam_msi_device_setup,
#endif
};

#if CONFIG_PCIE_MSI
#define DEVICE_DT_GET_MSI_PARENT(n) \
.msi_parent = DEVICE_DT_GET(DT_PHANDLE(DT_DRV_INST(n), msi_parent)),
#else
#define DEVICE_DT_GET_MSI_PARENT(n)
#endif

#define PCIE_ECAM_INIT(n) \
static struct pcie_ecam_data pcie_ecam_data##n; \
static const struct pcie_ctrl_config pcie_ecam_config##n = { \
DEVICE_DT_GET_MSI_PARENT(n) \
.cfg_addr = DT_INST_REG_ADDR(n), \
.cfg_size = DT_INST_REG_SIZE(n), \
.ranges_count = DT_NUM_RANGES(DT_DRV_INST(n)), \
Expand Down

0 comments on commit d89efe0

Please sign in to comment.