git: 7733521e2b49 - main - dpaa/qman: per-CPU pool channel service + FQID range allocator

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Mon, 24 Aug 2026 03:11:49 UTC
The branch main has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=7733521e2b4948d5e3374b65d1af15a1b8abbf5a

commit 7733521e2b4948d5e3374b65d1af15a1b8abbf5a
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2026-08-10 13:03:46 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2026-08-24 03:11:25 +0000

    dpaa/qman: per-CPU pool channel service + FQID range allocator
    
    Add plumbing for future FMan KeyGen-driven multi-queue RX.  Pure
    infrastructure; no behavioural change for existing single-FQ
    consumers.
    
    qman:
    * New qman_percpu_channel(cpu) to get the per-CPU channel, needed for
      receive-side scaling.
    * New qman_alloc_fqid_range(count, *basep) / qman_free_fqid_range()
      reserve a contiguous FQID range so a later KeyGen-distribution
      caller can compute FQID = base + (hash & mask) and create each FQ
      individually with force_fqid=true (each landing on its own
      per-CPU channel).
    
    qman_fq_create:
    * Honor the force_fqid / fqid_or_align parameters: when force_fqid is
      set, use the caller-supplied FQID and skip the internal vmem_alloc.
      The fqids_num != 1 restriction is lifted; qman_fq_list[] now records
      the handle at every FQID slot in the range so DQRR dispatch works for
      the whole range.
    * Add fqid_count and force_fqid to struct qman_fq so qman_fq_free()
      can retire every FQ in the range.
---
 sys/dev/dpaa/qman.c     | 96 ++++++++++++++++++++++++++++++++++++++++---------
 sys/dev/dpaa/qman.h     | 15 ++++++++
 sys/dev/dpaa/qman_var.h |  4 ++-
 3 files changed, 98 insertions(+), 17 deletions(-)

diff --git a/sys/dev/dpaa/qman.c b/sys/dev/dpaa/qman.c
index 2cebae163dab..f0964502413d 100644
--- a/sys/dev/dpaa/qman.c
+++ b/sys/dev/dpaa/qman.c
@@ -446,6 +446,43 @@ qman_free_channel(int channel)
 	vmem_free(sc->sc_qpalloc, channel, 1);
 }
 
+int
+qman_percpu_channel(int cpu)
+{
+	device_t portal;
+	struct qman_portal_softc *sc;
+
+	portal = DPCPU_ID_GET(cpu, qman_affine_portal);
+	if (portal == NULL)
+		return (-1);
+
+	sc = device_get_softc(portal);
+
+	return (sc->sc_affine_channel);
+}
+
+int
+qman_alloc_fqid_range(uint32_t count, uint32_t *basep)
+{
+	struct qman_softc *sc = qman_sc;
+	vmem_addr_t base;
+	int error;
+
+	error = vmem_alloc(sc->sc_fqalloc, count, M_BESTFIT | M_NOWAIT, &base);
+	if (error != 0)
+		return (error);
+	*basep = base;
+	return (0);
+}
+
+void
+qman_free_fqid_range(uint32_t base, uint32_t count)
+{
+	struct qman_softc *sc = qman_sc;
+
+	vmem_free(sc->sc_fqalloc, base, count);
+}
+
 /**
  * @group QMan API functions implementation.
  * @{
@@ -478,14 +515,28 @@ qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq,
 
 	sc = qman_sc;
 
-	if (fqids_num != 1) {
-		device_printf(sc->sc_dev,
-		    "Only one fq allocation allowed currently\n");
-		return (NULL);
-	}
-
 	bzero(&cmd, sizeof(cmd));
-	vmem_alloc(sc->sc_fqalloc, fqids_num, M_BESTFIT | M_WAITOK, &fqid_base);
+	if (force_fqid) {
+		/*
+		 * Caller has already reserved the FQID (typically via
+		 * qman_alloc_fqid_range() for a KeyGen distribution range)
+		 * and passes the concrete FQID via fqid_or_align.  Do not
+		 * touch the vmem allocator; just record the base for
+		 * downstream book-keeping.
+		 */
+		fqid_base = fqid_or_align;
+	} else {
+		int error;
+
+		error = vmem_alloc(sc->sc_fqalloc, fqids_num,
+		    M_BESTFIT | M_WAITOK, &fqid_base);
+		if (error != 0) {
+			device_printf(sc->sc_dev,
+			    "qman_fq_create: no FQID range of %u\n",
+			    fqids_num);
+			return (NULL);
+		}
+	}
 	cmd.init_fq.fqid = fqid_base;
 	cmd.init_fq.count = fqids_num - 1;
 	cmd.init_fq.dest_chan = channel;
