1 /* 2 * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 * 32 */ 33 34 #include <linux/rcupdate.h> 35 36 #include <dev/mlx4/cq.h> 37 #include <dev/mlx4/qp.h> 38 #include <dev/mlx4/cmd.h> 39 40 #include "en.h" 41 42 static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) 43 { 44 return; 45 } 46 47 static void mlx4_en_tx_que(void *arg, int pending) 48 { 49 50 } 51 52 int mlx4_en_create_cq(struct mlx4_en_priv *priv, 53 struct mlx4_en_cq **pcq, 54 int entries, int ring, enum cq_type mode, 55 int node) 56 { 57 struct mlx4_en_dev *mdev = priv->mdev; 58 struct mlx4_en_cq *cq; 59 int err; 60 61 cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, node); 62 if (!cq) { 63 cq = kzalloc(sizeof(*cq), GFP_KERNEL); 64 if (!cq) { 65 en_err(priv, "Failed to allocate CQ structure\n"); 66 return -ENOMEM; 67 } 68 } 69 70 cq->size = entries; 71 cq->buf_size = cq->size * mdev->dev->caps.cqe_size; 72 73 cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT, 74 taskqueue_thread_enqueue, &cq->tq); 75 if (mode == RX) { 76 TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq); 77 taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s rx cq", 78 if_name(priv->dev)); 79 80 } else { 81 TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq); 82 taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s tx cq", 83 if_name(priv->dev)); 84 } 85 86 cq->ring = ring; 87 cq->is_tx = mode; 88 cq->vector = mdev->dev->caps.num_comp_vectors; 89 spin_lock_init(&cq->lock); 90 91 err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, 92 cq->buf_size, 2 * PAGE_SIZE); 93 if (err) 94 goto err_cq; 95 96 err = mlx4_en_map_buffer(&cq->wqres.buf); 97 if (err) 98 goto err_res; 99 100 cq->buf = (struct mlx4_cqe *)cq->wqres.buf.direct.buf; 101 *pcq = cq; 102 103 return 0; 104 105 err_res: 106 mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 107 err_cq: 108 kfree(cq); 109 *pcq = NULL; 110 return err; 111 } 112 113 int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, 114 int cq_idx) 115 { 116 struct mlx4_en_dev *mdev = priv->mdev; 117 int err = 0; 118 int timestamp_en = 0; 119 bool assigned_eq = false; 120 121 cq->dev = mdev->pndev[priv->port]; 122 cq->mcq.set_ci_db = cq->wqres.db.db; 123 cq->mcq.arm_db = cq->wqres.db.db + 1; 124 *cq->mcq.set_ci_db = 0; 125 *cq->mcq.arm_db = 0; 126 memset(cq->buf, 0, cq->buf_size); 127 128 if (cq->is_tx == RX) { 129 if (!mlx4_is_eq_vector_valid(mdev->dev, priv->port, 130 cq->vector)) { 131 cq->vector = cq_idx % mdev->dev->caps.num_comp_vectors; 132 133 err = mlx4_assign_eq(mdev->dev, priv->port, 134 &cq->vector); 135 if (err) { 136 mlx4_err(mdev, "Failed assigning an EQ to CQ vector %d\n", 137 cq->vector); 138 goto free_eq; 139 } 140 141 assigned_eq = true; 142 } 143 } else { 144 struct mlx4_en_cq *rx_cq; 145 /* 146 * For TX we use the same irq per 147 * ring we assigned for the RX 148 */ 149 cq_idx = cq_idx % priv->rx_ring_num; 150 rx_cq = priv->rx_cq[cq_idx]; 151 cq->vector = rx_cq->vector; 152 } 153 154 if (!cq->is_tx) 155 cq->size = priv->rx_ring[cq->ring]->actual_size; 156 157 err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, 158 &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, 159 cq->vector, 0, timestamp_en); 160 if (err) 161 goto free_eq; 162 163 cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; 164 cq->mcq.event = mlx4_en_cq_event; 165 166 if (cq->is_tx) { 167 init_timer(&cq->timer); 168 cq->timer.function = mlx4_en_poll_tx_cq; 169 cq->timer.data = (unsigned long) cq; 170 } 171 172 173 return 0; 174 175 free_eq: 176 if (assigned_eq) 177 mlx4_release_eq(mdev->dev, cq->vector); 178 cq->vector = mdev->dev->caps.num_comp_vectors; 179 return err; 180 } 181 182 void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) 183 { 184 struct mlx4_en_dev *mdev = priv->mdev; 185 struct mlx4_en_cq *cq = *pcq; 186 187 taskqueue_drain(cq->tq, &cq->cq_task); 188 taskqueue_free(cq->tq); 189 mlx4_en_unmap_buffer(&cq->wqres.buf); 190 mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 191 if (mlx4_is_eq_vector_valid(mdev->dev, priv->port, cq->vector) && 192 cq->is_tx == RX) 193 mlx4_release_eq(priv->mdev->dev, cq->vector); 194 cq->vector = 0; 195 cq->buf_size = 0; 196 cq->buf = NULL; 197 kfree(cq); 198 *pcq = NULL; 199 } 200 201 void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 202 { 203 taskqueue_drain(cq->tq, &cq->cq_task); 204 if (!cq->is_tx) { 205 synchronize_rcu(); 206 } else { 207 del_timer_sync(&cq->timer); 208 } 209 210 mlx4_cq_free(priv->mdev->dev, &cq->mcq); 211 } 212 213 /* Set rx cq moderation parameters */ 214 int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 215 { 216 return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, 217 cq->moder_cnt, cq->moder_time); 218 } 219 220 int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 221 { 222 mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, 223 &priv->mdev->uar_lock); 224 225 return 0; 226 } 227 228 229