1219820Sjeff/* 2219820Sjeff * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 3219820Sjeff * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#include <linux/init.h> 35219820Sjeff#include <linux/interrupt.h> 36255932Salfred#include <linux/slab.h> 37219820Sjeff#include <linux/mm.h> 38219820Sjeff#include <linux/dma-mapping.h> 39219820Sjeff 40219820Sjeff#include <linux/mlx4/cmd.h> 41219820Sjeff 42219820Sjeff#include "mlx4.h" 43219820Sjeff#include "fw.h" 44219820Sjeff 45219820Sjeffenum { 46255932Salfred MLX4_IRQNAME_SIZE = 32 47255932Salfred}; 48255932Salfred 49255932Salfredenum { 50219820Sjeff MLX4_NUM_ASYNC_EQE = 0x100, 51219820Sjeff MLX4_NUM_SPARE_EQE = 0x80, 52219820Sjeff MLX4_EQ_ENTRY_SIZE = 0x20 53219820Sjeff}; 54219820Sjeff 55219820Sjeff#define MLX4_EQ_STATUS_OK ( 0 << 28) 56219820Sjeff#define MLX4_EQ_STATUS_WRITE_FAIL (10 << 28) 57219820Sjeff#define MLX4_EQ_OWNER_SW ( 0 << 24) 58219820Sjeff#define MLX4_EQ_OWNER_HW ( 1 << 24) 59219820Sjeff#define MLX4_EQ_FLAG_EC ( 1 << 18) 60219820Sjeff#define MLX4_EQ_FLAG_OI ( 1 << 17) 61219820Sjeff#define MLX4_EQ_STATE_ARMED ( 9 << 8) 62219820Sjeff#define MLX4_EQ_STATE_FIRED (10 << 8) 63219820Sjeff#define MLX4_EQ_STATE_ALWAYS_ARMED (11 << 8) 64219820Sjeff 65219820Sjeff#define MLX4_ASYNC_EVENT_MASK ((1ull << MLX4_EVENT_TYPE_PATH_MIG) | \ 66219820Sjeff (1ull << MLX4_EVENT_TYPE_COMM_EST) | \ 67219820Sjeff (1ull << MLX4_EVENT_TYPE_SQ_DRAINED) | \ 68219820Sjeff (1ull << MLX4_EVENT_TYPE_CQ_ERROR) | \ 69219820Sjeff (1ull << MLX4_EVENT_TYPE_WQ_CATAS_ERROR) | \ 70219820Sjeff (1ull << MLX4_EVENT_TYPE_EEC_CATAS_ERROR) | \ 71219820Sjeff (1ull << MLX4_EVENT_TYPE_PATH_MIG_FAILED) | \ 72219820Sjeff (1ull << MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR) | \ 73219820Sjeff (1ull << MLX4_EVENT_TYPE_WQ_ACCESS_ERROR) | \ 74219820Sjeff (1ull << MLX4_EVENT_TYPE_PORT_CHANGE) | \ 75219820Sjeff (1ull << MLX4_EVENT_TYPE_ECC_DETECT) | \ 76219820Sjeff (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ 77219820Sjeff (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ 78219820Sjeff (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ 79255932Salfred (1ull << MLX4_EVENT_TYPE_CMD) | \ 80255932Salfred (1ull << MLX4_EVENT_TYPE_OP_REQUIRED) | \ 81255932Salfred (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL) | \ 82255932Salfred (1ull << MLX4_EVENT_TYPE_FLR_EVENT) | \ 83255932Salfred (1ull << MLX4_EVENT_TYPE_FATAL_WARNING)) 84219820Sjeff 85255932Salfredstatic u64 get_async_ev_mask(struct mlx4_dev *dev) 86255932Salfred{ 87255932Salfred u64 async_ev_mask = MLX4_ASYNC_EVENT_MASK; 88255932Salfred if (dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV) 89255932Salfred async_ev_mask |= (1ull << MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT); 90219820Sjeff 91255932Salfred return async_ev_mask; 92255932Salfred} 93255932Salfred 94219820Sjeffstatic void eq_set_ci(struct mlx4_eq *eq, int req_not) 95219820Sjeff{ 96219820Sjeff __raw_writel((__force u32) cpu_to_be32((eq->cons_index & 0xffffff) | 97219820Sjeff req_not << 31), 98219820Sjeff eq->doorbell); 99219820Sjeff /* We still want ordering, just not swabbing, so add a barrier */ 100219820Sjeff mb(); 101219820Sjeff} 102219820Sjeff 103255932Salfredstatic struct mlx4_eqe *get_eqe(struct mlx4_eq *eq, u32 entry, u8 eqe_factor) 104219820Sjeff{ 105255932Salfred /* (entry & (eq->nent - 1)) gives us a cyclic array */ 106255932Salfred unsigned long offset = (entry & (eq->nent - 1)) * (MLX4_EQ_ENTRY_SIZE << eqe_factor); 107255932Salfred /* CX3 is capable of extending the EQE from 32 to 64 bytes. 108255932Salfred * When this feature is enabled, the first (in the lower addresses) 109255932Salfred * 32 bytes in the 64 byte EQE are reserved and the next 32 bytes 110255932Salfred * contain the legacy EQE information. 111255932Salfred */ 112255932Salfred return eq->page_list[offset / PAGE_SIZE].buf + (offset + (eqe_factor ? MLX4_EQ_ENTRY_SIZE : 0)) % PAGE_SIZE; 113219820Sjeff} 114219820Sjeff 115255932Salfredstatic struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq, u8 eqe_factor) 116219820Sjeff{ 117255932Salfred struct mlx4_eqe *eqe = get_eqe(eq, eq->cons_index, eqe_factor); 118219820Sjeff return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe; 119219820Sjeff} 120219820Sjeff 121255932Salfredstatic struct mlx4_eqe *next_slave_event_eqe(struct mlx4_slave_event_eq *slave_eq) 122255932Salfred{ 123255932Salfred struct mlx4_eqe *eqe = 124255932Salfred &slave_eq->event_eqe[slave_eq->cons & (SLAVE_EVENT_EQ_SIZE - 1)]; 125255932Salfred return (!!(eqe->owner & 0x80) ^ 126255932Salfred !!(slave_eq->cons & SLAVE_EVENT_EQ_SIZE)) ? 127255932Salfred eqe : NULL; 128255932Salfred} 129255932Salfred 130255932Salfredvoid mlx4_gen_slave_eqe(struct work_struct *work) 131255932Salfred{ 132255932Salfred struct mlx4_mfunc_master_ctx *master = 133255932Salfred container_of(work, struct mlx4_mfunc_master_ctx, 134255932Salfred slave_event_work); 135255932Salfred struct mlx4_mfunc *mfunc = 136255932Salfred container_of(master, struct mlx4_mfunc, master); 137255932Salfred struct mlx4_priv *priv = container_of(mfunc, struct mlx4_priv, mfunc); 138255932Salfred struct mlx4_dev *dev = &priv->dev; 139255932Salfred struct mlx4_slave_event_eq *slave_eq = &mfunc->master.slave_eq; 140255932Salfred struct mlx4_eqe *eqe; 141255932Salfred u8 slave; 142255932Salfred int i; 143255932Salfred 144255932Salfred for (eqe = next_slave_event_eqe(slave_eq); eqe; 145255932Salfred eqe = next_slave_event_eqe(slave_eq)) { 146255932Salfred slave = eqe->slave_id; 147255932Salfred 148255932Salfred /* All active slaves need to receive the event */ 149255932Salfred if (slave == ALL_SLAVES) { 150255932Salfred for (i = 0; i < dev->num_slaves; i++) { 151255932Salfred if (i != dev->caps.function && 152255932Salfred master->slave_state[i].active) 153255932Salfred if (mlx4_GEN_EQE(dev, i, eqe)) 154255932Salfred mlx4_warn(dev, "Failed to " 155255932Salfred " generate event " 156255932Salfred "for slave %d\n", i); 157255932Salfred } 158255932Salfred } else { 159255932Salfred if (mlx4_GEN_EQE(dev, slave, eqe)) 160255932Salfred mlx4_warn(dev, "Failed to generate event " 161255932Salfred "for slave %d\n", slave); 162255932Salfred } 163255932Salfred ++slave_eq->cons; 164255932Salfred } 165255932Salfred} 166255932Salfred 167255932Salfred 168255932Salfredstatic void slave_event(struct mlx4_dev *dev, u8 slave, struct mlx4_eqe *eqe) 169255932Salfred{ 170255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 171255932Salfred struct mlx4_slave_event_eq *slave_eq = &priv->mfunc.master.slave_eq; 172255932Salfred struct mlx4_eqe *s_eqe; 173255932Salfred unsigned long flags; 174255932Salfred 175255932Salfred spin_lock_irqsave(&slave_eq->event_lock, flags); 176255932Salfred s_eqe = &slave_eq->event_eqe[slave_eq->prod & (SLAVE_EVENT_EQ_SIZE - 1)]; 177255932Salfred if ((!!(s_eqe->owner & 0x80)) ^ 178255932Salfred (!!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE))) { 179255932Salfred mlx4_warn(dev, "Master failed to generate an EQE for slave: %d. " 180255932Salfred "No free EQE on slave events queue\n", slave); 181255932Salfred spin_unlock_irqrestore(&slave_eq->event_lock, flags); 182255932Salfred return; 183255932Salfred } 184255932Salfred 185255932Salfred memcpy(s_eqe, eqe, dev->caps.eqe_size - 1); 186255932Salfred s_eqe->slave_id = slave; 187255932Salfred /* ensure all information is written before setting the ownersip bit */ 188255932Salfred wmb(); 189255932Salfred s_eqe->owner = !!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE) ? 0x0 : 0x80; 190255932Salfred ++slave_eq->prod; 191255932Salfred 192255932Salfred queue_work(priv->mfunc.master.comm_wq, 193255932Salfred &priv->mfunc.master.slave_event_work); 194255932Salfred spin_unlock_irqrestore(&slave_eq->event_lock, flags); 195255932Salfred} 196255932Salfred 197255932Salfredstatic void mlx4_slave_event(struct mlx4_dev *dev, int slave, 198255932Salfred struct mlx4_eqe *eqe) 199255932Salfred{ 200255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 201255932Salfred struct mlx4_slave_state *s_slave = 202255932Salfred &priv->mfunc.master.slave_state[slave]; 203255932Salfred 204255932Salfred if (!s_slave->active) { 205255932Salfred /*mlx4_warn(dev, "Trying to pass event to inactive slave\n");*/ 206255932Salfred return; 207255932Salfred } 208255932Salfred 209255932Salfred slave_event(dev, slave, eqe); 210255932Salfred} 211255932Salfred 212255932Salfredint mlx4_gen_pkey_eqe(struct mlx4_dev *dev, int slave, u8 port) 213255932Salfred{ 214255932Salfred struct mlx4_eqe eqe; 215255932Salfred 216255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 217255932Salfred struct mlx4_slave_state *s_slave = &priv->mfunc.master.slave_state[slave]; 218255932Salfred 219255932Salfred if (!s_slave->active) 220255932Salfred return 0; 221255932Salfred 222255932Salfred memset(&eqe, 0, sizeof eqe); 223255932Salfred 224255932Salfred eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; 225255932Salfred eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE; 226255932Salfred eqe.event.port_mgmt_change.port = port; 227255932Salfred 228255932Salfred return mlx4_GEN_EQE(dev, slave, &eqe); 229255932Salfred} 230255932SalfredEXPORT_SYMBOL(mlx4_gen_pkey_eqe); 231255932Salfred 232255932Salfredint mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port) 233255932Salfred{ 234255932Salfred struct mlx4_eqe eqe; 235255932Salfred 236255932Salfred /*don't send if we don't have the that slave */ 237255932Salfred if (dev->num_vfs < slave) 238255932Salfred return 0; 239255932Salfred memset(&eqe, 0, sizeof eqe); 240255932Salfred 241255932Salfred eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; 242255932Salfred eqe.subtype = MLX4_DEV_PMC_SUBTYPE_GUID_INFO; 243255932Salfred eqe.event.port_mgmt_change.port = port; 244255932Salfred 245255932Salfred return mlx4_GEN_EQE(dev, slave, &eqe); 246255932Salfred} 247255932SalfredEXPORT_SYMBOL(mlx4_gen_guid_change_eqe); 248255932Salfred 249255932Salfredint mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port, 250255932Salfred u8 port_subtype_change) 251255932Salfred{ 252255932Salfred struct mlx4_eqe eqe; 253255932Salfred 254255932Salfred /*don't send if we don't have the that slave */ 255255932Salfred if (dev->num_vfs < slave) 256255932Salfred return 0; 257255932Salfred memset(&eqe, 0, sizeof eqe); 258255932Salfred 259255932Salfred eqe.type = MLX4_EVENT_TYPE_PORT_CHANGE; 260255932Salfred eqe.subtype = port_subtype_change; 261255932Salfred eqe.event.port_change.port = cpu_to_be32(port << 28); 262255932Salfred 263255932Salfred mlx4_dbg(dev, "%s: sending: %d to slave: %d on port: %d\n", __func__, 264255932Salfred port_subtype_change, slave, port); 265255932Salfred return mlx4_GEN_EQE(dev, slave, &eqe); 266255932Salfred} 267255932SalfredEXPORT_SYMBOL(mlx4_gen_port_state_change_eqe); 268255932Salfred 269255932Salfredenum slave_port_state mlx4_get_slave_port_state(struct mlx4_dev *dev, int slave, u8 port) 270255932Salfred{ 271255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 272255932Salfred struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state; 273255932Salfred if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS) { 274255932Salfred pr_err("%s: Error: asking for slave:%d, port:%d\n", 275255932Salfred __func__, slave, port); 276255932Salfred return SLAVE_PORT_DOWN; 277255932Salfred } 278255932Salfred return s_state[slave].port_state[port]; 279255932Salfred} 280255932SalfredEXPORT_SYMBOL(mlx4_get_slave_port_state); 281255932Salfred 282255932Salfredstatic int mlx4_set_slave_port_state(struct mlx4_dev *dev, int slave, u8 port, 283255932Salfred enum slave_port_state state) 284255932Salfred{ 285255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 286255932Salfred struct mlx4_slave_state *s_state = priv->mfunc.master.slave_state; 287255932Salfred 288255932Salfred if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) { 289255932Salfred pr_err("%s: Error: asking for slave:%d, port:%d\n", 290255932Salfred __func__, slave, port); 291255932Salfred return -1; 292255932Salfred } 293255932Salfred s_state[slave].port_state[port] = state; 294255932Salfred 295255932Salfred return 0; 296255932Salfred} 297255932Salfred 298255932Salfredstatic void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event) 299255932Salfred{ 300255932Salfred int i; 301255932Salfred enum slave_port_gen_event gen_event; 302255932Salfred 303255932Salfred for (i = 0; i < dev->num_slaves; i++) 304255932Salfred set_and_calc_slave_port_state(dev, i, port, event, &gen_event); 305255932Salfred} 306255932Salfred/************************************************************************** 307255932Salfred The function get as input the new event to that port, 308255932Salfred and according to the prev state change the slave's port state. 309255932Salfred The events are: 310255932Salfred MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, 311255932Salfred MLX4_PORT_STATE_DEV_EVENT_PORT_UP 312255932Salfred MLX4_PORT_STATE_IB_EVENT_GID_VALID 313255932Salfred MLX4_PORT_STATE_IB_EVENT_GID_INVALID 314255932Salfred***************************************************************************/ 315255932Salfredint set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave, 316255932Salfred u8 port, int event, 317255932Salfred enum slave_port_gen_event *gen_event) 318255932Salfred{ 319255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 320255932Salfred struct mlx4_slave_state *ctx = NULL; 321255932Salfred unsigned long flags; 322255932Salfred int ret = -1; 323255932Salfred enum slave_port_state cur_state = 324255932Salfred mlx4_get_slave_port_state(dev, slave, port); 325255932Salfred 326255932Salfred *gen_event = SLAVE_PORT_GEN_EVENT_NONE; 327255932Salfred 328255932Salfred if (slave >= dev->num_slaves || port > MLX4_MAX_PORTS || port == 0) { 329255932Salfred pr_err("%s: Error: asking for slave:%d, port:%d\n", 330255932Salfred __func__, slave, port); 331255932Salfred return ret; 332255932Salfred } 333255932Salfred 334255932Salfred ctx = &priv->mfunc.master.slave_state[slave]; 335255932Salfred spin_lock_irqsave(&ctx->lock, flags); 336255932Salfred 337255932Salfred switch (cur_state) { 338255932Salfred case SLAVE_PORT_DOWN: 339255932Salfred if (MLX4_PORT_STATE_DEV_EVENT_PORT_UP == event) 340255932Salfred mlx4_set_slave_port_state(dev, slave, port, 341255932Salfred SLAVE_PENDING_UP); 342255932Salfred break; 343255932Salfred case SLAVE_PENDING_UP: 344255932Salfred if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) 345255932Salfred mlx4_set_slave_port_state(dev, slave, port, 346255932Salfred SLAVE_PORT_DOWN); 347255932Salfred else if (MLX4_PORT_STATE_IB_PORT_STATE_EVENT_GID_VALID == event) { 348255932Salfred mlx4_set_slave_port_state(dev, slave, port, 349255932Salfred SLAVE_PORT_UP); 350255932Salfred *gen_event = SLAVE_PORT_GEN_EVENT_UP; 351255932Salfred } 352255932Salfred break; 353255932Salfred case SLAVE_PORT_UP: 354255932Salfred if (MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN == event) { 355255932Salfred mlx4_set_slave_port_state(dev, slave, port, 356255932Salfred SLAVE_PORT_DOWN); 357255932Salfred *gen_event = SLAVE_PORT_GEN_EVENT_DOWN; 358255932Salfred } else if (MLX4_PORT_STATE_IB_EVENT_GID_INVALID == 359255932Salfred event) { 360255932Salfred mlx4_set_slave_port_state(dev, slave, port, 361255932Salfred SLAVE_PENDING_UP); 362255932Salfred *gen_event = SLAVE_PORT_GEN_EVENT_DOWN; 363255932Salfred } 364255932Salfred break; 365255932Salfred default: 366255932Salfred pr_err("%s: BUG!!! UNKNOWN state: " 367255932Salfred "slave:%d, port:%d\n", __func__, slave, port); 368255932Salfred goto out; 369255932Salfred } 370255932Salfred ret = mlx4_get_slave_port_state(dev, slave, port); 371255932Salfred 372255932Salfredout: 373255932Salfred spin_unlock_irqrestore(&ctx->lock, flags); 374255932Salfred return ret; 375255932Salfred} 376255932Salfred 377255932SalfredEXPORT_SYMBOL(set_and_calc_slave_port_state); 378255932Salfred 379255932Salfredint mlx4_gen_slaves_port_mgt_ev(struct mlx4_dev *dev, u8 port, int attr) 380255932Salfred{ 381255932Salfred struct mlx4_eqe eqe; 382255932Salfred 383255932Salfred memset(&eqe, 0, sizeof eqe); 384255932Salfred 385255932Salfred eqe.type = MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT; 386255932Salfred eqe.subtype = MLX4_DEV_PMC_SUBTYPE_PORT_INFO; 387255932Salfred eqe.event.port_mgmt_change.port = port; 388255932Salfred eqe.event.port_mgmt_change.params.port_info.changed_attr = 389255932Salfred cpu_to_be32((u32) attr); 390255932Salfred 391255932Salfred slave_event(dev, ALL_SLAVES, &eqe); 392255932Salfred return 0; 393255932Salfred} 394255932SalfredEXPORT_SYMBOL(mlx4_gen_slaves_port_mgt_ev); 395255932Salfred 396255932Salfredvoid mlx4_master_handle_slave_flr(struct work_struct *work) 397255932Salfred{ 398255932Salfred struct mlx4_mfunc_master_ctx *master = 399255932Salfred container_of(work, struct mlx4_mfunc_master_ctx, 400255932Salfred slave_flr_event_work); 401255932Salfred struct mlx4_mfunc *mfunc = 402255932Salfred container_of(master, struct mlx4_mfunc, master); 403255932Salfred struct mlx4_priv *priv = 404255932Salfred container_of(mfunc, struct mlx4_priv, mfunc); 405255932Salfred struct mlx4_dev *dev = &priv->dev; 406255932Salfred struct mlx4_slave_state *slave_state = priv->mfunc.master.slave_state; 407255932Salfred int i; 408255932Salfred int err; 409255932Salfred unsigned long flags; 410255932Salfred 411255932Salfred mlx4_dbg(dev, "mlx4_handle_slave_flr\n"); 412255932Salfred 413255932Salfred for (i = 0 ; i < dev->num_slaves; i++) { 414255932Salfred 415255932Salfred if (MLX4_COMM_CMD_FLR == slave_state[i].last_cmd) { 416255932Salfred mlx4_dbg(dev, "mlx4_handle_slave_flr: " 417255932Salfred "clean slave: %d\n", i); 418255932Salfred 419255932Salfred mlx4_delete_all_resources_for_slave(dev, i); 420255932Salfred /*return the slave to running mode*/ 421255932Salfred spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 422255932Salfred slave_state[i].last_cmd = MLX4_COMM_CMD_RESET; 423255932Salfred slave_state[i].is_slave_going_down = 0; 424255932Salfred spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 425255932Salfred /*notify the FW:*/ 426255932Salfred err = mlx4_cmd(dev, 0, i, 0, MLX4_CMD_INFORM_FLR_DONE, 427255932Salfred MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED); 428255932Salfred if (err) 429255932Salfred mlx4_warn(dev, "Failed to notify FW on " 430255932Salfred "FLR done (slave:%d)\n", i); 431255932Salfred } 432255932Salfred } 433255932Salfred} 434255932Salfred 435219820Sjeffstatic int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) 436219820Sjeff{ 437255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 438219820Sjeff struct mlx4_eqe *eqe; 439219820Sjeff int cqn; 440219820Sjeff int eqes_found = 0; 441219820Sjeff int set_ci = 0; 442219820Sjeff int port; 443255932Salfred int slave = 0; 444255932Salfred int ret; 445255932Salfred u32 flr_slave; 446255932Salfred u8 update_slave_state; 447255932Salfred int i; 448255932Salfred enum slave_port_gen_event gen_event; 449255932Salfred unsigned long flags; 450219820Sjeff 451255932Salfred while ((eqe = next_eqe_sw(eq, dev->caps.eqe_factor))) { 452219820Sjeff /* 453219820Sjeff * Make sure we read EQ entry contents after we've 454219820Sjeff * checked the ownership bit. 455219820Sjeff */ 456219820Sjeff rmb(); 457219820Sjeff 458219820Sjeff switch (eqe->type) { 459219820Sjeff case MLX4_EVENT_TYPE_COMP: 460219820Sjeff cqn = be32_to_cpu(eqe->event.comp.cqn) & 0xffffff; 461219820Sjeff mlx4_cq_completion(dev, cqn); 462219820Sjeff break; 463219820Sjeff 464219820Sjeff case MLX4_EVENT_TYPE_PATH_MIG: 465219820Sjeff case MLX4_EVENT_TYPE_COMM_EST: 466219820Sjeff case MLX4_EVENT_TYPE_SQ_DRAINED: 467219820Sjeff case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: 468219820Sjeff case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: 469219820Sjeff case MLX4_EVENT_TYPE_PATH_MIG_FAILED: 470219820Sjeff case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: 471219820Sjeff case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: 472255932Salfred mlx4_dbg(dev, "event %d arrived\n", eqe->type); 473255932Salfred if (mlx4_is_master(dev)) { 474255932Salfred /* forward only to slave owning the QP */ 475255932Salfred ret = mlx4_get_slave_from_resource_id(dev, 476255932Salfred RES_QP, 477255932Salfred be32_to_cpu(eqe->event.qp.qpn) 478255932Salfred & 0xffffff, &slave); 479255932Salfred if (ret && ret != -ENOENT) { 480255932Salfred mlx4_dbg(dev, "QP event %02x(%02x) on " 481255932Salfred "EQ %d at index %u: could " 482255932Salfred "not get slave id (%d)\n", 483255932Salfred eqe->type, eqe->subtype, 484255932Salfred eq->eqn, eq->cons_index, ret); 485255932Salfred break; 486255932Salfred } 487255932Salfred 488255932Salfred if (!ret && slave != dev->caps.function) { 489255932Salfred mlx4_slave_event(dev, slave, eqe); 490255932Salfred break; 491255932Salfred } 492255932Salfred 493255932Salfred } 494255932Salfred mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 495255932Salfred 0xffffff, eqe->type); 496219820Sjeff break; 497219820Sjeff 498219820Sjeff case MLX4_EVENT_TYPE_SRQ_LIMIT: 499255932Salfred mlx4_warn(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", 500255932Salfred __func__); 501219820Sjeff case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: 502255932Salfred if (mlx4_is_master(dev)) { 503255932Salfred /* forward only to slave owning the SRQ */ 504255932Salfred ret = mlx4_get_slave_from_resource_id(dev, 505255932Salfred RES_SRQ, 506255932Salfred be32_to_cpu(eqe->event.srq.srqn) 507255932Salfred & 0xffffff, 508255932Salfred &slave); 509255932Salfred if (ret && ret != -ENOENT) { 510255932Salfred mlx4_warn(dev, "SRQ event %02x(%02x) " 511255932Salfred "on EQ %d at index %u: could" 512255932Salfred " not get slave id (%d)\n", 513255932Salfred eqe->type, eqe->subtype, 514255932Salfred eq->eqn, eq->cons_index, ret); 515255932Salfred break; 516255932Salfred } 517255932Salfred mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x," 518255932Salfred " event: %02x(%02x)\n", __func__, 519255932Salfred slave, 520255932Salfred be32_to_cpu(eqe->event.srq.srqn), 521255932Salfred eqe->type, eqe->subtype); 522255932Salfred 523255932Salfred if (!ret && slave != dev->caps.function) { 524255932Salfred mlx4_warn(dev, "%s: sending event " 525255932Salfred "%02x(%02x) to slave:%d\n", 526255932Salfred __func__, eqe->type, 527255932Salfred eqe->subtype, slave); 528255932Salfred mlx4_slave_event(dev, slave, eqe); 529255932Salfred break; 530255932Salfred } 531255932Salfred } 532255932Salfred mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 533255932Salfred 0xffffff, eqe->type); 534219820Sjeff break; 535219820Sjeff 536219820Sjeff case MLX4_EVENT_TYPE_CMD: 537219820Sjeff mlx4_cmd_event(dev, 538219820Sjeff be16_to_cpu(eqe->event.cmd.token), 539219820Sjeff eqe->event.cmd.status, 540219820Sjeff be64_to_cpu(eqe->event.cmd.out_param)); 541219820Sjeff break; 542219820Sjeff 543219820Sjeff case MLX4_EVENT_TYPE_PORT_CHANGE: 544219820Sjeff port = be32_to_cpu(eqe->event.port_change.port) >> 28; 545219820Sjeff if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { 546219820Sjeff mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN, 547219820Sjeff port); 548219820Sjeff mlx4_priv(dev)->sense.do_sense_port[port] = 1; 549255932Salfred if (!mlx4_is_master(dev)) 550255932Salfred break; 551255932Salfred for (i = 0; i < dev->num_slaves; i++) { 552255932Salfred if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) { 553255932Salfred if (i == mlx4_master_func_num(dev)) 554255932Salfred continue; 555255932Salfred mlx4_dbg(dev, "%s: Sending MLX4_PORT_CHANGE_SUBTYPE_DOWN" 556255932Salfred " to slave: %d, port:%d\n", 557255932Salfred __func__, i, port); 558255932Salfred mlx4_slave_event(dev, i, eqe); 559255932Salfred } else { /* IB port */ 560255932Salfred set_and_calc_slave_port_state(dev, i, port, 561255932Salfred MLX4_PORT_STATE_DEV_EVENT_PORT_DOWN, 562255932Salfred &gen_event); 563255932Salfred /*we can be in pending state, then do not send port_down event*/ 564255932Salfred if (SLAVE_PORT_GEN_EVENT_DOWN == gen_event) { 565255932Salfred if (i == mlx4_master_func_num(dev)) 566255932Salfred continue; 567255932Salfred mlx4_slave_event(dev, i, eqe); 568255932Salfred } 569255932Salfred } 570255932Salfred } 571219820Sjeff } else { 572255932Salfred mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port); 573255932Salfred 574219820Sjeff mlx4_priv(dev)->sense.do_sense_port[port] = 0; 575255932Salfred 576255932Salfred if (!mlx4_is_master(dev)) 577255932Salfred break; 578255932Salfred if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) 579255932Salfred for (i = 0; i < dev->num_slaves; i++) { 580255932Salfred if (i == mlx4_master_func_num(dev)) 581255932Salfred continue; 582255932Salfred mlx4_slave_event(dev, i, eqe); 583255932Salfred } 584255932Salfred else /* IB port */ 585255932Salfred /* port-up event will be sent to a slave when the 586255932Salfred * slave's alias-guid is set. This is done in alias_GUID.c 587255932Salfred */ 588255932Salfred set_all_slave_state(dev, port, MLX4_DEV_EVENT_PORT_UP); 589219820Sjeff } 590219820Sjeff break; 591219820Sjeff 592219820Sjeff case MLX4_EVENT_TYPE_CQ_ERROR: 593219820Sjeff mlx4_warn(dev, "CQ %s on CQN %06x\n", 594219820Sjeff eqe->event.cq_err.syndrome == 1 ? 595219820Sjeff "overrun" : "access violation", 596219820Sjeff be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); 597255932Salfred if (mlx4_is_master(dev)) { 598255932Salfred ret = mlx4_get_slave_from_resource_id(dev, 599255932Salfred RES_CQ, 600255932Salfred be32_to_cpu(eqe->event.cq_err.cqn) 601255932Salfred & 0xffffff, &slave); 602255932Salfred if (ret && ret != -ENOENT) { 603255932Salfred mlx4_dbg(dev, "CQ event %02x(%02x) on " 604255932Salfred "EQ %d at index %u: could " 605255932Salfred "not get slave id (%d)\n", 606255932Salfred eqe->type, eqe->subtype, 607255932Salfred eq->eqn, eq->cons_index, ret); 608255932Salfred break; 609255932Salfred } 610255932Salfred 611255932Salfred if (!ret && slave != dev->caps.function) { 612255932Salfred mlx4_slave_event(dev, slave, eqe); 613255932Salfred break; 614255932Salfred } 615255932Salfred } 616255932Salfred mlx4_cq_event(dev, 617255932Salfred be32_to_cpu(eqe->event.cq_err.cqn) 618255932Salfred & 0xffffff, 619219820Sjeff eqe->type); 620219820Sjeff break; 621219820Sjeff 622219820Sjeff case MLX4_EVENT_TYPE_EQ_OVERFLOW: 623219820Sjeff mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); 624219820Sjeff break; 625219820Sjeff 626255932Salfred case MLX4_EVENT_TYPE_OP_REQUIRED: 627255932Salfred atomic_inc(&priv->opreq_count); 628255932Salfred /* FW commands can't be executed from interrupt context 629255932Salfred working in deferred task */ 630255932Salfred queue_work(mlx4_wq, &priv->opreq_task); 631255932Salfred break; 632255932Salfred 633255932Salfred case MLX4_EVENT_TYPE_COMM_CHANNEL: 634255932Salfred if (!mlx4_is_master(dev)) { 635255932Salfred mlx4_warn(dev, "Received comm channel event " 636255932Salfred "for non master device\n"); 637255932Salfred break; 638255932Salfred } 639255932Salfred memcpy(&priv->mfunc.master.comm_arm_bit_vector, 640255932Salfred eqe->event.comm_channel_arm.bit_vec, 641255932Salfred sizeof eqe->event.comm_channel_arm.bit_vec); 642255932Salfred queue_work(priv->mfunc.master.comm_wq, 643255932Salfred &priv->mfunc.master.comm_work); 644255932Salfred break; 645255932Salfred 646255932Salfred case MLX4_EVENT_TYPE_FLR_EVENT: 647255932Salfred flr_slave = be32_to_cpu(eqe->event.flr_event.slave_id); 648255932Salfred if (!mlx4_is_master(dev)) { 649255932Salfred mlx4_warn(dev, "Non-master function received" 650255932Salfred "FLR event\n"); 651255932Salfred break; 652255932Salfred } 653255932Salfred 654255932Salfred mlx4_dbg(dev, "FLR event for slave: %d\n", flr_slave); 655255932Salfred 656255932Salfred if (flr_slave >= dev->num_slaves) { 657255932Salfred mlx4_warn(dev, 658255932Salfred "Got FLR for unknown function: %d\n", 659255932Salfred flr_slave); 660255932Salfred update_slave_state = 0; 661255932Salfred } else 662255932Salfred update_slave_state = 1; 663255932Salfred 664255932Salfred spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags); 665255932Salfred if (update_slave_state) { 666255932Salfred priv->mfunc.master.slave_state[flr_slave].active = false; 667255932Salfred priv->mfunc.master.slave_state[flr_slave].last_cmd = MLX4_COMM_CMD_FLR; 668255932Salfred priv->mfunc.master.slave_state[flr_slave].is_slave_going_down = 1; 669255932Salfred } 670255932Salfred spin_unlock_irqrestore(&priv->mfunc.master.slave_state_lock, flags); 671255932Salfred queue_work(priv->mfunc.master.comm_wq, 672255932Salfred &priv->mfunc.master.slave_flr_event_work); 673255932Salfred break; 674255932Salfred 675255932Salfred case MLX4_EVENT_TYPE_FATAL_WARNING: 676255932Salfred if (eqe->subtype == MLX4_FATAL_WARNING_SUBTYPE_WARMING) { 677255932Salfred if (mlx4_is_master(dev)) 678255932Salfred for (i = 0; i < dev->num_slaves; i++) { 679255932Salfred mlx4_dbg(dev, "%s: Sending " 680255932Salfred "MLX4_FATAL_WARNING_SUBTYPE_WARMING" 681255932Salfred " to slave: %d\n", __func__, i); 682255932Salfred if (i == dev->caps.function) 683255932Salfred continue; 684255932Salfred mlx4_slave_event(dev, i, eqe); 685255932Salfred } 686255932Salfred mlx4_err(dev, "Temperature Threshold was reached! " 687255932Salfred "Threshold: %d celsius degrees; " 688255932Salfred "Current Temperature: %d\n", 689255932Salfred be16_to_cpu(eqe->event.warming.warning_threshold), 690255932Salfred be16_to_cpu(eqe->event.warming.current_temperature)); 691255932Salfred } else 692255932Salfred mlx4_warn(dev, "Unhandled event FATAL WARNING (%02x), " 693255932Salfred "subtype %02x on EQ %d at index %u. owner=%x, " 694255932Salfred "nent=0x%x, slave=%x, ownership=%s\n", 695255932Salfred eqe->type, eqe->subtype, eq->eqn, 696255932Salfred eq->cons_index, eqe->owner, eq->nent, 697255932Salfred eqe->slave_id, 698255932Salfred !!(eqe->owner & 0x80) ^ 699255932Salfred !!(eq->cons_index & eq->nent) ? "HW" : "SW"); 700255932Salfred 701255932Salfred break; 702255932Salfred 703255932Salfred case MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT: 704255932Salfred mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_MGMT_CHANGE, 705255932Salfred (unsigned long) eqe); 706255932Salfred break; 707255932Salfred 708219820Sjeff case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: 709219820Sjeff case MLX4_EVENT_TYPE_ECC_DETECT: 710219820Sjeff default: 711255932Salfred mlx4_warn(dev, "Unhandled event %02x(%02x) on EQ %d at " 712255932Salfred "index %u. owner=%x, nent=0x%x, slave=%x, " 713255932Salfred "ownership=%s\n", 714255932Salfred eqe->type, eqe->subtype, eq->eqn, 715255932Salfred eq->cons_index, eqe->owner, eq->nent, 716255932Salfred eqe->slave_id, 717255932Salfred !!(eqe->owner & 0x80) ^ 718255932Salfred !!(eq->cons_index & eq->nent) ? "HW" : "SW"); 719219820Sjeff break; 720219820Sjeff }; 721219820Sjeff 722219820Sjeff ++eq->cons_index; 723219820Sjeff eqes_found = 1; 724219820Sjeff ++set_ci; 725219820Sjeff 726219820Sjeff /* 727219820Sjeff * The HCA will think the queue has overflowed if we 728219820Sjeff * don't tell it we've been processing events. We 729219820Sjeff * create our EQs with MLX4_NUM_SPARE_EQE extra 730219820Sjeff * entries, so we must update our consumer index at 731219820Sjeff * least that often. 732219820Sjeff */ 733219820Sjeff if (unlikely(set_ci >= MLX4_NUM_SPARE_EQE)) { 734219820Sjeff eq_set_ci(eq, 0); 735219820Sjeff set_ci = 0; 736219820Sjeff } 737219820Sjeff } 738219820Sjeff 739219820Sjeff eq_set_ci(eq, 1); 740219820Sjeff 741219820Sjeff return eqes_found; 742219820Sjeff} 743219820Sjeff 744219820Sjeffstatic irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) 745219820Sjeff{ 746219820Sjeff struct mlx4_dev *dev = dev_ptr; 747219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 748219820Sjeff int work = 0; 749219820Sjeff int i; 750219820Sjeff 751255932Salfred 752219820Sjeff writel(priv->eq_table.clr_mask, priv->eq_table.clr_int); 753219820Sjeff 754219820Sjeff for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) 755219820Sjeff work |= mlx4_eq_int(dev, &priv->eq_table.eq[i]); 756219820Sjeff 757219820Sjeff return IRQ_RETVAL(work); 758219820Sjeff} 759219820Sjeff 760219820Sjeffstatic irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr) 761219820Sjeff{ 762219820Sjeff struct mlx4_eq *eq = eq_ptr; 763219820Sjeff struct mlx4_dev *dev = eq->dev; 764219820Sjeff 765219820Sjeff mlx4_eq_int(dev, eq); 766219820Sjeff 767219820Sjeff /* MSI-X vectors always belong to us */ 768219820Sjeff return IRQ_HANDLED; 769219820Sjeff} 770219820Sjeff 771255932Salfredint mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, 772255932Salfred struct mlx4_vhcr *vhcr, 773255932Salfred struct mlx4_cmd_mailbox *inbox, 774255932Salfred struct mlx4_cmd_mailbox *outbox, 775255932Salfred struct mlx4_cmd_info *cmd) 776255932Salfred{ 777255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 778255932Salfred struct mlx4_slave_event_eq_info *event_eq = 779255932Salfred priv->mfunc.master.slave_state[slave].event_eq; 780255932Salfred u32 in_modifier = vhcr->in_modifier; 781255932Salfred u32 eqn = in_modifier & 0x1FF; 782255932Salfred u64 in_param = vhcr->in_param; 783255932Salfred int err = 0; 784255932Salfred int i; 785255932Salfred 786255932Salfred if (slave == dev->caps.function) 787255932Salfred err = mlx4_cmd(dev, in_param, (in_modifier & 0x80000000) | eqn, 788255932Salfred 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, 789255932Salfred MLX4_CMD_NATIVE); 790255932Salfred if (!err) 791255932Salfred for (i = 0; i < MLX4_EVENT_TYPES_NUM; ++i) 792255932Salfred if (in_param & (1LL << i)) 793255932Salfred event_eq[i].eqn = in_modifier >> 31 ? -1 : eqn; 794255932Salfred 795255932Salfred return err; 796255932Salfred} 797255932Salfred 798219820Sjeffstatic int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, 799219820Sjeff int eq_num) 800219820Sjeff{ 801219820Sjeff return mlx4_cmd(dev, event_mask, (unmap << 31) | eq_num, 802255932Salfred 0, MLX4_CMD_MAP_EQ, MLX4_CMD_TIME_CLASS_B, 803255932Salfred MLX4_CMD_WRAPPED); 804219820Sjeff} 805219820Sjeff 806219820Sjeffstatic int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 807219820Sjeff int eq_num) 808219820Sjeff{ 809255932Salfred return mlx4_cmd(dev, mailbox->dma, eq_num, 0, 810255932Salfred MLX4_CMD_SW2HW_EQ, MLX4_CMD_TIME_CLASS_A, 811255932Salfred MLX4_CMD_WRAPPED); 812219820Sjeff} 813219820Sjeff 814219820Sjeffstatic int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, 815219820Sjeff int eq_num) 816219820Sjeff{ 817255932Salfred return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num, 818255932Salfred 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A, 819255932Salfred MLX4_CMD_WRAPPED); 820219820Sjeff} 821219820Sjeff 822219820Sjeffstatic int mlx4_num_eq_uar(struct mlx4_dev *dev) 823219820Sjeff{ 824219820Sjeff /* 825219820Sjeff * Each UAR holds 4 EQ doorbells. To figure out how many UARs 826219820Sjeff * we need to map, take the difference of highest index and 827219820Sjeff * the lowest index we'll use and add 1. 828219820Sjeff */ 829255932Salfred return (dev->caps.num_comp_vectors + 1 + dev->caps.reserved_eqs + 830255932Salfred dev->caps.comp_pool)/4 - dev->caps.reserved_eqs/4 + 1; 831219820Sjeff} 832219820Sjeff 833219820Sjeffstatic void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq) 834219820Sjeff{ 835219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 836219820Sjeff int index; 837219820Sjeff 838219820Sjeff index = eq->eqn / 4 - dev->caps.reserved_eqs / 4; 839219820Sjeff 840219820Sjeff if (!priv->eq_table.uar_map[index]) { 841219820Sjeff priv->eq_table.uar_map[index] = 842219820Sjeff ioremap(pci_resource_start(dev->pdev, 2) + 843219820Sjeff ((eq->eqn / 4) << PAGE_SHIFT), 844219820Sjeff PAGE_SIZE); 845219820Sjeff if (!priv->eq_table.uar_map[index]) { 846219820Sjeff mlx4_err(dev, "Couldn't map EQ doorbell for EQN 0x%06x\n", 847219820Sjeff eq->eqn); 848219820Sjeff return NULL; 849219820Sjeff } 850219820Sjeff } 851219820Sjeff 852219820Sjeff return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4); 853219820Sjeff} 854219820Sjeff 855255932Salfredstatic void mlx4_unmap_uar(struct mlx4_dev *dev) 856255932Salfred{ 857255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 858255932Salfred int i; 859255932Salfred 860255932Salfred for (i = 0; i < mlx4_num_eq_uar(dev); ++i) 861255932Salfred if (priv->eq_table.uar_map[i]) { 862255932Salfred iounmap(priv->eq_table.uar_map[i]); 863255932Salfred priv->eq_table.uar_map[i] = NULL; 864255932Salfred } 865255932Salfred} 866255932Salfred 867219820Sjeffstatic int mlx4_create_eq(struct mlx4_dev *dev, int nent, 868219820Sjeff u8 intr, struct mlx4_eq *eq) 869219820Sjeff{ 870219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 871219820Sjeff struct mlx4_cmd_mailbox *mailbox; 872219820Sjeff struct mlx4_eq_context *eq_context; 873219820Sjeff int npages; 874219820Sjeff u64 *dma_list = NULL; 875219820Sjeff dma_addr_t t; 876219820Sjeff u64 mtt_addr; 877219820Sjeff int err = -ENOMEM; 878219820Sjeff int i; 879219820Sjeff 880219820Sjeff eq->dev = dev; 881219820Sjeff eq->nent = roundup_pow_of_two(max(nent, 2)); 882255932Salfred /* CX3 is capable of extending the CQE\EQE from 32 to 64 bytes */ 883255932Salfred npages = PAGE_ALIGN(eq->nent * (MLX4_EQ_ENTRY_SIZE << dev->caps.eqe_factor)) / PAGE_SIZE; 884219820Sjeff 885219820Sjeff eq->page_list = kmalloc(npages * sizeof *eq->page_list, 886219820Sjeff GFP_KERNEL); 887219820Sjeff if (!eq->page_list) 888219820Sjeff goto err_out; 889219820Sjeff 890219820Sjeff for (i = 0; i < npages; ++i) 891219820Sjeff eq->page_list[i].buf = NULL; 892219820Sjeff 893219820Sjeff dma_list = kmalloc(npages * sizeof *dma_list, GFP_KERNEL); 894219820Sjeff if (!dma_list) 895219820Sjeff goto err_out_free; 896219820Sjeff 897219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 898219820Sjeff if (IS_ERR(mailbox)) 899219820Sjeff goto err_out_free; 900219820Sjeff eq_context = mailbox->buf; 901219820Sjeff 902219820Sjeff for (i = 0; i < npages; ++i) { 903219820Sjeff eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev, 904219820Sjeff PAGE_SIZE, &t, GFP_KERNEL); 905219820Sjeff if (!eq->page_list[i].buf) 906219820Sjeff goto err_out_free_pages; 907219820Sjeff 908219820Sjeff dma_list[i] = t; 909219820Sjeff eq->page_list[i].map = t; 910219820Sjeff 911219820Sjeff memset(eq->page_list[i].buf, 0, PAGE_SIZE); 912219820Sjeff } 913219820Sjeff 914219820Sjeff eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap); 915219820Sjeff if (eq->eqn == -1) 916219820Sjeff goto err_out_free_pages; 917219820Sjeff 918219820Sjeff eq->doorbell = mlx4_get_eq_uar(dev, eq); 919219820Sjeff if (!eq->doorbell) { 920219820Sjeff err = -ENOMEM; 921219820Sjeff goto err_out_free_eq; 922219820Sjeff } 923219820Sjeff 924219820Sjeff err = mlx4_mtt_init(dev, npages, PAGE_SHIFT, &eq->mtt); 925219820Sjeff if (err) 926219820Sjeff goto err_out_free_eq; 927219820Sjeff 928219820Sjeff err = mlx4_write_mtt(dev, &eq->mtt, 0, npages, dma_list); 929219820Sjeff if (err) 930219820Sjeff goto err_out_free_mtt; 931219820Sjeff 932219820Sjeff memset(eq_context, 0, sizeof *eq_context); 933219820Sjeff eq_context->flags = cpu_to_be32(MLX4_EQ_STATUS_OK | 934219820Sjeff MLX4_EQ_STATE_ARMED); 935219820Sjeff eq_context->log_eq_size = ilog2(eq->nent); 936219820Sjeff eq_context->intr = intr; 937219820Sjeff eq_context->log_page_size = PAGE_SHIFT - MLX4_ICM_PAGE_SHIFT; 938219820Sjeff 939219820Sjeff mtt_addr = mlx4_mtt_addr(dev, &eq->mtt); 940219820Sjeff eq_context->mtt_base_addr_h = mtt_addr >> 32; 941219820Sjeff eq_context->mtt_base_addr_l = cpu_to_be32(mtt_addr & 0xffffffff); 942219820Sjeff 943219820Sjeff err = mlx4_SW2HW_EQ(dev, mailbox, eq->eqn); 944219820Sjeff if (err) { 945219820Sjeff mlx4_warn(dev, "SW2HW_EQ failed (%d)\n", err); 946219820Sjeff goto err_out_free_mtt; 947219820Sjeff } 948219820Sjeff 949219820Sjeff kfree(dma_list); 950219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 951219820Sjeff 952219820Sjeff eq->cons_index = 0; 953219820Sjeff 954219820Sjeff return err; 955219820Sjeff 956219820Sjefferr_out_free_mtt: 957219820Sjeff mlx4_mtt_cleanup(dev, &eq->mtt); 958219820Sjeff 959219820Sjefferr_out_free_eq: 960219820Sjeff mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); 961219820Sjeff 962219820Sjefferr_out_free_pages: 963219820Sjeff for (i = 0; i < npages; ++i) 964219820Sjeff if (eq->page_list[i].buf) 965219820Sjeff dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 966219820Sjeff eq->page_list[i].buf, 967219820Sjeff eq->page_list[i].map); 968219820Sjeff 969219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 970219820Sjeff 971219820Sjefferr_out_free: 972219820Sjeff kfree(eq->page_list); 973219820Sjeff kfree(dma_list); 974219820Sjeff 975219820Sjefferr_out: 976219820Sjeff return err; 977219820Sjeff} 978219820Sjeff 979219820Sjeffstatic void mlx4_free_eq(struct mlx4_dev *dev, 980219820Sjeff struct mlx4_eq *eq) 981219820Sjeff{ 982219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 983219820Sjeff struct mlx4_cmd_mailbox *mailbox; 984219820Sjeff int err; 985219820Sjeff int i; 986255932Salfred /* CX3 is capable of extending the CQE\EQE from 32 to 64 bytes */ 987255932Salfred int npages = PAGE_ALIGN((MLX4_EQ_ENTRY_SIZE << dev->caps.eqe_factor) * eq->nent) / PAGE_SIZE; 988219820Sjeff 989219820Sjeff mailbox = mlx4_alloc_cmd_mailbox(dev); 990219820Sjeff if (IS_ERR(mailbox)) 991219820Sjeff return; 992219820Sjeff 993219820Sjeff err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn); 994219820Sjeff if (err) 995219820Sjeff mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err); 996219820Sjeff 997219820Sjeff if (0) { 998219820Sjeff mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn); 999219820Sjeff for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) { 1000219820Sjeff if (i % 4 == 0) 1001255932Salfred pr_cont("[%02x] ", i * 4); 1002255932Salfred pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4)); 1003219820Sjeff if ((i + 1) % 4 == 0) 1004255932Salfred pr_cont("\n"); 1005219820Sjeff } 1006219820Sjeff } 1007219820Sjeff 1008219820Sjeff mlx4_mtt_cleanup(dev, &eq->mtt); 1009219820Sjeff for (i = 0; i < npages; ++i) 1010255932Salfred dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, 1011219820Sjeff eq->page_list[i].buf, 1012219820Sjeff eq->page_list[i].map); 1013219820Sjeff 1014219820Sjeff kfree(eq->page_list); 1015219820Sjeff mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn); 1016219820Sjeff mlx4_free_cmd_mailbox(dev, mailbox); 1017219820Sjeff} 1018219820Sjeff 1019219820Sjeffstatic void mlx4_free_irqs(struct mlx4_dev *dev) 1020219820Sjeff{ 1021219820Sjeff struct mlx4_eq_table *eq_table = &mlx4_priv(dev)->eq_table; 1022255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1023255932Salfred int i, vec; 1024219820Sjeff 1025219820Sjeff if (eq_table->have_irq) 1026219820Sjeff free_irq(dev->pdev->irq, dev); 1027255932Salfred 1028219820Sjeff for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) 1029219820Sjeff if (eq_table->eq[i].have_irq) { 1030219820Sjeff free_irq(eq_table->eq[i].irq, eq_table->eq + i); 1031219820Sjeff eq_table->eq[i].have_irq = 0; 1032219820Sjeff } 1033219820Sjeff 1034255932Salfred for (i = 0; i < dev->caps.comp_pool; i++) { 1035255932Salfred /* 1036255932Salfred * Freeing the assigned irq's 1037255932Salfred * all bits should be 0, but we need to validate 1038255932Salfred */ 1039255932Salfred if (priv->msix_ctl.pool_bm & 1ULL << i) { 1040255932Salfred /* NO need protecting*/ 1041255932Salfred vec = dev->caps.num_comp_vectors + 1 + i; 1042255932Salfred free_irq(priv->eq_table.eq[vec].irq, 1043255932Salfred &priv->eq_table.eq[vec]); 1044255932Salfred } 1045255932Salfred } 1046255932Salfred 1047255932Salfred 1048219820Sjeff kfree(eq_table->irq_names); 1049219820Sjeff} 1050219820Sjeff 1051219820Sjeffstatic int mlx4_map_clr_int(struct mlx4_dev *dev) 1052219820Sjeff{ 1053219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1054219820Sjeff 1055219820Sjeff priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) + 1056219820Sjeff priv->fw.clr_int_base, MLX4_CLR_INT_SIZE); 1057219820Sjeff if (!priv->clr_base) { 1058219820Sjeff mlx4_err(dev, "Couldn't map interrupt clear register, aborting.\n"); 1059219820Sjeff return -ENOMEM; 1060219820Sjeff } 1061219820Sjeff 1062219820Sjeff return 0; 1063219820Sjeff} 1064219820Sjeff 1065219820Sjeffstatic void mlx4_unmap_clr_int(struct mlx4_dev *dev) 1066219820Sjeff{ 1067219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1068219820Sjeff 1069219820Sjeff iounmap(priv->clr_base); 1070219820Sjeff} 1071219820Sjeff 1072219820Sjeffint mlx4_alloc_eq_table(struct mlx4_dev *dev) 1073219820Sjeff{ 1074219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1075219820Sjeff 1076219820Sjeff priv->eq_table.eq = kcalloc(dev->caps.num_eqs - dev->caps.reserved_eqs, 1077219820Sjeff sizeof *priv->eq_table.eq, GFP_KERNEL); 1078219820Sjeff if (!priv->eq_table.eq) 1079219820Sjeff return -ENOMEM; 1080219820Sjeff 1081219820Sjeff return 0; 1082219820Sjeff} 1083219820Sjeff 1084219820Sjeffvoid mlx4_free_eq_table(struct mlx4_dev *dev) 1085219820Sjeff{ 1086219820Sjeff kfree(mlx4_priv(dev)->eq_table.eq); 1087219820Sjeff} 1088219820Sjeff 1089219820Sjeffint mlx4_init_eq_table(struct mlx4_dev *dev) 1090219820Sjeff{ 1091219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1092219820Sjeff int err; 1093219820Sjeff int i; 1094219820Sjeff 1095255932Salfred priv->eq_table.uar_map = kcalloc(mlx4_num_eq_uar(dev), 1096255932Salfred sizeof *priv->eq_table.uar_map, 1097255932Salfred GFP_KERNEL); 1098219820Sjeff if (!priv->eq_table.uar_map) { 1099219820Sjeff err = -ENOMEM; 1100219820Sjeff goto err_out_free; 1101219820Sjeff } 1102219820Sjeff 1103219820Sjeff err = mlx4_bitmap_init(&priv->eq_table.bitmap, dev->caps.num_eqs, 1104219820Sjeff dev->caps.num_eqs - 1, dev->caps.reserved_eqs, 0); 1105219820Sjeff if (err) 1106219820Sjeff goto err_out_free; 1107219820Sjeff 1108219820Sjeff for (i = 0; i < mlx4_num_eq_uar(dev); ++i) 1109219820Sjeff priv->eq_table.uar_map[i] = NULL; 1110219820Sjeff 1111255932Salfred if (!mlx4_is_slave(dev)) { 1112255932Salfred err = mlx4_map_clr_int(dev); 1113255932Salfred if (err) 1114255932Salfred goto err_out_bitmap; 1115219820Sjeff 1116255932Salfred priv->eq_table.clr_mask = 1117255932Salfred swab32(1 << (priv->eq_table.inta_pin & 31)); 1118255932Salfred priv->eq_table.clr_int = priv->clr_base + 1119255932Salfred (priv->eq_table.inta_pin < 32 ? 4 : 0); 1120255932Salfred } 1121219820Sjeff 1122255932Salfred priv->eq_table.irq_names = 1123255932Salfred kmalloc(MLX4_IRQNAME_SIZE * (dev->caps.num_comp_vectors + 1 + 1124255932Salfred dev->caps.comp_pool), 1125255932Salfred GFP_KERNEL); 1126219820Sjeff if (!priv->eq_table.irq_names) { 1127219820Sjeff err = -ENOMEM; 1128255932Salfred goto err_out_clr_int; 1129219820Sjeff } 1130219820Sjeff 1131219820Sjeff for (i = 0; i < dev->caps.num_comp_vectors; ++i) { 1132255932Salfred err = mlx4_create_eq(dev, dev->caps.num_cqs - 1133255932Salfred dev->caps.reserved_cqs + 1134255932Salfred MLX4_NUM_SPARE_EQE, 1135219820Sjeff (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, 1136219820Sjeff &priv->eq_table.eq[i]); 1137219820Sjeff if (err) { 1138219820Sjeff --i; 1139219820Sjeff goto err_out_unmap; 1140219820Sjeff } 1141219820Sjeff } 1142219820Sjeff 1143219820Sjeff err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, 1144219820Sjeff (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, 1145219820Sjeff &priv->eq_table.eq[dev->caps.num_comp_vectors]); 1146219820Sjeff if (err) 1147219820Sjeff goto err_out_comp; 1148219820Sjeff 1149255932Salfred /*if additional completion vectors poolsize is 0 this loop will not run*/ 1150255932Salfred for (i = dev->caps.num_comp_vectors + 1; 1151255932Salfred i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) { 1152255932Salfred 1153255932Salfred err = mlx4_create_eq(dev, dev->caps.num_cqs - 1154255932Salfred dev->caps.reserved_cqs + 1155255932Salfred MLX4_NUM_SPARE_EQE, 1156255932Salfred (dev->flags & MLX4_FLAG_MSI_X) ? i : 0, 1157255932Salfred &priv->eq_table.eq[i]); 1158255932Salfred if (err) { 1159255932Salfred --i; 1160255932Salfred goto err_out_unmap; 1161255932Salfred } 1162255932Salfred } 1163255932Salfred 1164255932Salfred 1165219820Sjeff if (dev->flags & MLX4_FLAG_MSI_X) { 1166219820Sjeff const char *eq_name; 1167219820Sjeff 1168219820Sjeff for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { 1169219820Sjeff if (i < dev->caps.num_comp_vectors) { 1170255932Salfred snprintf(priv->eq_table.irq_names + 1171255932Salfred i * MLX4_IRQNAME_SIZE, 1172255932Salfred MLX4_IRQNAME_SIZE, 1173255932Salfred "mlx4-comp-%d@pci:%s", i, 1174255932Salfred pci_name(dev->pdev)); 1175255932Salfred } else { 1176255932Salfred snprintf(priv->eq_table.irq_names + 1177255932Salfred i * MLX4_IRQNAME_SIZE, 1178255932Salfred MLX4_IRQNAME_SIZE, 1179255932Salfred "mlx4-async@pci:%s", 1180255932Salfred pci_name(dev->pdev)); 1181255932Salfred } 1182219820Sjeff 1183255932Salfred eq_name = priv->eq_table.irq_names + 1184255932Salfred i * MLX4_IRQNAME_SIZE; 1185219820Sjeff err = request_irq(priv->eq_table.eq[i].irq, 1186219820Sjeff mlx4_msi_x_interrupt, 0, eq_name, 1187219820Sjeff priv->eq_table.eq + i); 1188219820Sjeff if (err) 1189219820Sjeff goto err_out_async; 1190219820Sjeff 1191219820Sjeff priv->eq_table.eq[i].have_irq = 1; 1192219820Sjeff } 1193219820Sjeff } else { 1194255932Salfred snprintf(priv->eq_table.irq_names, 1195255932Salfred MLX4_IRQNAME_SIZE, 1196255932Salfred DRV_NAME "@pci:%s", 1197255932Salfred pci_name(dev->pdev)); 1198219820Sjeff err = request_irq(dev->pdev->irq, mlx4_interrupt, 1199255932Salfred IRQF_SHARED, priv->eq_table.irq_names, dev); 1200219820Sjeff if (err) 1201219820Sjeff goto err_out_async; 1202219820Sjeff 1203219820Sjeff priv->eq_table.have_irq = 1; 1204219820Sjeff } 1205219820Sjeff 1206255932Salfred err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, 1207219820Sjeff priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); 1208219820Sjeff if (err) 1209219820Sjeff mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", 1210219820Sjeff priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); 1211219820Sjeff 1212219820Sjeff for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) 1213219820Sjeff eq_set_ci(&priv->eq_table.eq[i], 1); 1214219820Sjeff 1215219820Sjeff return 0; 1216219820Sjeff 1217219820Sjefferr_out_async: 1218219820Sjeff mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); 1219219820Sjeff 1220219820Sjefferr_out_comp: 1221219820Sjeff i = dev->caps.num_comp_vectors - 1; 1222219820Sjeff 1223219820Sjefferr_out_unmap: 1224219820Sjeff while (i >= 0) { 1225219820Sjeff mlx4_free_eq(dev, &priv->eq_table.eq[i]); 1226219820Sjeff --i; 1227219820Sjeff } 1228219820Sjeff mlx4_free_irqs(dev); 1229219820Sjeff 1230255932Salfrederr_out_clr_int: 1231255932Salfred if (!mlx4_is_slave(dev)) 1232255932Salfred mlx4_unmap_clr_int(dev); 1233255932Salfred 1234219820Sjefferr_out_bitmap: 1235255932Salfred mlx4_unmap_uar(dev); 1236219820Sjeff mlx4_bitmap_cleanup(&priv->eq_table.bitmap); 1237219820Sjeff 1238219820Sjefferr_out_free: 1239219820Sjeff kfree(priv->eq_table.uar_map); 1240219820Sjeff 1241219820Sjeff return err; 1242219820Sjeff} 1243219820Sjeff 1244219820Sjeffvoid mlx4_cleanup_eq_table(struct mlx4_dev *dev) 1245219820Sjeff{ 1246219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1247219820Sjeff int i; 1248219820Sjeff 1249255932Salfred mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 1, 1250219820Sjeff priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); 1251219820Sjeff 1252219820Sjeff mlx4_free_irqs(dev); 1253219820Sjeff 1254255932Salfred for (i = 0; i < dev->caps.num_comp_vectors + dev->caps.comp_pool + 1; ++i) 1255219820Sjeff mlx4_free_eq(dev, &priv->eq_table.eq[i]); 1256219820Sjeff 1257255932Salfred if (!mlx4_is_slave(dev)) 1258255932Salfred mlx4_unmap_clr_int(dev); 1259219820Sjeff 1260255932Salfred mlx4_unmap_uar(dev); 1261219820Sjeff mlx4_bitmap_cleanup(&priv->eq_table.bitmap); 1262219820Sjeff 1263219820Sjeff kfree(priv->eq_table.uar_map); 1264219820Sjeff} 1265219820Sjeff 1266219820Sjeff/* A test that verifies that we can accept interrupts on all 1267219820Sjeff * the irq vectors of the device. 1268219820Sjeff * Interrupts are checked using the NOP command. 1269219820Sjeff */ 1270219820Sjeffint mlx4_test_interrupts(struct mlx4_dev *dev) 1271219820Sjeff{ 1272219820Sjeff struct mlx4_priv *priv = mlx4_priv(dev); 1273219820Sjeff int i; 1274219820Sjeff int err; 1275219820Sjeff 1276219820Sjeff err = mlx4_NOP(dev); 1277219820Sjeff /* When not in MSI_X, there is only one irq to check */ 1278255932Salfred if (!(dev->flags & MLX4_FLAG_MSI_X) || mlx4_is_slave(dev)) 1279219820Sjeff return err; 1280219820Sjeff 1281219820Sjeff /* A loop over all completion vectors, for each vector we will check 1282219820Sjeff * whether it works by mapping command completions to that vector 1283219820Sjeff * and performing a NOP command 1284219820Sjeff */ 1285219820Sjeff for(i = 0; !err && (i < dev->caps.num_comp_vectors); ++i) { 1286219820Sjeff /* Temporary use polling for command completions */ 1287219820Sjeff mlx4_cmd_use_polling(dev); 1288219820Sjeff 1289255932Salfred /* Map the new eq to handle all asyncronous events */ 1290255932Salfred err = mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, 1291219820Sjeff priv->eq_table.eq[i].eqn); 1292219820Sjeff if (err) { 1293219820Sjeff mlx4_warn(dev, "Failed mapping eq for interrupt test\n"); 1294219820Sjeff mlx4_cmd_use_events(dev); 1295219820Sjeff break; 1296219820Sjeff } 1297219820Sjeff 1298219820Sjeff /* Go back to using events */ 1299219820Sjeff mlx4_cmd_use_events(dev); 1300219820Sjeff err = mlx4_NOP(dev); 1301219820Sjeff } 1302219820Sjeff 1303219820Sjeff /* Return to default */ 1304255932Salfred mlx4_MAP_EQ(dev, get_async_ev_mask(dev), 0, 1305219820Sjeff priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); 1306219820Sjeff return err; 1307219820Sjeff} 1308219820SjeffEXPORT_SYMBOL(mlx4_test_interrupts); 1309255932Salfred 1310255932Salfredint mlx4_assign_eq(struct mlx4_dev *dev, char *name, int *vector) 1311255932Salfred{ 1312255932Salfred 1313255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1314255932Salfred int vec = 0, err = 0, i; 1315255932Salfred 1316255932Salfred mutex_lock(&priv->msix_ctl.pool_lock); 1317255932Salfred for (i = 0; !vec && i < dev->caps.comp_pool; i++) { 1318255932Salfred if (~priv->msix_ctl.pool_bm & 1ULL << i) { 1319255932Salfred priv->msix_ctl.pool_bm |= 1ULL << i; 1320255932Salfred vec = dev->caps.num_comp_vectors + 1 + i; 1321255932Salfred snprintf(priv->eq_table.irq_names + 1322255932Salfred vec * MLX4_IRQNAME_SIZE, 1323255932Salfred MLX4_IRQNAME_SIZE, "%s", name); 1324255932Salfred err = request_irq(priv->eq_table.eq[vec].irq, 1325255932Salfred mlx4_msi_x_interrupt, 0, 1326255932Salfred &priv->eq_table.irq_names[vec<<5], 1327255932Salfred priv->eq_table.eq + vec); 1328255932Salfred if (err) { 1329255932Salfred /*zero out bit by fliping it*/ 1330255932Salfred priv->msix_ctl.pool_bm ^= 1 << i; 1331255932Salfred vec = 0; 1332255932Salfred continue; 1333255932Salfred /*we dont want to break here*/ 1334255932Salfred } 1335255932Salfred eq_set_ci(&priv->eq_table.eq[vec], 1); 1336255932Salfred } 1337255932Salfred } 1338255932Salfred mutex_unlock(&priv->msix_ctl.pool_lock); 1339255932Salfred 1340255932Salfred if (vec) { 1341255932Salfred *vector = vec; 1342255932Salfred } else { 1343255932Salfred *vector = 0; 1344255932Salfred err = (i == dev->caps.comp_pool) ? -ENOSPC : err; 1345255932Salfred } 1346255932Salfred return err; 1347255932Salfred} 1348255932SalfredEXPORT_SYMBOL(mlx4_assign_eq); 1349255932Salfred 1350255932Salfredvoid mlx4_release_eq(struct mlx4_dev *dev, int vec) 1351255932Salfred{ 1352255932Salfred struct mlx4_priv *priv = mlx4_priv(dev); 1353255932Salfred /*bm index*/ 1354255932Salfred int i = vec - dev->caps.num_comp_vectors - 1; 1355255932Salfred 1356255932Salfred if (likely(i >= 0)) { 1357255932Salfred /*sanity check , making sure were not trying to free irq's 1358255932Salfred Belonging to a legacy EQ*/ 1359255932Salfred mutex_lock(&priv->msix_ctl.pool_lock); 1360255932Salfred if (priv->msix_ctl.pool_bm & 1ULL << i) { 1361255932Salfred free_irq(priv->eq_table.eq[vec].irq, 1362255932Salfred &priv->eq_table.eq[vec]); 1363255932Salfred priv->msix_ctl.pool_bm &= ~(1ULL << i); 1364255932Salfred } 1365255932Salfred mutex_unlock(&priv->msix_ctl.pool_lock); 1366255932Salfred } 1367255932Salfred 1368255932Salfred} 1369255932SalfredEXPORT_SYMBOL(mlx4_release_eq); 1370255932Salfred 1371