git: 7733521e2b49 - main - dpaa/qman: per-CPU pool channel service + FQID range allocator
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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;
};