in pru_rproc.c [286:371]
static int pru_handle_intrmap(struct rproc *rproc)
{
struct device *dev = rproc->dev.parent;
struct pru_rproc *pru = rproc->priv;
struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
struct irq_fwspec fwspec;
struct device_node *parent, *irq_parent;
int i, ret = 0;
/* not having pru_interrupt_map is not an error */
if (!rsc)
return 0;
/* currently supporting only type 0 */
if (rsc->type != 0) {
dev_err(dev, "unsupported rsc type: %d\n", rsc->type);
return -EINVAL;
}
if (rsc->num_evts > MAX_PRU_SYS_EVENTS)
return -EINVAL;
if (sizeof(*rsc) + rsc->num_evts * sizeof(struct pruss_int_map) !=
pru->pru_interrupt_map_sz)
return -EINVAL;
pru->evt_count = rsc->num_evts;
pru->mapped_irq = kcalloc(pru->evt_count, sizeof(unsigned int),
GFP_KERNEL);
if (!pru->mapped_irq) {
pru->evt_count = 0;
return -ENOMEM;
}
/*
* parse and fill in system event to interrupt channel and
* channel-to-host mapping. The interrupt controller to be used
* for these mappings for a given PRU remoteproc is always its
* corresponding sibling PRUSS INTC node.
*/
parent = of_get_parent(dev_of_node(pru->dev));
if (!parent) {
kfree(pru->mapped_irq);
pru->mapped_irq = NULL;
pru->evt_count = 0;
return -ENODEV;
}
irq_parent = of_get_child_by_name(parent, "interrupt-controller");
of_node_put(parent);
if (!irq_parent) {
kfree(pru->mapped_irq);
pru->mapped_irq = NULL;
pru->evt_count = 0;
return -ENODEV;
}
fwspec.fwnode = of_node_to_fwnode(irq_parent);
fwspec.param_count = 3;
for (i = 0; i < pru->evt_count; i++) {
fwspec.param[0] = rsc->pru_intc_map[i].event;
fwspec.param[1] = rsc->pru_intc_map[i].chnl;
fwspec.param[2] = rsc->pru_intc_map[i].host;
dev_dbg(dev, "mapping%d: event %d, chnl %d, host %d\n",
i, fwspec.param[0], fwspec.param[1], fwspec.param[2]);
pru->mapped_irq[i] = irq_create_fwspec_mapping(&fwspec);
if (!pru->mapped_irq[i]) {
dev_err(dev, "failed to get virq for fw mapping %d: event %d chnl %d host %d\n",
i, fwspec.param[0], fwspec.param[1],
fwspec.param[2]);
ret = -EINVAL;
goto map_fail;
}
}
of_node_put(irq_parent);
return ret;
map_fail:
pru_dispose_irq_mapping(pru);
of_node_put(irq_parent);
return ret;
}