1219820Sjeff/* 2272407Shselasky * 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 34219820Sjeff#include <linux/mlx4/cq.h> 35219820Sjeff#include <linux/mlx4/qp.h> 36219820Sjeff#include <linux/mlx4/cmd.h> 37219820Sjeff 38272407Shselasky#include "mlx4_en.h" 39272407Shselasky 40272407Shselasky 41219820Sjeffstatic void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event) 42219820Sjeff{ 43219820Sjeff return; 44219820Sjeff} 45219820Sjeff 46219820Sjeff 47219820Sjeffint mlx4_en_create_cq(struct mlx4_en_priv *priv, 48272407Shselasky struct mlx4_en_cq **pcq, 49272407Shselasky int entries, int ring, enum cq_type mode, 50272407Shselasky int node) 51219820Sjeff{ 52219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 53272407Shselasky struct mlx4_en_cq *cq; 54219820Sjeff int err; 55219820Sjeff 56272407Shselasky cq = kzalloc_node(sizeof(struct mlx4_en_cq), GFP_KERNEL, node); 57272407Shselasky if (!cq) { 58272407Shselasky cq = kzalloc(sizeof(struct mlx4_en_cq), GFP_KERNEL); 59272407Shselasky if (!cq) { 60272407Shselasky en_err(priv, "Failed to allocate CW struture\n"); 61272407Shselasky return -ENOMEM; 62272407Shselasky } 63272407Shselasky } 64272407Shselasky 65219820Sjeff cq->size = entries; 66272407Shselasky cq->buf_size = cq->size * mdev->dev->caps.cqe_size; 67272407Shselasky 68219893Sjeff cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT, 69272407Shselasky taskqueue_thread_enqueue, &cq->tq); 70272407Shselasky if (mode == RX) { 71219820Sjeff TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq); 72219893Sjeff taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s rx cq", 73272407Shselasky if_name(priv->dev)); 74272407Shselasky 75219820Sjeff } else { 76219820Sjeff TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq); 77219893Sjeff taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s tx cq", 78272407Shselasky if_name(priv->dev)); 79219820Sjeff } 80219820Sjeff 81219820Sjeff cq->ring = ring; 82219820Sjeff cq->is_tx = mode; 83272407Shselasky spin_lock_init(&cq->lock); 84219820Sjeff 85219820Sjeff err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres, 86219820Sjeff cq->buf_size, 2 * PAGE_SIZE); 87219820Sjeff if (err) 88272407Shselasky goto err_cq; 89219820Sjeff 90219820Sjeff err = mlx4_en_map_buffer(&cq->wqres.buf); 91219820Sjeff if (err) 92272407Shselasky goto err_res; 93219820Sjeff 94272407Shselasky cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; 95272407Shselasky *pcq = cq; 96272407Shselasky 97272407Shselasky return 0; 98272407Shselasky 99272407Shselaskyerr_res: 100272407Shselasky mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 101272407Shselaskyerr_cq: 102272407Shselasky kfree(cq); 103219820Sjeff return err; 104219820Sjeff} 105219820Sjeff 106272407Shselasky 107272407Shselaskyint mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, 108272407Shselasky int cq_idx) 109219820Sjeff{ 110219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 111272407Shselasky int err = 0; 112272407Shselasky char name[25]; 113272407Shselasky int timestamp_en = 0; 114219820Sjeff 115219820Sjeff cq->dev = mdev->pndev[priv->port]; 116219820Sjeff cq->mcq.set_ci_db = cq->wqres.db.db; 117219820Sjeff cq->mcq.arm_db = cq->wqres.db.db + 1; 118219820Sjeff *cq->mcq.set_ci_db = 0; 119219820Sjeff *cq->mcq.arm_db = 0; 120219820Sjeff memset(cq->buf, 0, cq->buf_size); 121219820Sjeff 122272407Shselasky if (cq->is_tx == RX) { 123272407Shselasky if (mdev->dev->caps.comp_pool) { 124272407Shselasky if (!cq->vector) { 125272407Shselasky sprintf(name, "%s-%d", if_name(priv->dev), 126272407Shselasky cq->ring); 127272407Shselasky /* Set IRQ for specific name (per ring) */ 128272407Shselasky if (mlx4_assign_eq(mdev->dev, name, &cq->vector)) { 129272407Shselasky cq->vector = (cq->ring + 1 + priv->port) 130272407Shselasky % mdev->dev->caps.num_comp_vectors; 131272407Shselasky mlx4_warn(mdev, "Failed Assigning an EQ to " 132272407Shselasky "%s ,Falling back to legacy EQ's\n", 133272407Shselasky name); 134272407Shselasky } 135272407Shselasky } 136272407Shselasky } else { 137272407Shselasky cq->vector = (cq->ring + 1 + priv->port) % 138272407Shselasky mdev->dev->caps.num_comp_vectors; 139272407Shselasky } 140272407Shselasky } else { 141272407Shselasky struct mlx4_en_cq *rx_cq; 142272407Shselasky /* 143272407Shselasky * For TX we use the same irq per 144272407Shselasky * ring we assigned for the RX 145272407Shselasky */ 146272407Shselasky cq_idx = cq_idx % priv->rx_ring_num; 147272407Shselasky rx_cq = priv->rx_cq[cq_idx]; 148272407Shselasky cq->vector = rx_cq->vector; 149272407Shselasky } 150272407Shselasky 151219820Sjeff if (!cq->is_tx) 152272407Shselasky cq->size = priv->rx_ring[cq->ring]->actual_size; 153272407Shselasky err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, 154272407Shselasky &mdev->priv_uar, cq->wqres.db.dma, &cq->mcq, 155272407Shselasky cq->vector, 0, timestamp_en); 156272407Shselasky if (err) 157219820Sjeff return err; 158219820Sjeff 159219820Sjeff cq->mcq.comp = cq->is_tx ? mlx4_en_tx_irq : mlx4_en_rx_irq; 160219820Sjeff cq->mcq.event = mlx4_en_cq_event; 161219820Sjeff 162272407Shselasky if (cq->is_tx) { 163272407Shselasky init_timer(&cq->timer); 164272407Shselasky cq->timer.function = mlx4_en_poll_tx_cq; 165272407Shselasky cq->timer.data = (unsigned long) cq; 166272407Shselasky } 167219820Sjeff 168272407Shselasky 169219820Sjeff return 0; 170219820Sjeff} 171219820Sjeff 172272407Shselaskyvoid mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq) 173219820Sjeff{ 174219820Sjeff struct mlx4_en_dev *mdev = priv->mdev; 175272407Shselasky struct mlx4_en_cq *cq = *pcq; 176219820Sjeff 177219820Sjeff taskqueue_drain(cq->tq, &cq->cq_task); 178219820Sjeff taskqueue_free(cq->tq); 179219820Sjeff mlx4_en_unmap_buffer(&cq->wqres.buf); 180219820Sjeff mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); 181272407Shselasky if (priv->mdev->dev->caps.comp_pool && cq->vector) 182272407Shselasky mlx4_release_eq(priv->mdev->dev, cq->vector); 183272407Shselasky kfree(cq); 184272407Shselasky *pcq = NULL; 185219820Sjeff} 186219820Sjeff 187219820Sjeffvoid mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 188219820Sjeff{ 189272407Shselasky struct mlx4_en_dev *mdev = priv->mdev; 190219820Sjeff 191272407Shselasky taskqueue_drain(cq->tq, &cq->cq_task); 192272407Shselasky if (cq->is_tx) 193272407Shselasky del_timer(&cq->timer); 194219820Sjeff 195272407Shselasky mlx4_cq_free(mdev->dev, &cq->mcq); 196219820Sjeff} 197219820Sjeff 198272407Shselasky 199219820Sjeff/* Set rx cq moderation parameters */ 200219820Sjeffint mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 201219820Sjeff{ 202219820Sjeff return mlx4_cq_modify(priv->mdev->dev, &cq->mcq, 203219820Sjeff cq->moder_cnt, cq->moder_time); 204219820Sjeff} 205219820Sjeff 206219820Sjeffint mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) 207219820Sjeff{ 208219820Sjeff mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, 209219820Sjeff &priv->mdev->uar_lock); 210219820Sjeff 211219820Sjeff return 0; 212219820Sjeff} 213219820Sjeff 214219820Sjeff 215