169426357SHans Petter Selasky /*-
2*d735d604SHans Petter Selasky * Copyright (c) 2021-2022 NVIDIA corporation & affiliates.
369426357SHans Petter Selasky *
469426357SHans Petter Selasky * Redistribution and use in source and binary forms, with or without
569426357SHans Petter Selasky * modification, are permitted provided that the following conditions
669426357SHans Petter Selasky * are met:
769426357SHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
869426357SHans Petter Selasky * notice, this list of conditions and the following disclaimer.
969426357SHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
1069426357SHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
1169426357SHans Petter Selasky * documentation and/or other materials provided with the distribution.
1269426357SHans Petter Selasky *
1369426357SHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
1469426357SHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1569426357SHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1669426357SHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1769426357SHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1869426357SHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1969426357SHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2069426357SHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2169426357SHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2269426357SHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2369426357SHans Petter Selasky * SUCH DAMAGE.
2469426357SHans Petter Selasky */
2569426357SHans Petter Selasky
2669426357SHans Petter Selasky /*
2769426357SHans Petter Selasky * The internal queue, IQ, code is more or less a stripped down copy
2869426357SHans Petter Selasky * of the existing SQ managing code with exception of:
2969426357SHans Petter Selasky *
3069426357SHans Petter Selasky * - an optional single segment memory buffer which can be read or
3169426357SHans Petter Selasky * written as a whole by the hardware, may be provided.
3269426357SHans Petter Selasky *
3369426357SHans Petter Selasky * - an optional completion callback for all transmit operations, may
3469426357SHans Petter Selasky * be provided.
3569426357SHans Petter Selasky *
3669426357SHans Petter Selasky * - does not support mbufs.
3769426357SHans Petter Selasky */
3869426357SHans Petter Selasky
3969426357SHans Petter Selasky #include <dev/mlx5/mlx5_en/en.h>
4069426357SHans Petter Selasky
4169426357SHans Petter Selasky static void
mlx5e_iq_poll(struct mlx5e_iq * iq,int budget)4269426357SHans Petter Selasky mlx5e_iq_poll(struct mlx5e_iq *iq, int budget)
4369426357SHans Petter Selasky {
4469426357SHans Petter Selasky const struct mlx5_cqe64 *cqe;
4569426357SHans Petter Selasky u16 ci;
4669426357SHans Petter Selasky u16 iqcc;
4769426357SHans Petter Selasky
4869426357SHans Petter Selasky /*
4969426357SHans Petter Selasky * iq->cc must be updated only after mlx5_cqwq_update_db_record(),
5069426357SHans Petter Selasky * otherwise a cq overrun may occur
5169426357SHans Petter Selasky */
5269426357SHans Petter Selasky iqcc = iq->cc;
5369426357SHans Petter Selasky
5469426357SHans Petter Selasky while (budget-- > 0) {
5569426357SHans Petter Selasky
5669426357SHans Petter Selasky cqe = mlx5e_get_cqe(&iq->cq);
5769426357SHans Petter Selasky if (!cqe)
5869426357SHans Petter Selasky break;
5969426357SHans Petter Selasky
6069426357SHans Petter Selasky mlx5_cqwq_pop(&iq->cq.wq);
6169426357SHans Petter Selasky
6269426357SHans Petter Selasky ci = iqcc & iq->wq.sz_m1;
6369426357SHans Petter Selasky
6469426357SHans Petter Selasky if (likely(iq->data[ci].dma_sync != 0)) {
6569426357SHans Petter Selasky /* make sure data written by hardware is visible to CPU */
6669426357SHans Petter Selasky bus_dmamap_sync(iq->dma_tag, iq->data[ci].dma_map, iq->data[ci].dma_sync);
6769426357SHans Petter Selasky bus_dmamap_unload(iq->dma_tag, iq->data[ci].dma_map);
6869426357SHans Petter Selasky
6969426357SHans Petter Selasky iq->data[ci].dma_sync = 0;
7069426357SHans Petter Selasky }
7169426357SHans Petter Selasky
7269426357SHans Petter Selasky if (likely(iq->data[ci].callback != NULL)) {
7369426357SHans Petter Selasky iq->data[ci].callback(iq->data[ci].arg);
7469426357SHans Petter Selasky iq->data[ci].callback = NULL;
7569426357SHans Petter Selasky }
7669426357SHans Petter Selasky
7769426357SHans Petter Selasky if (unlikely(iq->data[ci].p_refcount != NULL)) {
7869426357SHans Petter Selasky atomic_add_int(iq->data[ci].p_refcount, -1);
7969426357SHans Petter Selasky iq->data[ci].p_refcount = NULL;
8069426357SHans Petter Selasky }
8169426357SHans Petter Selasky iqcc += iq->data[ci].num_wqebbs;
8269426357SHans Petter Selasky }
8369426357SHans Petter Selasky
8469426357SHans Petter Selasky mlx5_cqwq_update_db_record(&iq->cq.wq);
8569426357SHans Petter Selasky
8669426357SHans Petter Selasky /* Ensure cq space is freed before enabling more cqes */
8769426357SHans Petter Selasky atomic_thread_fence_rel();
8869426357SHans Petter Selasky
8969426357SHans Petter Selasky iq->cc = iqcc;
9069426357SHans Petter Selasky }
9169426357SHans Petter Selasky
9269426357SHans Petter Selasky static void
mlx5e_iq_completion(struct mlx5_core_cq * mcq,struct mlx5_eqe * eqe __unused)9369426357SHans Petter Selasky mlx5e_iq_completion(struct mlx5_core_cq *mcq, struct mlx5_eqe *eqe __unused)
9469426357SHans Petter Selasky {
9569426357SHans Petter Selasky struct mlx5e_iq *iq = container_of(mcq, struct mlx5e_iq, cq.mcq);
9669426357SHans Petter Selasky
9769426357SHans Petter Selasky mtx_lock(&iq->comp_lock);
9869426357SHans Petter Selasky mlx5e_iq_poll(iq, MLX5E_BUDGET_MAX);
9969426357SHans Petter Selasky mlx5e_cq_arm(&iq->cq, MLX5_GET_DOORBELL_LOCK(&iq->priv->doorbell_lock));
10069426357SHans Petter Selasky mtx_unlock(&iq->comp_lock);
10169426357SHans Petter Selasky }
10269426357SHans Petter Selasky
10369426357SHans Petter Selasky void
mlx5e_iq_send_nop(struct mlx5e_iq * iq,u32 ds_cnt)10469426357SHans Petter Selasky mlx5e_iq_send_nop(struct mlx5e_iq *iq, u32 ds_cnt)
10569426357SHans Petter Selasky {
10669426357SHans Petter Selasky u16 pi = iq->pc & iq->wq.sz_m1;
10769426357SHans Petter Selasky struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(&iq->wq, pi);
10869426357SHans Petter Selasky
10969426357SHans Petter Selasky mtx_assert(&iq->lock, MA_OWNED);
11069426357SHans Petter Selasky
11169426357SHans Petter Selasky memset(&wqe->ctrl, 0, sizeof(wqe->ctrl));
11269426357SHans Petter Selasky
11369426357SHans Petter Selasky wqe->ctrl.opmod_idx_opcode = cpu_to_be32((iq->pc << 8) | MLX5_OPCODE_NOP);
11469426357SHans Petter Selasky wqe->ctrl.qpn_ds = cpu_to_be32((iq->sqn << 8) | ds_cnt);
11569426357SHans Petter Selasky wqe->ctrl.fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
11669426357SHans Petter Selasky
11769426357SHans Petter Selasky /* Copy data for doorbell */
11869426357SHans Petter Selasky memcpy(iq->doorbell.d32, &wqe->ctrl, sizeof(iq->doorbell.d32));
11969426357SHans Petter Selasky
12069426357SHans Petter Selasky iq->data[pi].callback = NULL;
12169426357SHans Petter Selasky iq->data[pi].arg = NULL;
12269426357SHans Petter Selasky iq->data[pi].num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
12369426357SHans Petter Selasky iq->data[pi].dma_sync = 0;
12469426357SHans Petter Selasky iq->pc += iq->data[pi].num_wqebbs;
12569426357SHans Petter Selasky }
12669426357SHans Petter Selasky
12769426357SHans Petter Selasky static void
mlx5e_iq_free_db(struct mlx5e_iq * iq)12869426357SHans Petter Selasky mlx5e_iq_free_db(struct mlx5e_iq *iq)
12969426357SHans Petter Selasky {
13069426357SHans Petter Selasky int wq_sz = mlx5_wq_cyc_get_size(&iq->wq);
13169426357SHans Petter Selasky int x;
13269426357SHans Petter Selasky
13369426357SHans Petter Selasky for (x = 0; x != wq_sz; x++) {
13469426357SHans Petter Selasky if (likely(iq->data[x].dma_sync != 0)) {
13569426357SHans Petter Selasky bus_dmamap_unload(iq->dma_tag, iq->data[x].dma_map);
13669426357SHans Petter Selasky iq->data[x].dma_sync = 0;
13769426357SHans Petter Selasky }
13869426357SHans Petter Selasky if (likely(iq->data[x].callback != NULL)) {
13969426357SHans Petter Selasky iq->data[x].callback(iq->data[x].arg);
14069426357SHans Petter Selasky iq->data[x].callback = NULL;
14169426357SHans Petter Selasky }
142d2a788a5SHans Petter Selasky if (unlikely(iq->data[x].p_refcount != NULL)) {
143d2a788a5SHans Petter Selasky atomic_add_int(iq->data[x].p_refcount, -1);
144d2a788a5SHans Petter Selasky iq->data[x].p_refcount = NULL;
145d2a788a5SHans Petter Selasky }
14669426357SHans Petter Selasky bus_dmamap_destroy(iq->dma_tag, iq->data[x].dma_map);
14769426357SHans Petter Selasky }
14869426357SHans Petter Selasky free(iq->data, M_MLX5EN);
14969426357SHans Petter Selasky }
15069426357SHans Petter Selasky
15169426357SHans Petter Selasky static int
mlx5e_iq_alloc_db(struct mlx5e_iq * iq)15269426357SHans Petter Selasky mlx5e_iq_alloc_db(struct mlx5e_iq *iq)
15369426357SHans Petter Selasky {
15469426357SHans Petter Selasky int wq_sz = mlx5_wq_cyc_get_size(&iq->wq);
15569426357SHans Petter Selasky int err;
15669426357SHans Petter Selasky int x;
15769426357SHans Petter Selasky
15869426357SHans Petter Selasky iq->data = malloc_domainset(wq_sz * sizeof(iq->data[0]), M_MLX5EN,
15969426357SHans Petter Selasky mlx5_dev_domainset(iq->priv->mdev), M_WAITOK | M_ZERO);
16069426357SHans Petter Selasky
16169426357SHans Petter Selasky /* Create DMA descriptor maps */
16269426357SHans Petter Selasky for (x = 0; x != wq_sz; x++) {
16369426357SHans Petter Selasky err = -bus_dmamap_create(iq->dma_tag, 0, &iq->data[x].dma_map);
16469426357SHans Petter Selasky if (err != 0) {
16569426357SHans Petter Selasky while (x--)
16669426357SHans Petter Selasky bus_dmamap_destroy(iq->dma_tag, iq->data[x].dma_map);
16769426357SHans Petter Selasky free(iq->data, M_MLX5EN);
16869426357SHans Petter Selasky return (err);
16969426357SHans Petter Selasky }
17069426357SHans Petter Selasky }
17169426357SHans Petter Selasky return (0);
17269426357SHans Petter Selasky }
17369426357SHans Petter Selasky
17469426357SHans Petter Selasky static int
mlx5e_iq_create(struct mlx5e_channel * c,struct mlx5e_sq_param * param,struct mlx5e_iq * iq)17569426357SHans Petter Selasky mlx5e_iq_create(struct mlx5e_channel *c,
17669426357SHans Petter Selasky struct mlx5e_sq_param *param,
17769426357SHans Petter Selasky struct mlx5e_iq *iq)
17869426357SHans Petter Selasky {
17969426357SHans Petter Selasky struct mlx5e_priv *priv = c->priv;
18069426357SHans Petter Selasky struct mlx5_core_dev *mdev = priv->mdev;
18169426357SHans Petter Selasky void *sqc = param->sqc;
18269426357SHans Petter Selasky void *sqc_wq = MLX5_ADDR_OF(sqc, sqc, wq);
18369426357SHans Petter Selasky int err;
18469426357SHans Petter Selasky
18569426357SHans Petter Selasky /* Create DMA descriptor TAG */
18669426357SHans Petter Selasky if ((err = -bus_dma_tag_create(
18769426357SHans Petter Selasky bus_get_dma_tag(mdev->pdev->dev.bsddev),
18869426357SHans Petter Selasky 1, /* any alignment */
18969426357SHans Petter Selasky 0, /* no boundary */
19069426357SHans Petter Selasky BUS_SPACE_MAXADDR, /* lowaddr */
19169426357SHans Petter Selasky BUS_SPACE_MAXADDR, /* highaddr */
19269426357SHans Petter Selasky NULL, NULL, /* filter, filterarg */
19369426357SHans Petter Selasky PAGE_SIZE, /* maxsize */
19469426357SHans Petter Selasky 1, /* nsegments */
19569426357SHans Petter Selasky PAGE_SIZE, /* maxsegsize */
19669426357SHans Petter Selasky 0, /* flags */
19769426357SHans Petter Selasky NULL, NULL, /* lockfunc, lockfuncarg */
19869426357SHans Petter Selasky &iq->dma_tag)))
19969426357SHans Petter Selasky goto done;
20069426357SHans Petter Selasky
20169426357SHans Petter Selasky iq->mkey_be = cpu_to_be32(priv->mr.key);
20269426357SHans Petter Selasky iq->priv = priv;
20369426357SHans Petter Selasky
20469426357SHans Petter Selasky err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq,
20569426357SHans Petter Selasky &iq->wq, &iq->wq_ctrl);
20669426357SHans Petter Selasky if (err)
20769426357SHans Petter Selasky goto err_free_dma_tag;
20869426357SHans Petter Selasky
20969426357SHans Petter Selasky iq->wq.db = &iq->wq.db[MLX5_SND_DBR];
21069426357SHans Petter Selasky
21169426357SHans Petter Selasky err = mlx5e_iq_alloc_db(iq);
21269426357SHans Petter Selasky if (err)
21369426357SHans Petter Selasky goto err_iq_wq_destroy;
21469426357SHans Petter Selasky
21569426357SHans Petter Selasky return (0);
21669426357SHans Petter Selasky
21769426357SHans Petter Selasky err_iq_wq_destroy:
21869426357SHans Petter Selasky mlx5_wq_destroy(&iq->wq_ctrl);
21969426357SHans Petter Selasky
22069426357SHans Petter Selasky err_free_dma_tag:
22169426357SHans Petter Selasky bus_dma_tag_destroy(iq->dma_tag);
22269426357SHans Petter Selasky done:
22369426357SHans Petter Selasky return (err);
22469426357SHans Petter Selasky }
22569426357SHans Petter Selasky
22669426357SHans Petter Selasky static void
mlx5e_iq_destroy(struct mlx5e_iq * iq)22769426357SHans Petter Selasky mlx5e_iq_destroy(struct mlx5e_iq *iq)
22869426357SHans Petter Selasky {
22969426357SHans Petter Selasky mlx5e_iq_free_db(iq);
23069426357SHans Petter Selasky mlx5_wq_destroy(&iq->wq_ctrl);
23169426357SHans Petter Selasky bus_dma_tag_destroy(iq->dma_tag);
23269426357SHans Petter Selasky }
23369426357SHans Petter Selasky
23469426357SHans Petter Selasky static int
mlx5e_iq_enable(struct mlx5e_iq * iq,struct mlx5e_sq_param * param,const struct mlx5_sq_bfreg * bfreg,int tis_num)23569426357SHans Petter Selasky mlx5e_iq_enable(struct mlx5e_iq *iq, struct mlx5e_sq_param *param,
23669426357SHans Petter Selasky const struct mlx5_sq_bfreg *bfreg, int tis_num)
23769426357SHans Petter Selasky {
23869426357SHans Petter Selasky void *in;
23969426357SHans Petter Selasky void *sqc;
24069426357SHans Petter Selasky void *wq;
24169426357SHans Petter Selasky int inlen;
24269426357SHans Petter Selasky int err;
24369426357SHans Petter Selasky u8 ts_format;
24469426357SHans Petter Selasky
24569426357SHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(create_sq_in) +
24669426357SHans Petter Selasky sizeof(u64) * iq->wq_ctrl.buf.npages;
24769426357SHans Petter Selasky in = mlx5_vzalloc(inlen);
24869426357SHans Petter Selasky if (in == NULL)
24969426357SHans Petter Selasky return (-ENOMEM);
25069426357SHans Petter Selasky
25169426357SHans Petter Selasky iq->uar_map = bfreg->map;
25269426357SHans Petter Selasky
25369426357SHans Petter Selasky ts_format = mlx5_get_sq_default_ts(iq->priv->mdev);
25469426357SHans Petter Selasky sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
25569426357SHans Petter Selasky wq = MLX5_ADDR_OF(sqc, sqc, wq);
25669426357SHans Petter Selasky
25769426357SHans Petter Selasky memcpy(sqc, param->sqc, sizeof(param->sqc));
25869426357SHans Petter Selasky
25969426357SHans Petter Selasky MLX5_SET(sqc, sqc, tis_num_0, tis_num);
26069426357SHans Petter Selasky MLX5_SET(sqc, sqc, cqn, iq->cq.mcq.cqn);
26169426357SHans Petter Selasky MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
26269426357SHans Petter Selasky MLX5_SET(sqc, sqc, ts_format, ts_format);
26369426357SHans Petter Selasky MLX5_SET(sqc, sqc, tis_lst_sz, 1);
26469426357SHans Petter Selasky MLX5_SET(sqc, sqc, flush_in_error_en, 1);
26569426357SHans Petter Selasky MLX5_SET(sqc, sqc, allow_swp, 1);
26669426357SHans Petter Selasky
267266c81aaSHans Petter Selasky /* SQ remap support requires reg_umr privileges level */
268266c81aaSHans Petter Selasky if (MLX5_CAP_QOS(iq->priv->mdev, qos_remap_pp)) {
269266c81aaSHans Petter Selasky MLX5_SET(sqc, sqc, qos_remap_en, 1);
270266c81aaSHans Petter Selasky if (MLX5_CAP_ETH(iq->priv->mdev, reg_umr_sq))
271266c81aaSHans Petter Selasky MLX5_SET(sqc, sqc, reg_umr, 1);
272266c81aaSHans Petter Selasky else
273266c81aaSHans Petter Selasky mlx5_en_err(iq->priv->ifp,
274266c81aaSHans Petter Selasky "No reg umr SQ capability, SQ remap disabled\n");
275266c81aaSHans Petter Selasky }
276266c81aaSHans Petter Selasky
27769426357SHans Petter Selasky MLX5_SET(wq, wq, wq_type, MLX5_WQ_TYPE_CYCLIC);
27869426357SHans Petter Selasky MLX5_SET(wq, wq, uar_page, bfreg->index);
27969426357SHans Petter Selasky MLX5_SET(wq, wq, log_wq_pg_sz, iq->wq_ctrl.buf.page_shift -
280*d735d604SHans Petter Selasky MLX5_ADAPTER_PAGE_SHIFT);
28169426357SHans Petter Selasky MLX5_SET64(wq, wq, dbr_addr, iq->wq_ctrl.db.dma);
28269426357SHans Petter Selasky
28369426357SHans Petter Selasky mlx5_fill_page_array(&iq->wq_ctrl.buf,
28469426357SHans Petter Selasky (__be64 *) MLX5_ADDR_OF(wq, wq, pas));
28569426357SHans Petter Selasky
28669426357SHans Petter Selasky err = mlx5_core_create_sq(iq->priv->mdev, in, inlen, &iq->sqn);
28769426357SHans Petter Selasky
28869426357SHans Petter Selasky kvfree(in);
28969426357SHans Petter Selasky
29069426357SHans Petter Selasky return (err);
29169426357SHans Petter Selasky }
29269426357SHans Petter Selasky
29369426357SHans Petter Selasky static int
mlx5e_iq_modify(struct mlx5e_iq * iq,int curr_state,int next_state)29469426357SHans Petter Selasky mlx5e_iq_modify(struct mlx5e_iq *iq, int curr_state, int next_state)
29569426357SHans Petter Selasky {
29669426357SHans Petter Selasky void *in;
29769426357SHans Petter Selasky void *sqc;
29869426357SHans Petter Selasky int inlen;
29969426357SHans Petter Selasky int err;
30069426357SHans Petter Selasky
30169426357SHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
30269426357SHans Petter Selasky in = mlx5_vzalloc(inlen);
30369426357SHans Petter Selasky if (in == NULL)
30469426357SHans Petter Selasky return (-ENOMEM);
30569426357SHans Petter Selasky
30669426357SHans Petter Selasky sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
30769426357SHans Petter Selasky
30869426357SHans Petter Selasky MLX5_SET(modify_sq_in, in, sqn, iq->sqn);
30969426357SHans Petter Selasky MLX5_SET(modify_sq_in, in, sq_state, curr_state);
31069426357SHans Petter Selasky MLX5_SET(sqc, sqc, state, next_state);
31169426357SHans Petter Selasky
31269426357SHans Petter Selasky err = mlx5_core_modify_sq(iq->priv->mdev, in, inlen);
31369426357SHans Petter Selasky
31469426357SHans Petter Selasky kvfree(in);
31569426357SHans Petter Selasky
31669426357SHans Petter Selasky return (err);
31769426357SHans Petter Selasky }
31869426357SHans Petter Selasky
31969426357SHans Petter Selasky static void
mlx5e_iq_disable(struct mlx5e_iq * iq)32069426357SHans Petter Selasky mlx5e_iq_disable(struct mlx5e_iq *iq)
32169426357SHans Petter Selasky {
32269426357SHans Petter Selasky mlx5_core_destroy_sq(iq->priv->mdev, iq->sqn);
32369426357SHans Petter Selasky }
32469426357SHans Petter Selasky
32569426357SHans Petter Selasky int
mlx5e_iq_open(struct mlx5e_channel * c,struct mlx5e_sq_param * sq_param,struct mlx5e_cq_param * cq_param,struct mlx5e_iq * iq)32669426357SHans Petter Selasky mlx5e_iq_open(struct mlx5e_channel *c,
32769426357SHans Petter Selasky struct mlx5e_sq_param *sq_param,
32869426357SHans Petter Selasky struct mlx5e_cq_param *cq_param,
32969426357SHans Petter Selasky struct mlx5e_iq *iq)
33069426357SHans Petter Selasky {
33169426357SHans Petter Selasky int err;
33269426357SHans Petter Selasky
33369426357SHans Petter Selasky err = mlx5e_open_cq(c->priv, cq_param, &iq->cq,
33469426357SHans Petter Selasky &mlx5e_iq_completion, c->ix);
33569426357SHans Petter Selasky if (err)
33669426357SHans Petter Selasky return (err);
33769426357SHans Petter Selasky
33869426357SHans Petter Selasky err = mlx5e_iq_create(c, sq_param, iq);
33969426357SHans Petter Selasky if (err)
34069426357SHans Petter Selasky goto err_close_cq;
34169426357SHans Petter Selasky
34269426357SHans Petter Selasky err = mlx5e_iq_enable(iq, sq_param, &c->bfreg, c->priv->tisn[0]);
34369426357SHans Petter Selasky if (err)
34469426357SHans Petter Selasky goto err_destroy_sq;
34569426357SHans Petter Selasky
34669426357SHans Petter Selasky err = mlx5e_iq_modify(iq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY);
34769426357SHans Petter Selasky if (err)
34869426357SHans Petter Selasky goto err_disable_sq;
34969426357SHans Petter Selasky
35069426357SHans Petter Selasky WRITE_ONCE(iq->running, 1);
35169426357SHans Petter Selasky
35269426357SHans Petter Selasky return (0);
35369426357SHans Petter Selasky
35469426357SHans Petter Selasky err_disable_sq:
35569426357SHans Petter Selasky mlx5e_iq_disable(iq);
35669426357SHans Petter Selasky err_destroy_sq:
35769426357SHans Petter Selasky mlx5e_iq_destroy(iq);
35869426357SHans Petter Selasky err_close_cq:
35969426357SHans Petter Selasky mlx5e_close_cq(&iq->cq);
36069426357SHans Petter Selasky
36169426357SHans Petter Selasky return (err);
36269426357SHans Petter Selasky }
36369426357SHans Petter Selasky
36469426357SHans Petter Selasky static void
mlx5e_iq_drain(struct mlx5e_iq * iq)36569426357SHans Petter Selasky mlx5e_iq_drain(struct mlx5e_iq *iq)
36669426357SHans Petter Selasky {
36769426357SHans Petter Selasky struct mlx5_core_dev *mdev = iq->priv->mdev;
36869426357SHans Petter Selasky
36969426357SHans Petter Selasky /*
37069426357SHans Petter Selasky * Check if already stopped.
37169426357SHans Petter Selasky *
37269426357SHans Petter Selasky * NOTE: Serialization of this function is managed by the
37369426357SHans Petter Selasky * caller ensuring the priv's state lock is locked or in case
37469426357SHans Petter Selasky * of rate limit support, a single thread manages drain and
37569426357SHans Petter Selasky * resume of SQs. The "running" variable can therefore safely
37669426357SHans Petter Selasky * be read without any locks.
37769426357SHans Petter Selasky */
37869426357SHans Petter Selasky if (READ_ONCE(iq->running) == 0)
37969426357SHans Petter Selasky return;
38069426357SHans Petter Selasky
38169426357SHans Petter Selasky /* don't put more packets into the SQ */
38269426357SHans Petter Selasky WRITE_ONCE(iq->running, 0);
38369426357SHans Petter Selasky
38469426357SHans Petter Selasky /* wait till SQ is empty or link is down */
38569426357SHans Petter Selasky mtx_lock(&iq->lock);
38669426357SHans Petter Selasky while (iq->cc != iq->pc &&
38769426357SHans Petter Selasky (iq->priv->media_status_last & IFM_ACTIVE) != 0 &&
38869426357SHans Petter Selasky mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR &&
38969426357SHans Petter Selasky pci_channel_offline(mdev->pdev) == 0) {
39069426357SHans Petter Selasky mtx_unlock(&iq->lock);
39169426357SHans Petter Selasky msleep(1);
39269426357SHans Petter Selasky iq->cq.mcq.comp(&iq->cq.mcq, NULL);
39369426357SHans Petter Selasky mtx_lock(&iq->lock);
39469426357SHans Petter Selasky }
39569426357SHans Petter Selasky mtx_unlock(&iq->lock);
39669426357SHans Petter Selasky
39769426357SHans Petter Selasky /* error out remaining requests */
39869426357SHans Petter Selasky (void) mlx5e_iq_modify(iq, MLX5_SQC_STATE_RDY, MLX5_SQC_STATE_ERR);
39969426357SHans Petter Selasky
40069426357SHans Petter Selasky /* wait till SQ is empty */
40169426357SHans Petter Selasky mtx_lock(&iq->lock);
40269426357SHans Petter Selasky while (iq->cc != iq->pc &&
40369426357SHans Petter Selasky mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR &&
40469426357SHans Petter Selasky pci_channel_offline(mdev->pdev) == 0) {
40569426357SHans Petter Selasky mtx_unlock(&iq->lock);
40669426357SHans Petter Selasky msleep(1);
40769426357SHans Petter Selasky iq->cq.mcq.comp(&iq->cq.mcq, NULL);
40869426357SHans Petter Selasky mtx_lock(&iq->lock);
40969426357SHans Petter Selasky }
41069426357SHans Petter Selasky mtx_unlock(&iq->lock);
41169426357SHans Petter Selasky }
41269426357SHans Petter Selasky
41369426357SHans Petter Selasky void
mlx5e_iq_close(struct mlx5e_iq * iq)41469426357SHans Petter Selasky mlx5e_iq_close(struct mlx5e_iq *iq)
41569426357SHans Petter Selasky {
41669426357SHans Petter Selasky mlx5e_iq_drain(iq);
41769426357SHans Petter Selasky mlx5e_iq_disable(iq);
41869426357SHans Petter Selasky mlx5e_iq_destroy(iq);
41969426357SHans Petter Selasky mlx5e_close_cq(&iq->cq);
42069426357SHans Petter Selasky }
42169426357SHans Petter Selasky
42269426357SHans Petter Selasky void
mlx5e_iq_static_init(struct mlx5e_iq * iq)42369426357SHans Petter Selasky mlx5e_iq_static_init(struct mlx5e_iq *iq)
42469426357SHans Petter Selasky {
42569426357SHans Petter Selasky mtx_init(&iq->lock, "mlx5iq",
42669426357SHans Petter Selasky MTX_NETWORK_LOCK " IQ", MTX_DEF);
42769426357SHans Petter Selasky mtx_init(&iq->comp_lock, "mlx5iq_comp",
42869426357SHans Petter Selasky MTX_NETWORK_LOCK " IQ COMP", MTX_DEF);
42969426357SHans Petter Selasky }
43069426357SHans Petter Selasky
43169426357SHans Petter Selasky void
mlx5e_iq_static_destroy(struct mlx5e_iq * iq)43269426357SHans Petter Selasky mlx5e_iq_static_destroy(struct mlx5e_iq *iq)
43369426357SHans Petter Selasky {
43469426357SHans Petter Selasky mtx_destroy(&iq->lock);
43569426357SHans Petter Selasky mtx_destroy(&iq->comp_lock);
43669426357SHans Petter Selasky }
43769426357SHans Petter Selasky
43869426357SHans Petter Selasky void
mlx5e_iq_notify_hw(struct mlx5e_iq * iq)43969426357SHans Petter Selasky mlx5e_iq_notify_hw(struct mlx5e_iq *iq)
44069426357SHans Petter Selasky {
44169426357SHans Petter Selasky mtx_assert(&iq->lock, MA_OWNED);
44269426357SHans Petter Selasky
44369426357SHans Petter Selasky /* Check if we need to write the doorbell */
44469426357SHans Petter Selasky if (unlikely(iq->db_inhibit != 0 || iq->doorbell.d64 == 0))
44569426357SHans Petter Selasky return;
44669426357SHans Petter Selasky
44769426357SHans Petter Selasky /* Ensure wqe is visible to device before updating doorbell record */
44869426357SHans Petter Selasky wmb();
44969426357SHans Petter Selasky
45069426357SHans Petter Selasky *iq->wq.db = cpu_to_be32(iq->pc);
45169426357SHans Petter Selasky
45269426357SHans Petter Selasky /*
45369426357SHans Petter Selasky * Ensure the doorbell record is visible to device before ringing
45469426357SHans Petter Selasky * the doorbell:
45569426357SHans Petter Selasky */
45669426357SHans Petter Selasky wmb();
45769426357SHans Petter Selasky
45869426357SHans Petter Selasky mlx5_write64(iq->doorbell.d32, iq->uar_map,
45969426357SHans Petter Selasky MLX5_GET_DOORBELL_LOCK(&iq->priv->doorbell_lock));
46069426357SHans Petter Selasky
46169426357SHans Petter Selasky iq->doorbell.d64 = 0;
46269426357SHans Petter Selasky }
46369426357SHans Petter Selasky
46469426357SHans Petter Selasky static inline bool
mlx5e_iq_has_room_for(struct mlx5e_iq * iq,u16 n)46569426357SHans Petter Selasky mlx5e_iq_has_room_for(struct mlx5e_iq *iq, u16 n)
46669426357SHans Petter Selasky {
46769426357SHans Petter Selasky u16 cc = iq->cc;
46869426357SHans Petter Selasky u16 pc = iq->pc;
46969426357SHans Petter Selasky
47069426357SHans Petter Selasky return ((iq->wq.sz_m1 & (cc - pc)) >= n || cc == pc);
47169426357SHans Petter Selasky }
47269426357SHans Petter Selasky
47369426357SHans Petter Selasky int
mlx5e_iq_get_producer_index(struct mlx5e_iq * iq)47469426357SHans Petter Selasky mlx5e_iq_get_producer_index(struct mlx5e_iq *iq)
47569426357SHans Petter Selasky {
47669426357SHans Petter Selasky u16 pi;
47769426357SHans Petter Selasky
47869426357SHans Petter Selasky mtx_assert(&iq->lock, MA_OWNED);
47969426357SHans Petter Selasky
48069426357SHans Petter Selasky if (unlikely(iq->running == 0))
48169426357SHans Petter Selasky return (-1);
48269426357SHans Petter Selasky if (unlikely(!mlx5e_iq_has_room_for(iq, 2 * MLX5_SEND_WQE_MAX_WQEBBS)))
48369426357SHans Petter Selasky return (-1);
48469426357SHans Petter Selasky
48569426357SHans Petter Selasky /* Align IQ edge with NOPs to avoid WQE wrap around */
48669426357SHans Petter Selasky pi = ((~iq->pc) & iq->wq.sz_m1);
48769426357SHans Petter Selasky if (unlikely(pi < (MLX5_SEND_WQE_MAX_WQEBBS - 1))) {
48869426357SHans Petter Selasky /* Send one multi NOP message instead of many */
48969426357SHans Petter Selasky mlx5e_iq_send_nop(iq, (pi + 1) * MLX5_SEND_WQEBB_NUM_DS);
49069426357SHans Petter Selasky pi = ((~iq->pc) & iq->wq.sz_m1);
49169426357SHans Petter Selasky if (unlikely(pi < (MLX5_SEND_WQE_MAX_WQEBBS - 1)))
49269426357SHans Petter Selasky return (-1);
49369426357SHans Petter Selasky }
49469426357SHans Petter Selasky return (iq->pc & iq->wq.sz_m1);
49569426357SHans Petter Selasky }
49669426357SHans Petter Selasky
49769426357SHans Petter Selasky static void
mlx5e_iq_load_memory_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)49869426357SHans Petter Selasky mlx5e_iq_load_memory_cb(void *arg, bus_dma_segment_t *segs,
49969426357SHans Petter Selasky int nseg, int error)
50069426357SHans Petter Selasky {
50169426357SHans Petter Selasky u64 *pdma_address = arg;
50269426357SHans Petter Selasky
50369426357SHans Petter Selasky if (unlikely(error || nseg != 1))
50469426357SHans Petter Selasky panic("mlx5e_iq_load_memory_cb: error=%d nseg=%d", error, nseg);
50569426357SHans Petter Selasky
50669426357SHans Petter Selasky *pdma_address = segs[0].ds_addr;
50769426357SHans Petter Selasky }
50869426357SHans Petter Selasky
50969426357SHans Petter Selasky CTASSERT(BUS_DMASYNC_POSTREAD != 0);
51069426357SHans Petter Selasky CTASSERT(BUS_DMASYNC_POSTWRITE != 0);
51169426357SHans Petter Selasky
51269426357SHans Petter Selasky void
mlx5e_iq_load_memory_single(struct mlx5e_iq * iq,u16 pi,void * buffer,size_t size,u64 * pdma_address,u32 dma_sync)51369426357SHans Petter Selasky mlx5e_iq_load_memory_single(struct mlx5e_iq *iq, u16 pi, void *buffer, size_t size,
51469426357SHans Petter Selasky u64 *pdma_address, u32 dma_sync)
51569426357SHans Petter Selasky {
51669426357SHans Petter Selasky int error;
51769426357SHans Petter Selasky
51869426357SHans Petter Selasky error = bus_dmamap_load(iq->dma_tag, iq->data[pi].dma_map, buffer, size,
51969426357SHans Petter Selasky &mlx5e_iq_load_memory_cb, pdma_address, BUS_DMA_NOWAIT);
52069426357SHans Petter Selasky if (unlikely(error))
52169426357SHans Petter Selasky panic("mlx5e_iq_load_memory: error=%d buffer=%p size=%zd", error, buffer, size);
52269426357SHans Petter Selasky
52369426357SHans Petter Selasky switch (dma_sync) {
52469426357SHans Petter Selasky case BUS_DMASYNC_PREREAD:
52569426357SHans Petter Selasky iq->data[pi].dma_sync = BUS_DMASYNC_POSTREAD;
52669426357SHans Petter Selasky break;
52769426357SHans Petter Selasky case BUS_DMASYNC_PREWRITE:
52869426357SHans Petter Selasky iq->data[pi].dma_sync = BUS_DMASYNC_POSTWRITE;
52969426357SHans Petter Selasky break;
53069426357SHans Petter Selasky default:
53169426357SHans Petter Selasky panic("mlx5e_iq_load_memory_single: Invalid DMA sync operation(%d)", dma_sync);
53269426357SHans Petter Selasky }
53369426357SHans Petter Selasky
53469426357SHans Petter Selasky /* make sure data in buffer is visible to hardware */
53569426357SHans Petter Selasky bus_dmamap_sync(iq->dma_tag, iq->data[pi].dma_map, dma_sync);
53669426357SHans Petter Selasky }
537