static int parse_feature_irqs()

in dfl.c [937:1007]


static int parse_feature_irqs(struct build_feature_devs_info *binfo,
			      resource_size_t ofst, u16 fid,
			      unsigned int *irq_base, unsigned int *nr_irqs)
{
	void __iomem *base = binfo->ioaddr + ofst;
	unsigned int i, ibase, inr = 0;
	int virq;
	u64 v;

	/*
	 * Ideally DFL framework should only read info from DFL header, but
	 * current version DFL only provides mmio resources information for
	 * each feature in DFL Header, no field for interrupt resources.
	 * Interrupt resource information is provided by specific mmio
	 * registers of each private feature which supports interrupt. So in
	 * order to parse and assign irq resources, DFL framework has to look
	 * into specific capability registers of these private features.
	 *
	 * Once future DFL version supports generic interrupt resource
	 * information in common DFL headers, the generic interrupt parsing
	 * code will be added. But in order to be compatible to old version
	 * DFL, the driver may still fall back to these quirks.
	 */
	switch (fid) {
	case PORT_FEATURE_ID_UINT:
		v = readq(base + PORT_UINT_CAP);
		ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
		inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
		break;
	case PORT_FEATURE_ID_ERROR:
		v = readq(base + PORT_ERROR_CAP);
		ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
		inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
		break;
	case FME_FEATURE_ID_GLOBAL_ERR:
		v = readq(base + FME_ERROR_CAP);
		ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
		inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
		break;
	}

	if (!inr) {
		*irq_base = 0;
		*nr_irqs = 0;
		return 0;
	}

	dev_dbg(binfo->dev, "feature: 0x%x, irq_base: %u, nr_irqs: %u\n",
		fid, ibase, inr);

	if (ibase + inr > binfo->nr_irqs) {
		dev_err(binfo->dev,
			"Invalid interrupt number in feature 0x%x\n", fid);
		return -EINVAL;
	}

	for (i = 0; i < inr; i++) {
		virq = binfo->irq_table[ibase + i];
		if (virq < 0 || virq > NR_IRQS) {
			dev_err(binfo->dev,
				"Invalid irq table entry for feature 0x%x\n",
				fid);
			return -EINVAL;
		}
	}

	*irq_base = ibase;
	*nr_irqs = inr;

	return 0;
}