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