@@ -529,14 +580,18 @@ qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq,
 
 	critical_exit();
 	if (res == NULL || rslt != QMAN_MC_RES_OK) {
-		vmem_free(sc->sc_fqalloc, fqid_base, fqids_num);
+		if (!force_fqid)
+			vmem_free(sc->sc_fqalloc, fqid_base, fqids_num);
 		goto err;
 	}
 
 	fqh = malloc(sizeof(*fqh), M_QMAN, M_WAITOK | M_ZERO);
 	fqh->fqid = fqid_base;
+	fqh->fqid_count = fqids_num;
+	fqh->force_fqid = force_fqid;
 
-	qman_fq_list[fqid_base] = fqh;
+	for (uint32_t i = 0; i < fqids_num; i++)
+		qman_fq_list[fqid_base + i] = fqh;
 
 	return (fqh);
 
@@ -546,7 +601,7 @@ err:
 }
 
 static int
-qman_fq_retire(device_t portal, struct qman_fq *fq)
+qman_fq_retire_one(device_t portal, uint32_t fqid)
 {
 	union qman_mc_command cmd;
 	union qman_mc_result *rr;
@@ -554,7 +609,7 @@ qman_fq_retire(device_t portal, struct qman_fq *fq)
 	bzero(&cmd, sizeof(cmd));
 
 	cmd.alter_fqs.verb = QCSP_VERB_ALTER_FQ_RETIRE;
-	cmd.alter_fqs.fqid = fq->fqid;
+	cmd.alter_fqs.fqid = fqid;
 	rr = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd);
 	if (rr == NULL)
 		return (ETIMEDOUT);
@@ -573,18 +628,27 @@ int
 qman_fq_free(struct qman_fq *fq)
 {
 	struct qman_softc *sc;
+	device_t portal;
 	int error;
 
 	sc = qman_sc;
 
 	critical_enter();
-	error = qman_fq_retire(DPCPU_GET(qman_affine_portal), fq);
+	portal = DPCPU_GET(qman_affine_portal);
+	for (uint32_t i = 0; i < fq->fqid_count; i++) {
+		error = qman_fq_retire_one(portal, fq->fqid + i);
+		if (error != 0) {
+			critical_exit();
+			return (error);
+		}
+	}
 	/* TODO: Take FQ out of service. */
 	critical_exit();
-	if (error != 0)
-		return (error);
-	vmem_free(sc->sc_fqalloc, fq->fqid, 1);
-	qman_fq_list[fq->fqid] = NULL;
+
+	if (!fq->force_fqid)
+		vmem_free(sc->sc_fqalloc, fq->fqid, fq->fqid_count);
+	for (uint32_t i = 0; i < fq->fqid_count; i++)
+		qman_fq_list[fq->fqid + i] = NULL;
 	free(fq, M_QMAN);
 
 	return (0);
diff --git a/sys/dev/dpaa/qman.h b/sys/dev/dpaa/qman.h
index d02e6d8bf94c..f09d57dc45c6 100644
--- a/sys/dev/dpaa/qman.h
+++ b/sys/dev/dpaa/qman.h
@@ -314,6 +314,21 @@ int qman_alloc_channel(void);
  */
 void qman_free_channel(int);
 
+/*
+ * Look up the pool channel for @cpu.  Each portal has a dedicated channel, and
+ * there is one portal per CPU.
+ */
+int qman_percpu_channel(int cpu);
+
+/*
+ * Reserve a contiguous range of @count FQIDs (needed by callers that
+ * program a KeyGen-style base+mask distribution and then create the
+ * individual FQs one-by-one with force_fqid=true).  Returns 0 on
+ * success and writes the base FQID to *basep.
+ */
+int qman_alloc_fqid_range(uint32_t count, uint32_t *basep);
+void qman_free_fqid_range(uint32_t base, uint32_t count);
+
 /**
  * Poll frames from QMan.
  * This polls frames from the current software portal.
diff --git a/sys/dev/dpaa/qman_var.h b/sys/dev/dpaa/qman_var.h
index 8e30314688c0..2d64c10d534c 100644
--- a/sys/dev/dpaa/qman_var.h
+++ b/sys/dev/dpaa/qman_var.h
@@ -178,7 +178,9 @@ struct qman_mc {
 };
 
 struct qman_fq {
-	uint32_t fqid;
+	uint32_t fqid;			/* base FQID of the range */
+	uint32_t fqid_count;		/* length of the range (>=1) */
+	bool	 force_fqid;		/* caller owns the FQID allocation */
 	struct qman_cb cb;
 };