Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2013-2015, Mellanox Technologies, Ltd.  All rights reserved.
0003  *
0004  * This software is available to you under a choice of one of two
0005  * licenses.  You may choose to be licensed under the terms of the GNU
0006  * General Public License (GPL) Version 2, available from the file
0007  * COPYING in the main directory of this source tree, or the
0008  * OpenIB.org BSD license below:
0009  *
0010  *     Redistribution and use in source and binary forms, with or
0011  *     without modification, are permitted provided that the following
0012  *     conditions are met:
0013  *
0014  *      - Redistributions of source code must retain the above
0015  *        copyright notice, this list of conditions and the following
0016  *        disclaimer.
0017  *
0018  *      - Redistributions in binary form must reproduce the above
0019  *        copyright notice, this list of conditions and the following
0020  *        disclaimer in the documentation and/or other materials
0021  *        provided with the distribution.
0022  *
0023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0024  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0025  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
0026  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
0027  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
0028  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0029  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
0030  * SOFTWARE.
0031  */
0032 
0033 #include <linux/mlx5/driver.h>
0034 #include "mlx5_core.h"
0035 #include <linux/mlx5/transobj.h>
0036 
0037 int mlx5_core_alloc_transport_domain(struct mlx5_core_dev *dev, u32 *tdn)
0038 {
0039     u32 out[MLX5_ST_SZ_DW(alloc_transport_domain_out)] = {};
0040     u32 in[MLX5_ST_SZ_DW(alloc_transport_domain_in)] = {};
0041     int err;
0042 
0043     MLX5_SET(alloc_transport_domain_in, in, opcode,
0044          MLX5_CMD_OP_ALLOC_TRANSPORT_DOMAIN);
0045 
0046     err = mlx5_cmd_exec_inout(dev, alloc_transport_domain, in, out);
0047     if (!err)
0048         *tdn = MLX5_GET(alloc_transport_domain_out, out,
0049                 transport_domain);
0050 
0051     return err;
0052 }
0053 EXPORT_SYMBOL(mlx5_core_alloc_transport_domain);
0054 
0055 void mlx5_core_dealloc_transport_domain(struct mlx5_core_dev *dev, u32 tdn)
0056 {
0057     u32 in[MLX5_ST_SZ_DW(dealloc_transport_domain_in)] = {};
0058 
0059     MLX5_SET(dealloc_transport_domain_in, in, opcode,
0060          MLX5_CMD_OP_DEALLOC_TRANSPORT_DOMAIN);
0061     MLX5_SET(dealloc_transport_domain_in, in, transport_domain, tdn);
0062     mlx5_cmd_exec_in(dev, dealloc_transport_domain, in);
0063 }
0064 EXPORT_SYMBOL(mlx5_core_dealloc_transport_domain);
0065 
0066 int mlx5_core_create_rq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *rqn)
0067 {
0068     u32 out[MLX5_ST_SZ_DW(create_rq_out)] = {};
0069     int err;
0070 
0071     MLX5_SET(create_rq_in, in, opcode, MLX5_CMD_OP_CREATE_RQ);
0072     err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
0073     if (!err)
0074         *rqn = MLX5_GET(create_rq_out, out, rqn);
0075 
0076     return err;
0077 }
0078 EXPORT_SYMBOL(mlx5_core_create_rq);
0079 
0080 int mlx5_core_modify_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *in)
0081 {
0082     MLX5_SET(modify_rq_in, in, rqn, rqn);
0083     MLX5_SET(modify_rq_in, in, opcode, MLX5_CMD_OP_MODIFY_RQ);
0084 
0085     return mlx5_cmd_exec_in(dev, modify_rq, in);
0086 }
0087 EXPORT_SYMBOL(mlx5_core_modify_rq);
0088 
0089 void mlx5_core_destroy_rq(struct mlx5_core_dev *dev, u32 rqn)
0090 {
0091     u32 in[MLX5_ST_SZ_DW(destroy_rq_in)] = {};
0092 
0093     MLX5_SET(destroy_rq_in, in, opcode, MLX5_CMD_OP_DESTROY_RQ);
0094     MLX5_SET(destroy_rq_in, in, rqn, rqn);
0095     mlx5_cmd_exec_in(dev, destroy_rq, in);
0096 }
0097 EXPORT_SYMBOL(mlx5_core_destroy_rq);
0098 
0099 int mlx5_core_query_rq(struct mlx5_core_dev *dev, u32 rqn, u32 *out)
0100 {
0101     u32 in[MLX5_ST_SZ_DW(query_rq_in)] = {};
0102 
0103     MLX5_SET(query_rq_in, in, opcode, MLX5_CMD_OP_QUERY_RQ);
0104     MLX5_SET(query_rq_in, in, rqn, rqn);
0105 
0106     return mlx5_cmd_exec_inout(dev, query_rq, in, out);
0107 }
0108 EXPORT_SYMBOL(mlx5_core_query_rq);
0109 
0110 int mlx5_core_create_sq(struct mlx5_core_dev *dev, u32 *in, int inlen, u32 *sqn)
0111 {
0112     u32 out[MLX5_ST_SZ_DW(create_sq_out)] = {};
0113     int err;
0114 
0115     MLX5_SET(create_sq_in, in, opcode, MLX5_CMD_OP_CREATE_SQ);
0116     err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
0117     if (!err)
0118         *sqn = MLX5_GET(create_sq_out, out, sqn);
0119 
0120     return err;
0121 }
0122 
0123 int mlx5_core_modify_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *in)
0124 {
0125     MLX5_SET(modify_sq_in, in, sqn, sqn);
0126     MLX5_SET(modify_sq_in, in, opcode, MLX5_CMD_OP_MODIFY_SQ);
0127     return mlx5_cmd_exec_in(dev, modify_sq, in);
0128 }
0129 EXPORT_SYMBOL(mlx5_core_modify_sq);
0130 
0131 void mlx5_core_destroy_sq(struct mlx5_core_dev *dev, u32 sqn)
0132 {
0133     u32 in[MLX5_ST_SZ_DW(destroy_sq_in)] = {};
0134 
0135     MLX5_SET(destroy_sq_in, in, opcode, MLX5_CMD_OP_DESTROY_SQ);
0136     MLX5_SET(destroy_sq_in, in, sqn, sqn);
0137     mlx5_cmd_exec_in(dev, destroy_sq, in);
0138 }
0139 
0140 int mlx5_core_query_sq(struct mlx5_core_dev *dev, u32 sqn, u32 *out)
0141 {
0142     u32 in[MLX5_ST_SZ_DW(query_sq_in)] = {};
0143 
0144     MLX5_SET(query_sq_in, in, opcode, MLX5_CMD_OP_QUERY_SQ);
0145     MLX5_SET(query_sq_in, in, sqn, sqn);
0146     return mlx5_cmd_exec_inout(dev, query_sq, in, out);
0147 }
0148 EXPORT_SYMBOL(mlx5_core_query_sq);
0149 
0150 int mlx5_core_query_sq_state(struct mlx5_core_dev *dev, u32 sqn, u8 *state)
0151 {
0152     void *out;
0153     void *sqc;
0154     int inlen;
0155     int err;
0156 
0157     inlen = MLX5_ST_SZ_BYTES(query_sq_out);
0158     out = kvzalloc(inlen, GFP_KERNEL);
0159     if (!out)
0160         return -ENOMEM;
0161 
0162     err = mlx5_core_query_sq(dev, sqn, out);
0163     if (err)
0164         goto out;
0165 
0166     sqc = MLX5_ADDR_OF(query_sq_out, out, sq_context);
0167     *state = MLX5_GET(sqc, sqc, state);
0168 
0169 out:
0170     kvfree(out);
0171     return err;
0172 }
0173 EXPORT_SYMBOL_GPL(mlx5_core_query_sq_state);
0174 
0175 int mlx5_core_create_tir(struct mlx5_core_dev *dev, u32 *in, u32 *tirn)
0176 {
0177     u32 out[MLX5_ST_SZ_DW(create_tir_out)] = {};
0178     int err;
0179 
0180     MLX5_SET(create_tir_in, in, opcode, MLX5_CMD_OP_CREATE_TIR);
0181     err = mlx5_cmd_exec_inout(dev, create_tir, in, out);
0182     if (!err)
0183         *tirn = MLX5_GET(create_tir_out, out, tirn);
0184 
0185     return err;
0186 }
0187 EXPORT_SYMBOL(mlx5_core_create_tir);
0188 
0189 int mlx5_core_modify_tir(struct mlx5_core_dev *dev, u32 tirn, u32 *in)
0190 {
0191     MLX5_SET(modify_tir_in, in, tirn, tirn);
0192     MLX5_SET(modify_tir_in, in, opcode, MLX5_CMD_OP_MODIFY_TIR);
0193     return mlx5_cmd_exec_in(dev, modify_tir, in);
0194 }
0195 
0196 void mlx5_core_destroy_tir(struct mlx5_core_dev *dev, u32 tirn)
0197 {
0198     u32 in[MLX5_ST_SZ_DW(destroy_tir_in)] = {};
0199 
0200     MLX5_SET(destroy_tir_in, in, opcode, MLX5_CMD_OP_DESTROY_TIR);
0201     MLX5_SET(destroy_tir_in, in, tirn, tirn);
0202     mlx5_cmd_exec_in(dev, destroy_tir, in);
0203 }
0204 EXPORT_SYMBOL(mlx5_core_destroy_tir);
0205 
0206 int mlx5_core_create_tis(struct mlx5_core_dev *dev, u32 *in, u32 *tisn)
0207 {
0208     u32 out[MLX5_ST_SZ_DW(create_tis_out)] = {};
0209     int err;
0210 
0211     MLX5_SET(create_tis_in, in, opcode, MLX5_CMD_OP_CREATE_TIS);
0212     err = mlx5_cmd_exec_inout(dev, create_tis, in, out);
0213     if (!err)
0214         *tisn = MLX5_GET(create_tis_out, out, tisn);
0215 
0216     return err;
0217 }
0218 EXPORT_SYMBOL(mlx5_core_create_tis);
0219 
0220 int mlx5_core_modify_tis(struct mlx5_core_dev *dev, u32 tisn, u32 *in)
0221 {
0222     MLX5_SET(modify_tis_in, in, tisn, tisn);
0223     MLX5_SET(modify_tis_in, in, opcode, MLX5_CMD_OP_MODIFY_TIS);
0224 
0225     return mlx5_cmd_exec_in(dev, modify_tis, in);
0226 }
0227 EXPORT_SYMBOL(mlx5_core_modify_tis);
0228 
0229 void mlx5_core_destroy_tis(struct mlx5_core_dev *dev, u32 tisn)
0230 {
0231     u32 in[MLX5_ST_SZ_DW(destroy_tis_in)] = {};
0232 
0233     MLX5_SET(destroy_tis_in, in, opcode, MLX5_CMD_OP_DESTROY_TIS);
0234     MLX5_SET(destroy_tis_in, in, tisn, tisn);
0235     mlx5_cmd_exec_in(dev, destroy_tis, in);
0236 }
0237 EXPORT_SYMBOL(mlx5_core_destroy_tis);
0238 
0239 int mlx5_core_create_rqt(struct mlx5_core_dev *dev, u32 *in, int inlen,
0240              u32 *rqtn)
0241 {
0242     u32 out[MLX5_ST_SZ_DW(create_rqt_out)] = {};
0243     int err;
0244 
0245     MLX5_SET(create_rqt_in, in, opcode, MLX5_CMD_OP_CREATE_RQT);
0246     err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
0247     if (!err)
0248         *rqtn = MLX5_GET(create_rqt_out, out, rqtn);
0249 
0250     return err;
0251 }
0252 EXPORT_SYMBOL(mlx5_core_create_rqt);
0253 
0254 int mlx5_core_modify_rqt(struct mlx5_core_dev *dev, u32 rqtn, u32 *in,
0255              int inlen)
0256 {
0257     u32 out[MLX5_ST_SZ_DW(modify_rqt_out)] = {};
0258 
0259     MLX5_SET(modify_rqt_in, in, rqtn, rqtn);
0260     MLX5_SET(modify_rqt_in, in, opcode, MLX5_CMD_OP_MODIFY_RQT);
0261     return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
0262 }
0263 
0264 void mlx5_core_destroy_rqt(struct mlx5_core_dev *dev, u32 rqtn)
0265 {
0266     u32 in[MLX5_ST_SZ_DW(destroy_rqt_in)] = {};
0267 
0268     MLX5_SET(destroy_rqt_in, in, opcode, MLX5_CMD_OP_DESTROY_RQT);
0269     MLX5_SET(destroy_rqt_in, in, rqtn, rqtn);
0270     mlx5_cmd_exec_in(dev, destroy_rqt, in);
0271 }
0272 EXPORT_SYMBOL(mlx5_core_destroy_rqt);
0273 
0274 static int mlx5_hairpin_create_rq(struct mlx5_core_dev *mdev,
0275                   struct mlx5_hairpin_params *params, u32 *rqn)
0276 {
0277     u32 in[MLX5_ST_SZ_DW(create_rq_in)] = {0};
0278     void *rqc, *wq;
0279 
0280     rqc = MLX5_ADDR_OF(create_rq_in, in, ctx);
0281     wq  = MLX5_ADDR_OF(rqc, rqc, wq);
0282 
0283     MLX5_SET(rqc, rqc, hairpin, 1);
0284     MLX5_SET(rqc, rqc, state, MLX5_RQC_STATE_RST);
0285     MLX5_SET(rqc, rqc, counter_set_id, params->q_counter);
0286 
0287     MLX5_SET(wq, wq, log_hairpin_data_sz, params->log_data_size);
0288     MLX5_SET(wq, wq, log_hairpin_num_packets, params->log_num_packets);
0289 
0290     return mlx5_core_create_rq(mdev, in, MLX5_ST_SZ_BYTES(create_rq_in), rqn);
0291 }
0292 
0293 static int mlx5_hairpin_create_sq(struct mlx5_core_dev *mdev,
0294                   struct mlx5_hairpin_params *params, u32 *sqn)
0295 {
0296     u32 in[MLX5_ST_SZ_DW(create_sq_in)] = {0};
0297     void *sqc, *wq;
0298 
0299     sqc = MLX5_ADDR_OF(create_sq_in, in, ctx);
0300     wq  = MLX5_ADDR_OF(sqc, sqc, wq);
0301 
0302     MLX5_SET(sqc, sqc, hairpin, 1);
0303     MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RST);
0304 
0305     MLX5_SET(wq, wq, log_hairpin_data_sz, params->log_data_size);
0306     MLX5_SET(wq, wq, log_hairpin_num_packets, params->log_num_packets);
0307 
0308     return mlx5_core_create_sq(mdev, in, MLX5_ST_SZ_BYTES(create_sq_in), sqn);
0309 }
0310 
0311 static int mlx5_hairpin_create_queues(struct mlx5_hairpin *hp,
0312                       struct mlx5_hairpin_params *params)
0313 {
0314     int i, j, err;
0315 
0316     for (i = 0; i < hp->num_channels; i++) {
0317         err = mlx5_hairpin_create_rq(hp->func_mdev, params, &hp->rqn[i]);
0318         if (err)
0319             goto out_err_rq;
0320     }
0321 
0322     for (i = 0; i < hp->num_channels; i++) {
0323         err = mlx5_hairpin_create_sq(hp->peer_mdev, params, &hp->sqn[i]);
0324         if (err)
0325             goto out_err_sq;
0326     }
0327 
0328     return 0;
0329 
0330 out_err_sq:
0331     for (j = 0; j < i; j++)
0332         mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[j]);
0333     i = hp->num_channels;
0334 out_err_rq:
0335     for (j = 0; j < i; j++)
0336         mlx5_core_destroy_rq(hp->func_mdev, hp->rqn[j]);
0337     return err;
0338 }
0339 
0340 static void mlx5_hairpin_destroy_queues(struct mlx5_hairpin *hp)
0341 {
0342     int i;
0343 
0344     for (i = 0; i < hp->num_channels; i++) {
0345         mlx5_core_destroy_rq(hp->func_mdev, hp->rqn[i]);
0346         if (!hp->peer_gone)
0347             mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
0348     }
0349 }
0350 
0351 static int mlx5_hairpin_modify_rq(struct mlx5_core_dev *func_mdev, u32 rqn,
0352                   int curr_state, int next_state,
0353                   u16 peer_vhca, u32 peer_sq)
0354 {
0355     u32 in[MLX5_ST_SZ_DW(modify_rq_in)] = {};
0356     void *rqc;
0357 
0358     rqc = MLX5_ADDR_OF(modify_rq_in, in, ctx);
0359 
0360     if (next_state == MLX5_RQC_STATE_RDY) {
0361         MLX5_SET(rqc, rqc, hairpin_peer_sq, peer_sq);
0362         MLX5_SET(rqc, rqc, hairpin_peer_vhca, peer_vhca);
0363     }
0364 
0365     MLX5_SET(modify_rq_in, in, rq_state, curr_state);
0366     MLX5_SET(rqc, rqc, state, next_state);
0367 
0368     return mlx5_core_modify_rq(func_mdev, rqn, in);
0369 }
0370 
0371 static int mlx5_hairpin_modify_sq(struct mlx5_core_dev *peer_mdev, u32 sqn,
0372                   int curr_state, int next_state,
0373                   u16 peer_vhca, u32 peer_rq)
0374 {
0375     u32 in[MLX5_ST_SZ_DW(modify_sq_in)] = {0};
0376     void *sqc;
0377 
0378     sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
0379 
0380     if (next_state == MLX5_SQC_STATE_RDY) {
0381         MLX5_SET(sqc, sqc, hairpin_peer_rq, peer_rq);
0382         MLX5_SET(sqc, sqc, hairpin_peer_vhca, peer_vhca);
0383     }
0384 
0385     MLX5_SET(modify_sq_in, in, sq_state, curr_state);
0386     MLX5_SET(sqc, sqc, state, next_state);
0387 
0388     return mlx5_core_modify_sq(peer_mdev, sqn, in);
0389 }
0390 
0391 static int mlx5_hairpin_pair_queues(struct mlx5_hairpin *hp)
0392 {
0393     int i, j, err;
0394 
0395     /* set peer SQs */
0396     for (i = 0; i < hp->num_channels; i++) {
0397         err = mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i],
0398                          MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY,
0399                          MLX5_CAP_GEN(hp->func_mdev, vhca_id), hp->rqn[i]);
0400         if (err)
0401             goto err_modify_sq;
0402     }
0403 
0404     /* set func RQs */
0405     for (i = 0; i < hp->num_channels; i++) {
0406         err = mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn[i],
0407                          MLX5_RQC_STATE_RST, MLX5_RQC_STATE_RDY,
0408                          MLX5_CAP_GEN(hp->peer_mdev, vhca_id), hp->sqn[i]);
0409         if (err)
0410             goto err_modify_rq;
0411     }
0412 
0413     return 0;
0414 
0415 err_modify_rq:
0416     for (j = 0; j < i; j++)
0417         mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn[j], MLX5_RQC_STATE_RDY,
0418                        MLX5_RQC_STATE_RST, 0, 0);
0419     i = hp->num_channels;
0420 err_modify_sq:
0421     for (j = 0; j < i; j++)
0422         mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[j], MLX5_SQC_STATE_RDY,
0423                        MLX5_SQC_STATE_RST, 0, 0);
0424     return err;
0425 }
0426 
0427 static void mlx5_hairpin_unpair_peer_sq(struct mlx5_hairpin *hp)
0428 {
0429     int i;
0430 
0431     for (i = 0; i < hp->num_channels; i++)
0432         mlx5_hairpin_modify_sq(hp->peer_mdev, hp->sqn[i], MLX5_SQC_STATE_RDY,
0433                        MLX5_SQC_STATE_RST, 0, 0);
0434 }
0435 
0436 static void mlx5_hairpin_unpair_queues(struct mlx5_hairpin *hp)
0437 {
0438     int i;
0439 
0440     /* unset func RQs */
0441     for (i = 0; i < hp->num_channels; i++)
0442         mlx5_hairpin_modify_rq(hp->func_mdev, hp->rqn[i], MLX5_RQC_STATE_RDY,
0443                        MLX5_RQC_STATE_RST, 0, 0);
0444     /* unset peer SQs */
0445     if (!hp->peer_gone)
0446         mlx5_hairpin_unpair_peer_sq(hp);
0447 }
0448 
0449 struct mlx5_hairpin *
0450 mlx5_core_hairpin_create(struct mlx5_core_dev *func_mdev,
0451              struct mlx5_core_dev *peer_mdev,
0452              struct mlx5_hairpin_params *params)
0453 {
0454     struct mlx5_hairpin *hp;
0455     int size, err;
0456 
0457     size = sizeof(*hp) + params->num_channels * 2 * sizeof(u32);
0458     hp = kzalloc(size, GFP_KERNEL);
0459     if (!hp)
0460         return ERR_PTR(-ENOMEM);
0461 
0462     hp->func_mdev = func_mdev;
0463     hp->peer_mdev = peer_mdev;
0464     hp->num_channels = params->num_channels;
0465 
0466     hp->rqn = (void *)hp + sizeof(*hp);
0467     hp->sqn = hp->rqn + params->num_channels;
0468 
0469     /* alloc and pair func --> peer hairpin */
0470     err = mlx5_hairpin_create_queues(hp, params);
0471     if (err)
0472         goto err_create_queues;
0473 
0474     err = mlx5_hairpin_pair_queues(hp);
0475     if (err)
0476         goto err_pair_queues;
0477 
0478     return hp;
0479 
0480 err_pair_queues:
0481     mlx5_hairpin_destroy_queues(hp);
0482 err_create_queues:
0483     kfree(hp);
0484     return ERR_PTR(err);
0485 }
0486 
0487 void mlx5_core_hairpin_destroy(struct mlx5_hairpin *hp)
0488 {
0489     mlx5_hairpin_unpair_queues(hp);
0490     mlx5_hairpin_destroy_queues(hp);
0491     kfree(hp);
0492 }
0493 
0494 void mlx5_core_hairpin_clear_dead_peer(struct mlx5_hairpin *hp)
0495 {
0496     int i;
0497 
0498     mlx5_hairpin_unpair_peer_sq(hp);
0499 
0500     /* destroy peer SQ */
0501     for (i = 0; i < hp->num_channels; i++)
0502         mlx5_core_destroy_sq(hp->peer_mdev, hp->sqn[i]);
0503 
0504     hp->peer_gone = true;
0505 }