1219820Sjeff/* 2272027Shselasky * Copyright (c) 2007, 2014 Mellanox Technologies. All rights reserved. 3219820Sjeff * 4219820Sjeff * This software is available to you under a choice of one of two 5219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 6219820Sjeff * General Public License (GPL) Version 2, available from the file 7219820Sjeff * COPYING in the main directory of this source tree, or the 8219820Sjeff * OpenIB.org BSD license below: 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or 11219820Sjeff * without modification, are permitted provided that the following 12219820Sjeff * conditions are met: 13219820Sjeff * 14219820Sjeff * - Redistributions of source code must retain the above 15219820Sjeff * copyright notice, this list of conditions and the following 16219820Sjeff * disclaimer. 17219820Sjeff * 18219820Sjeff * - Redistributions in binary form must reproduce the above 19219820Sjeff * copyright notice, this list of conditions and the following 20219820Sjeff * disclaimer in the documentation and/or other materials 21219820Sjeff * provided with the distribution. 22219820Sjeff * 23219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30219820Sjeff * SOFTWARE. 31219820Sjeff * 32219820Sjeff */ 33219820Sjeff 34329159Shselasky#include <linux/rcupdate.h> 35329159Shselasky 36306486Shselasky#include <dev/mlx4/cq.h> 37306486Shselasky#include <dev/mlx4/qp.h> 38306486Shselasky#include <dev/mlx4/cmd.h> 39219820Sjeff 40306486Shselasky#include "en.h" 41272027Shselasky 42219820Sjeffstatic void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) 43219820Sjeff{ 44219820Sjeff return; 45219820Sjeff} 46219820Sjeff 47341909Shselaskystatic void mlx4_en_tx_que(void *arg, int pending) 48341909Shselasky{ 49219820Sjeff 50341909Shselasky} 51341909Shselasky 52219820Sjeffint mlx4_en_create_cq(struct mlx4_en_priv *priv, 53272027Shselasky struct mlx4_en_cq **pcq, 54272027Shselasky int entries, int ring, enum cq_type mode, 55272027Shselasky int node) 56219820Sjeff{ 57219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 58272027Shselasky struct mlx4_en_cq *cq; 59219820Sjeff int err; 60219820Sjeff 61329159Shselasky cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, node); 62272027Shselasky if (!cq) { 63329159Shselasky cq = kzalloc(sizeof(*cq), GFP_KERNEL); 64272027Shselasky if (!cq) { 65329159Shselasky en_err(priv, "Failed to allocate CQ structure\n"); 66272027Shselasky return -ENOMEM; 67272027Shselasky } 68272027Shselasky } 69272027Shselasky 70219820Sjeff cq->size = entries; 71272027Shselasky cq->buf_size = cq->size * mdev->dev->caps.cqe_size; 72272027Shselasky 73219893Sjeff cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT, 74272027Shselasky taskqueue_thread_enqueue, &cq->tq); 75272027Shselasky if (mode == RX) { 76219820Sjeff TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq); 77219893Sjeff taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s rx cq", 78272027Shselasky if_name(priv->dev)); 79272027Shselasky 80219820Sjeff } else { 81219820Sjeff TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq); 82219893Sjeff taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s tx cq", 83272027Shselasky if_name(priv->dev)); 84219820Sjeff } 85219820Sjeff 86219820Sjeff cq->ring = ring; 87219820Sjeff cq->is_tx = mode; 88329159Shselasky cq->vector = mdev->dev->caps.num_comp_vectors; 89272027Shselasky spin_lock_init(&cq->lock); 90219820Sjeff 91219820Sjeff err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, 92219820Sjeff cq->buf_size, 2 * PAGE_SIZE); 93219820Sjeff if (err) 94272027Shselasky goto err_cq; 95219820Sjeff 96219820Sjeff err = mlx4_en_map_buffer(&cq->wqres.buf); 97219820Sjeff if (err) 98272027Shselasky goto err_res; 99219820Sjeff 100329159Shselasky cq->buf = (struct mlx4_cqe *)cq->wqres.buf.direct.buf; 101272027Shselasky *pcq = cq; 102272027Shselasky 103272027Shselasky return 0; 104272027Shselasky 105272027Shselaskyerr_res: 106272027Shselasky mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 107272027Shselaskyerr_cq: 108272027Shselasky kfree(cq); 109329159Shselasky *pcq = NULL; 110219820Sjeff return err; 111219820Sjeff} 112219820Sjeff 113272027Shselaskyint mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, 114272027Shselasky int cq_idx) 115219820Sjeff{ 116219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 117272027Shselasky int err = 0; 118272027Shselasky int timestamp_en = 0; 119329159Shselasky bool assigned_eq = false; 120219820Sjeff 121219820Sjeff cq->dev = mdev->pndev[priv->port]; 122219820Sjeff cq->mcq.set_ci_db = cq->wqres.db.db; 123219820Sjeff cq->mcq.arm_db = cq->wqres.db.db + 1; 124219820Sjeff *cq->mcq.set_ci_db = 0; 125219820Sjeff *cq->mcq.arm_db = 0; 126219820Sjeff memset(cq->buf, 0, cq->buf_size); 127219820Sjeff 128272027Shselasky if (cq->is_tx == RX) { 129329159Shselasky if (!mlx4_is_eq_vector_valid(mdev->dev, priv->port, 130329159Shselasky cq->vector)) { 131329159Shselasky cq->vector = cq_idx % mdev->dev->caps.num_comp_vectors; 132329159Shselasky 133329159Shselasky err = mlx4_assign_eq(mdev->dev, priv->port, 134329159Shselasky &cq->vector); 135329159Shselasky if (err) { 136329159Shselasky mlx4_err(mdev, "Failed assigning an EQ to CQ vector %d\n", 137329159Shselasky cq->vector); 138329159Shselasky goto free_eq; 139272027Shselasky } 140329159Shselasky 141329159Shselasky assigned_eq = true; 142272027Shselasky } 143272027Shselasky } else { 144272027Shselasky struct mlx4_en_cq *rx_cq; 145272027Shselasky /* 146272027Shselasky * For TX we use the same irq per 147272027Shselasky * ring we assigned for the RX 148272027Shselasky */ 149272027Shselasky cq_idx = cq_idx % priv->rx_ring_num; 150272027Shselasky rx_cq = priv->rx_cq[cq_idx]; 151272027Shselasky cq->vector = rx_cq->vector; 152272027Shselasky } 153272027Shselasky 154219820Sjeff if (!cq->is_tx) 155272027Shselasky cq->size = priv->rx_ring[cq->ring]->actual_size; 156329159Shselasky 157272027Shselasky err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, 158272027Shselasky &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, 159272027Shselasky cq->vector, 0, timestamp_en); 160272027Shselasky if (err) 161329159Shselasky goto free_eq; 162219820Sjeff 163219820Sjeff cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; 164219820Sjeff cq->mcq.event = mlx4_en_cq_event; 165219820Sjeff 166272027Shselasky if (cq->is_tx) { 167272027Shselasky init_timer(&cq->timer); 168272027Shselasky cq->timer.function = mlx4_en_poll_tx_cq; 169272027Shselasky cq->timer.data = (unsigned long) cq; 170272027Shselasky } 171219820Sjeff 172272027Shselasky 173219820Sjeff return 0; 174329159Shselasky 175329159Shselaskyfree_eq: 176329159Shselasky if (assigned_eq) 177329159Shselasky mlx4_release_eq(mdev->dev, cq->vector); 178329159Shselasky cq->vector = mdev->dev->caps.num_comp_vectors; 179329159Shselasky return err; 180219820Sjeff} 181219820Sjeff 182272027Shselaskyvoid mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) 183219820Sjeff{ 184219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 185272027Shselasky struct mlx4_en_cq *cq = *pcq; 186219820Sjeff 187219820Sjeff taskqueue_drain(cq->tq, &cq->cq_task); 188219820Sjeff taskqueue_free(cq->tq); 189219820Sjeff mlx4_en_unmap_buffer(&cq->wqres.buf); 190219820Sjeff mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 191329159Shselasky if (mlx4_is_eq_vector_valid(mdev->dev, priv->port, cq->vector) && 192329159Shselasky cq->is_tx == RX) 193272027Shselasky mlx4_release_eq(priv->mdev->dev, cq->vector); 194329159Shselasky cq->vector = 0; 195329159Shselasky cq->buf_size = 0; 196329159Shselasky cq->buf = NULL; 197272027Shselasky kfree(cq); 198272027Shselasky *pcq = NULL; 199219820Sjeff} 200219820Sjeff 201219820Sjeffvoid mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 202219820Sjeff{ 203329159Shselasky taskqueue_drain(cq->tq, &cq->cq_task); 204329159Shselasky if (!cq->is_tx) { 205329159Shselasky synchronize_rcu(); 206329159Shselasky } else { 207329159Shselasky del_timer_sync(&cq->timer); 208329159Shselasky } 209219820Sjeff 210329159Shselasky mlx4_cq_free(priv->mdev->dev, &cq->mcq); 211219820Sjeff} 212219820Sjeff 213219820Sjeff/* Set rx cq moderation parameters */ 214219820Sjeffint mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 215219820Sjeff{ 216219820Sjeff return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, 217219820Sjeff cq->moder_cnt, cq->moder_time); 218219820Sjeff} 219219820Sjeff 220219820Sjeffint mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 221219820Sjeff{ 222219820Sjeff mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, 223219820Sjeff &priv->mdev->uar_lock); 224219820Sjeff 225219820Sjeff return 0; 226219820Sjeff} 227219820Sjeff 228219820Sjeff 229