static int qman_create_portal()

in fsl/qbman/qman.c [1223:1353]


static int qman_create_portal(struct qman_portal *portal,
			      const struct qm_portal_config *c,
			      const struct qman_cgrs *cgrs)
{
	struct qm_portal *p;
	int ret;
	u32 isdr;

	p = &portal->p;

#ifdef CONFIG_FSL_PAMU
	/* PAMU is required for stashing */
	portal->use_eqcr_ci_stashing = ((qman_ip_rev >= QMAN_REV30) ? 1 : 0);
#else
	portal->use_eqcr_ci_stashing = 0;
#endif
	/*
	 * prep the low-level portal struct with the mapped addresses from the
	 * config, everything that follows depends on it and "config" is more
	 * for (de)reference
	 */
	p->addr.ce = c->addr_virt_ce;
	p->addr.ce_be = c->addr_virt_ce;
	p->addr.ci = c->addr_virt_ci;
	/*
	 * If CI-stashing is used, the current defaults use a threshold of 3,
	 * and stash with high-than-DQRR priority.
	 */
	if (qm_eqcr_init(p, qm_eqcr_pvb,
			portal->use_eqcr_ci_stashing ? 3 : 0, 1)) {
		dev_err(c->dev, "EQCR initialisation failed\n");
		goto fail_eqcr;
	}
	if (qm_dqrr_init(p, c, qm_dqrr_dpush, qm_dqrr_pvb,
			qm_dqrr_cdc, DQRR_MAXFILL)) {
		dev_err(c->dev, "DQRR initialisation failed\n");
		goto fail_dqrr;
	}
	if (qm_mr_init(p, qm_mr_pvb, qm_mr_cci)) {
		dev_err(c->dev, "MR initialisation failed\n");
		goto fail_mr;
	}
	if (qm_mc_init(p)) {
		dev_err(c->dev, "MC initialisation failed\n");
		goto fail_mc;
	}
	/* static interrupt-gating controls */
	qm_dqrr_set_ithresh(p, QMAN_PIRQ_DQRR_ITHRESH);
	qm_mr_set_ithresh(p, QMAN_PIRQ_MR_ITHRESH);
	qm_out(p, QM_REG_ITPR, QMAN_PIRQ_IPERIOD);
	portal->cgrs = kmalloc_array(2, sizeof(*cgrs), GFP_KERNEL);
	if (!portal->cgrs)
		goto fail_cgrs;
	/* initial snapshot is no-depletion */
	qman_cgrs_init(&portal->cgrs[1]);
	if (cgrs)
		portal->cgrs[0] = *cgrs;
	else
		/* if the given mask is NULL, assume all CGRs can be seen */
		qman_cgrs_fill(&portal->cgrs[0]);
	INIT_LIST_HEAD(&portal->cgr_cbs);
	spin_lock_init(&portal->cgr_lock);
	INIT_WORK(&portal->congestion_work, qm_congestion_task);
	INIT_WORK(&portal->mr_work, qm_mr_process_task);
	portal->bits = 0;
	portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 |
			QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS |
			QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED;
	isdr = 0xffffffff;
	qm_out(p, QM_REG_ISDR, isdr);
	portal->irq_sources = 0;
	qm_out(p, QM_REG_IER, 0);
	snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
	qm_out(p, QM_REG_IIR, 1);
	if (request_irq(c->irq, portal_isr, 0, portal->irqname,	portal)) {
		dev_err(c->dev, "request_irq() failed\n");
		goto fail_irq;
	}

	if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
		goto fail_affinity;

	/* Need EQCR to be empty before continuing */
	isdr &= ~QM_PIRQ_EQCI;
	qm_out(p, QM_REG_ISDR, isdr);
	ret = qm_eqcr_get_fill(p);
	if (ret) {
		dev_err(c->dev, "EQCR unclean\n");
		goto fail_eqcr_empty;
	}
	isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI);
	qm_out(p, QM_REG_ISDR, isdr);
	if (qm_dqrr_current(p)) {
		dev_dbg(c->dev, "DQRR unclean\n");
		qm_dqrr_cdc_consume_n(p, 0xffff);
	}
	if (qm_mr_current(p) && drain_mr_fqrni(p)) {
		/* special handling, drain just in case it's a few FQRNIs */
		const union qm_mr_entry *e = qm_mr_current(p);

		dev_err(c->dev, "MR dirty, VB 0x%x, rc 0x%x, addr 0x%llx\n",
			e->verb, e->ern.rc, qm_fd_addr_get64(&e->ern.fd));
		goto fail_dqrr_mr_empty;
	}
	/* Success */
	portal->config = c;
	qm_out(p, QM_REG_ISR, 0xffffffff);
	qm_out(p, QM_REG_ISDR, 0);
	if (!qman_requires_cleanup())
		qm_out(p, QM_REG_IIR, 0);
	/* Write a sane SDQCR */
	qm_dqrr_sdqcr_set(p, portal->sdqcr);
	return 0;

fail_dqrr_mr_empty:
fail_eqcr_empty:
fail_affinity:
	free_irq(c->irq, portal);
fail_irq:
	kfree(portal->cgrs);
fail_cgrs:
	qm_mc_finish(p);
fail_mc:
	qm_mr_finish(p);
fail_mr:
	qm_dqrr_finish(p);
fail_dqrr:
	qm_eqcr_finish(p);
fail_eqcr:
	return -EIO;
}