From patchwork Thu Jun 10 19:10:31 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yevgeny Petrilin X-Patchwork-Id: 105445 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o5AJAapE018657 for ; Thu, 10 Jun 2010 19:10:36 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759733Ab0FJTKf (ORCPT ); Thu, 10 Jun 2010 15:10:35 -0400 Received: from mail.mellanox.co.il ([194.90.237.43]:57486 "EHLO mellanox.co.il" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1759732Ab0FJTKe (ORCPT ); Thu, 10 Jun 2010 15:10:34 -0400 Received: from Internal Mail-Server by MTLPINE1 (envelope-from yevgenyp@mellanox.co.il) with SMTP; 10 Jun 2010 22:11:22 +0300 Received: from vnc8.lab.mtl.com ([10.4.45.8]) by mtlexch01.mtl.com with Microsoft SMTPSVC(6.0.3790.3959); Thu, 10 Jun 2010 22:10:31 +0300 Message-ID: <4C1138A7.6070804@mellanox.co.il> Date: Thu, 10 Jun 2010 22:10:31 +0300 From: Yevgeny Petrilin User-Agent: Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.9) Gecko/20100317 Thunderbird/3.0.4 MIME-Version: 1.0 To: Roland Dreier CC: linux-rdma@vger.kernel.org Subject: [PATCH 19/19 V4] mlx4: Communication channel interrupts X-OriginalArrivalTime: 10 Jun 2010 19:10:31.0274 (UTC) FILETIME=[985E7CA0:01CB08D0] X-TM-AS-Product-Ver: SMEX-8.0.0.1181-6.000.1038-17438.001 X-TM-AS-Result: No--21.586100-8.000000-31 X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No Sender: linux-rdma-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-rdma@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Thu, 10 Jun 2010 19:10:36 +0000 (UTC) diff --git a/drivers/net/mlx4/cmd.c b/drivers/net/mlx4/cmd.c index 7efa85f..083ae0f 100644 --- a/drivers/net/mlx4/cmd.c +++ b/drivers/net/mlx4/cmd.c @@ -148,19 +148,11 @@ static int comm_pending(struct mlx4_dev *dev) return (swab32(status) >> 30) != priv->cmd.comm_toggle; } -int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, unsigned long timeout) +static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param) { struct mlx4_priv *priv = mlx4_priv(dev); - unsigned long end; u32 val; - /* First, verify that the master reports correct status */ - if (comm_pending(dev)) { - mlx4_warn(dev, "Communication channel is not idle\n"); - return -EAGAIN; - } - - /* Write command */ if (cmd == MLX4_COMM_CMD_RESET) priv->cmd.comm_toggle = 0; else if (++priv->cmd.comm_toggle > 2) @@ -168,6 +160,23 @@ int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, unsigned long timeout val = param | (cmd << 16) | (priv->cmd.comm_toggle << 30); __raw_writel((__force u32) cpu_to_be32(val), &priv->mfunc.comm->slave_write); wmb(); +} + +int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param, unsigned long timeout) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + unsigned long end; + int err = 0; + + /* First, verify that the master reports correct status */ + if (comm_pending(dev)) { + mlx4_warn(dev, "Communication channel is not idle\n"); + return -EAGAIN; + } + + /* Write command */ + down(&priv->cmd.poll_sem); + mlx4_comm_cmd_post(dev, cmd, param); end = msecs_to_jiffies(timeout) + jiffies; while (comm_pending(dev) && time_before(jiffies, end)) @@ -175,11 +184,57 @@ int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, unsigned long timeout if (comm_pending(dev)) { mlx4_warn(dev, "Communication channel timed out\n"); - return -ETIMEDOUT; + err = -ETIMEDOUT; } + + up(&priv->cmd.poll_sem); return 0; } +static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op, + u16 param, unsigned long timeout) +{ + struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; + struct mlx4_cmd_context *context; + int err = 0; + + down(&cmd->event_sem); + + spin_lock(&cmd->context_lock); + BUG_ON(cmd->free_head < 0); + context = &cmd->context[cmd->free_head]; + context->token += cmd->token_mask + 1; + cmd->free_head = context->next; + spin_unlock(&cmd->context_lock); + + init_completion(&context->done); + + mlx4_comm_cmd_post(dev, op, param); + + if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { + err = -EBUSY; + goto out; + } + + err = context->result; + +out: + spin_lock(&cmd->context_lock); + context->next = cmd->free_head; + cmd->free_head = context - cmd->context; + spin_unlock(&cmd->context_lock); + + up(&cmd->event_sem); + return err; +} + +int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param, unsigned long timeout) +{ + if (mlx4_priv(dev)->cmd.use_events) + return mlx4_comm_cmd_wait(dev, cmd, param, timeout); + return mlx4_comm_cmd_poll(dev, cmd, param, timeout); +} + static int cmd_pending(struct mlx4_dev *dev) { u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); @@ -247,15 +302,15 @@ out: return ret; } -static int mlx4_slave_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, - int out_is_imm, u32 in_modifier, u8 op_modifier, - u16 op, unsigned long timeout) +static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, + int out_is_imm, u32 in_modifier, u8 op_modifier, + u16 op, unsigned long timeout) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_vhcr *vhcr = priv->mfunc.vhcr; int ret; - down(&priv->cmd.poll_sem); + down(&priv->cmd.slave_sem); vhcr->in_param = in_param; vhcr->out_param = out_param ? *out_param : 0; vhcr->in_modifier = in_modifier; @@ -270,7 +325,7 @@ static int mlx4_slave_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_para *out_param = vhcr->out_param; ret = vhcr->errno; } - up(&priv->cmd.poll_sem); + up(&priv->cmd.slave_sem); return ret; } @@ -378,19 +433,61 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, int out_is_imm, u32 in_modifier, u8 op_modifier, u16 op, unsigned long timeout) { + if (mlx4_is_slave(dev)) + return mlx4_slave_cmd(dev, in_param, out_param, out_is_imm, + in_modifier, op_modifier, op, timeout); + if (mlx4_priv(dev)->cmd.use_events) return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, in_modifier, op_modifier, op, timeout); - - if (mlx4_is_slave(dev)) - return mlx4_slave_cmd_poll(dev, in_param, out_param, out_is_imm, - in_modifier, op_modifier, op, timeout); else return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm, in_modifier, op_modifier, op, timeout); } EXPORT_SYMBOL_GPL(__mlx4_cmd); + +static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev) +{ + return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL, MLX4_CMD_TIME_CLASS_B); +} + +int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_slave_event_eq_info *event_eq = + &priv->mfunc.master.slave_state[slave].event_eq; + struct mlx4_cmd_mailbox *mailbox; + u32 in_modifier = 0; + int err; + + if (!event_eq->use_int) + return 0; + + /* Create the event only if the slave is registered */ + if ((event_eq->event_type & eqe->type) == 0) + return 0; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + + if (eqe->type == MLX4_EVENT_TYPE_CMD) { + ++event_eq->token; + eqe->event.cmd.token = cpu_to_be16(event_eq->token); + } + + memcpy(mailbox->buf, (u8 *) eqe, 28); + + in_modifier = (slave & 0xff) | ((event_eq->eqn & 0xff) << 16); + + err = mlx4_cmd(dev, mailbox->dma, in_modifier, 0, + MLX4_CMD_GEN_EQE, MLX4_CMD_TIME_CLASS_B); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + static int mlx4_ACCESS_MEM(struct mlx4_dev *dev, u64 master_addr, int slave, u64 slave_addr, int size, int is_read) @@ -597,12 +694,21 @@ static struct mlx4_cmd_info { }, { + .opcode = MLX4_CMD_COMM_INT, + .has_inbox = false, + .has_outbox = false, + .out_is_imm = false, + .verify = NULL, + .wrapper = mlx4_COMM_INT_wrapper + }, + { .opcode = MLX4_CMD_INIT_PORT, .has_inbox = false, .has_outbox = false, .out_is_imm = false, .verify = NULL, - .wrapper = mlx4_INIT_PORT_wrapper}, + .wrapper = mlx4_INIT_PORT_wrapper + }, { .opcode = MLX4_CMD_CLOSE_PORT, .has_inbox = false, @@ -629,6 +735,14 @@ static struct mlx4_cmd_info { }, { + .opcode = MLX4_CMD_MAP_EQ, + .has_inbox = false, + .has_outbox = false, + .out_is_imm = false, + .verify = NULL, + .wrapper = mlx4_MAP_EQ_wrapper + }, + { .opcode = MLX4_CMD_SW2HW_EQ, .has_inbox = true, .has_outbox = false, @@ -1108,6 +1222,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, u16 para if (cmd == MLX4_COMM_CMD_RESET) { mlx4_warn(dev, "Received reset from slave:%d\n", slave); + slave_state[slave].active = false; goto reset_slave; } @@ -1146,6 +1261,7 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, u16 para "number for slave %d\n", slave); goto reset_slave; } + slave_state[slave].active = true; break; case MLX4_COMM_CMD_VHCR_POST: if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) && @@ -1167,45 +1283,59 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd, u16 para __raw_writel((__force u32) cpu_to_be32(reply), &priv->mfunc.comm[slave].slave_read); wmb(); + if (mlx4_GEN_EQE(dev, slave, &priv->mfunc.master.cmd_eqe)) + mlx4_warn(dev, "Failed to generate command completion eqe " + "for slave %d\n", slave); + return; reset_slave: /* FIXME: cleanup any slave resources */ slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET; slave_state[slave].comm_toggle = 0; + memset(&slave_state[slave].event_eq, 0, + sizeof(struct mlx4_slave_event_eq_info)); __raw_writel((__force u32) 0, &priv->mfunc.comm[slave].slave_write); __raw_writel((__force u32) 0, &priv->mfunc.comm[slave].slave_read); wmb(); } /* master command processing */ -static void mlx4_master_poll_comm(struct work_struct *work) +void mlx4_master_comm_channel(struct work_struct *work) { - struct delayed_work *delay = container_of(work, struct delayed_work, work); - struct mlx4_mfunc *mfunc = container_of(delay, struct mlx4_mfunc, comm_work); + struct mlx4_mfunc_master_ctx *master = container_of(work, + struct mlx4_mfunc_master_ctx, + comm_work); + struct mlx4_mfunc *mfunc = container_of(master, struct mlx4_mfunc, master); struct mlx4_priv *priv = container_of(mfunc, struct mlx4_priv, mfunc); struct mlx4_dev *dev = &priv->dev; + u32 *bit_vec; u32 comm_cmd; - int polled = 0; - int i; - - /* Give each slave a chance for one command */ - for (i = 0; i < dev->num_slaves; i++) { - comm_cmd = swab32(readl(&priv->mfunc.comm[i].slave_write)); - if (comm_cmd >> 30 != priv->mfunc.master.slave_state[i].comm_toggle) { - mlx4_master_do_cmd(dev, i, comm_cmd >> 16, comm_cmd, comm_cmd >> 30); - polled = 1; + u32 vec; + int i, j, slave; + + bit_vec = master->comm_arm_bit_vector; + for (i = 0; i < COMM_CHANNEL_BIT_ARRAY_SIZE; i++) { + vec = be32_to_cpu(bit_vec[i]); + for (j = 0; j < 32; j++) { + if (!(vec & (1 << j))) + continue; + slave = (i * 32) + j; + comm_cmd = swab32(readl(&mfunc->comm[slave].slave_write)); + if (comm_cmd >> 30 != master->slave_state[slave].comm_toggle) + mlx4_master_do_cmd(dev, slave, comm_cmd >> 16, comm_cmd, comm_cmd >> 30); } } - queue_delayed_work(priv->mfunc.comm_wq, &priv->mfunc.comm_work, - polled ? 0 : HZ / 10); + + if (mlx4_ARM_COMM_CHANNEL(dev)) + mlx4_warn(dev, "Failed to arm comm channel events"); } int mlx4_multi_func_init(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_slave_state *s_state; - int i, port; + int i, err, port; priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE, &priv->mfunc.vhcr_dma, @@ -1253,20 +1383,30 @@ int mlx4_multi_func_init(struct mlx4_dev *dev) spin_lock_init(&s_state->lock); } - INIT_DELAYED_WORK(&priv->mfunc.comm_work, mlx4_master_poll_comm); - priv->mfunc.comm_wq = create_singlethread_workqueue("mlx4_comm"); - if (!priv->mfunc.comm_wq) + memset(&priv->mfunc.master.cmd_eqe, 0, sizeof(struct mlx4_eqe)); + priv->mfunc.master.cmd_eqe.type = MLX4_EVENT_TYPE_CMD; + INIT_WORK(&priv->mfunc.master.comm_work, mlx4_master_comm_channel); + INIT_WORK(&priv->mfunc.master.slave_event_work, mlx4_gen_slave_eqe); + priv->mfunc.master.comm_wq = create_singlethread_workqueue("mlx4_comm"); + if (!priv->mfunc.master.comm_wq) goto err_slaves; + err = mlx4_ARM_COMM_CHANNEL(dev); + if (err) { + mlx4_err(dev, " Failed to arm comm channel eq: %x\n", err); + goto err_thread; + } + } else { + sema_init(&priv->cmd.slave_sem, 1); priv->cmd.comm_toggle = 0; - INIT_DELAYED_WORK(&priv->mfunc.comm_work, mlx4_slave_async_eq_poll); - priv->mfunc.comm_wq = create_singlethread_workqueue("mlx4_event"); - if (!priv->mfunc.comm_wq) goto err_comm; } return 0; +err_thread: + flush_workqueue(priv->mfunc.master.comm_wq); + destroy_workqueue(priv->mfunc.master.comm_wq); err_slaves: while (--i) { for (port = 1; port <= MLX4_MAX_PORTS; port++) @@ -1323,8 +1463,9 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); int i, port; - if (priv->mfunc.vhcr) { - destroy_workqueue(priv->mfunc.comm_wq); + if (mlx4_is_master(dev)) { + flush_workqueue(priv->mfunc.master.comm_wq); + destroy_workqueue(priv->mfunc.master.comm_wq); for (i = 0; i < dev->num_slaves; i++) { for (port = 1; port <= MLX4_MAX_PORTS; port++) kfree(priv->mfunc.master.slave_state[i].vlan_filter[port]); @@ -1356,6 +1497,7 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); int i; + int err = 0; priv->cmd.context = kmalloc(priv->cmd.max_cmds * sizeof (struct mlx4_cmd_context), @@ -1382,9 +1524,17 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev) priv->cmd.use_events = 1; + if (mlx4_is_slave(dev)) { + err = mlx4_cmd(dev, 0, 1, 0, MLX4_CMD_COMM_INT, MLX4_CMD_TIME_CLASS_A); + if (err) { + mlx4_err(dev, "Failed to move to events for the slave\n"); + priv->cmd.use_events = 0; + } + } + down(&priv->cmd.poll_sem); - return 0; + return err; } /* @@ -1403,6 +1553,9 @@ void mlx4_cmd_use_polling(struct mlx4_dev *dev) kfree(priv->cmd.context); up(&priv->cmd.poll_sem); + + if (mlx4_is_slave(dev)) + mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_COMM_INT, MLX4_CMD_TIME_CLASS_A); } struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) @@ -1433,3 +1586,20 @@ void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbo kfree(mailbox); } EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); + +int mlx4_COMM_INT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, + struct mlx4_cmd_mailbox *inbox, + struct mlx4_cmd_mailbox *outbox) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_slave_event_eq_info *event_eq = + &priv->mfunc.master.slave_state[slave].event_eq; + + if (vhcr->in_modifier) + event_eq->use_int = true; + else + event_eq->use_int = false; + + return 0; +} + diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c index 9126c8e..e5adca2 100644 --- a/drivers/net/mlx4/eq.c +++ b/drivers/net/mlx4/eq.c @@ -99,46 +99,8 @@ struct mlx4_eq_context { (1ull << MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) | \ (1ull << MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE) | \ (1ull << MLX4_EVENT_TYPE_SRQ_LIMIT) | \ - (1ull << MLX4_EVENT_TYPE_CMD)) - -struct mlx4_eqe { - u8 reserved1; - u8 type; - u8 reserved2; - u8 subtype; - union { - u32 raw[6]; - struct { - __be32 cqn; - } __attribute__((packed)) comp; - struct { - u16 reserved1; - __be16 token; - u32 reserved2; - u8 reserved3[3]; - u8 status; - __be64 out_param; - } __attribute__((packed)) cmd; - struct { - __be32 qpn; - } __attribute__((packed)) qp; - struct { - __be32 srqn; - } __attribute__((packed)) srq; - struct { - __be32 cqn; - u32 reserved1; - u8 reserved2[3]; - u8 syndrome; - } __attribute__((packed)) cq_err; - struct { - u32 reserved1[2]; - __be32 port; - } __attribute__((packed)) port_change; - } event; - u8 reserved3[3]; - u8 owner; -} __attribute__((packed)); + (1ull << MLX4_EVENT_TYPE_CMD) | \ + (1ull << MLX4_EVENT_TYPE_COMM_CHANNEL)) static void eq_set_ci(struct mlx4_eq *eq, int req_not) { @@ -161,35 +123,87 @@ static struct mlx4_eqe *next_eqe_sw(struct mlx4_eq *eq) return !!(eqe->owner & 0x80) ^ !!(eq->cons_index & eq->nent) ? NULL : eqe; } -void mlx4_slave_event(struct mlx4_dev *dev, int slave, u8 type, u8 port, u32 param) +static struct mlx4_eqe *next_slave_event_eqe(struct mlx4_slave_event_eq *slave_eq) +{ + struct mlx4_eqe *eqe = + &slave_eq->event_eqe[slave_eq->cons & (SLAVE_EVENT_EQ_SIZE - 1)]; + return (!!(eqe->owner & 0x80) ^ !!(slave_eq->cons & SLAVE_EVENT_EQ_SIZE)) ? + eqe : NULL; +} +void mlx4_gen_slave_eqe(struct work_struct *work) +{ + struct mlx4_mfunc_master_ctx *master = container_of(work, + struct mlx4_mfunc_master_ctx, + slave_event_work); + struct mlx4_mfunc *mfunc = container_of(master, struct mlx4_mfunc, master); + struct mlx4_priv *priv = container_of(mfunc, struct mlx4_priv, mfunc); + struct mlx4_dev *dev = &priv->dev; + struct mlx4_slave_event_eq *slave_eq = &mfunc->master.slave_eq; + struct mlx4_eqe *eqe; + u8 slave; + int i; + + for (eqe = next_slave_event_eqe(slave_eq); eqe; + eqe = next_slave_event_eqe(slave_eq)) { + slave = eqe->slave_id; + + /* All active slaves need to receive the event */ + if (slave == ALL_SLAVES) { + for (i = 0; i < dev->num_slaves; i++) { + if (master->slave_state[i].active) + if (mlx4_GEN_EQE(dev, i, eqe)) + mlx4_warn(dev, "Failed to generate event " + "for slave %d\n", i); + } + } else { + if (mlx4_GEN_EQE(dev, slave, eqe)) + mlx4_warn(dev, "Failed to generate event " + "for slave %d\n", slave); + } + ++slave_eq->cons; + } +} + + +static void slave_event(struct mlx4_dev *dev, u8 slave, struct mlx4_eqe *eqe) { struct mlx4_priv *priv = mlx4_priv(dev); - struct mlx4_slave_state *ctx = &priv->mfunc.master.slave_state[slave]; - unsigned long flags; + struct mlx4_slave_event_eq *slave_eq = &priv->mfunc.master.slave_eq; + struct mlx4_eqe *s_eqe = + &slave_eq->event_eqe[slave_eq->prod & (SLAVE_EVENT_EQ_SIZE - 1)]; - if (ctx->last_cmd != MLX4_COMM_CMD_VHCR_POST) { - mlx4_warn(dev, "received event for inactive slave:%d\n", slave); + if ((!!(s_eqe->owner & 0x80)) ^ (!!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE))) { + mlx4_warn(dev, "Master failed to generate an EQE for slave: %d. " + "No free EQE on slave events queue\n", slave); return; } - /* Unconditionally add the new event - during overflows, we drop the - * oldest events */ - spin_lock_irqsave(&ctx->lock, flags); - ctx->eq[ctx->eq_pi & MLX4_MFUNC_EQE_MASK].type = type; - ctx->eq[ctx->eq_pi & MLX4_MFUNC_EQE_MASK].port = port; - ctx->eq[ctx->eq_pi & MLX4_MFUNC_EQE_MASK].param = param; - ++ctx->eq_pi; - spin_unlock_irqrestore(&ctx->lock, flags); + memcpy(s_eqe, eqe, sizeof(struct mlx4_eqe) - 1); + s_eqe->slave_id = slave; + /* ensure all information is written before setting the ownersip bit */ + wmb(); + s_eqe->owner = !!(slave_eq->prod & SLAVE_EVENT_EQ_SIZE) ? 0x0 : 0x80; + ++slave_eq->prod; + + queue_work(priv->mfunc.master.comm_wq, &priv->mfunc.master.slave_event_work); } -static void mlx4_slave_event_all(struct mlx4_dev *dev, u8 type, u8 port, u32 param) +static void mlx4_slave_event(struct mlx4_dev *dev, int slave, struct mlx4_eqe* eqe) { struct mlx4_priv *priv = mlx4_priv(dev); - int i; + struct mlx4_slave_state *s_slave = &priv->mfunc.master.slave_state[slave]; - for (i = 0; i < dev->num_slaves; ++i) - if (priv->mfunc.master.slave_state[i].last_cmd == MLX4_COMM_CMD_VHCR_POST) - mlx4_slave_event(dev, i, type, port, param); + if (!s_slave->active) { + mlx4_warn(dev, "Trying to pass event to inactive slave\n"); + return; + } + + slave_event(dev, slave, eqe); +} + +static void mlx4_slave_event_all(struct mlx4_dev *dev, struct mlx4_eqe* eqe) +{ + slave_event(dev, ALL_SLAVES, eqe); } int mlx4_GET_EVENT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, @@ -216,24 +230,9 @@ int mlx4_GET_EVENT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vh return 0; } -static int mlx4_GET_EVENT(struct mlx4_dev *dev, struct mlx4_slave_eqe *eqe) -{ - int ret; - u64 out_param; - - ret = mlx4_cmd_imm(dev, 0, &out_param, 0, 0, MLX4_CMD_GET_EVENT, - MLX4_CMD_TIME_CLASS_A); - if (!ret) { - eqe->type = out_param & 0xff; - eqe->port = (out_param >> 8) & 0xff; - eqe->param = out_param >> 32; - } else - mlx4_err(dev, "Failed retrieving event\n"); - return ret; -} - static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) { + struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_eqe *eqe; int cqn; int eqes_found = 0; @@ -263,9 +262,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: if (mlx4_is_master(dev)) { /* TODO: forward only to slave owning the QP */ - mlx4_slave_event(dev, 0, eqe->type, 0, - be32_to_cpu(eqe->event.qp.qpn) & - 0xffffff); + mlx4_slave_event(dev, 0, eqe); } else mlx4_qp_event(dev, be32_to_cpu(eqe->event.qp.qpn) & 0xffffff, eqe->type); @@ -275,9 +272,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: if (mlx4_is_master(dev)) { /* TODO: forward only to slave owning the SRQ */ - mlx4_slave_event(dev, 0, eqe->type, 0, - be32_to_cpu(eqe->event.srq.srqn) & - 0xffffff); + mlx4_slave_event(dev, 0, eqe); } else mlx4_srq_event(dev, be32_to_cpu(eqe->event.srq.srqn) & 0xffffff, eqe->type); @@ -295,20 +290,14 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) if (eqe->subtype == MLX4_PORT_CHANGE_SUBTYPE_DOWN) { mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_DOWN, port); - if (mlx4_is_master(dev)) { - mlx4_slave_event_all(dev, MLX4_EVENT_TYPE_PORT_CHANGE, - port, MLX4_DEV_EVENT_PORT_DOWN); - } mlx4_priv(dev)->sense.do_sense_port[port] = 1; } else { mlx4_dispatch_event(dev, MLX4_DEV_EVENT_PORT_UP, port); - if (mlx4_is_master(dev)) { - mlx4_slave_event_all(dev, MLX4_EVENT_TYPE_PORT_CHANGE, - port, MLX4_DEV_EVENT_PORT_UP); - } mlx4_priv(dev)->sense.do_sense_port[port] = 0; } + if (mlx4_is_master(dev)) + mlx4_slave_event_all(dev, eqe); break; case MLX4_EVENT_TYPE_CQ_ERROR: @@ -318,8 +307,7 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) be32_to_cpu(eqe->event.cq_err.cqn) & 0xffffff); if (mlx4_is_master(dev)) { /* TODO: forward only to slave owning the CQ */ - mlx4_slave_event(dev, 0, eqe->type, 0, - be32_to_cpu(eqe->event.cq_err.cqn)); + mlx4_slave_event(dev, 0, eqe); } else mlx4_cq_event(dev, be32_to_cpu(eqe->event.cq_err.cqn), eqe->type); @@ -329,6 +317,20 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) mlx4_warn(dev, "EQ overrun on EQN %d\n", eq->eqn); break; + case MLX4_EVENT_TYPE_COMM_CHANNEL: + if (!mlx4_is_master(dev)) { + mlx4_warn(dev, "Received comm channel event " + "for non master device\n"); + break; + } + memcpy(&priv->mfunc.master.comm_arm_bit_vector, + eqe->event.comm_channel_arm.bit_vec, + sizeof(u32) * COMM_CHANNEL_BIT_ARRAY_SIZE); + queue_work(priv->mfunc.master.comm_wq, + &priv->mfunc.master.comm_work); + break; + + case MLX4_EVENT_TYPE_EEC_CATAS_ERROR: case MLX4_EVENT_TYPE_ECC_DETECT: default: @@ -359,57 +361,6 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) return eqes_found; } -void mlx4_slave_async_eq_poll(struct work_struct *work) -{ - struct delayed_work *delay = container_of(work, struct delayed_work, work); - struct mlx4_mfunc *mfunc = container_of(delay, struct mlx4_mfunc, comm_work); - struct mlx4_priv *priv = container_of(mfunc, struct mlx4_priv, mfunc); - struct mlx4_dev *dev = &priv->dev; - struct mlx4_slave_eqe eqe; - int ret; - int i; - - for (i = 0; i < MLX4_MFUNC_MAX_EQES; i++) { - ret = mlx4_GET_EVENT(dev, &eqe); - if (ret || eqe.type == MLX4_EVENT_TYPE_NONE) - break; - - switch (eqe.type) { - case MLX4_EVENT_TYPE_PATH_MIG: - case MLX4_EVENT_TYPE_COMM_EST: - case MLX4_EVENT_TYPE_SQ_DRAINED: - case MLX4_EVENT_TYPE_SRQ_QP_LAST_WQE: - case MLX4_EVENT_TYPE_WQ_CATAS_ERROR: - case MLX4_EVENT_TYPE_PATH_MIG_FAILED: - case MLX4_EVENT_TYPE_WQ_INVAL_REQ_ERROR: - case MLX4_EVENT_TYPE_WQ_ACCESS_ERROR: - mlx4_qp_event(dev, eqe.param, eqe.type); - break; - - case MLX4_EVENT_TYPE_SRQ_LIMIT: - case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: - mlx4_srq_event(dev, eqe.param, eqe.type); - break; - - case MLX4_EVENT_TYPE_PORT_CHANGE: - mlx4_dispatch_event(dev, eqe.param, eqe.port); - break; - - case MLX4_EVENT_TYPE_CQ_ERROR: - mlx4_cq_event(dev, eqe.param, eqe.type); - break; - - case MLX4_EVENT_TYPE_EQ_OVERFLOW: - mlx4_warn(dev, "slave async EQ overrun\n"); - break; - - default: - mlx4_warn(dev, "Unhandled event:%02x\n", eqe.type); - } - } - queue_delayed_work(priv->mfunc.comm_wq, &priv->mfunc.comm_work, HZ); -} - static irqreturn_t mlx4_interrupt(int irq, void *dev_ptr) { struct mlx4_dev *dev = dev_ptr; @@ -436,6 +387,30 @@ static irqreturn_t mlx4_msi_x_interrupt(int irq, void *eq_ptr) return IRQ_HANDLED; } +int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, + struct mlx4_vhcr *vhcr, + struct mlx4_cmd_mailbox *inbox, + struct mlx4_cmd_mailbox *outbox) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_slave_event_eq_info *event_eq = + &priv->mfunc.master.slave_state[slave].event_eq; + u32 in_modifier = vhcr->in_modifier; + u32 eqn = in_modifier & 0x1FF; + u64 in_param = vhcr->in_param; + + if (in_modifier >> 31) { + /* unmap */ + event_eq->event_type &= ~in_param; + return 0; + } + + event_eq->eqn = eqn; + event_eq->event_type = in_param; + + return 0; +} + static int mlx4_MAP_EQ(struct mlx4_dev *dev, u64 event_mask, int unmap, int eq_num) { @@ -748,18 +723,16 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) } } - if (!mlx4_is_slave(dev)) { - err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, - (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, - &priv->eq_table.eq[dev->caps.num_comp_vectors]); - if (err) - goto err_out_comp; - } + err = mlx4_create_eq(dev, MLX4_NUM_ASYNC_EQE + MLX4_NUM_SPARE_EQE, + (dev->flags & MLX4_FLAG_MSI_X) ? dev->caps.num_comp_vectors : 0, + &priv->eq_table.eq[dev->caps.num_comp_vectors]); + if (err) + goto err_out_comp; if (dev->flags & MLX4_FLAG_MSI_X) { const char *eq_name; - for (i = 0; i < dev->caps.num_comp_vectors + !mlx4_is_slave(dev); ++i) { + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) { if (i < dev->caps.num_comp_vectors) { snprintf(priv->eq_table.irq_names + i * MLX4_IRQNAME_SIZE, @@ -797,22 +770,19 @@ int mlx4_init_eq_table(struct mlx4_dev *dev) priv->eq_table.have_irq = 1; } - if (!mlx4_is_slave(dev)) { /* hw async events cannot be shared */ - err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - if (err) - mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); - } + err = mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 0, + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); + if (err) + mlx4_warn(dev, "MAP_EQ for async EQ %d failed (%d)\n", + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn, err); - for (i = 0; i < dev->caps.num_comp_vectors + !(mlx4_is_slave(dev)); ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) eq_set_ci(&priv->eq_table.eq[i], 1); return 0; err_out_async: - if (!mlx4_is_slave(dev)) - mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); + mlx4_free_eq(dev, &priv->eq_table.eq[dev->caps.num_comp_vectors]); err_out_comp: i = dev->caps.num_comp_vectors; @@ -840,14 +810,12 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); int i; - if (!mlx4_is_slave(dev)) { - mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, - priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); - } + mlx4_MAP_EQ(dev, MLX4_ASYNC_EVENT_MASK, 1, + priv->eq_table.eq[dev->caps.num_comp_vectors].eqn); mlx4_free_irqs(dev); - for (i = 0; i < dev->caps.num_comp_vectors + !mlx4_is_slave(dev); ++i) + for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i) mlx4_free_eq(dev, &priv->eq_table.eq[i]); if (!mlx4_is_slave(dev)) diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index f7fed9a..78a6255 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -807,10 +807,10 @@ static void mlx4_slave_exit(struct mlx4_dev *dev) { struct mlx4_priv *priv = mlx4_priv(dev); - down(&priv->cmd.poll_sem); + down(&priv->cmd.slave_sem); if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) mlx4_warn(dev, "Failed to close slave function.\n"); - up(&priv->cmd.poll_sem); + up(&priv->cmd.slave_sem); } static void mlx4_close_hca(struct mlx4_dev *dev) @@ -830,7 +830,8 @@ static int mlx4_init_slave(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); u64 dma = (u64) priv->mfunc.vhcr_dma; - down(&priv->cmd.poll_sem); + down(&priv->cmd.slave_sem); + priv->cmd.max_cmds = 1; mlx4_warn(dev, "Sending reset\n"); if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME)) goto err; @@ -846,12 +847,12 @@ static int mlx4_init_slave(struct mlx4_dev *dev) goto err; if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME)) goto err; - up(&priv->cmd.poll_sem); + up(&priv->cmd.slave_sem); return 0; err: mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0); - up(&priv->cmd.poll_sem); + up(&priv->cmd.slave_sem); return -EIO; } @@ -1005,13 +1006,11 @@ static int mlx4_setup_hca(struct mlx4_dev *dev) goto err_mr_table_free; } - if (!mlx4_is_slave(dev)) { - err = mlx4_cmd_use_events(dev); - if (err) { - mlx4_err(dev, "Failed to switch to event-driven " - "firmware commands, aborting.\n"); - goto err_eq_table_free; - } + err = mlx4_cmd_use_events(dev); + if (err) { + mlx4_err(dev, "Failed to switch to event-driven " + "firmware commands, aborting.\n"); + goto err_eq_table_free; } err = mlx4_NOP(dev); @@ -1094,8 +1093,7 @@ err_cq_table_free: mlx4_cleanup_cq_table(dev); err_cmd_poll: - if (!mlx4_is_slave(dev)) - mlx4_cmd_use_polling(dev); + mlx4_cmd_use_polling(dev); err_eq_table_free: mlx4_cleanup_eq_table(dev); @@ -1126,10 +1124,11 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) int i; if (msi_x) { - /* The master only uses en event EQ, - * Each one of the slaves have 1 completion eq */ + /* In multifunction mode each function gets 2 msi-X vectors + * one for data path completions anf the other for asynch events + * or command completions */ if (mlx4_is_mfunc(dev)) - nreq = 1 + !!mlx4_is_master(dev); + nreq = 4; else nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, num_possible_cpus() + 1); @@ -1155,7 +1154,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) goto no_msi; } - dev->caps.num_comp_vectors = nreq - !mlx4_is_slave(dev); + dev->caps.num_comp_vectors = nreq - 1; for (i = 0; i < nreq; ++i) priv->eq_table.eq[i].irq = entries[i].vector; @@ -1470,12 +1469,6 @@ slave_start: pci_set_drvdata(pdev, dev); - /* Start serving comm channel: - * - In master function: poll for commands - * - in slave functions: poll for events - * TODO - enable comm channel interrupts */ - if (mlx4_is_mfunc(dev)) - queue_delayed_work(priv->mfunc.comm_wq, &priv->mfunc.comm_work, 0); return 0; err_port: @@ -1486,8 +1479,7 @@ err_port: mlx4_cleanup_qp_table(dev); mlx4_cleanup_srq_table(dev); mlx4_cleanup_cq_table(dev); - if (!mlx4_is_slave(dev)) - mlx4_cmd_use_polling(dev); + mlx4_cmd_use_polling(dev); mlx4_cleanup_eq_table(dev); mlx4_cleanup_mr_table(dev); mlx4_cleanup_pd_table(dev); @@ -1549,9 +1541,6 @@ static void mlx4_remove_one(struct pci_dev *pdev) int p; if (dev) { - /* Stop serving commands and events over comm channel */ - if (mlx4_is_mfunc(dev)) - cancel_delayed_work_sync(&priv->mfunc.comm_work); mlx4_stop_sense(dev); mlx4_unregister_device(dev); @@ -1564,8 +1553,7 @@ static void mlx4_remove_one(struct pci_dev *pdev) mlx4_cleanup_qp_table(dev); mlx4_cleanup_srq_table(dev); mlx4_cleanup_cq_table(dev); - if (!mlx4_is_slave(dev)) - mlx4_cmd_use_polling(dev); + mlx4_cmd_use_polling(dev); mlx4_cleanup_eq_table(dev); mlx4_cleanup_mr_table(dev); mlx4_cleanup_pd_table(dev); diff --git a/drivers/net/mlx4/mlx4.h b/drivers/net/mlx4/mlx4.h index 7a7f787..91803aa 100644 --- a/drivers/net/mlx4/mlx4.h +++ b/drivers/net/mlx4/mlx4.h @@ -178,6 +178,53 @@ struct mlx4_icm_table { struct mlx4_icm **icm; }; + +struct mlx4_eqe { + u8 reserved1; + u8 type; + u8 reserved2; + u8 subtype; + union { + u32 raw[6]; + struct { + __be32 cqn; + } __attribute__((packed)) comp; + struct { + u16 reserved1; + __be16 token; + u32 reserved2; + u8 reserved3[3]; + u8 status; + __be64 out_param; + } __attribute__((packed)) cmd; + struct { + __be32 qpn; + } __attribute__((packed)) qp; + struct { + __be32 srqn; + } __attribute__((packed)) srq; + struct { + __be32 cqn; + u32 reserved1; + u8 reserved2[3]; + u8 syndrome; + } __attribute__((packed)) cq_err; + struct { + u32 reserved1[2]; + __be32 port; + } __attribute__((packed)) port_change; + struct { + #define COMM_CHANNEL_BIT_ARRAY_SIZE 4 + u32 reserved; + u32 bit_vec[COMM_CHANNEL_BIT_ARRAY_SIZE]; + } __attribute__((packed)) comm_channel_arm; + } event; +#define ALL_SLAVES 0xff + u8 slave_id; + u8 reserved3[2]; + u8 owner; +} __attribute__((packed)); + struct mlx4_eq { struct mlx4_dev *dev; void __iomem *doorbell; @@ -190,6 +237,19 @@ struct mlx4_eq { struct mlx4_mtt mtt; }; +struct mlx4_slave_eqe { + u8 type; + u8 port; + u32 param; +}; + +struct mlx4_slave_event_eq_info { + u32 eqn; + bool use_int; + u16 token; + u64 event_type; +}; + struct mlx4_profile { int num_qp; int rdmarc_per_qp; @@ -218,12 +278,6 @@ struct mlx4_comm { u32 slave_read; }; -struct mlx4_slave_eqe { - u8 type; - u8 port; - u32 param; -}; - struct mlx4_mcast_entry { struct list_head list; u64 addr; @@ -250,6 +304,7 @@ struct mlx4_slave_state { u8 last_cmd; u8 init_port_mask; u8 pf_num; + bool active; u8 function; dma_addr_t vhcr_dma; u16 mtu[MLX4_MAX_PORTS + 1]; @@ -257,16 +312,31 @@ struct mlx4_slave_state { struct mlx4_slave_eqe eq[MLX4_MFUNC_MAX_EQES]; struct list_head mcast_filters[MLX4_MAX_PORTS + 1]; struct mlx4_vlan_fltr *vlan_filter[MLX4_MAX_PORTS + 1]; + struct mlx4_slave_event_eq_info event_eq; u16 eq_pi; u16 eq_ci; spinlock_t lock; }; +#define SLAVE_EVENT_EQ_SIZE 128 +struct mlx4_slave_event_eq { + u32 eqn; + u32 cons; + u32 prod; + struct mlx4_eqe event_eqe[SLAVE_EVENT_EQ_SIZE]; +}; + struct mlx4_mfunc_master_ctx { struct mlx4_slave_state *slave_state; int init_port_ref[MLX4_MAX_PORTS + 1]; u16 max_mtu[MLX4_MAX_PORTS + 1]; int disable_mcast_ref[MLX4_MAX_PORTS + 1]; + struct workqueue_struct *comm_wq; + struct work_struct comm_work; + struct work_struct slave_event_work; + u32 comm_arm_bit_vector[4]; + struct mlx4_eqe cmd_eqe; + struct mlx4_slave_event_eq slave_eq; }; struct mlx4_vhcr { @@ -282,8 +352,6 @@ struct mlx4_vhcr { struct mlx4_mfunc { struct mlx4_comm __iomem *comm; - struct workqueue_struct *comm_wq; - struct delayed_work comm_work; struct mlx4_vhcr *vhcr; dma_addr_t vhcr_dma; @@ -296,6 +364,7 @@ struct mlx4_cmd { struct mutex hcr_mutex; struct semaphore poll_sem; struct semaphore event_sem; + struct semaphore slave_sem; int max_cmds; spinlock_t context_lock; int free_head; @@ -522,7 +591,6 @@ void mlx4_free_ownership(struct mlx4_dev *dev); int mlx4_alloc_eq_table(struct mlx4_dev *dev); void mlx4_free_eq_table(struct mlx4_dev *dev); -void mlx4_slave_event(struct mlx4_dev *dev, int slave, u8 type, u8 port, u32 param); int mlx4_GET_EVENT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, struct mlx4_cmd_mailbox *outbox); @@ -576,7 +644,16 @@ u64 mlx4_make_profile(struct mlx4_dev *dev, struct mlx4_profile *request, struct mlx4_dev_cap *dev_cap, struct mlx4_init_hca_param *init_hca); -void mlx4_slave_async_eq_poll(struct work_struct *work); +void mlx4_master_comm_channel(struct work_struct *work); +void mlx4_gen_slave_eqe(struct work_struct *work); + +int mlx4_MAP_EQ_wrapper(struct mlx4_dev *dev, int slave, + struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, + struct mlx4_cmd_mailbox *outbox); +int mlx4_COMM_INT_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, + struct mlx4_cmd_mailbox *inbox, + struct mlx4_cmd_mailbox *outbox); +int mlx4_GEN_EQE(struct mlx4_dev *dev, int slave, struct mlx4_eqe *eqe); int mlx4_cmd_init(struct mlx4_dev *dev); void mlx4_cmd_cleanup(struct mlx4_dev *dev); diff --git a/include/linux/mlx4/cmd.h b/include/linux/mlx4/cmd.h index 9225791..a6901c3 100644 --- a/include/linux/mlx4/cmd.h +++ b/include/linux/mlx4/cmd.h @@ -125,6 +125,10 @@ enum { MLX4_CMD_SET_MCAST_FLTR = 0x48, MLX4_CMD_DUMP_ETH_STATS = 0x49, + /* Communication channel commands */ + MLX4_CMD_ARM_COMM_CHANNEL = 0x57, + MLX4_CMD_GEN_EQE = 0x58, + /* virtual commands */ MLX4_CMD_ALLOC_RES = 0xf00, MLX4_CMD_FREE_RES = 0xf01, @@ -132,7 +136,8 @@ enum { MLX4_CMD_GET_EVENT = 0xf03, MLX4_CMD_QUERY_SLAVE_CAP = 0xf04, MLX4_CMD_MCAST_ATTACH = 0xf05, - MLX4_CMD_PROMISC = 0xf07, + MLX4_CMD_COMM_INT = 0xf07, + MLX4_CMD_PROMISC = 0xf08, /* debug commands */ MLX4_CMD_QUERY_DEBUG_MSG = 0x2a, diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index c03a176..1b553b0 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -101,6 +101,7 @@ enum mlx4_event { MLX4_EVENT_TYPE_EQ_OVERFLOW = 0x0f, MLX4_EVENT_TYPE_ECC_DETECT = 0x0e, MLX4_EVENT_TYPE_CMD = 0x0a, + MLX4_EVENT_TYPE_COMM_CHANNEL = 0x18, MLX4_EVENT_TYPE_NONE = 0xff, };