mlx4_qp.c revision 219820
1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004 Topspin Communications. All rights reserved. 3219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 4219820Sjeff * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 5219820Sjeff * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 6219820Sjeff * 7219820Sjeff * This software is available to you under a choice of one of two 8219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 9219820Sjeff * General Public License (GPL) Version 2, available from the file 10219820Sjeff * COPYING in the main directory of this source tree, or the 11219820Sjeff * OpenIB.org BSD license below: 12219820Sjeff * 13219820Sjeff * Redistribution and use in source and binary forms, with or 14219820Sjeff * without modification, are permitted provided that the following 15219820Sjeff * conditions are met: 16219820Sjeff * 17219820Sjeff * - Redistributions of source code must retain the above 18219820Sjeff * copyright notice, this list of conditions and the following 19219820Sjeff * disclaimer. 20219820Sjeff * 21219820Sjeff * - Redistributions in binary form must reproduce the above 22219820Sjeff * copyright notice, this list of conditions and the following 23219820Sjeff * disclaimer in the documentation and/or other materials 24219820Sjeff * provided with the distribution. 25219820Sjeff * 26219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 30219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33219820Sjeff * SOFTWARE. 34219820Sjeff */ 35219820Sjeff 36219820Sjeff#include <linux/init.h> 37219820Sjeff 38219820Sjeff#include <linux/mlx4/cmd.h> 39219820Sjeff#include <linux/mlx4/qp.h> 40219820Sjeff 41219820Sjeff#include "mlx4.h" 42219820Sjeff#include "icm.h" 43219820Sjeff 44219820Sjeffvoid mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type) 45219820Sjeff{ 46219820Sjeff struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 47219820Sjeff struct mlx4_qp *qp; 48219820Sjeff 49219820Sjeff spin_lock(&qp_table->lock); 50219820Sjeff 51219820Sjeff qp = __mlx4_qp_lookup(dev, qpn); 52219820Sjeff if (qp) 53219820Sjeff atomic_inc(&qp->refcount); 54219820Sjeff 55219820Sjeff spin_unlock(&qp_table->lock); 56219820Sjeff 57219820Sjeff if (!qp) { 58219820Sjeff mlx4_warn(dev, "Async event for bogus QP %08x\n", qpn); 59219820Sjeff return; 60219820Sjeff } 61219820Sjeff 62219820Sjeff qp->event(qp, event_type); 63219820Sjeff 64219820Sjeff if (atomic_dec_and_test(&qp->refcount)) 65219820Sjeff complete(&qp->free); 66219820Sjeff} 67219820Sjeff 68219820Sjeffint mlx4_qp_modify(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 69219820Sjeff enum mlx4_qp_state cur_state, enum mlx4_qp_state new_state, 70219820Sjeff struct mlx4_qp_context *context, enum mlx4_qp_optpar optpar, 71219820Sjeff int sqd_event, struct mlx4_qp *qp) 72219820Sjeff{ 73219820Sjeff static const u16 op[MLX4_QP_NUM_STATE][MLX4_QP_NUM_STATE] = { 74219820Sjeff [MLX4_QP_STATE_RST] = { 75219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 76219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 77219820Sjeff [MLX4_QP_STATE_INIT] = MLX4_CMD_RST2INIT_QP, 78219820Sjeff }, 79219820Sjeff [MLX4_QP_STATE_INIT] = { 80219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 81219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 82219820Sjeff [MLX4_QP_STATE_INIT] = MLX4_CMD_INIT2INIT_QP, 83219820Sjeff [MLX4_QP_STATE_RTR] = MLX4_CMD_INIT2RTR_QP, 84219820Sjeff }, 85219820Sjeff [MLX4_QP_STATE_RTR] = { 86219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 87219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 88219820Sjeff [MLX4_QP_STATE_RTS] = MLX4_CMD_RTR2RTS_QP, 89219820Sjeff }, 90219820Sjeff [MLX4_QP_STATE_RTS] = { 91219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 92219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 93219820Sjeff [MLX4_QP_STATE_RTS] = MLX4_CMD_RTS2RTS_QP, 94219820Sjeff [MLX4_QP_STATE_SQD] = MLX4_CMD_RTS2SQD_QP, 95219820Sjeff }, 96219820Sjeff [MLX4_QP_STATE_SQD] = { 97219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 98219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 99219820Sjeff [MLX4_QP_STATE_RTS] = MLX4_CMD_SQD2RTS_QP, 100219820Sjeff [MLX4_QP_STATE_SQD] = MLX4_CMD_SQD2SQD_QP, 101219820Sjeff }, 102219820Sjeff [MLX4_QP_STATE_SQER] = { 103219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 104219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 105219820Sjeff [MLX4_QP_STATE_RTS] = MLX4_CMD_SQERR2RTS_QP, 106219820Sjeff }, 107219820Sjeff [MLX4_QP_STATE_ERR] = { 108219820Sjeff [MLX4_QP_STATE_RST] = MLX4_CMD_2RST_QP, 109219820Sjeff [MLX4_QP_STATE_ERR] = MLX4_CMD_2ERR_QP, 110219820Sjeff } 111219820Sjeff }; 112219820Sjeff 113219820Sjeff struct mlx4_cmd_mailbox *mailbox; 114219820Sjeff int ret = 0; 115219820Sjeff 116219820Sjeff if (cur_state >= MLX4_QP_NUM_STATE || new_state >= MLX4_QP_NUM_STATE || 117219820Sjeff !op[cur_state][new_state]) 118219820Sjeff return -EINVAL; 119219820Sjeff 120219820Sjeff if (op[cur_state][new_state] == MLX4_CMD_2RST_QP) 121219820Sjeff return mlx4_cmd(dev, 0, qp->qpn, 2, 122219820Sjeff MLX4_CMD_2RST_QP, MLX4_CMD_TIME_CLASS_A); 123219820Sjeff 124219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 125219820Sjeff if (IS_ERR(mailbox)) 126219820Sjeff return PTR_ERR(mailbox); 127219820Sjeff 128219820Sjeff if (cur_state == MLX4_QP_STATE_RST && new_state == MLX4_QP_STATE_INIT) { 129219820Sjeff u64 mtt_addr = mlx4_mtt_addr(dev, mtt); 130219820Sjeff context->mtt_base_addr_h = mtt_addr >> 32; 131219820Sjeff context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); 132219820Sjeff context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT; 133219820Sjeff } 134219820Sjeff 135219820Sjeff *(__be32 *) mailbox->buf = cpu_to_be32(optpar); 136219820Sjeff memcpy(mailbox->buf + 8, context, sizeof *context); 137219820Sjeff 138219820Sjeff ((struct mlx4_qp_context *) (mailbox->buf + 8))->local_qpn = 139219820Sjeff cpu_to_be32(qp->qpn); 140219820Sjeff 141219820Sjeff ret = mlx4_cmd(dev, mailbox->dma, qp->qpn | (!!sqd_event << 31), 142219820Sjeff new_state == MLX4_QP_STATE_RST ? 2 : 0, 143219820Sjeff op[cur_state][new_state], MLX4_CMD_TIME_CLASS_C); 144219820Sjeff 145219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 146219820Sjeff return ret; 147219820Sjeff} 148219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_modify); 149219820Sjeff 150219820Sjeffint mlx4_qp_reserve_range(struct mlx4_dev *dev, int cnt, int align, int *base) 151219820Sjeff{ 152219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 153219820Sjeff struct mlx4_qp_table *qp_table = &priv->qp_table; 154219820Sjeff int qpn; 155219820Sjeff 156219820Sjeff qpn = mlx4_bitmap_alloc_range(&qp_table->bitmap, cnt, align); 157219820Sjeff if (qpn == -1) 158219820Sjeff return -ENOMEM; 159219820Sjeff 160219820Sjeff *base = qpn; 161219820Sjeff return 0; 162219820Sjeff} 163219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_reserve_range); 164219820Sjeff 165219820Sjeffvoid mlx4_qp_release_range(struct mlx4_dev *dev, int base_qpn, int cnt) 166219820Sjeff{ 167219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 168219820Sjeff struct mlx4_qp_table *qp_table = &priv->qp_table; 169219820Sjeff if (base_qpn < dev->caps.sqp_start + 8) 170219820Sjeff return; 171219820Sjeff 172219820Sjeff mlx4_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); 173219820Sjeff} 174219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_release_range); 175219820Sjeff 176219820Sjeffint mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp) 177219820Sjeff{ 178219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 179219820Sjeff struct mlx4_qp_table *qp_table = &priv->qp_table; 180219820Sjeff int err; 181219820Sjeff 182219820Sjeff if (!qpn) 183219820Sjeff return -EINVAL; 184219820Sjeff 185219820Sjeff qp->qpn = qpn; 186219820Sjeff 187219820Sjeff err = mlx4_table_get(dev, &qp_table->qp_table, qp->qpn); 188219820Sjeff if (err) 189219820Sjeff goto err_out; 190219820Sjeff 191219820Sjeff err = mlx4_table_get(dev, &qp_table->auxc_table, qp->qpn); 192219820Sjeff if (err) 193219820Sjeff goto err_put_qp; 194219820Sjeff 195219820Sjeff err = mlx4_table_get(dev, &qp_table->altc_table, qp->qpn); 196219820Sjeff if (err) 197219820Sjeff goto err_put_auxc; 198219820Sjeff 199219820Sjeff err = mlx4_table_get(dev, &qp_table->rdmarc_table, qp->qpn); 200219820Sjeff if (err) 201219820Sjeff goto err_put_altc; 202219820Sjeff 203219820Sjeff err = mlx4_table_get(dev, &qp_table->cmpt_table, qp->qpn); 204219820Sjeff if (err) 205219820Sjeff goto err_put_rdmarc; 206219820Sjeff 207219820Sjeff spin_lock_irq(&qp_table->lock); 208219820Sjeff err = radix_tree_insert(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1), qp); 209219820Sjeff spin_unlock_irq(&qp_table->lock); 210219820Sjeff if (err) 211219820Sjeff goto err_put_cmpt; 212219820Sjeff 213219820Sjeff atomic_set(&qp->refcount, 1); 214219820Sjeff init_completion(&qp->free); 215219820Sjeff 216219820Sjeff return 0; 217219820Sjeff 218219820Sjefferr_put_cmpt: 219219820Sjeff mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn); 220219820Sjeff 221219820Sjefferr_put_rdmarc: 222219820Sjeff mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn); 223219820Sjeff 224219820Sjefferr_put_altc: 225219820Sjeff mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); 226219820Sjeff 227219820Sjefferr_put_auxc: 228219820Sjeff mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); 229219820Sjeff 230219820Sjefferr_put_qp: 231219820Sjeff mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); 232219820Sjeff 233219820Sjefferr_out: 234219820Sjeff return err; 235219820Sjeff} 236219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_alloc); 237219820Sjeff 238219820Sjeffstruct mlx4_qp *mlx4_qp_lookup_lock(struct mlx4_dev *dev, u32 qpn) 239219820Sjeff{ 240219820Sjeff struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 241219820Sjeff unsigned long flags; 242219820Sjeff struct mlx4_qp *qp; 243219820Sjeff 244219820Sjeff spin_lock_irqsave(&qp_table->lock, flags); 245219820Sjeff qp = radix_tree_lookup(&dev->qp_table_tree, qpn & (dev->caps.num_qps - 1)); 246219820Sjeff spin_unlock_irqrestore(&qp_table->lock, flags); 247219820Sjeff return qp; 248219820Sjeff} 249219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_lookup_lock); 250219820Sjeff 251219820Sjeffvoid mlx4_qp_remove(struct mlx4_dev *dev, struct mlx4_qp *qp) 252219820Sjeff{ 253219820Sjeff struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 254219820Sjeff unsigned long flags; 255219820Sjeff 256219820Sjeff spin_lock_irqsave(&qp_table->lock, flags); 257219820Sjeff radix_tree_delete(&dev->qp_table_tree, qp->qpn & (dev->caps.num_qps - 1)); 258219820Sjeff spin_unlock_irqrestore(&qp_table->lock, flags); 259219820Sjeff} 260219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_remove); 261219820Sjeff 262219820Sjeffvoid mlx4_qp_free(struct mlx4_dev *dev, struct mlx4_qp *qp) 263219820Sjeff{ 264219820Sjeff struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 265219820Sjeff 266219820Sjeff if (atomic_dec_and_test(&qp->refcount)) 267219820Sjeff complete(&qp->free); 268219820Sjeff wait_for_completion(&qp->free); 269219820Sjeff 270219820Sjeff mlx4_table_put(dev, &qp_table->cmpt_table, qp->qpn); 271219820Sjeff mlx4_table_put(dev, &qp_table->rdmarc_table, qp->qpn); 272219820Sjeff mlx4_table_put(dev, &qp_table->altc_table, qp->qpn); 273219820Sjeff mlx4_table_put(dev, &qp_table->auxc_table, qp->qpn); 274219820Sjeff mlx4_table_put(dev, &qp_table->qp_table, qp->qpn); 275219820Sjeff} 276219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_free); 277219820Sjeff 278219820Sjeffstatic int mlx4_CONF_SPECIAL_QP(struct mlx4_dev *dev, u32 base_qpn) 279219820Sjeff{ 280219820Sjeff return mlx4_cmd(dev, 0, base_qpn, 281219820Sjeff (dev->caps.flags & MLX4_DEV_CAP_FLAG_RAW_ETY) ? 4 : 0, 282219820Sjeff MLX4_CMD_CONF_SPECIAL_QP, MLX4_CMD_TIME_CLASS_B); 283219820Sjeff} 284219820Sjeff 285219820Sjeffint mlx4_init_qp_table(struct mlx4_dev *dev) 286219820Sjeff{ 287219820Sjeff struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; 288219820Sjeff int err; 289219820Sjeff int reserved_from_top = 0; 290219820Sjeff 291219820Sjeff spin_lock_init(&qp_table->lock); 292219820Sjeff INIT_RADIX_TREE(&dev->qp_table_tree, GFP_ATOMIC); 293219820Sjeff 294219820Sjeff /* 295219820Sjeff * We reserve 2 extra QPs per port for the special QPs. The 296219820Sjeff * block of special QPs must be aligned to a multiple of 8, so 297219820Sjeff * round up. 298219820Sjeff * We also reserve the MSB of the 24-bit QP number to indicate 299219820Sjeff * an XRC qp. 300219820Sjeff */ 301219820Sjeff dev->caps.sqp_start = 302219820Sjeff ALIGN(dev->caps.reserved_qps_cnt[MLX4_QP_REGION_FW], 8); 303219820Sjeff 304219820Sjeff { 305219820Sjeff int sort[MLX4_NUM_QP_REGION]; 306219820Sjeff int i, j, tmp; 307219820Sjeff int last_base = dev->caps.num_qps; 308219820Sjeff 309219820Sjeff for (i = 1; i < MLX4_NUM_QP_REGION; ++i) 310219820Sjeff sort[i] = i; 311219820Sjeff 312219820Sjeff for (i = MLX4_NUM_QP_REGION; i > 0; --i) { 313219820Sjeff for (j = 2; j < i; ++j) { 314219820Sjeff if (dev->caps.reserved_qps_cnt[sort[j]] > 315219820Sjeff dev->caps.reserved_qps_cnt[sort[j - 1]]) { 316219820Sjeff tmp = sort[j]; 317219820Sjeff sort[j] = sort[j - 1]; 318219820Sjeff sort[j - 1] = tmp; 319219820Sjeff } 320219820Sjeff } 321219820Sjeff } 322219820Sjeff 323219820Sjeff for (i = 1; i < MLX4_NUM_QP_REGION; ++i) { 324219820Sjeff last_base -= dev->caps.reserved_qps_cnt[sort[i]]; 325219820Sjeff dev->caps.reserved_qps_base[sort[i]] = last_base; 326219820Sjeff reserved_from_top += 327219820Sjeff dev->caps.reserved_qps_cnt[sort[i]]; 328219820Sjeff } 329219820Sjeff 330219820Sjeff } 331219820Sjeff 332219820Sjeff err = mlx4_bitmap_init(&qp_table->bitmap, dev->caps.num_qps, 333219820Sjeff (1 << 23) - 1, dev->caps.sqp_start + 8, 334219820Sjeff reserved_from_top); 335219820Sjeff if (err) 336219820Sjeff return err; 337219820Sjeff 338219820Sjeff return mlx4_CONF_SPECIAL_QP(dev, dev->caps.sqp_start); 339219820Sjeff} 340219820Sjeff 341219820Sjeffvoid mlx4_cleanup_qp_table(struct mlx4_dev *dev) 342219820Sjeff{ 343219820Sjeff mlx4_CONF_SPECIAL_QP(dev, 0); 344219820Sjeff mlx4_bitmap_cleanup(&mlx4_priv(dev)->qp_table.bitmap); 345219820Sjeff} 346219820Sjeff 347219820Sjeffint mlx4_qp_get_region(struct mlx4_dev *dev, enum mlx4_qp_region region, 348219820Sjeff int *base_qpn, int *cnt) 349219820Sjeff{ 350219820Sjeff if ((region < 0) || (region >= MLX4_NUM_QP_REGION)) 351219820Sjeff return -EINVAL; 352219820Sjeff 353219820Sjeff *base_qpn = dev->caps.reserved_qps_base[region]; 354219820Sjeff *cnt = dev->caps.reserved_qps_cnt[region]; 355219820Sjeff 356219820Sjeff return 0; 357219820Sjeff} 358219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_get_region); 359219820Sjeff 360219820Sjeffint mlx4_qp_query(struct mlx4_dev *dev, struct mlx4_qp *qp, 361219820Sjeff struct mlx4_qp_context *context) 362219820Sjeff{ 363219820Sjeff struct mlx4_cmd_mailbox *mailbox; 364219820Sjeff int err; 365219820Sjeff 366219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 367219820Sjeff if (IS_ERR(mailbox)) 368219820Sjeff return PTR_ERR(mailbox); 369219820Sjeff 370219820Sjeff err = mlx4_cmd_box(dev, 0, mailbox->dma, qp->qpn, 0, 371219820Sjeff MLX4_CMD_QUERY_QP, MLX4_CMD_TIME_CLASS_A); 372219820Sjeff if (!err) 373219820Sjeff memcpy(context, mailbox->buf + 8, sizeof *context); 374219820Sjeff 375219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 376219820Sjeff return err; 377219820Sjeff} 378219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_query); 379219820Sjeff 380219820Sjeffint mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt, 381219820Sjeff struct mlx4_qp_context *context, 382219820Sjeff struct mlx4_qp *qp, enum mlx4_qp_state *qp_state) 383219820Sjeff{ 384219820Sjeff int err; 385219820Sjeff int i; 386219820Sjeff enum mlx4_qp_state states[] = { 387219820Sjeff MLX4_QP_STATE_RST, 388219820Sjeff MLX4_QP_STATE_INIT, 389219820Sjeff MLX4_QP_STATE_RTR, 390219820Sjeff MLX4_QP_STATE_RTS 391219820Sjeff }; 392219820Sjeff 393219820Sjeff for (i = 0; i < ARRAY_SIZE(states) - 1; i++) { 394219820Sjeff context->flags &= cpu_to_be32(~(0xf << 28)); 395219820Sjeff context->flags |= cpu_to_be32(states[i + 1] << 28); 396219820Sjeff err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1], 397219820Sjeff context, 0, 0, qp); 398219820Sjeff if (err) { 399219820Sjeff mlx4_err(dev, "Failed to bring QP to state: " 400219820Sjeff "%d with error: %d\n", 401219820Sjeff states[i + 1], err); 402219820Sjeff return err; 403219820Sjeff } 404219820Sjeff 405219820Sjeff *qp_state = states[i + 1]; 406219820Sjeff } 407219820Sjeff 408219820Sjeff return 0; 409219820Sjeff} 410219820SjeffEXPORT_SYMBOL_GPL(mlx4_qp_to_ready); 411