xref: /freebsd/sys/dev/gve/gve_utils.c (revision e0464f74d5579e1538ce741b0a15e6604dbc53c4)
154dfc97bSShailend Chand /*-
254dfc97bSShailend Chand  * SPDX-License-Identifier: BSD-3-Clause
354dfc97bSShailend Chand  *
4d438b4efSShailend Chand  * Copyright (c) 2023-2024 Google LLC
554dfc97bSShailend Chand  *
654dfc97bSShailend Chand  * Redistribution and use in source and binary forms, with or without modification,
754dfc97bSShailend Chand  * are permitted provided that the following conditions are met:
854dfc97bSShailend Chand  *
954dfc97bSShailend Chand  * 1. Redistributions of source code must retain the above copyright notice, this
1054dfc97bSShailend Chand  *    list of conditions and the following disclaimer.
1154dfc97bSShailend Chand  *
1254dfc97bSShailend Chand  * 2. Redistributions in binary form must reproduce the above copyright notice,
1354dfc97bSShailend Chand  *    this list of conditions and the following disclaimer in the documentation
1454dfc97bSShailend Chand  *    and/or other materials provided with the distribution.
1554dfc97bSShailend Chand  *
1654dfc97bSShailend Chand  * 3. Neither the name of the copyright holder nor the names of its contributors
1754dfc97bSShailend Chand  *    may be used to endorse or promote products derived from this software without
1854dfc97bSShailend Chand  *    specific prior written permission.
1954dfc97bSShailend Chand  *
2054dfc97bSShailend Chand  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
2154dfc97bSShailend Chand  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2254dfc97bSShailend Chand  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2354dfc97bSShailend Chand  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
2454dfc97bSShailend Chand  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2554dfc97bSShailend Chand  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2654dfc97bSShailend Chand  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2754dfc97bSShailend Chand  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2854dfc97bSShailend Chand  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2954dfc97bSShailend Chand  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3054dfc97bSShailend Chand  */
3154dfc97bSShailend Chand #include "gve.h"
32d438b4efSShailend Chand #include "gve_dqo.h"
3354dfc97bSShailend Chand 
3454dfc97bSShailend Chand uint32_t
gve_reg_bar_read_4(struct gve_priv * priv,bus_size_t offset)3554dfc97bSShailend Chand gve_reg_bar_read_4(struct gve_priv *priv, bus_size_t offset)
3654dfc97bSShailend Chand {
3754dfc97bSShailend Chand 	return (be32toh(bus_read_4(priv->reg_bar, offset)));
3854dfc97bSShailend Chand }
3954dfc97bSShailend Chand 
4054dfc97bSShailend Chand void
gve_reg_bar_write_4(struct gve_priv * priv,bus_size_t offset,uint32_t val)4154dfc97bSShailend Chand gve_reg_bar_write_4(struct gve_priv *priv, bus_size_t offset, uint32_t val)
4254dfc97bSShailend Chand {
4354dfc97bSShailend Chand 	bus_write_4(priv->reg_bar, offset, htobe32(val));
4454dfc97bSShailend Chand }
4554dfc97bSShailend Chand 
4654dfc97bSShailend Chand void
gve_db_bar_write_4(struct gve_priv * priv,bus_size_t offset,uint32_t val)4754dfc97bSShailend Chand gve_db_bar_write_4(struct gve_priv *priv, bus_size_t offset, uint32_t val)
4854dfc97bSShailend Chand {
4954dfc97bSShailend Chand 	bus_write_4(priv->db_bar, offset, htobe32(val));
5054dfc97bSShailend Chand }
5154dfc97bSShailend Chand 
5254dfc97bSShailend Chand void
gve_db_bar_dqo_write_4(struct gve_priv * priv,bus_size_t offset,uint32_t val)53d438b4efSShailend Chand gve_db_bar_dqo_write_4(struct gve_priv *priv, bus_size_t offset, uint32_t val)
54d438b4efSShailend Chand {
55d438b4efSShailend Chand 	bus_write_4(priv->db_bar, offset, val);
56d438b4efSShailend Chand }
57d438b4efSShailend Chand 
58d438b4efSShailend Chand void
gve_alloc_counters(counter_u64_t * stat,int num_stats)5954dfc97bSShailend Chand gve_alloc_counters(counter_u64_t *stat, int num_stats)
6054dfc97bSShailend Chand {
6154dfc97bSShailend Chand 	int i;
6254dfc97bSShailend Chand 
6354dfc97bSShailend Chand 	for (i = 0; i < num_stats; i++)
6454dfc97bSShailend Chand 		stat[i] = counter_u64_alloc(M_WAITOK);
6554dfc97bSShailend Chand }
6654dfc97bSShailend Chand 
6754dfc97bSShailend Chand void
gve_free_counters(counter_u64_t * stat,int num_stats)6854dfc97bSShailend Chand gve_free_counters(counter_u64_t *stat, int num_stats)
6954dfc97bSShailend Chand {
7054dfc97bSShailend Chand 	int i;
7154dfc97bSShailend Chand 
7254dfc97bSShailend Chand 	for (i = 0; i < num_stats; i++)
7354dfc97bSShailend Chand 		counter_u64_free(stat[i]);
7454dfc97bSShailend Chand }
7554dfc97bSShailend Chand 
7654dfc97bSShailend Chand /* Currently assumes a single segment. */
7754dfc97bSShailend Chand static void
gve_dmamap_load_callback(void * arg,bus_dma_segment_t * segs,int nseg,int error)7854dfc97bSShailend Chand gve_dmamap_load_callback(void *arg, bus_dma_segment_t *segs, int nseg,
7954dfc97bSShailend Chand     int error)
8054dfc97bSShailend Chand {
8154dfc97bSShailend Chand 	if (error == 0)
8254dfc97bSShailend Chand 		*(bus_addr_t *) arg = segs[0].ds_addr;
8354dfc97bSShailend Chand }
8454dfc97bSShailend Chand 
8554dfc97bSShailend Chand int
gve_dma_alloc_coherent(struct gve_priv * priv,int size,int align,struct gve_dma_handle * dma)8654dfc97bSShailend Chand gve_dma_alloc_coherent(struct gve_priv *priv, int size, int align,
8754dfc97bSShailend Chand     struct gve_dma_handle *dma)
8854dfc97bSShailend Chand {
8954dfc97bSShailend Chand 	int err;
9054dfc97bSShailend Chand 	device_t dev = priv->dev;
9154dfc97bSShailend Chand 
9254dfc97bSShailend Chand 	err = bus_dma_tag_create(
9354dfc97bSShailend Chand 	    bus_get_dma_tag(dev),	/* parent */
9454dfc97bSShailend Chand 	    align, 0,			/* alignment, bounds */
9554dfc97bSShailend Chand 	    BUS_SPACE_MAXADDR,		/* lowaddr */
9654dfc97bSShailend Chand 	    BUS_SPACE_MAXADDR,		/* highaddr */
9754dfc97bSShailend Chand 	    NULL, NULL,			/* filter, filterarg */
9854dfc97bSShailend Chand 	    size,			/* maxsize */
9954dfc97bSShailend Chand 	    1,				/* nsegments */
10054dfc97bSShailend Chand 	    size,			/* maxsegsize */
10154dfc97bSShailend Chand 	    BUS_DMA_ALLOCNOW,		/* flags */
10254dfc97bSShailend Chand 	    NULL,			/* lockfunc */
10354dfc97bSShailend Chand 	    NULL,			/* lockarg */
10454dfc97bSShailend Chand 	    &dma->tag);
10554dfc97bSShailend Chand 	if (err != 0) {
10654dfc97bSShailend Chand 		device_printf(dev, "%s: bus_dma_tag_create failed: %d\n",
10754dfc97bSShailend Chand 		    __func__, err);
10854dfc97bSShailend Chand 		goto clear_tag;
10954dfc97bSShailend Chand 	}
11054dfc97bSShailend Chand 
11154dfc97bSShailend Chand 	err = bus_dmamem_alloc(dma->tag, (void **) &dma->cpu_addr,
11254dfc97bSShailend Chand 	    BUS_DMA_WAITOK | BUS_DMA_COHERENT | BUS_DMA_ZERO,
11354dfc97bSShailend Chand 	    &dma->map);
11454dfc97bSShailend Chand 	if (err != 0) {
11554dfc97bSShailend Chand 		device_printf(dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n",
11654dfc97bSShailend Chand 		    __func__, (uintmax_t)size, err);
11754dfc97bSShailend Chand 		goto destroy_tag;
11854dfc97bSShailend Chand 	}
11954dfc97bSShailend Chand 
12054dfc97bSShailend Chand 	/* An address set by the callback will never be -1 */
12154dfc97bSShailend Chand 	dma->bus_addr = (bus_addr_t)-1;
12254dfc97bSShailend Chand 	err = bus_dmamap_load(dma->tag, dma->map, dma->cpu_addr, size,
12354dfc97bSShailend Chand 	    gve_dmamap_load_callback, &dma->bus_addr, BUS_DMA_NOWAIT);
12454dfc97bSShailend Chand 	if (err != 0 || dma->bus_addr == (bus_addr_t)-1) {
12554dfc97bSShailend Chand 		device_printf(dev, "%s: bus_dmamap_load failed: %d\n", __func__, err);
12654dfc97bSShailend Chand 		goto free_mem;
12754dfc97bSShailend Chand 	}
12854dfc97bSShailend Chand 
12954dfc97bSShailend Chand 	return (0);
13054dfc97bSShailend Chand 
13154dfc97bSShailend Chand free_mem:
13254dfc97bSShailend Chand 	bus_dmamem_free(dma->tag, dma->cpu_addr, dma->map);
13354dfc97bSShailend Chand destroy_tag:
13454dfc97bSShailend Chand 	bus_dma_tag_destroy(dma->tag);
13554dfc97bSShailend Chand clear_tag:
13654dfc97bSShailend Chand 	dma->tag = NULL;
13754dfc97bSShailend Chand 
13854dfc97bSShailend Chand 	return (err);
13954dfc97bSShailend Chand }
14054dfc97bSShailend Chand 
14154dfc97bSShailend Chand void
gve_dma_free_coherent(struct gve_dma_handle * dma)14254dfc97bSShailend Chand gve_dma_free_coherent(struct gve_dma_handle *dma)
14354dfc97bSShailend Chand {
14454dfc97bSShailend Chand 	bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
14554dfc97bSShailend Chand 	bus_dmamap_unload(dma->tag, dma->map);
14654dfc97bSShailend Chand 	bus_dmamem_free(dma->tag, dma->cpu_addr, dma->map);
14754dfc97bSShailend Chand 	bus_dma_tag_destroy(dma->tag);
14854dfc97bSShailend Chand }
14954dfc97bSShailend Chand 
15054dfc97bSShailend Chand int
gve_dmamap_create(struct gve_priv * priv,int size,int align,struct gve_dma_handle * dma)15154dfc97bSShailend Chand gve_dmamap_create(struct gve_priv *priv, int size, int align,
15254dfc97bSShailend Chand     struct gve_dma_handle *dma)
15354dfc97bSShailend Chand {
15454dfc97bSShailend Chand 	int err;
15554dfc97bSShailend Chand 	device_t dev = priv->dev;
15654dfc97bSShailend Chand 
15754dfc97bSShailend Chand 	err = bus_dma_tag_create(
15854dfc97bSShailend Chand 	    bus_get_dma_tag(dev),	/* parent */
15954dfc97bSShailend Chand 	    align, 0,			/* alignment, bounds */
16054dfc97bSShailend Chand 	    BUS_SPACE_MAXADDR,		/* lowaddr */
16154dfc97bSShailend Chand 	    BUS_SPACE_MAXADDR,		/* highaddr */
16254dfc97bSShailend Chand 	    NULL, NULL,			/* filter, filterarg */
16354dfc97bSShailend Chand 	    size,			/* maxsize */
16454dfc97bSShailend Chand 	    1,				/* nsegments */
16554dfc97bSShailend Chand 	    size,			/* maxsegsize */
16654dfc97bSShailend Chand 	    BUS_DMA_ALLOCNOW,		/* flags */
16754dfc97bSShailend Chand 	    NULL,			/* lockfunc */
16854dfc97bSShailend Chand 	    NULL,			/* lockarg */
16954dfc97bSShailend Chand 	    &dma->tag);
17054dfc97bSShailend Chand 	if (err != 0) {
17154dfc97bSShailend Chand 		device_printf(dev, "%s: bus_dma_tag_create failed: %d\n",
17254dfc97bSShailend Chand 		    __func__, err);
17354dfc97bSShailend Chand 		goto clear_tag;
17454dfc97bSShailend Chand 	}
17554dfc97bSShailend Chand 
17654dfc97bSShailend Chand 	err = bus_dmamap_create(dma->tag, BUS_DMA_COHERENT, &dma->map);
17754dfc97bSShailend Chand 	if (err != 0) {
17854dfc97bSShailend Chand 		device_printf(dev, "%s: bus_dmamap_create failed: %d\n",
17954dfc97bSShailend Chand 		    __func__, err);
18054dfc97bSShailend Chand 		goto destroy_tag;
18154dfc97bSShailend Chand 	}
18254dfc97bSShailend Chand 
18354dfc97bSShailend Chand 	/* An address set by the callback will never be -1 */
18454dfc97bSShailend Chand 	dma->bus_addr = (bus_addr_t)-1;
18554dfc97bSShailend Chand 	err = bus_dmamap_load(dma->tag, dma->map, dma->cpu_addr, size,
18654dfc97bSShailend Chand 	    gve_dmamap_load_callback, &dma->bus_addr, BUS_DMA_WAITOK);
18754dfc97bSShailend Chand 	if (err != 0 || dma->bus_addr == (bus_addr_t)-1) {
18854dfc97bSShailend Chand 		device_printf(dev, "%s: bus_dmamap_load failed: %d\n",
18954dfc97bSShailend Chand 		    __func__, err);
19054dfc97bSShailend Chand 		goto destroy_map;
19154dfc97bSShailend Chand 	}
19254dfc97bSShailend Chand 
19354dfc97bSShailend Chand 	return (0);
19454dfc97bSShailend Chand 
19554dfc97bSShailend Chand destroy_map:
19654dfc97bSShailend Chand 	bus_dmamap_destroy(dma->tag, dma->map);
19754dfc97bSShailend Chand destroy_tag:
19854dfc97bSShailend Chand 	bus_dma_tag_destroy(dma->tag);
19954dfc97bSShailend Chand clear_tag:
20054dfc97bSShailend Chand 	dma->tag = NULL;
20154dfc97bSShailend Chand 
20254dfc97bSShailend Chand 	return (err);
20354dfc97bSShailend Chand }
20454dfc97bSShailend Chand 
20554dfc97bSShailend Chand void
gve_dmamap_destroy(struct gve_dma_handle * dma)20654dfc97bSShailend Chand gve_dmamap_destroy(struct gve_dma_handle *dma)
20754dfc97bSShailend Chand {
20854dfc97bSShailend Chand 	bus_dmamap_sync(dma->tag, dma->map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
20954dfc97bSShailend Chand 	bus_dmamap_unload(dma->tag, dma->map);
21054dfc97bSShailend Chand 	bus_dmamap_destroy(dma->tag, dma->map);
21154dfc97bSShailend Chand 	bus_dma_tag_destroy(dma->tag);
21254dfc97bSShailend Chand }
21354dfc97bSShailend Chand 
21454dfc97bSShailend Chand static int
gve_mgmnt_intr(void * arg)21554dfc97bSShailend Chand gve_mgmnt_intr(void *arg)
21654dfc97bSShailend Chand {
21754dfc97bSShailend Chand 	struct gve_priv *priv = arg;
21854dfc97bSShailend Chand 
21954dfc97bSShailend Chand 	taskqueue_enqueue(priv->service_tq, &priv->service_task);
22054dfc97bSShailend Chand 	return (FILTER_HANDLED);
22154dfc97bSShailend Chand }
22254dfc97bSShailend Chand 
22354dfc97bSShailend Chand void
gve_free_irqs(struct gve_priv * priv)22454dfc97bSShailend Chand gve_free_irqs(struct gve_priv *priv)
22554dfc97bSShailend Chand {
22654dfc97bSShailend Chand 	struct gve_irq *irq;
22754dfc97bSShailend Chand 	int num_irqs;
22854dfc97bSShailend Chand 	int rid;
22954dfc97bSShailend Chand 	int rc;
23054dfc97bSShailend Chand 	int i;
23154dfc97bSShailend Chand 
23254dfc97bSShailend Chand 	if (priv->irq_tbl == NULL) {
23354dfc97bSShailend Chand 		device_printf(priv->dev, "No irq table, nothing to free\n");
23454dfc97bSShailend Chand 		return;
23554dfc97bSShailend Chand 	}
23654dfc97bSShailend Chand 
237*e0464f74SVee Agarwal 	num_irqs = priv->tx_cfg.max_queues + priv->rx_cfg.max_queues + 1;
23854dfc97bSShailend Chand 
23954dfc97bSShailend Chand 	for (i = 0; i < num_irqs; i++) {
24054dfc97bSShailend Chand 		irq = &priv->irq_tbl[i];
24154dfc97bSShailend Chand 		if (irq->res == NULL)
24254dfc97bSShailend Chand 			continue;
24354dfc97bSShailend Chand 
24454dfc97bSShailend Chand 		rid = rman_get_rid(irq->res);
24554dfc97bSShailend Chand 
24654dfc97bSShailend Chand 		rc = bus_teardown_intr(priv->dev, irq->res, irq->cookie);
24754dfc97bSShailend Chand 		if (rc != 0)
24854dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to teardown irq num %d\n",
24954dfc97bSShailend Chand 			    rid);
25054dfc97bSShailend Chand 
25154dfc97bSShailend Chand 		rc = bus_release_resource(priv->dev, SYS_RES_IRQ,
25254dfc97bSShailend Chand 		    rid, irq->res);
25354dfc97bSShailend Chand 		if (rc != 0)
25454dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to release irq num %d\n",
25554dfc97bSShailend Chand 			    rid);
25654dfc97bSShailend Chand 
25754dfc97bSShailend Chand 		irq->res = NULL;
25854dfc97bSShailend Chand 		irq->cookie = NULL;
25954dfc97bSShailend Chand 	}
26054dfc97bSShailend Chand 
26154dfc97bSShailend Chand 	free(priv->irq_tbl, M_GVE);
26254dfc97bSShailend Chand 	priv->irq_tbl = NULL;
26354dfc97bSShailend Chand 
26454dfc97bSShailend Chand 	/* Safe to call even if msix was never alloced */
26554dfc97bSShailend Chand 	pci_release_msi(priv->dev);
26654dfc97bSShailend Chand }
26754dfc97bSShailend Chand 
26854dfc97bSShailend Chand int
gve_alloc_irqs(struct gve_priv * priv)26954dfc97bSShailend Chand gve_alloc_irqs(struct gve_priv *priv)
27054dfc97bSShailend Chand {
271*e0464f74SVee Agarwal 	int num_tx = priv->tx_cfg.max_queues;
272*e0464f74SVee Agarwal 	int num_rx = priv->rx_cfg.max_queues;
27354dfc97bSShailend Chand 	int req_nvecs = num_tx + num_rx + 1;
27454dfc97bSShailend Chand 	int got_nvecs = req_nvecs;
27554dfc97bSShailend Chand 	struct gve_irq *irq;
27654dfc97bSShailend Chand 	int i, j, m;
27754dfc97bSShailend Chand 	int rid;
27854dfc97bSShailend Chand 	int err;
27954dfc97bSShailend Chand 
28054dfc97bSShailend Chand 	struct gve_ring_com *com;
28154dfc97bSShailend Chand 	struct gve_rx_ring *rx;
28254dfc97bSShailend Chand 	struct gve_tx_ring *tx;
28354dfc97bSShailend Chand 
28454dfc97bSShailend Chand 	if (pci_alloc_msix(priv->dev, &got_nvecs) != 0) {
28554dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to acquire any msix vectors\n");
28654dfc97bSShailend Chand 		err = ENXIO;
28754dfc97bSShailend Chand 		goto abort;
28854dfc97bSShailend Chand 	} else if (got_nvecs != req_nvecs) {
28954dfc97bSShailend Chand 		device_printf(priv->dev, "Tried to acquire %d msix vectors, got only %d\n",
29054dfc97bSShailend Chand 		    req_nvecs, got_nvecs);
29154dfc97bSShailend Chand 		err = ENOSPC;
29254dfc97bSShailend Chand 		goto abort;
29354dfc97bSShailend Chand         }
29454dfc97bSShailend Chand 
29554dfc97bSShailend Chand 	if (bootverbose)
29654dfc97bSShailend Chand 		device_printf(priv->dev, "Enabled MSIX with %d vectors\n", got_nvecs);
29754dfc97bSShailend Chand 
29854dfc97bSShailend Chand 	priv->irq_tbl = malloc(sizeof(struct gve_irq) * req_nvecs, M_GVE,
29954dfc97bSShailend Chand 	    M_WAITOK | M_ZERO);
30054dfc97bSShailend Chand 
30154dfc97bSShailend Chand 	for (i = 0; i < num_tx; i++) {
30254dfc97bSShailend Chand 		irq = &priv->irq_tbl[i];
30354dfc97bSShailend Chand 		tx = &priv->tx[i];
30454dfc97bSShailend Chand 		com = &tx->com;
30554dfc97bSShailend Chand 		rid = i + 1;
30654dfc97bSShailend Chand 
30754dfc97bSShailend Chand 		irq->res = bus_alloc_resource_any(priv->dev, SYS_RES_IRQ,
30854dfc97bSShailend Chand 		    &rid, RF_ACTIVE);
30954dfc97bSShailend Chand 		if (irq->res == NULL) {
31054dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to alloc irq %d for Tx queue %d\n",
31154dfc97bSShailend Chand 			    rid, i);
31254dfc97bSShailend Chand 			err = ENOMEM;
31354dfc97bSShailend Chand 			goto abort;
31454dfc97bSShailend Chand 		}
31554dfc97bSShailend Chand 
31654dfc97bSShailend Chand 		err = bus_setup_intr(priv->dev, irq->res, INTR_TYPE_NET | INTR_MPSAFE,
317d438b4efSShailend Chand 		    gve_is_gqi(priv) ? gve_tx_intr : gve_tx_intr_dqo, NULL,
318d438b4efSShailend Chand 		    &priv->tx[i], &irq->cookie);
31954dfc97bSShailend Chand 		if (err != 0) {
32054dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to setup irq %d for Tx queue %d, "
32154dfc97bSShailend Chand 			    "err: %d\n", rid, i, err);
32254dfc97bSShailend Chand 			goto abort;
32354dfc97bSShailend Chand 		}
32454dfc97bSShailend Chand 
32554dfc97bSShailend Chand 		bus_describe_intr(priv->dev, irq->res, irq->cookie, "tx%d", i);
32654dfc97bSShailend Chand 		com->ntfy_id = i;
32754dfc97bSShailend Chand 	}
32854dfc97bSShailend Chand 
32954dfc97bSShailend Chand 	for (j = 0; j < num_rx; j++) {
33054dfc97bSShailend Chand 		irq = &priv->irq_tbl[i + j];
33154dfc97bSShailend Chand 		rx = &priv->rx[j];
33254dfc97bSShailend Chand 		com = &rx->com;
33354dfc97bSShailend Chand 		rid = i + j + 1;
33454dfc97bSShailend Chand 
33554dfc97bSShailend Chand 		irq->res = bus_alloc_resource_any(priv->dev, SYS_RES_IRQ,
33654dfc97bSShailend Chand 		    &rid, RF_ACTIVE);
33754dfc97bSShailend Chand 		if (irq->res == NULL) {
33854dfc97bSShailend Chand 			device_printf(priv->dev,
33954dfc97bSShailend Chand 			    "Failed to alloc irq %d for Rx queue %d", rid, j);
34054dfc97bSShailend Chand 			err = ENOMEM;
34154dfc97bSShailend Chand 			goto abort;
34254dfc97bSShailend Chand 		}
34354dfc97bSShailend Chand 
34454dfc97bSShailend Chand 		err = bus_setup_intr(priv->dev, irq->res, INTR_TYPE_NET | INTR_MPSAFE,
345d438b4efSShailend Chand 		    gve_is_gqi(priv) ? gve_rx_intr : gve_rx_intr_dqo, NULL,
346d438b4efSShailend Chand 		    &priv->rx[j], &irq->cookie);
34754dfc97bSShailend Chand 		if (err != 0) {
34854dfc97bSShailend Chand 			device_printf(priv->dev, "Failed to setup irq %d for Rx queue %d, "
34954dfc97bSShailend Chand 			    "err: %d\n", rid, j, err);
35054dfc97bSShailend Chand 			goto abort;
35154dfc97bSShailend Chand 		}
35254dfc97bSShailend Chand 
35354dfc97bSShailend Chand 		bus_describe_intr(priv->dev, irq->res, irq->cookie, "rx%d", j);
35454dfc97bSShailend Chand 		com->ntfy_id = i + j;
35554dfc97bSShailend Chand 	}
35654dfc97bSShailend Chand 
35754dfc97bSShailend Chand 	m = i + j;
35854dfc97bSShailend Chand 	rid = m + 1;
35954dfc97bSShailend Chand 	irq = &priv->irq_tbl[m];
36054dfc97bSShailend Chand 
36154dfc97bSShailend Chand 	irq->res = bus_alloc_resource_any(priv->dev, SYS_RES_IRQ,
36254dfc97bSShailend Chand 	    &rid, RF_ACTIVE);
36354dfc97bSShailend Chand 	if (irq->res == NULL) {
36454dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to allocate irq %d for mgmnt queue\n", rid);
36554dfc97bSShailend Chand 		err = ENOMEM;
36654dfc97bSShailend Chand 		goto abort;
36754dfc97bSShailend Chand 	}
36854dfc97bSShailend Chand 
36954dfc97bSShailend Chand 	err = bus_setup_intr(priv->dev, irq->res, INTR_TYPE_NET | INTR_MPSAFE,
37054dfc97bSShailend Chand 	    gve_mgmnt_intr, NULL, priv, &irq->cookie);
37154dfc97bSShailend Chand 	if (err != 0) {
37254dfc97bSShailend Chand 		device_printf(priv->dev, "Failed to setup irq %d for mgmnt queue, err: %d\n",
37354dfc97bSShailend Chand 		    rid, err);
37454dfc97bSShailend Chand 		goto abort;
37554dfc97bSShailend Chand 	}
37654dfc97bSShailend Chand 
37754dfc97bSShailend Chand 	bus_describe_intr(priv->dev, irq->res, irq->cookie, "mgmnt");
37854dfc97bSShailend Chand 
37954dfc97bSShailend Chand 	return (0);
38054dfc97bSShailend Chand 
38154dfc97bSShailend Chand abort:
38254dfc97bSShailend Chand 	gve_free_irqs(priv);
38354dfc97bSShailend Chand 	return (err);
38454dfc97bSShailend Chand }
38554dfc97bSShailend Chand 
386d438b4efSShailend Chand /*
387d438b4efSShailend Chand  * Builds register value to write to DQO IRQ doorbell to enable with specified
388d438b4efSShailend Chand  * ITR interval.
389d438b4efSShailend Chand  */
390d438b4efSShailend Chand static uint32_t
gve_setup_itr_interval_dqo(uint32_t interval_us)391d438b4efSShailend Chand gve_setup_itr_interval_dqo(uint32_t interval_us)
392d438b4efSShailend Chand {
393d438b4efSShailend Chand 	uint32_t result = GVE_ITR_ENABLE_BIT_DQO;
394d438b4efSShailend Chand 
395d438b4efSShailend Chand 	/* Interval has 2us granularity. */
396d438b4efSShailend Chand 	interval_us >>= 1;
397d438b4efSShailend Chand 
398d438b4efSShailend Chand 	interval_us &= GVE_ITR_INTERVAL_DQO_MASK;
399d438b4efSShailend Chand 	result |= (interval_us << GVE_ITR_INTERVAL_DQO_SHIFT);
400d438b4efSShailend Chand 
401d438b4efSShailend Chand 	return (result);
402d438b4efSShailend Chand }
403d438b4efSShailend Chand 
40454dfc97bSShailend Chand void
gve_unmask_all_queue_irqs(struct gve_priv * priv)40554dfc97bSShailend Chand gve_unmask_all_queue_irqs(struct gve_priv *priv)
40654dfc97bSShailend Chand {
40754dfc97bSShailend Chand 	struct gve_tx_ring *tx;
40854dfc97bSShailend Chand 	struct gve_rx_ring *rx;
40954dfc97bSShailend Chand 	int idx;
41054dfc97bSShailend Chand 
41154dfc97bSShailend Chand 	for (idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
41254dfc97bSShailend Chand 		tx = &priv->tx[idx];
413d438b4efSShailend Chand 		if (gve_is_gqi(priv))
41454dfc97bSShailend Chand 			gve_db_bar_write_4(priv, tx->com.irq_db_offset, 0);
415d438b4efSShailend Chand 		else
416d438b4efSShailend Chand 			gve_db_bar_dqo_write_4(priv, tx->com.irq_db_offset,
417d438b4efSShailend Chand 			    gve_setup_itr_interval_dqo(GVE_TX_IRQ_RATELIMIT_US_DQO));
41854dfc97bSShailend Chand 	}
419d438b4efSShailend Chand 
42054dfc97bSShailend Chand 	for (idx = 0; idx < priv->rx_cfg.num_queues; idx++) {
42154dfc97bSShailend Chand 		rx = &priv->rx[idx];
422d438b4efSShailend Chand 		if (gve_is_gqi(priv))
42354dfc97bSShailend Chand 			gve_db_bar_write_4(priv, rx->com.irq_db_offset, 0);
424d438b4efSShailend Chand 		else
425d438b4efSShailend Chand 			gve_db_bar_dqo_write_4(priv, rx->com.irq_db_offset,
426d438b4efSShailend Chand 			    gve_setup_itr_interval_dqo(GVE_RX_IRQ_RATELIMIT_US_DQO));
42754dfc97bSShailend Chand 	}
42854dfc97bSShailend Chand }
42954dfc97bSShailend Chand 
43054dfc97bSShailend Chand void
gve_mask_all_queue_irqs(struct gve_priv * priv)43154dfc97bSShailend Chand gve_mask_all_queue_irqs(struct gve_priv *priv)
43254dfc97bSShailend Chand {
43354dfc97bSShailend Chand 	for (int idx = 0; idx < priv->tx_cfg.num_queues; idx++) {
43454dfc97bSShailend Chand 		struct gve_tx_ring *tx = &priv->tx[idx];
43554dfc97bSShailend Chand 		gve_db_bar_write_4(priv, tx->com.irq_db_offset, GVE_IRQ_MASK);
43654dfc97bSShailend Chand 	}
43754dfc97bSShailend Chand 	for (int idx = 0; idx < priv->rx_cfg.num_queues; idx++) {
43854dfc97bSShailend Chand 		struct gve_rx_ring *rx = &priv->rx[idx];
43954dfc97bSShailend Chand 		gve_db_bar_write_4(priv, rx->com.irq_db_offset, GVE_IRQ_MASK);
44054dfc97bSShailend Chand 	}
44154dfc97bSShailend Chand }
442