15a2cc190SJeff Kirsher /* 25a2cc190SJeff Kirsher * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 35a2cc190SJeff Kirsher * Copyright (c) 2005, 2006, 2007, 2008 Mellanox Technologies. All rights reserved. 45a2cc190SJeff Kirsher * Copyright (c) 2005, 2006, 2007 Cisco Systems, Inc. All rights reserved. 55a2cc190SJeff Kirsher * 65a2cc190SJeff Kirsher * This software is available to you under a choice of one of two 75a2cc190SJeff Kirsher * licenses. You may choose to be licensed under the terms of the GNU 85a2cc190SJeff Kirsher * General Public License (GPL) Version 2, available from the file 95a2cc190SJeff Kirsher * COPYING in the main directory of this source tree, or the 105a2cc190SJeff Kirsher * OpenIB.org BSD license below: 115a2cc190SJeff Kirsher * 125a2cc190SJeff Kirsher * Redistribution and use in source and binary forms, with or 135a2cc190SJeff Kirsher * without modification, are permitted provided that the following 145a2cc190SJeff Kirsher * conditions are met: 155a2cc190SJeff Kirsher * 165a2cc190SJeff Kirsher * - Redistributions of source code must retain the above 175a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following 185a2cc190SJeff Kirsher * disclaimer. 195a2cc190SJeff Kirsher * 205a2cc190SJeff Kirsher * - Redistributions in binary form must reproduce the above 215a2cc190SJeff Kirsher * copyright notice, this list of conditions and the following 225a2cc190SJeff Kirsher * disclaimer in the documentation and/or other materials 235a2cc190SJeff Kirsher * provided with the distribution. 245a2cc190SJeff Kirsher * 255a2cc190SJeff Kirsher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 265a2cc190SJeff Kirsher * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 275a2cc190SJeff Kirsher * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 285a2cc190SJeff Kirsher * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 295a2cc190SJeff Kirsher * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 305a2cc190SJeff Kirsher * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 315a2cc190SJeff Kirsher * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 325a2cc190SJeff Kirsher * SOFTWARE. 335a2cc190SJeff Kirsher */ 345a2cc190SJeff Kirsher 355a2cc190SJeff Kirsher #include <linux/sched.h> 365a2cc190SJeff Kirsher #include <linux/slab.h> 37ee40fa06SPaul Gortmaker #include <linux/export.h> 385a2cc190SJeff Kirsher #include <linux/pci.h> 395a2cc190SJeff Kirsher #include <linux/errno.h> 405a2cc190SJeff Kirsher 415a2cc190SJeff Kirsher #include <linux/mlx4/cmd.h> 425a2cc190SJeff Kirsher 435a2cc190SJeff Kirsher #include <asm/io.h> 445a2cc190SJeff Kirsher 455a2cc190SJeff Kirsher #include "mlx4.h" 465a2cc190SJeff Kirsher 475a2cc190SJeff Kirsher #define CMD_POLL_TOKEN 0xffff 485a2cc190SJeff Kirsher 495a2cc190SJeff Kirsher enum { 505a2cc190SJeff Kirsher /* command completed successfully: */ 515a2cc190SJeff Kirsher CMD_STAT_OK = 0x00, 525a2cc190SJeff Kirsher /* Internal error (such as a bus error) occurred while processing command: */ 535a2cc190SJeff Kirsher CMD_STAT_INTERNAL_ERR = 0x01, 545a2cc190SJeff Kirsher /* Operation/command not supported or opcode modifier not supported: */ 555a2cc190SJeff Kirsher CMD_STAT_BAD_OP = 0x02, 565a2cc190SJeff Kirsher /* Parameter not supported or parameter out of range: */ 575a2cc190SJeff Kirsher CMD_STAT_BAD_PARAM = 0x03, 585a2cc190SJeff Kirsher /* System not enabled or bad system state: */ 595a2cc190SJeff Kirsher CMD_STAT_BAD_SYS_STATE = 0x04, 605a2cc190SJeff Kirsher /* Attempt to access reserved or unallocaterd resource: */ 615a2cc190SJeff Kirsher CMD_STAT_BAD_RESOURCE = 0x05, 625a2cc190SJeff Kirsher /* Requested resource is currently executing a command, or is otherwise busy: */ 635a2cc190SJeff Kirsher CMD_STAT_RESOURCE_BUSY = 0x06, 645a2cc190SJeff Kirsher /* Required capability exceeds device limits: */ 655a2cc190SJeff Kirsher CMD_STAT_EXCEED_LIM = 0x08, 665a2cc190SJeff Kirsher /* Resource is not in the appropriate state or ownership: */ 675a2cc190SJeff Kirsher CMD_STAT_BAD_RES_STATE = 0x09, 685a2cc190SJeff Kirsher /* Index out of range: */ 695a2cc190SJeff Kirsher CMD_STAT_BAD_INDEX = 0x0a, 705a2cc190SJeff Kirsher /* FW image corrupted: */ 715a2cc190SJeff Kirsher CMD_STAT_BAD_NVMEM = 0x0b, 725a2cc190SJeff Kirsher /* Error in ICM mapping (e.g. not enough auxiliary ICM pages to execute command): */ 735a2cc190SJeff Kirsher CMD_STAT_ICM_ERROR = 0x0c, 745a2cc190SJeff Kirsher /* Attempt to modify a QP/EE which is not in the presumed state: */ 755a2cc190SJeff Kirsher CMD_STAT_BAD_QP_STATE = 0x10, 765a2cc190SJeff Kirsher /* Bad segment parameters (Address/Size): */ 775a2cc190SJeff Kirsher CMD_STAT_BAD_SEG_PARAM = 0x20, 785a2cc190SJeff Kirsher /* Memory Region has Memory Windows bound to: */ 795a2cc190SJeff Kirsher CMD_STAT_REG_BOUND = 0x21, 805a2cc190SJeff Kirsher /* HCA local attached memory not present: */ 815a2cc190SJeff Kirsher CMD_STAT_LAM_NOT_PRE = 0x22, 825a2cc190SJeff Kirsher /* Bad management packet (silently discarded): */ 835a2cc190SJeff Kirsher CMD_STAT_BAD_PKT = 0x30, 845a2cc190SJeff Kirsher /* More outstanding CQEs in CQ than new CQ size: */ 855a2cc190SJeff Kirsher CMD_STAT_BAD_SIZE = 0x40, 865a2cc190SJeff Kirsher /* Multi Function device support required: */ 875a2cc190SJeff Kirsher CMD_STAT_MULTI_FUNC_REQ = 0x50, 885a2cc190SJeff Kirsher }; 895a2cc190SJeff Kirsher 905a2cc190SJeff Kirsher enum { 915a2cc190SJeff Kirsher HCR_IN_PARAM_OFFSET = 0x00, 925a2cc190SJeff Kirsher HCR_IN_MODIFIER_OFFSET = 0x08, 935a2cc190SJeff Kirsher HCR_OUT_PARAM_OFFSET = 0x0c, 945a2cc190SJeff Kirsher HCR_TOKEN_OFFSET = 0x14, 955a2cc190SJeff Kirsher HCR_STATUS_OFFSET = 0x18, 965a2cc190SJeff Kirsher 975a2cc190SJeff Kirsher HCR_OPMOD_SHIFT = 12, 985a2cc190SJeff Kirsher HCR_T_BIT = 21, 995a2cc190SJeff Kirsher HCR_E_BIT = 22, 1005a2cc190SJeff Kirsher HCR_GO_BIT = 23 1015a2cc190SJeff Kirsher }; 1025a2cc190SJeff Kirsher 1035a2cc190SJeff Kirsher enum { 1045a2cc190SJeff Kirsher GO_BIT_TIMEOUT_MSECS = 10000 1055a2cc190SJeff Kirsher }; 1065a2cc190SJeff Kirsher 1075a2cc190SJeff Kirsher struct mlx4_cmd_context { 1085a2cc190SJeff Kirsher struct completion done; 1095a2cc190SJeff Kirsher int result; 1105a2cc190SJeff Kirsher int next; 1115a2cc190SJeff Kirsher u64 out_param; 1125a2cc190SJeff Kirsher u16 token; 1135a2cc190SJeff Kirsher }; 1145a2cc190SJeff Kirsher 1155a2cc190SJeff Kirsher static int mlx4_status_to_errno(u8 status) 1165a2cc190SJeff Kirsher { 1175a2cc190SJeff Kirsher static const int trans_table[] = { 1185a2cc190SJeff Kirsher [CMD_STAT_INTERNAL_ERR] = -EIO, 1195a2cc190SJeff Kirsher [CMD_STAT_BAD_OP] = -EPERM, 1205a2cc190SJeff Kirsher [CMD_STAT_BAD_PARAM] = -EINVAL, 1215a2cc190SJeff Kirsher [CMD_STAT_BAD_SYS_STATE] = -ENXIO, 1225a2cc190SJeff Kirsher [CMD_STAT_BAD_RESOURCE] = -EBADF, 1235a2cc190SJeff Kirsher [CMD_STAT_RESOURCE_BUSY] = -EBUSY, 1245a2cc190SJeff Kirsher [CMD_STAT_EXCEED_LIM] = -ENOMEM, 1255a2cc190SJeff Kirsher [CMD_STAT_BAD_RES_STATE] = -EBADF, 1265a2cc190SJeff Kirsher [CMD_STAT_BAD_INDEX] = -EBADF, 1275a2cc190SJeff Kirsher [CMD_STAT_BAD_NVMEM] = -EFAULT, 1285a2cc190SJeff Kirsher [CMD_STAT_ICM_ERROR] = -ENFILE, 1295a2cc190SJeff Kirsher [CMD_STAT_BAD_QP_STATE] = -EINVAL, 1305a2cc190SJeff Kirsher [CMD_STAT_BAD_SEG_PARAM] = -EFAULT, 1315a2cc190SJeff Kirsher [CMD_STAT_REG_BOUND] = -EBUSY, 1325a2cc190SJeff Kirsher [CMD_STAT_LAM_NOT_PRE] = -EAGAIN, 1335a2cc190SJeff Kirsher [CMD_STAT_BAD_PKT] = -EINVAL, 1345a2cc190SJeff Kirsher [CMD_STAT_BAD_SIZE] = -ENOMEM, 1355a2cc190SJeff Kirsher [CMD_STAT_MULTI_FUNC_REQ] = -EACCES, 1365a2cc190SJeff Kirsher }; 1375a2cc190SJeff Kirsher 1385a2cc190SJeff Kirsher if (status >= ARRAY_SIZE(trans_table) || 1395a2cc190SJeff Kirsher (status != CMD_STAT_OK && trans_table[status] == 0)) 1405a2cc190SJeff Kirsher return -EIO; 1415a2cc190SJeff Kirsher 1425a2cc190SJeff Kirsher return trans_table[status]; 1435a2cc190SJeff Kirsher } 1445a2cc190SJeff Kirsher 1455a2cc190SJeff Kirsher static int cmd_pending(struct mlx4_dev *dev) 1465a2cc190SJeff Kirsher { 1475a2cc190SJeff Kirsher u32 status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET); 1485a2cc190SJeff Kirsher 1495a2cc190SJeff Kirsher return (status & swab32(1 << HCR_GO_BIT)) || 1505a2cc190SJeff Kirsher (mlx4_priv(dev)->cmd.toggle == 1515a2cc190SJeff Kirsher !!(status & swab32(1 << HCR_T_BIT))); 1525a2cc190SJeff Kirsher } 1535a2cc190SJeff Kirsher 1545a2cc190SJeff Kirsher static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param, 1555a2cc190SJeff Kirsher u32 in_modifier, u8 op_modifier, u16 op, u16 token, 1565a2cc190SJeff Kirsher int event) 1575a2cc190SJeff Kirsher { 1585a2cc190SJeff Kirsher struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 1595a2cc190SJeff Kirsher u32 __iomem *hcr = cmd->hcr; 1605a2cc190SJeff Kirsher int ret = -EAGAIN; 1615a2cc190SJeff Kirsher unsigned long end; 1625a2cc190SJeff Kirsher 1635a2cc190SJeff Kirsher mutex_lock(&cmd->hcr_mutex); 1645a2cc190SJeff Kirsher 1655a2cc190SJeff Kirsher end = jiffies; 1665a2cc190SJeff Kirsher if (event) 1675a2cc190SJeff Kirsher end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS); 1685a2cc190SJeff Kirsher 1695a2cc190SJeff Kirsher while (cmd_pending(dev)) { 1705a2cc190SJeff Kirsher if (time_after_eq(jiffies, end)) 1715a2cc190SJeff Kirsher goto out; 1725a2cc190SJeff Kirsher cond_resched(); 1735a2cc190SJeff Kirsher } 1745a2cc190SJeff Kirsher 1755a2cc190SJeff Kirsher /* 1765a2cc190SJeff Kirsher * We use writel (instead of something like memcpy_toio) 1775a2cc190SJeff Kirsher * because writes of less than 32 bits to the HCR don't work 1785a2cc190SJeff Kirsher * (and some architectures such as ia64 implement memcpy_toio 1795a2cc190SJeff Kirsher * in terms of writeb). 1805a2cc190SJeff Kirsher */ 1815a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_param >> 32), hcr + 0); 1825a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_param & 0xfffffffful), hcr + 1); 1835a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(in_modifier), hcr + 2); 1845a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(out_param >> 32), hcr + 3); 1855a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(out_param & 0xfffffffful), hcr + 4); 1865a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32(token << 16), hcr + 5); 1875a2cc190SJeff Kirsher 1885a2cc190SJeff Kirsher /* __raw_writel may not order writes. */ 1895a2cc190SJeff Kirsher wmb(); 1905a2cc190SJeff Kirsher 1915a2cc190SJeff Kirsher __raw_writel((__force u32) cpu_to_be32((1 << HCR_GO_BIT) | 1925a2cc190SJeff Kirsher (cmd->toggle << HCR_T_BIT) | 1935a2cc190SJeff Kirsher (event ? (1 << HCR_E_BIT) : 0) | 1945a2cc190SJeff Kirsher (op_modifier << HCR_OPMOD_SHIFT) | 1955a2cc190SJeff Kirsher op), hcr + 6); 1965a2cc190SJeff Kirsher 1975a2cc190SJeff Kirsher /* 1985a2cc190SJeff Kirsher * Make sure that our HCR writes don't get mixed in with 1995a2cc190SJeff Kirsher * writes from another CPU starting a FW command. 2005a2cc190SJeff Kirsher */ 2015a2cc190SJeff Kirsher mmiowb(); 2025a2cc190SJeff Kirsher 2035a2cc190SJeff Kirsher cmd->toggle = cmd->toggle ^ 1; 2045a2cc190SJeff Kirsher 2055a2cc190SJeff Kirsher ret = 0; 2065a2cc190SJeff Kirsher 2075a2cc190SJeff Kirsher out: 2085a2cc190SJeff Kirsher mutex_unlock(&cmd->hcr_mutex); 2095a2cc190SJeff Kirsher return ret; 2105a2cc190SJeff Kirsher } 2115a2cc190SJeff Kirsher 2125a2cc190SJeff Kirsher static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 2135a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 2145a2cc190SJeff Kirsher u16 op, unsigned long timeout) 2155a2cc190SJeff Kirsher { 2165a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 2175a2cc190SJeff Kirsher void __iomem *hcr = priv->cmd.hcr; 2185a2cc190SJeff Kirsher int err = 0; 2195a2cc190SJeff Kirsher unsigned long end; 2205a2cc190SJeff Kirsher 2215a2cc190SJeff Kirsher down(&priv->cmd.poll_sem); 2225a2cc190SJeff Kirsher 2235a2cc190SJeff Kirsher err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 2245a2cc190SJeff Kirsher in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0); 2255a2cc190SJeff Kirsher if (err) 2265a2cc190SJeff Kirsher goto out; 2275a2cc190SJeff Kirsher 2285a2cc190SJeff Kirsher end = msecs_to_jiffies(timeout) + jiffies; 2295a2cc190SJeff Kirsher while (cmd_pending(dev) && time_before(jiffies, end)) 2305a2cc190SJeff Kirsher cond_resched(); 2315a2cc190SJeff Kirsher 2325a2cc190SJeff Kirsher if (cmd_pending(dev)) { 2335a2cc190SJeff Kirsher err = -ETIMEDOUT; 2345a2cc190SJeff Kirsher goto out; 2355a2cc190SJeff Kirsher } 2365a2cc190SJeff Kirsher 2375a2cc190SJeff Kirsher if (out_is_imm) 2385a2cc190SJeff Kirsher *out_param = 2395a2cc190SJeff Kirsher (u64) be32_to_cpu((__force __be32) 2405a2cc190SJeff Kirsher __raw_readl(hcr + HCR_OUT_PARAM_OFFSET)) << 32 | 2415a2cc190SJeff Kirsher (u64) be32_to_cpu((__force __be32) 2425a2cc190SJeff Kirsher __raw_readl(hcr + HCR_OUT_PARAM_OFFSET + 4)); 2435a2cc190SJeff Kirsher 2445a2cc190SJeff Kirsher err = mlx4_status_to_errno(be32_to_cpu((__force __be32) 2455a2cc190SJeff Kirsher __raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24); 2465a2cc190SJeff Kirsher 2475a2cc190SJeff Kirsher out: 2485a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 2495a2cc190SJeff Kirsher return err; 2505a2cc190SJeff Kirsher } 2515a2cc190SJeff Kirsher 2525a2cc190SJeff Kirsher void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param) 2535a2cc190SJeff Kirsher { 2545a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 2555a2cc190SJeff Kirsher struct mlx4_cmd_context *context = 2565a2cc190SJeff Kirsher &priv->cmd.context[token & priv->cmd.token_mask]; 2575a2cc190SJeff Kirsher 2585a2cc190SJeff Kirsher /* previously timed out command completing at long last */ 2595a2cc190SJeff Kirsher if (token != context->token) 2605a2cc190SJeff Kirsher return; 2615a2cc190SJeff Kirsher 2625a2cc190SJeff Kirsher context->result = mlx4_status_to_errno(status); 2635a2cc190SJeff Kirsher context->out_param = out_param; 2645a2cc190SJeff Kirsher 2655a2cc190SJeff Kirsher complete(&context->done); 2665a2cc190SJeff Kirsher } 2675a2cc190SJeff Kirsher 2685a2cc190SJeff Kirsher static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 2695a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 2705a2cc190SJeff Kirsher u16 op, unsigned long timeout) 2715a2cc190SJeff Kirsher { 2725a2cc190SJeff Kirsher struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd; 2735a2cc190SJeff Kirsher struct mlx4_cmd_context *context; 2745a2cc190SJeff Kirsher int err = 0; 2755a2cc190SJeff Kirsher 2765a2cc190SJeff Kirsher down(&cmd->event_sem); 2775a2cc190SJeff Kirsher 2785a2cc190SJeff Kirsher spin_lock(&cmd->context_lock); 2795a2cc190SJeff Kirsher BUG_ON(cmd->free_head < 0); 2805a2cc190SJeff Kirsher context = &cmd->context[cmd->free_head]; 2815a2cc190SJeff Kirsher context->token += cmd->token_mask + 1; 2825a2cc190SJeff Kirsher cmd->free_head = context->next; 2835a2cc190SJeff Kirsher spin_unlock(&cmd->context_lock); 2845a2cc190SJeff Kirsher 2855a2cc190SJeff Kirsher init_completion(&context->done); 2865a2cc190SJeff Kirsher 2875a2cc190SJeff Kirsher mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0, 2885a2cc190SJeff Kirsher in_modifier, op_modifier, op, context->token, 1); 2895a2cc190SJeff Kirsher 2905a2cc190SJeff Kirsher if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { 2915a2cc190SJeff Kirsher err = -EBUSY; 2925a2cc190SJeff Kirsher goto out; 2935a2cc190SJeff Kirsher } 2945a2cc190SJeff Kirsher 2955a2cc190SJeff Kirsher err = context->result; 2965a2cc190SJeff Kirsher if (err) 2975a2cc190SJeff Kirsher goto out; 2985a2cc190SJeff Kirsher 2995a2cc190SJeff Kirsher if (out_is_imm) 3005a2cc190SJeff Kirsher *out_param = context->out_param; 3015a2cc190SJeff Kirsher 3025a2cc190SJeff Kirsher out: 3035a2cc190SJeff Kirsher spin_lock(&cmd->context_lock); 3045a2cc190SJeff Kirsher context->next = cmd->free_head; 3055a2cc190SJeff Kirsher cmd->free_head = context - cmd->context; 3065a2cc190SJeff Kirsher spin_unlock(&cmd->context_lock); 3075a2cc190SJeff Kirsher 3085a2cc190SJeff Kirsher up(&cmd->event_sem); 3095a2cc190SJeff Kirsher return err; 3105a2cc190SJeff Kirsher } 3115a2cc190SJeff Kirsher 3125a2cc190SJeff Kirsher int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param, 3135a2cc190SJeff Kirsher int out_is_imm, u32 in_modifier, u8 op_modifier, 314*f9baff50SJack Morgenstein u16 op, unsigned long timeout, int native) 3155a2cc190SJeff Kirsher { 3165a2cc190SJeff Kirsher if (mlx4_priv(dev)->cmd.use_events) 3175a2cc190SJeff Kirsher return mlx4_cmd_wait(dev, in_param, out_param, out_is_imm, 3185a2cc190SJeff Kirsher in_modifier, op_modifier, op, timeout); 3195a2cc190SJeff Kirsher else 3205a2cc190SJeff Kirsher return mlx4_cmd_poll(dev, in_param, out_param, out_is_imm, 3215a2cc190SJeff Kirsher in_modifier, op_modifier, op, timeout); 3225a2cc190SJeff Kirsher } 3235a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(__mlx4_cmd); 3245a2cc190SJeff Kirsher 3255a2cc190SJeff Kirsher int mlx4_cmd_init(struct mlx4_dev *dev) 3265a2cc190SJeff Kirsher { 3275a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 3285a2cc190SJeff Kirsher 3295a2cc190SJeff Kirsher mutex_init(&priv->cmd.hcr_mutex); 3305a2cc190SJeff Kirsher sema_init(&priv->cmd.poll_sem, 1); 3315a2cc190SJeff Kirsher priv->cmd.use_events = 0; 3325a2cc190SJeff Kirsher priv->cmd.toggle = 1; 3335a2cc190SJeff Kirsher 3345a2cc190SJeff Kirsher priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_HCR_BASE, 3355a2cc190SJeff Kirsher MLX4_HCR_SIZE); 3365a2cc190SJeff Kirsher if (!priv->cmd.hcr) { 3375a2cc190SJeff Kirsher mlx4_err(dev, "Couldn't map command register."); 3385a2cc190SJeff Kirsher return -ENOMEM; 3395a2cc190SJeff Kirsher } 3405a2cc190SJeff Kirsher 3415a2cc190SJeff Kirsher priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev, 3425a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 3435a2cc190SJeff Kirsher MLX4_MAILBOX_SIZE, 0); 3445a2cc190SJeff Kirsher if (!priv->cmd.pool) { 3455a2cc190SJeff Kirsher iounmap(priv->cmd.hcr); 3465a2cc190SJeff Kirsher return -ENOMEM; 3475a2cc190SJeff Kirsher } 3485a2cc190SJeff Kirsher 3495a2cc190SJeff Kirsher return 0; 3505a2cc190SJeff Kirsher } 3515a2cc190SJeff Kirsher 3525a2cc190SJeff Kirsher void mlx4_cmd_cleanup(struct mlx4_dev *dev) 3535a2cc190SJeff Kirsher { 3545a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 3555a2cc190SJeff Kirsher 3565a2cc190SJeff Kirsher pci_pool_destroy(priv->cmd.pool); 3575a2cc190SJeff Kirsher iounmap(priv->cmd.hcr); 3585a2cc190SJeff Kirsher } 3595a2cc190SJeff Kirsher 3605a2cc190SJeff Kirsher /* 3615a2cc190SJeff Kirsher * Switch to using events to issue FW commands (can only be called 3625a2cc190SJeff Kirsher * after event queue for command events has been initialized). 3635a2cc190SJeff Kirsher */ 3645a2cc190SJeff Kirsher int mlx4_cmd_use_events(struct mlx4_dev *dev) 3655a2cc190SJeff Kirsher { 3665a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 3675a2cc190SJeff Kirsher int i; 3685a2cc190SJeff Kirsher 3695a2cc190SJeff Kirsher priv->cmd.context = kmalloc(priv->cmd.max_cmds * 3705a2cc190SJeff Kirsher sizeof (struct mlx4_cmd_context), 3715a2cc190SJeff Kirsher GFP_KERNEL); 3725a2cc190SJeff Kirsher if (!priv->cmd.context) 3735a2cc190SJeff Kirsher return -ENOMEM; 3745a2cc190SJeff Kirsher 3755a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) { 3765a2cc190SJeff Kirsher priv->cmd.context[i].token = i; 3775a2cc190SJeff Kirsher priv->cmd.context[i].next = i + 1; 3785a2cc190SJeff Kirsher } 3795a2cc190SJeff Kirsher 3805a2cc190SJeff Kirsher priv->cmd.context[priv->cmd.max_cmds - 1].next = -1; 3815a2cc190SJeff Kirsher priv->cmd.free_head = 0; 3825a2cc190SJeff Kirsher 3835a2cc190SJeff Kirsher sema_init(&priv->cmd.event_sem, priv->cmd.max_cmds); 3845a2cc190SJeff Kirsher spin_lock_init(&priv->cmd.context_lock); 3855a2cc190SJeff Kirsher 3865a2cc190SJeff Kirsher for (priv->cmd.token_mask = 1; 3875a2cc190SJeff Kirsher priv->cmd.token_mask < priv->cmd.max_cmds; 3885a2cc190SJeff Kirsher priv->cmd.token_mask <<= 1) 3895a2cc190SJeff Kirsher ; /* nothing */ 3905a2cc190SJeff Kirsher --priv->cmd.token_mask; 3915a2cc190SJeff Kirsher 3925a2cc190SJeff Kirsher priv->cmd.use_events = 1; 3935a2cc190SJeff Kirsher 3945a2cc190SJeff Kirsher down(&priv->cmd.poll_sem); 3955a2cc190SJeff Kirsher 3965a2cc190SJeff Kirsher return 0; 3975a2cc190SJeff Kirsher } 3985a2cc190SJeff Kirsher 3995a2cc190SJeff Kirsher /* 4005a2cc190SJeff Kirsher * Switch back to polling (used when shutting down the device) 4015a2cc190SJeff Kirsher */ 4025a2cc190SJeff Kirsher void mlx4_cmd_use_polling(struct mlx4_dev *dev) 4035a2cc190SJeff Kirsher { 4045a2cc190SJeff Kirsher struct mlx4_priv *priv = mlx4_priv(dev); 4055a2cc190SJeff Kirsher int i; 4065a2cc190SJeff Kirsher 4075a2cc190SJeff Kirsher priv->cmd.use_events = 0; 4085a2cc190SJeff Kirsher 4095a2cc190SJeff Kirsher for (i = 0; i < priv->cmd.max_cmds; ++i) 4105a2cc190SJeff Kirsher down(&priv->cmd.event_sem); 4115a2cc190SJeff Kirsher 4125a2cc190SJeff Kirsher kfree(priv->cmd.context); 4135a2cc190SJeff Kirsher 4145a2cc190SJeff Kirsher up(&priv->cmd.poll_sem); 4155a2cc190SJeff Kirsher } 4165a2cc190SJeff Kirsher 4175a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mlx4_alloc_cmd_mailbox(struct mlx4_dev *dev) 4185a2cc190SJeff Kirsher { 4195a2cc190SJeff Kirsher struct mlx4_cmd_mailbox *mailbox; 4205a2cc190SJeff Kirsher 4215a2cc190SJeff Kirsher mailbox = kmalloc(sizeof *mailbox, GFP_KERNEL); 4225a2cc190SJeff Kirsher if (!mailbox) 4235a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 4245a2cc190SJeff Kirsher 4255a2cc190SJeff Kirsher mailbox->buf = pci_pool_alloc(mlx4_priv(dev)->cmd.pool, GFP_KERNEL, 4265a2cc190SJeff Kirsher &mailbox->dma); 4275a2cc190SJeff Kirsher if (!mailbox->buf) { 4285a2cc190SJeff Kirsher kfree(mailbox); 4295a2cc190SJeff Kirsher return ERR_PTR(-ENOMEM); 4305a2cc190SJeff Kirsher } 4315a2cc190SJeff Kirsher 4325a2cc190SJeff Kirsher return mailbox; 4335a2cc190SJeff Kirsher } 4345a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_alloc_cmd_mailbox); 4355a2cc190SJeff Kirsher 4365a2cc190SJeff Kirsher void mlx4_free_cmd_mailbox(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox) 4375a2cc190SJeff Kirsher { 4385a2cc190SJeff Kirsher if (!mailbox) 4395a2cc190SJeff Kirsher return; 4405a2cc190SJeff Kirsher 4415a2cc190SJeff Kirsher pci_pool_free(mlx4_priv(dev)->cmd.pool, mailbox->buf, mailbox->dma); 4425a2cc190SJeff Kirsher kfree(mailbox); 4435a2cc190SJeff Kirsher } 4445a2cc190SJeff Kirsher EXPORT_SYMBOL_GPL(mlx4_free_cmd_mailbox); 445