18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2007 Mellanox Technologies. All rights reserved. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 58c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below: 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or 118c2ecf20Sopenharmony_ci * without modification, are permitted provided that the following 128c2ecf20Sopenharmony_ci * conditions are met: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * - Redistributions of source code must retain the above 158c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 168c2ecf20Sopenharmony_ci * disclaimer. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * - Redistributions in binary form must reproduce the above 198c2ecf20Sopenharmony_ci * copyright notice, this list of conditions and the following 208c2ecf20Sopenharmony_ci * disclaimer in the documentation and/or other materials 218c2ecf20Sopenharmony_ci * provided with the distribution. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 308c2ecf20Sopenharmony_ci * SOFTWARE. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/mlx4/cq.h> 358c2ecf20Sopenharmony_ci#include <linux/mlx4/qp.h> 368c2ecf20Sopenharmony_ci#include <linux/mlx4/cmd.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include "mlx4_en.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci return; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ciint mlx4_en_create_cq(struct mlx4_en_priv *priv, 478c2ecf20Sopenharmony_ci struct mlx4_en_cq **pcq, 488c2ecf20Sopenharmony_ci int entries, int ring, enum cq_type mode, 498c2ecf20Sopenharmony_ci int node) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 528c2ecf20Sopenharmony_ci struct mlx4_en_cq *cq; 538c2ecf20Sopenharmony_ci int err; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, node); 568c2ecf20Sopenharmony_ci if (!cq) { 578c2ecf20Sopenharmony_ci en_err(priv, "Failed to allocate CQ structure\n"); 588c2ecf20Sopenharmony_ci return -ENOMEM; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci cq->size = entries; 628c2ecf20Sopenharmony_ci cq->buf_size = cq->size * mdev->dev->caps.cqe_size; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci cq->ring = ring; 658c2ecf20Sopenharmony_ci cq->type = mode; 668c2ecf20Sopenharmony_ci cq->vector = mdev->dev->caps.num_comp_vectors; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Allocate HW buffers on provided NUMA node. 698c2ecf20Sopenharmony_ci * dev->numa_node is used in mtt range allocation flow. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci set_dev_node(&mdev->dev->persist->pdev->dev, node); 728c2ecf20Sopenharmony_ci err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, 738c2ecf20Sopenharmony_ci cq->buf_size); 748c2ecf20Sopenharmony_ci set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node); 758c2ecf20Sopenharmony_ci if (err) 768c2ecf20Sopenharmony_ci goto err_cq; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci cq->buf = (struct mlx4_cqe *)cq->wqres.buf.direct.buf; 798c2ecf20Sopenharmony_ci *pcq = cq; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cierr_cq: 848c2ecf20Sopenharmony_ci kfree(cq); 858c2ecf20Sopenharmony_ci *pcq = NULL; 868c2ecf20Sopenharmony_ci return err; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ciint mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, 908c2ecf20Sopenharmony_ci int cq_idx) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 938c2ecf20Sopenharmony_ci int err = 0; 948c2ecf20Sopenharmony_ci int timestamp_en = 0; 958c2ecf20Sopenharmony_ci bool assigned_eq = false; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci cq->dev = mdev->pndev[priv->port]; 988c2ecf20Sopenharmony_ci cq->mcq.set_ci_db = cq->wqres.db.db; 998c2ecf20Sopenharmony_ci cq->mcq.arm_db = cq->wqres.db.db + 1; 1008c2ecf20Sopenharmony_ci *cq->mcq.set_ci_db = 0; 1018c2ecf20Sopenharmony_ci *cq->mcq.arm_db = 0; 1028c2ecf20Sopenharmony_ci memset(cq->buf, 0, cq->buf_size); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (cq->type == RX) { 1058c2ecf20Sopenharmony_ci if (!mlx4_is_eq_vector_valid(mdev->dev, priv->port, 1068c2ecf20Sopenharmony_ci cq->vector)) { 1078c2ecf20Sopenharmony_ci cq->vector = cpumask_first(priv->rx_ring[cq->ring]->affinity_mask); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci err = mlx4_assign_eq(mdev->dev, priv->port, 1108c2ecf20Sopenharmony_ci &cq->vector); 1118c2ecf20Sopenharmony_ci if (err) { 1128c2ecf20Sopenharmony_ci mlx4_err(mdev, "Failed assigning an EQ to CQ vector %d\n", 1138c2ecf20Sopenharmony_ci cq->vector); 1148c2ecf20Sopenharmony_ci goto free_eq; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci assigned_eq = true; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci cq->irq_desc = 1218c2ecf20Sopenharmony_ci irq_to_desc(mlx4_eq_get_irq(mdev->dev, 1228c2ecf20Sopenharmony_ci cq->vector)); 1238c2ecf20Sopenharmony_ci } else { 1248c2ecf20Sopenharmony_ci /* For TX we use the same irq per 1258c2ecf20Sopenharmony_ci ring we assigned for the RX */ 1268c2ecf20Sopenharmony_ci struct mlx4_en_cq *rx_cq; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci cq_idx = cq_idx % priv->rx_ring_num; 1298c2ecf20Sopenharmony_ci rx_cq = priv->rx_cq[cq_idx]; 1308c2ecf20Sopenharmony_ci cq->vector = rx_cq->vector; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (cq->type == RX) 1348c2ecf20Sopenharmony_ci cq->size = priv->rx_ring[cq->ring]->actual_size; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if ((cq->type != RX && priv->hwtstamp_config.tx_type) || 1378c2ecf20Sopenharmony_ci (cq->type == RX && priv->hwtstamp_config.rx_filter)) 1388c2ecf20Sopenharmony_ci timestamp_en = 1; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci cq->mcq.usage = MLX4_RES_USAGE_DRIVER; 1418c2ecf20Sopenharmony_ci err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, 1428c2ecf20Sopenharmony_ci &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, 1438c2ecf20Sopenharmony_ci cq->vector, 0, timestamp_en, &cq->wqres.buf, false); 1448c2ecf20Sopenharmony_ci if (err) 1458c2ecf20Sopenharmony_ci goto free_eq; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci cq->mcq.event = mlx4_en_cq_event; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci switch (cq->type) { 1508c2ecf20Sopenharmony_ci case TX: 1518c2ecf20Sopenharmony_ci cq->mcq.comp = mlx4_en_tx_irq; 1528c2ecf20Sopenharmony_ci netif_tx_napi_add(cq->dev, &cq->napi, mlx4_en_poll_tx_cq, 1538c2ecf20Sopenharmony_ci NAPI_POLL_WEIGHT); 1548c2ecf20Sopenharmony_ci napi_enable(&cq->napi); 1558c2ecf20Sopenharmony_ci break; 1568c2ecf20Sopenharmony_ci case RX: 1578c2ecf20Sopenharmony_ci cq->mcq.comp = mlx4_en_rx_irq; 1588c2ecf20Sopenharmony_ci netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64); 1598c2ecf20Sopenharmony_ci napi_enable(&cq->napi); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci case TX_XDP: 1628c2ecf20Sopenharmony_ci /* nothing regarding napi, it's shared with rx ring */ 1638c2ecf20Sopenharmony_ci cq->xdp_busy = false; 1648c2ecf20Sopenharmony_ci break; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cifree_eq: 1708c2ecf20Sopenharmony_ci if (assigned_eq) 1718c2ecf20Sopenharmony_ci mlx4_release_eq(mdev->dev, cq->vector); 1728c2ecf20Sopenharmony_ci cq->vector = mdev->dev->caps.num_comp_vectors; 1738c2ecf20Sopenharmony_ci return err; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_civoid mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct mlx4_en_dev *mdev = priv->mdev; 1798c2ecf20Sopenharmony_ci struct mlx4_en_cq *cq = *pcq; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 1828c2ecf20Sopenharmony_ci if (mlx4_is_eq_vector_valid(mdev->dev, priv->port, cq->vector) && 1838c2ecf20Sopenharmony_ci cq->type == RX) 1848c2ecf20Sopenharmony_ci mlx4_release_eq(priv->mdev->dev, cq->vector); 1858c2ecf20Sopenharmony_ci cq->vector = 0; 1868c2ecf20Sopenharmony_ci cq->buf_size = 0; 1878c2ecf20Sopenharmony_ci cq->buf = NULL; 1888c2ecf20Sopenharmony_ci kfree(cq); 1898c2ecf20Sopenharmony_ci *pcq = NULL; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_civoid mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci if (cq->type != TX_XDP) { 1958c2ecf20Sopenharmony_ci napi_disable(&cq->napi); 1968c2ecf20Sopenharmony_ci netif_napi_del(&cq->napi); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci mlx4_cq_free(priv->mdev->dev, &cq->mcq); 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* Set rx cq moderation parameters */ 2038c2ecf20Sopenharmony_ciint mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, 2068c2ecf20Sopenharmony_ci cq->moder_cnt, cq->moder_time); 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_civoid mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, 2128c2ecf20Sopenharmony_ci &priv->mdev->uar_lock); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci 216