static int pru_handle_intrmap()

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;
}