git: 890309a67b50 - stable/14 - gve: Allocate qpl per ring at ring allocation time
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 18 Apr 2025 14:00:17 UTC
The branch stable/14 has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=890309a67b50c3b87f12e33bcc157e0757497ad3
commit 890309a67b50c3b87f12e33bcc157e0757497ad3
Author: Vee Agarwal <veethebee@google.com>
AuthorDate: 2025-04-04 22:53:31 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2025-04-18 13:52:07 +0000
gve: Allocate qpl per ring at ring allocation time
Every tx and rx ring has its own queue-page-list (QPL) that serves as
the bounce buffer. Previously we were allocating QPLs for all queues
before the queues themselves were allocated and later associating a QPL
with a queue. This is avoidable complexity: it is much more natural for
each queue to allocate and free its own QPL.
Signed-off-by: Vee Agarwal <veethebee@google.com>
Reviewed by: markj
MFC after: 2 weeks
Differential Revision: https://reviews.freebsd.org/D49426
(cherry picked from commit f8ed8382daf4b9a97056b1dba4fe4e5cb4f7485c)
---
sys/dev/gve/gve.h | 6 +-
sys/dev/gve/gve_main.c | 8 ---
sys/dev/gve/gve_qpl.c | 174 +++++++++++++++++------------------------------
sys/dev/gve/gve_rx.c | 15 +++-
sys/dev/gve/gve_rx_dqo.c | 15 +++-
sys/dev/gve/gve_tx.c | 12 +++-
sys/dev/gve/gve_tx_dqo.c | 16 ++++-
7 files changed, 114 insertions(+), 132 deletions(-)
diff --git a/sys/dev/gve/gve.h b/sys/dev/gve/gve.h
index 39965c8669cf..bf15eb3ccabc 100644
--- a/sys/dev/gve/gve.h
+++ b/sys/dev/gve/gve.h
@@ -542,7 +542,6 @@ struct gve_priv {
struct gve_irq_db *irq_db_indices;
enum gve_queue_format queue_format;
- struct gve_queue_page_list *qpls;
struct gve_queue_config tx_cfg;
struct gve_queue_config rx_cfg;
uint32_t num_queues;
@@ -629,8 +628,9 @@ void gve_db_bar_write_4(struct gve_priv *priv, bus_size_t offset, uint32_t val);
void gve_db_bar_dqo_write_4(struct gve_priv *priv, bus_size_t offset, uint32_t val);
/* QPL (Queue Page List) functions defined in gve_qpl.c */
-int gve_alloc_qpls(struct gve_priv *priv);
-void gve_free_qpls(struct gve_priv *priv);
+struct gve_queue_page_list *gve_alloc_qpl(struct gve_priv *priv, uint32_t id,
+ int npages, bool single_kva);
+void gve_free_qpl(struct gve_priv *priv, struct gve_queue_page_list *qpl);
int gve_register_qpls(struct gve_priv *priv);
int gve_unregister_qpls(struct gve_priv *priv);
void gve_mextadd_free(struct mbuf *mbuf);
diff --git a/sys/dev/gve/gve_main.c b/sys/dev/gve/gve_main.c
index 8e764f9660d7..72e7fc2e3f89 100644
--- a/sys/dev/gve/gve_main.c
+++ b/sys/dev/gve/gve_main.c
@@ -482,8 +482,6 @@ gve_free_rings(struct gve_priv *priv)
gve_free_irqs(priv);
gve_free_tx_rings(priv);
gve_free_rx_rings(priv);
- if (gve_is_qpl(priv))
- gve_free_qpls(priv);
}
static int
@@ -491,12 +489,6 @@ gve_alloc_rings(struct gve_priv *priv)
{
int err;
- if (gve_is_qpl(priv)) {
- err = gve_alloc_qpls(priv);
- if (err != 0)
- goto abort;
- }
-
err = gve_alloc_rx_rings(priv);
if (err != 0)
goto abort;
diff --git a/sys/dev/gve/gve_qpl.c b/sys/dev/gve/gve_qpl.c
index 1fcc2b5365c9..0e7098dcd4a1 100644
--- a/sys/dev/gve/gve_qpl.c
+++ b/sys/dev/gve/gve_qpl.c
@@ -36,28 +36,9 @@
static MALLOC_DEFINE(M_GVE_QPL, "gve qpl", "gve qpl allocations");
-static uint32_t
-gve_num_tx_qpls(struct gve_priv *priv)
-{
- if (!gve_is_qpl(priv))
- return (0);
-
- return (priv->tx_cfg.max_queues);
-}
-
-static uint32_t
-gve_num_rx_qpls(struct gve_priv *priv)
-{
- if (!gve_is_qpl(priv))
- return (0);
-
- return (priv->rx_cfg.max_queues);
-}
-
-static void
-gve_free_qpl(struct gve_priv *priv, uint32_t id)
+void
+gve_free_qpl(struct gve_priv *priv, struct gve_queue_page_list *qpl)
{
- struct gve_queue_page_list *qpl = &priv->qpls[id];
int i;
for (i = 0; i < qpl->num_dmas; i++) {
@@ -92,12 +73,14 @@ gve_free_qpl(struct gve_priv *priv, uint32_t id)
if (qpl->dmas != NULL)
free(qpl->dmas, M_GVE_QPL);
+
+ free(qpl, M_GVE_QPL);
}
-static int
+struct gve_queue_page_list *
gve_alloc_qpl(struct gve_priv *priv, uint32_t id, int npages, bool single_kva)
{
- struct gve_queue_page_list *qpl = &priv->qpls[id];
+ struct gve_queue_page_list *qpl;
int err;
int i;
@@ -105,9 +88,12 @@ gve_alloc_qpl(struct gve_priv *priv, uint32_t id, int npages, bool single_kva)
device_printf(priv->dev, "Reached max number of registered pages %ju > %ju\n",
(uintmax_t)npages + priv->num_registered_pages,
(uintmax_t)priv->max_registered_pages);
- return (EINVAL);
+ return (NULL);
}
+ qpl = malloc(sizeof(struct gve_queue_page_list), M_GVE_QPL,
+ M_WAITOK | M_ZERO);
+
qpl->id = id;
qpl->num_pages = 0;
qpl->num_dmas = 0;
@@ -163,126 +149,90 @@ gve_alloc_qpl(struct gve_priv *priv, uint32_t id, int npages, bool single_kva)
priv->num_registered_pages++;
}
- return (0);
+ return (qpl);
abort:
- gve_free_qpl(priv, id);
- return (err);
+ gve_free_qpl(priv, qpl);
+ return (NULL);
}
-void
-gve_free_qpls(struct gve_priv *priv)
-{
- int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
- int i;
-
- if (num_qpls == 0)
- return;
-
- if (priv->qpls != NULL) {
- for (i = 0; i < num_qpls; i++)
- gve_free_qpl(priv, i);
- free(priv->qpls, M_GVE_QPL);
- priv->qpls = NULL;
- }
-}
-
-int gve_alloc_qpls(struct gve_priv *priv)
+int
+gve_register_qpls(struct gve_priv *priv)
{
- int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
- int num_pages;
+ struct gve_ring_com *com;
+ struct gve_tx_ring *tx;
+ struct gve_rx_ring *rx;
int err;
int i;
- if (num_qpls == 0)
+ if (gve_get_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK))
return (0);
- priv->qpls = malloc(num_qpls * sizeof(*priv->qpls), M_GVE_QPL,
- M_WAITOK | M_ZERO);
-
- num_pages = gve_is_gqi(priv) ?
- priv->tx_desc_cnt / GVE_QPL_DIVISOR :
- GVE_TX_NUM_QPL_PAGES_DQO;
- for (i = 0; i < gve_num_tx_qpls(priv); i++) {
- err = gve_alloc_qpl(priv, i, num_pages,
- /*single_kva=*/true);
- if (err != 0)
- goto abort;
- }
-
- num_pages = gve_is_gqi(priv) ? priv->rx_desc_cnt : GVE_RX_NUM_QPL_PAGES_DQO;
- for (; i < num_qpls; i++) {
- err = gve_alloc_qpl(priv, i, num_pages, /*single_kva=*/false);
- if (err != 0)
- goto abort;
- }
-
- return (0);
-
-abort:
- gve_free_qpls(priv);
- return (err);
-}
-
-static int
-gve_unregister_n_qpls(struct gve_priv *priv, int n)
-{
- int err;
- int i;
-
- for (i = 0; i < n; i++) {
- err = gve_adminq_unregister_page_list(priv, priv->qpls[i].id);
+ /* Register TX qpls */
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ tx = &priv->tx[i];
+ com = &tx->com;
+ err = gve_adminq_register_page_list(priv, com->qpl);
if (err != 0) {
device_printf(priv->dev,
- "Failed to unregister qpl %d, err: %d\n",
- priv->qpls[i].id, err);
+ "Failed to register qpl %d, err: %d\n",
+ com->qpl->id, err);
+ /* Caller schedules a reset when this fails */
+ return (err);
}
}
- if (err != 0)
- return (err);
-
- return (0);
-}
-
-int
-gve_register_qpls(struct gve_priv *priv)
-{
- int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
- int err;
- int i;
-
- if (gve_get_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK))
- return (0);
-
- for (i = 0; i < num_qpls; i++) {
- err = gve_adminq_register_page_list(priv, &priv->qpls[i]);
+ /* Register RX qpls */
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ rx = &priv->rx[i];
+ com = &rx->com;
+ err = gve_adminq_register_page_list(priv, com->qpl);
if (err != 0) {
device_printf(priv->dev,
"Failed to register qpl %d, err: %d\n",
- priv->qpls[i].id, err);
- goto abort;
+ com->qpl->id, err);
+ /* Caller schedules a reset when this fails */
+ return (err);
}
}
-
gve_set_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK);
return (0);
-
-abort:
- gve_unregister_n_qpls(priv, i);
- return (err);
}
int
gve_unregister_qpls(struct gve_priv *priv)
{
- int num_qpls = gve_num_tx_qpls(priv) + gve_num_rx_qpls(priv);
int err;
+ int i;
+ struct gve_ring_com *com;
+ struct gve_tx_ring *tx;
+ struct gve_rx_ring *rx;
if (!gve_get_state_flag(priv, GVE_STATE_FLAG_QPLREG_OK))
return (0);
- err = gve_unregister_n_qpls(priv, num_qpls);
+ for (i = 0; i < priv->tx_cfg.num_queues; i++) {
+ tx = &priv->tx[i];
+ com = &tx->com;
+ err = gve_adminq_unregister_page_list(priv, com->qpl->id);
+ if (err != 0) {
+ device_printf(priv->dev,
+ "Failed to unregister qpl %d, err: %d\n",
+ com->qpl->id, err);
+ }
+ }
+
+ for (i = 0; i < priv->rx_cfg.num_queues; i++) {
+ rx = &priv->rx[i];
+ com = &rx->com;
+ err = gve_adminq_unregister_page_list(priv, com->qpl->id);
+ if (err != 0) {
+ device_printf(priv->dev,
+ "Failed to unregister qpl %d, err: %d\n",
+ com->qpl->id, err);
+ }
+ }
+
if (err != 0)
return (err);
diff --git a/sys/dev/gve/gve_rx.c b/sys/dev/gve/gve_rx.c
index e540ad6f4c11..e1a228c0e69c 100644
--- a/sys/dev/gve/gve_rx.c
+++ b/sys/dev/gve/gve_rx.c
@@ -36,6 +36,7 @@ static void
gve_rx_free_ring_gqi(struct gve_priv *priv, int i)
{
struct gve_rx_ring *rx = &priv->rx[i];
+ struct gve_ring_com *com = &rx->com;
if (rx->page_info != NULL) {
free(rx->page_info, M_GVE);
@@ -51,6 +52,11 @@ gve_rx_free_ring_gqi(struct gve_priv *priv, int i)
gve_dma_free_coherent(&rx->desc_ring_mem);
rx->desc_ring = NULL;
}
+
+ if (com->qpl != NULL) {
+ gve_free_qpl(priv, com->qpl);
+ com->qpl = NULL;
+ }
}
static void
@@ -113,10 +119,13 @@ gve_rx_alloc_ring_gqi(struct gve_priv *priv, int i)
rx->mask = priv->rx_pages_per_qpl - 1;
rx->desc_ring = rx->desc_ring_mem.cpu_addr;
- com->qpl = &priv->qpls[priv->tx_cfg.max_queues + i];
+ com->qpl = gve_alloc_qpl(priv, i + priv->tx_cfg.max_queues,
+ priv->rx_desc_cnt, /*single_kva=*/false);
if (com->qpl == NULL) {
- device_printf(priv->dev, "No QPL left for rx ring %d", i);
- return (ENOMEM);
+ device_printf(priv->dev,
+ "Failed to alloc QPL for rx ring %d", i);
+ err = ENOMEM;
+ goto abort;
}
rx->page_info = malloc(priv->rx_desc_cnt * sizeof(*rx->page_info),
diff --git a/sys/dev/gve/gve_rx_dqo.c b/sys/dev/gve/gve_rx_dqo.c
index 6ce9ddd887d0..a499ac9d3c6a 100644
--- a/sys/dev/gve/gve_rx_dqo.c
+++ b/sys/dev/gve/gve_rx_dqo.c
@@ -58,6 +58,7 @@ void
gve_rx_free_ring_dqo(struct gve_priv *priv, int i)
{
struct gve_rx_ring *rx = &priv->rx[i];
+ struct gve_ring_com *com = &rx->com;
int j;
if (rx->dqo.compl_ring != NULL) {
@@ -86,6 +87,11 @@ gve_rx_free_ring_dqo(struct gve_priv *priv, int i)
if (!gve_is_qpl(priv) && rx->dqo.buf_dmatag)
bus_dma_tag_destroy(rx->dqo.buf_dmatag);
+
+ if (com->qpl != NULL) {
+ gve_free_qpl(priv, com->qpl);
+ com->qpl = NULL;
+ }
}
int
@@ -123,10 +129,13 @@ gve_rx_alloc_ring_dqo(struct gve_priv *priv, int i)
M_GVE, M_WAITOK | M_ZERO);
if (gve_is_qpl(priv)) {
- rx->com.qpl = &priv->qpls[priv->tx_cfg.max_queues + i];
+ rx->com.qpl = gve_alloc_qpl(priv, i + priv->tx_cfg.max_queues,
+ GVE_RX_NUM_QPL_PAGES_DQO, /*single_kva=*/false);
if (rx->com.qpl == NULL) {
- device_printf(priv->dev, "No QPL left for rx ring %d", i);
- return (ENOMEM);
+ device_printf(priv->dev,
+ "Failed to alloc QPL for rx ring %d", i);
+ err = ENOMEM;
+ goto abort;
}
return (0);
}
diff --git a/sys/dev/gve/gve_tx.c b/sys/dev/gve/gve_tx.c
index 04dde4f1a79b..e594c66149bc 100644
--- a/sys/dev/gve/gve_tx.c
+++ b/sys/dev/gve/gve_tx.c
@@ -52,6 +52,7 @@ static void
gve_tx_free_ring_gqi(struct gve_priv *priv, int i)
{
struct gve_tx_ring *tx = &priv->tx[i];
+ struct gve_ring_com *com = &tx->com;
if (tx->desc_ring != NULL) {
gve_dma_free_coherent(&tx->desc_ring_mem);
@@ -62,6 +63,11 @@ gve_tx_free_ring_gqi(struct gve_priv *priv, int i)
free(tx->info, M_GVE);
tx->info = NULL;
}
+
+ if (com->qpl != NULL) {
+ gve_free_qpl(priv, com->qpl);
+ com->qpl = NULL;
+ }
}
static void
@@ -109,9 +115,11 @@ gve_tx_alloc_ring_gqi(struct gve_priv *priv, int i)
}
tx->desc_ring = tx->desc_ring_mem.cpu_addr;
- com->qpl = &priv->qpls[i];
+ com->qpl = gve_alloc_qpl(priv, i, priv->tx_desc_cnt / GVE_QPL_DIVISOR,
+ /*single_kva=*/true);
if (com->qpl == NULL) {
- device_printf(priv->dev, "No QPL left for tx ring %d\n", i);
+ device_printf(priv->dev,
+ "Failed to alloc QPL for tx ring %d\n", i);
err = ENOMEM;
goto abort;
}
diff --git a/sys/dev/gve/gve_tx_dqo.c b/sys/dev/gve/gve_tx_dqo.c
index bf314ef95173..7361d47b8ce6 100644
--- a/sys/dev/gve/gve_tx_dqo.c
+++ b/sys/dev/gve/gve_tx_dqo.c
@@ -75,6 +75,7 @@ void
gve_tx_free_ring_dqo(struct gve_priv *priv, int i)
{
struct gve_tx_ring *tx = &priv->tx[i];
+ struct gve_ring_com *com = &tx->com;
int j;
if (tx->dqo.desc_ring != NULL) {
@@ -109,6 +110,11 @@ gve_tx_free_ring_dqo(struct gve_priv *priv, int i)
free(tx->dqo.qpl_bufs, M_GVE);
tx->dqo.qpl_bufs = NULL;
}
+
+ if (com->qpl != NULL) {
+ gve_free_qpl(priv, com->qpl);
+ com->qpl = NULL;
+ }
}
static int
@@ -210,7 +216,15 @@ gve_tx_alloc_ring_dqo(struct gve_priv *priv, int i)
if (gve_is_qpl(priv)) {
int qpl_buf_cnt;
- tx->com.qpl = &priv->qpls[i];
+ tx->com.qpl = gve_alloc_qpl(priv, i, GVE_TX_NUM_QPL_PAGES_DQO,
+ /*single_kva*/false);
+ if (tx->com.qpl == NULL) {
+ device_printf(priv->dev,
+ "Failed to alloc QPL for tx ring %d", i);
+ err = ENOMEM;
+ goto abort;
+ }
+
qpl_buf_cnt = GVE_TX_BUFS_PER_PAGE_DQO *
tx->com.qpl->num_pages;